159 lines
5.5 KiB
TypeScript
159 lines
5.5 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import { Link, useSearchParams } from "react-router-dom";
|
|
import { HeaderMobile } from "../components/HeaderMobile";
|
|
import { MobileShell } from "../components/MobileShell";
|
|
import { DynamicFeedbackForm } from "../components/DynamicFeedbackForm";
|
|
import { useAutoNavigateToLiveQuizPoll } from "../hooks/useAutoNavigateToLiveQuizPoll";
|
|
import { useEventRegistrationSettings } from "../hooks/useEventRegistrationSettings";
|
|
import {
|
|
getVisitorFeedbackFormSchema,
|
|
getVisitorLoginPreview,
|
|
resolveVisitorFeedbackFormSchema,
|
|
type VisitorPublicFeedbackForm,
|
|
} from "../lib/api";
|
|
import { readStoredVisitorContext } from "../types/visitorContext";
|
|
|
|
export function FeedbackPage() {
|
|
const [searchParams] = useSearchParams();
|
|
const formId = searchParams.get("form_id")?.trim() || "";
|
|
const urlEventId = searchParams.get("event_id")?.trim() || "";
|
|
const urlSessionId = searchParams.get("session_id")?.trim() || "";
|
|
const ctx = readStoredVisitorContext();
|
|
const eventId = urlEventId || ctx?.eventId || "";
|
|
const sessionId = urlSessionId || ctx?.sessionId || "";
|
|
|
|
useAutoNavigateToLiveQuizPoll({
|
|
eventId,
|
|
sessionId,
|
|
enabled: Boolean(eventId && sessionId),
|
|
});
|
|
|
|
const [eventSnapshot, setEventSnapshot] = useState(
|
|
ctx?.eventId === eventId && ctx.event ? ctx.event : null,
|
|
);
|
|
const [schema, setSchema] = useState<VisitorPublicFeedbackForm | null>(null);
|
|
const [schemaLoading, setSchemaLoading] = useState(false);
|
|
const [schemaErr, setSchemaErr] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
if (!eventId) {
|
|
setEventSnapshot(null);
|
|
return;
|
|
}
|
|
if (ctx?.eventId === eventId && ctx.event) {
|
|
setEventSnapshot(ctx.event);
|
|
return;
|
|
}
|
|
let cancelled = false;
|
|
getVisitorLoginPreview(eventId)
|
|
.then((ev) => {
|
|
if (!cancelled) setEventSnapshot(ev);
|
|
})
|
|
.catch(() => {
|
|
if (!cancelled) setEventSnapshot(null);
|
|
});
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, [eventId, ctx?.eventId, ctx?.event]);
|
|
|
|
useEffect(() => {
|
|
if (!eventId) {
|
|
setSchema(null);
|
|
setSchemaErr(null);
|
|
setSchemaLoading(false);
|
|
return;
|
|
}
|
|
|
|
let cancelled = false;
|
|
setSchemaLoading(true);
|
|
setSchemaErr(null);
|
|
|
|
const load = formId
|
|
? getVisitorFeedbackFormSchema(eventId, formId)
|
|
: resolveVisitorFeedbackFormSchema(eventId, { sessionId, purpose: "feedback" });
|
|
|
|
load
|
|
.then((s) => {
|
|
if (!cancelled) setSchema(s);
|
|
})
|
|
.catch((e) => {
|
|
if (!cancelled) {
|
|
setSchema(null);
|
|
setSchemaErr(e instanceof Error ? e.message : "Could not load form.");
|
|
}
|
|
})
|
|
.finally(() => {
|
|
if (!cancelled) setSchemaLoading(false);
|
|
});
|
|
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, [formId, eventId, sessionId]);
|
|
|
|
const reg = useEventRegistrationSettings(eventSnapshot);
|
|
|
|
if (!eventId) {
|
|
return (
|
|
<MobileShell className="relative">
|
|
<HeaderMobile logoUrl={ctx?.event?.logoUrl} eventId={null} />
|
|
<main className="flex flex-1 flex-col bg-[#f2f2f7] px-4 pb-10 pt-6">
|
|
<div className="mx-auto w-full max-w-[370px]">
|
|
<h1 className="font-inter text-xl font-semibold text-[#24282f]">Feedback</h1>
|
|
<p className="mt-3 text-sm text-[rgba(36,40,47,0.67)]">Open feedback from your event or session link.</p>
|
|
<Link to="/" className="mt-4 inline-block text-sm font-semibold text-[#1e72ef] underline">
|
|
Home
|
|
</Link>
|
|
</div>
|
|
</main>
|
|
</MobileShell>
|
|
);
|
|
}
|
|
|
|
if (!reg.enableFeedback) {
|
|
return (
|
|
<MobileShell className="relative">
|
|
<HeaderMobile logoUrl={eventSnapshot?.logoUrl} eventId={eventId || null} />
|
|
<main className="flex flex-1 flex-col bg-[#f2f2f7] px-4 pb-10 pt-6">
|
|
<div className="mx-auto w-full max-w-[370px]">
|
|
<h1 className="font-inter text-xl font-semibold text-[#24282f]">Feedback</h1>
|
|
<p className="mt-3 text-sm text-[rgba(36,40,47,0.67)]">Feedback is disabled for this event.</p>
|
|
<Link to="/event" className="mt-4 inline-block text-sm font-semibold text-[#1e72ef] underline">
|
|
Back to event
|
|
</Link>
|
|
</div>
|
|
</main>
|
|
</MobileShell>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<MobileShell className="relative">
|
|
<HeaderMobile logoUrl={eventSnapshot?.logoUrl} eventId={eventId || null} />
|
|
<main className="flex flex-1 flex-col bg-[#f2f2f7 bg-transparent px-4 pb-10 pt-6">
|
|
<div className="mx-auto w-full max-w-[370px]">
|
|
<h1 className="font-inter text-xl font-semibold text-[var(--theme-text-color)]">{schema?.name || "Feedback"}</h1>
|
|
{schemaLoading ? (
|
|
<p className="mt-4 text-sm text-[rgba(36,40,47,0.67)]">Loading form…</p>
|
|
) : schemaErr ? (
|
|
<div className="mt-4">
|
|
<p className="text-sm text-red-600">{schemaErr}</p>
|
|
<p className="mt-2 text-sm text-[rgba(36,40,47,0.67)]">
|
|
Ask the organizer to publish an active feedback form for this event.
|
|
</p>
|
|
<Link to="/event" className="mt-4 inline-block text-sm font-semibold text-[#1e72ef] underline">
|
|
Back to event
|
|
</Link>
|
|
</div>
|
|
) : schema ? (
|
|
<div className="mt-6">
|
|
<DynamicFeedbackForm eventId={eventId} schema={schema} variant="light" />
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
</main>
|
|
</MobileShell>
|
|
);
|
|
}
|