This commit is contained in:
Ravi Gulhane 2026-07-03 16:55:57 +05:30
parent 76cfbf5581
commit 8643657fee
11 changed files with 223 additions and 3054 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
dist/index.html vendored
View File

@ -12,7 +12,7 @@
rel="stylesheet"
/>
<script src="https://accounts.google.com/gsi/client" async defer></script>
<script type="module" crossorigin src="/assets/index-Cq3hylG7.js"></script>
<script type="module" crossorigin src="/assets/index-DBI6VQnt.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-B2aqbk3U.css">
</head>

View File

@ -31,11 +31,6 @@ export function AppShell() {
setActiveNav("search");
};
useEffect(() => {
if (!selectedEventId || activeNav !== "agenda") return;
setActiveNav("dashboard");
}, [selectedEventId, activeNav, setActiveNav]);
useEffect(() => {
if (!selectedEventId) return;
if (activeNav === "questions" || activeNav === "quiz") {

View File

@ -146,6 +146,10 @@ export function MainContent() {
return <EventAnalyticsPage eventId={selectedEventId} onNavigate={setActiveNav} />;
}
if (activeNav === "agenda") {
return <AgendaPage />;
}
if (activeNav === "dashboard") {
return (
<div style={{ display: "flex", flexDirection: "column", gap: "20px" }}>
@ -205,8 +209,6 @@ export function MainContent() {
<EventHomeModules />
<AgendaPage embedInDashboard />
<div
style={{
paddingTop: "8px",
@ -222,7 +224,7 @@ export function MainContent() {
);
}
return <AgendaPage />;
return <HomePage />;
};
return <>{pageContent()}</>;

View File

@ -1,7 +1,7 @@
import React, { useRef, useState, useEffect } from "react";
import {
LayoutDashboard, LineChart, Users,
BarChart2, Trophy, ClipboardCheck, Zap,
BarChart2, Trophy, ClipboardCheck, Zap, CalendarDays,
} from "lucide-react";
import { useBreakpoint } from "../hooks/useBreakpoint";
@ -17,6 +17,7 @@ interface EventTab {
const EVENT_TABS: EventTab[] = [
{ id: "dashboard", label: "Event Home", shortLabel: "Home", icon: <LayoutDashboard size={13} /> },
{ id: "agenda", label: "Agenda", shortLabel: "Agenda", icon: <CalendarDays size={13} /> },
{ id: "participants", label: "Participants", shortLabel: "People", icon: <Users size={13} /> },
{ id: "attendance", label: "Attendance", shortLabel: "Attend", icon: <ClipboardCheck size={13} /> },
{ id: "event-activities", label: "Activities", shortLabel: "Activities", icon: <Zap size={13} /> },

View File

@ -621,7 +621,7 @@ function TrackAccordion({ track, isOpen, virtual, onToggle, onEdit, onDelete, on
}
/* ─────────────── Main Page ─────────────── */
export function AgendaPage({ embedInDashboard = false }: { embedInDashboard?: boolean } = {}) {
export function AgendaPage() {
const { selectedEventId, openAgendaSessionPanelOnce, setOpenAgendaSessionPanelOnce } = useAppNav();
const bp = useBreakpoint();
const isMobile = bp === "mobile";
@ -933,7 +933,7 @@ export function AgendaPage({ embedInDashboard = false }: { embedInDashboard?: bo
{loading ? "…" : eventName}
</p>
<h1 style={{ fontFamily: "var(--font-inter)", fontSize: isMobile ? "var(--text-xl)" : "var(--text-2xl)", fontWeight: "var(--font-weight-medium)", color: "var(--foreground)", lineHeight: "1.2", marginBottom: "4px" }}>
{embedInDashboard ? "Agenda" : "Event Home"}
Agenda
</h1>
<p style={{ fontSize: "var(--text-sm)", fontFamily: "var(--font-noto-sans)", color: "var(--muted)" }}>
{loadErr ? <span style={{ color: "var(--destructive)" }}>{loadErr}</span> : `${tracks.filter((t) => t.id !== UNASSIGNED_TRACK_ID).length} tracks · ${total} sessions`}
@ -1005,13 +1005,11 @@ export function AgendaPage({ embedInDashboard = false }: { embedInDashboard?: bo
</div>
)}
{!embedInDashboard && (
<div style={{ paddingTop: "16px", borderTop: "1px solid var(--border)", textAlign: "center" }}>
<p style={{ fontSize: "var(--text-xs)", fontFamily: "var(--font-noto-sans)", color: "var(--muted)" }}>
© 2026 Stratawiz Technologies Pvt Ltd · EventBuzz
</p>
</div>
)}
<div style={{ paddingTop: "16px", borderTop: "1px solid var(--border)", textAlign: "center" }}>
<p style={{ fontSize: "var(--text-xs)", fontFamily: "var(--font-noto-sans)", color: "var(--muted)" }}>
© 2026 Stratawiz Technologies Pvt Ltd · EventBuzz
</p>
</div>
{sessionPanel && selectedEventId && (
<AgendaSessionPanel

View File

@ -57,10 +57,6 @@ export function EventAnalyticsPage({
}, [load]);
const handleNavigate = (navId: string) => {
if (navId === "agenda") {
onNavigate?.("dashboard");
return;
}
onNavigate?.(navId);
};

View File

@ -1,5 +1,5 @@
import React, { useCallback, useEffect, useState } from "react";
import { BarChart2, FileText, MessageSquare, ShieldCheck, Tag, Ticket, Trophy, X } from "lucide-react";
import { BarChart2, CalendarDays, FileText, Plus, ShieldCheck, Tag, Ticket, Trophy } from "lucide-react";
import { useBreakpoint } from "../../hooks/useBreakpoint";
import { useAppNav } from "../../contexts/AppNavContext";
import { eventsApi } from "../../../services/api/events";
@ -16,18 +16,8 @@ import { AddQuizPollModal, buildQuizPollSettingsPayload } from "../quiz/AddQuizP
import type { QuizPollModalForm } from "../quiz/AddQuizPollModal";
import type { Question } from "../quiz/AddQuestionModal";
import { modalQuestionToApi } from "../quiz/quizQuestionMappers";
import { sessionsApi } from "../../../services/api";
import { sessionsApi, tracksApi, formsApi } from "../../../services/api";
import type { FormWithSubmissionCount } from "../../../services/api/types";
import {
DEFAULT_REGISTRATION_FORM_NAME,
registrationFormDisplayName,
resolveEventRegistrationForm,
} from "./registrationFormModule";
import {
DEFAULT_FEEDBACK_FORM_NAME,
feedbackFormDisplayName,
resolveEventFeedbackForm,
} from "./feedbackFormModule";
function ModuleCard({
icon,
@ -139,267 +129,27 @@ function moduleButtonStyle(primary = false): React.CSSProperties {
};
}
function DefaultRegistrationResponsesPanel({
formName,
onClose,
}: {
formName: string;
onClose: () => void;
}) {
return (
<>
<div
onClick={onClose}
role="presentation"
style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.5)", zIndex: 200 }}
/>
<div
role="dialog"
aria-modal="true"
aria-labelledby="default-reg-responses-title"
style={{
position: "fixed",
top: 0,
right: 0,
height: "100%",
width: "min(720px, 100vw)",
background: "var(--card)",
zIndex: 201,
display: "flex",
flexDirection: "column",
boxShadow: "-4px 0 40px rgba(0,0,0,0.2)",
}}
>
<div
style={{
display: "flex",
alignItems: "flex-start",
justifyContent: "space-between",
gap: 12,
padding: "16px 18px",
borderBottom: "1px solid var(--border)",
flexShrink: 0,
}}
>
<div style={{ minWidth: 0 }}>
<p
style={{
fontSize: "var(--text-xs)",
fontFamily: "var(--font-noto-sans)",
color: "var(--muted)",
margin: "0 0 4px",
}}
>
Submissions
</p>
<h2
id="default-reg-responses-title"
style={{
fontFamily: "var(--font-inter)",
fontSize: "var(--text-lg)",
fontWeight: "var(--font-weight-medium)",
color: "var(--foreground)",
margin: 0,
lineHeight: 1.3,
}}
>
{formName}
</h2>
</div>
<button
type="button"
onClick={onClose}
aria-label="Close"
style={{
flexShrink: 0,
width: 36,
height: 36,
display: "flex",
alignItems: "center",
justifyContent: "center",
borderRadius: "var(--radius-button)",
border: "1px solid var(--border)",
background: "var(--card)",
color: "var(--muted)",
cursor: "pointer",
}}
>
<X size={18} />
</button>
</div>
<div
style={{
flex: 1,
display: "flex",
alignItems: "center",
justifyContent: "center",
padding: "32px 24px",
textAlign: "center",
}}
>
<div>
<p
style={{
fontFamily: "var(--font-inter)",
fontSize: "var(--text-base)",
fontWeight: "var(--font-weight-medium)",
color: "var(--foreground)",
margin: "0 0 8px",
}}
>
No responses yet
</p>
<p
style={{
fontSize: "var(--text-sm)",
fontFamily: "var(--font-noto-sans)",
color: "var(--muted)",
margin: 0,
maxWidth: "360px",
lineHeight: 1.5,
}}
>
Using the default registration form (first name, last name, email). Save the form via Edit to
customize it and start collecting responses.
</p>
</div>
</div>
</div>
</>
);
function formDisplayType(apiType: string): string {
if (apiType === "feedback") return "Feedback";
if (apiType === "registration") return "Registration";
if (apiType === "other") return "Other";
if (apiType === "survey" || apiType === "custom") return "Other";
return apiType.charAt(0).toUpperCase() + apiType.slice(1);
}
function DefaultFeedbackResponsesPanel({
formName,
onClose,
}: {
formName: string;
onClose: () => void;
}) {
return (
<>
<div
onClick={onClose}
role="presentation"
style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.5)", zIndex: 200 }}
/>
<div
role="dialog"
aria-modal="true"
aria-labelledby="default-feedback-responses-title"
style={{
position: "fixed",
top: 0,
right: 0,
height: "100%",
width: "min(720px, 100vw)",
background: "var(--card)",
zIndex: 201,
display: "flex",
flexDirection: "column",
boxShadow: "-4px 0 40px rgba(0,0,0,0.2)",
}}
>
<div
style={{
display: "flex",
alignItems: "flex-start",
justifyContent: "space-between",
gap: 12,
padding: "16px 18px",
borderBottom: "1px solid var(--border)",
flexShrink: 0,
}}
>
<div style={{ minWidth: 0 }}>
<p
style={{
fontSize: "var(--text-xs)",
fontFamily: "var(--font-noto-sans)",
color: "var(--muted)",
margin: "0 0 4px",
}}
>
Submissions
</p>
<h2
id="default-feedback-responses-title"
style={{
fontFamily: "var(--font-inter)",
fontSize: "var(--text-lg)",
fontWeight: "var(--font-weight-medium)",
color: "var(--foreground)",
margin: 0,
lineHeight: 1.3,
}}
>
{formName}
</h2>
</div>
<button
type="button"
onClick={onClose}
aria-label="Close"
style={{
flexShrink: 0,
width: 36,
height: 36,
display: "flex",
alignItems: "center",
justifyContent: "center",
borderRadius: "var(--radius-button)",
border: "1px solid var(--border)",
background: "var(--card)",
color: "var(--muted)",
cursor: "pointer",
}}
>
<X size={18} />
</button>
</div>
<div
style={{
flex: 1,
display: "flex",
alignItems: "center",
justifyContent: "center",
padding: "32px 24px",
textAlign: "center",
}}
>
<div>
<p
style={{
fontFamily: "var(--font-inter)",
fontSize: "var(--text-base)",
fontWeight: "var(--font-weight-medium)",
color: "var(--foreground)",
margin: "0 0 8px",
}}
>
No responses yet
</p>
<p
style={{
fontSize: "var(--text-sm)",
fontFamily: "var(--font-noto-sans)",
color: "var(--muted)",
margin: 0,
maxWidth: "360px",
lineHeight: 1.5,
}}
>
Save a feedback form via Edit to start collecting responses from attendees.
</p>
</div>
</div>
</div>
</>
);
function formPanelMode(apiType: string): "feedback" | "registration" | "other" {
if (apiType === "feedback") return "feedback";
if (apiType === "registration") return "registration";
return "other";
}
function formMetaLine(form: FormWithSubmissionCount): string {
const count = form.submissionCount ?? 0;
return `${formDisplayType(form.type)} · ${count.toLocaleString()} response${count === 1 ? "" : "s"}`;
}
export function EventHomeModules() {
const { selectedEventId, setActiveNav, setPermissionsOpenAddOnce } = useAppNav();
const { selectedEventId, setActiveNav, setPermissionsOpenAddOnce, setOpenAgendaSessionPanelOnce } = useAppNav();
const bp = useBreakpoint();
const isMobile = bp === "mobile";
const isTablet = bp === "tablet";
@ -408,15 +158,10 @@ export function EventHomeModules() {
: isTablet
? "repeat(2, minmax(0, 1fr))"
: "repeat(auto-fill, minmax(240px, 1fr))";
const [linkedFormId, setLinkedFormId] = useState<string | undefined>();
const [registrationForm, setRegistrationForm] = useState<FormWithSubmissionCount | null>(null);
const [loading, setLoading] = useState(false);
const [editOpen, setEditOpen] = useState(false);
const [responsesOpen, setResponsesOpen] = useState(false);
const [feedbackForm, setFeedbackForm] = useState<FormWithSubmissionCount | null>(null);
const [feedbackLoading, setFeedbackLoading] = useState(false);
const [feedbackEditOpen, setFeedbackEditOpen] = useState(false);
const [feedbackResponsesOpen, setFeedbackResponsesOpen] = useState(false);
const [eventForms, setEventForms] = useState<FormWithSubmissionCount[]>([]);
const [formEditTarget, setFormEditTarget] = useState<FormWithSubmissionCount | null>(null);
const [formResponsesTarget, setFormResponsesTarget] = useState<FormWithSubmissionCount | null>(null);
const [newFormMode, setNewFormMode] = useState<"registration" | "feedback" | "other" | null>(null);
const [pollQuizCounts, setPollQuizCounts] = useState({ polls: 0, quizzes: 0 });
const [pollQuizLoading, setPollQuizLoading] = useState(false);
const [showAddPoll, setShowAddPoll] = useState(false);
@ -434,17 +179,17 @@ export function EventHomeModules() {
const [rewardRulesCount, setRewardRulesCount] = useState(0);
const [rewardLoading, setRewardLoading] = useState(false);
const [rewardRulesOpen, setRewardRulesOpen] = useState(false);
const [agendaCounts, setAgendaCounts] = useState({ tracks: 0, sessions: 0 });
const [agendaLoading, setAgendaLoading] = useState(false);
useEffect(() => {
if (!selectedEventId) {
setLinkedFormId(undefined);
setEventName(null);
return;
}
let cancelled = false;
void eventsApi.get(selectedEventId).then((res) => {
if (cancelled) return;
setLinkedFormId(res.data?.website?.registrationFormId);
setEventName(res.data?.name ?? null);
});
return () => {
@ -452,47 +197,25 @@ export function EventHomeModules() {
};
}, [selectedEventId]);
const loadRegistrationForm = useCallback(async () => {
const loadEventForms = useCallback(async () => {
if (!selectedEventId) {
setRegistrationForm(null);
setLoading(false);
setEventForms([]);
return;
}
setLoading(true);
try {
const form = await resolveEventRegistrationForm(selectedEventId, linkedFormId);
setRegistrationForm(form);
const forms = await formsApi.listForEvent(selectedEventId);
const sorted = [...forms].sort((a, b) =>
(a.name || "").localeCompare(b.name || "", undefined, { sensitivity: "base" }),
);
setEventForms(sorted);
} catch {
setRegistrationForm(null);
} finally {
setLoading(false);
}
}, [selectedEventId, linkedFormId]);
useEffect(() => {
void loadRegistrationForm();
}, [loadRegistrationForm]);
const loadFeedbackForm = useCallback(async () => {
if (!selectedEventId) {
setFeedbackForm(null);
setFeedbackLoading(false);
return;
}
setFeedbackLoading(true);
try {
const form = await resolveEventFeedbackForm(selectedEventId);
setFeedbackForm(form);
} catch {
setFeedbackForm(null);
} finally {
setFeedbackLoading(false);
setEventForms([]);
}
}, [selectedEventId]);
useEffect(() => {
void loadFeedbackForm();
}, [loadFeedbackForm]);
void loadEventForms();
}, [loadEventForms]);
const loadPollQuizCounts = useCallback(async () => {
if (!selectedEventId) {
@ -610,6 +333,32 @@ export function EventHomeModules() {
void loadRewardRulesMeta();
}, [loadRewardRulesMeta]);
const loadAgendaMeta = useCallback(async () => {
if (!selectedEventId) {
setAgendaCounts({ tracks: 0, sessions: 0 });
setAgendaLoading(false);
return;
}
setAgendaLoading(true);
try {
const [trRes, sesRes] = await Promise.all([
tracksApi.list(selectedEventId),
sessionsApi.list(selectedEventId),
]);
const tracks = (trRes.data as { tracks?: unknown[] } | undefined)?.tracks ?? [];
const sessions = (sesRes.data as { sessions?: unknown[] } | undefined)?.sessions ?? [];
setAgendaCounts({ tracks: tracks.length, sessions: sessions.length });
} catch {
setAgendaCounts({ tracks: 0, sessions: 0 });
} finally {
setAgendaLoading(false);
}
}, [selectedEventId]);
useEffect(() => {
void loadAgendaMeta();
}, [loadAgendaMeta]);
const handleBadgeSuccess = () => {
setShowAddBadge(false);
setDuplicateBadgeBatchId(null);
@ -627,28 +376,16 @@ export function EventHomeModules() {
setShowAddBadge(true);
};
const handleEditSuccess = () => {
setEditOpen(false);
void loadRegistrationForm();
const handleFormEditSuccess = () => {
setFormEditTarget(null);
void loadEventForms();
};
const handleFeedbackEditSuccess = () => {
setFeedbackEditOpen(false);
void loadFeedbackForm();
const handleNewFormSuccess = () => {
setNewFormMode(null);
void loadEventForms();
};
const formName = registrationFormDisplayName(registrationForm);
const feedbackFormName = feedbackFormDisplayName(feedbackForm);
const submissionMeta = !selectedEventId
? "Select an event to view responses"
: loading
? "Loading…"
: `${(registrationForm?.submissionCount ?? 0).toLocaleString()} response${(registrationForm?.submissionCount ?? 0) === 1 ? "" : "s"}`;
const feedbackSubmissionMeta = !selectedEventId
? "Select an event to view responses"
: feedbackLoading
? "Loading…"
: `${(feedbackForm?.submissionCount ?? 0).toLocaleString()} response${(feedbackForm?.submissionCount ?? 0) === 1 ? "" : "s"}`;
const actionsDisabled = !selectedEventId;
const pollQuizMeta = !selectedEventId
? "Select an event to create polls and quizzes"
@ -677,6 +414,11 @@ export function EventHomeModules() {
: rewardRulesCount === 0
? "No rules configured"
: `${rewardRulesCount} rule${rewardRulesCount === 1 ? "" : "s"} configured`;
const agendaMeta = !selectedEventId
? "Select an event to manage the agenda"
: agendaLoading
? "Loading…"
: `${agendaCounts.tracks} track${agendaCounts.tracks === 1 ? "" : "s"} · ${agendaCounts.sessions} session${agendaCounts.sessions === 1 ? "" : "s"}`;
const handleSavePollQuiz = async (
kind: "poll" | "quiz",
@ -712,9 +454,9 @@ export function EventHomeModules() {
}}
>
<ModuleCard
icon={<FileText size={18} />}
title={DEFAULT_REGISTRATION_FORM_NAME}
meta={submissionMeta}
icon={<CalendarDays size={18} />}
title="Agenda"
meta={agendaMeta}
actions={
<>
<button
@ -725,7 +467,7 @@ export function EventHomeModules() {
opacity: actionsDisabled ? 0.55 : 1,
cursor: actionsDisabled ? "not-allowed" : "pointer",
}}
onClick={() => setEditOpen(true)}
onClick={() => setActiveNav("agenda")}
onMouseEnter={(e) => {
if (actionsDisabled) return;
(e.currentTarget as HTMLElement).style.borderColor = "var(--primary)";
@ -737,7 +479,7 @@ export function EventHomeModules() {
(e.currentTarget as HTMLElement).style.color = "var(--card-foreground)";
}}
>
Edit
View Agenda
</button>
<button
type="button"
@ -747,56 +489,62 @@ export function EventHomeModules() {
opacity: actionsDisabled ? 0.55 : 1,
cursor: actionsDisabled ? "not-allowed" : "pointer",
}}
onClick={() => setResponsesOpen(true)}
onClick={() => {
setOpenAgendaSessionPanelOnce(true);
setActiveNav("agenda");
}}
>
Responses
</button>
</>
}
/>
<ModuleCard
icon={<MessageSquare size={18} />}
title={DEFAULT_FEEDBACK_FORM_NAME}
meta={feedbackSubmissionMeta}
actions={
<>
<button
type="button"
disabled={actionsDisabled}
style={{
...moduleButtonStyle(),
opacity: actionsDisabled ? 0.55 : 1,
cursor: actionsDisabled ? "not-allowed" : "pointer",
}}
onClick={() => setFeedbackEditOpen(true)}
onMouseEnter={(e) => {
if (actionsDisabled) return;
(e.currentTarget as HTMLElement).style.borderColor = "var(--primary)";
(e.currentTarget as HTMLElement).style.color = "var(--primary)";
}}
onMouseLeave={(e) => {
if (actionsDisabled) return;
(e.currentTarget as HTMLElement).style.borderColor = "var(--border)";
(e.currentTarget as HTMLElement).style.color = "var(--card-foreground)";
}}
>
Edit
</button>
<button
type="button"
disabled={actionsDisabled}
style={{
...moduleButtonStyle(true),
opacity: actionsDisabled ? 0.55 : 1,
cursor: actionsDisabled ? "not-allowed" : "pointer",
}}
onClick={() => setFeedbackResponsesOpen(true)}
>
View Responses
New Session
</button>
</>
}
/>
{eventForms.map((form) => (
<ModuleCard
key={form._id}
icon={<FileText size={18} />}
title={form.name?.trim() || "Untitled form"}
meta={formMetaLine(form)}
actions={
<>
<button
type="button"
disabled={actionsDisabled}
style={{
...moduleButtonStyle(),
opacity: actionsDisabled ? 0.55 : 1,
cursor: actionsDisabled ? "not-allowed" : "pointer",
}}
onClick={() => setFormEditTarget(form)}
onMouseEnter={(e) => {
if (actionsDisabled) return;
(e.currentTarget as HTMLElement).style.borderColor = "var(--primary)";
(e.currentTarget as HTMLElement).style.color = "var(--primary)";
}}
onMouseLeave={(e) => {
if (actionsDisabled) return;
(e.currentTarget as HTMLElement).style.borderColor = "var(--border)";
(e.currentTarget as HTMLElement).style.color = "var(--card-foreground)";
}}
>
Edit
</button>
<button
type="button"
disabled={actionsDisabled}
style={{
...moduleButtonStyle(true),
opacity: actionsDisabled ? 0.55 : 1,
cursor: actionsDisabled ? "not-allowed" : "pointer",
}}
onClick={() => setFormResponsesTarget(form)}
>
Responses
</button>
</>
}
/>
))}
<ModuleCard
icon={<ShieldCheck size={18} />}
title="Users & Permissions"
@ -967,54 +715,100 @@ export function EventHomeModules() {
</button>
}
/>
<ModuleCard
icon={<Plus size={18} />}
title="Create New Form"
description="Add a form assigned to this event"
actions={
<>
<button
type="button"
disabled={actionsDisabled}
style={{
...moduleButtonStyle(),
opacity: actionsDisabled ? 0.55 : 1,
cursor: actionsDisabled ? "not-allowed" : "pointer",
}}
onClick={() => setNewFormMode("registration")}
onMouseEnter={(e) => {
if (actionsDisabled) return;
(e.currentTarget as HTMLElement).style.borderColor = "var(--primary)";
(e.currentTarget as HTMLElement).style.color = "var(--primary)";
}}
onMouseLeave={(e) => {
if (actionsDisabled) return;
(e.currentTarget as HTMLElement).style.borderColor = "var(--border)";
(e.currentTarget as HTMLElement).style.color = "var(--card-foreground)";
}}
>
Registration
</button>
<button
type="button"
disabled={actionsDisabled}
style={{
...moduleButtonStyle(),
opacity: actionsDisabled ? 0.55 : 1,
cursor: actionsDisabled ? "not-allowed" : "pointer",
}}
onClick={() => setNewFormMode("feedback")}
onMouseEnter={(e) => {
if (actionsDisabled) return;
(e.currentTarget as HTMLElement).style.borderColor = "var(--primary)";
(e.currentTarget as HTMLElement).style.color = "var(--primary)";
}}
onMouseLeave={(e) => {
if (actionsDisabled) return;
(e.currentTarget as HTMLElement).style.borderColor = "var(--border)";
(e.currentTarget as HTMLElement).style.color = "var(--card-foreground)";
}}
>
Feedback
</button>
<button
type="button"
disabled={actionsDisabled}
style={{
...moduleButtonStyle(true),
opacity: actionsDisabled ? 0.55 : 1,
cursor: actionsDisabled ? "not-allowed" : "pointer",
}}
onClick={() => setNewFormMode("other")}
>
Other
</button>
</>
}
/>
</section>
{editOpen && selectedEventId ? (
{formEditTarget && selectedEventId ? (
<CreateFormPanel
mode="registration"
mode={formPanelMode(formEditTarget.type)}
eventId={selectedEventId}
formId={registrationForm?._id}
defaultFormName={registrationForm ? undefined : DEFAULT_REGISTRATION_FORM_NAME}
onClose={() => setEditOpen(false)}
onSuccess={handleEditSuccess}
formId={formEditTarget._id}
onClose={() => setFormEditTarget(null)}
onSuccess={handleFormEditSuccess}
/>
) : null}
{responsesOpen && selectedEventId && registrationForm?._id ? (
{formResponsesTarget ? (
<FormSubmissionsPanel
formId={registrationForm._id}
formName={formName}
onClose={() => setResponsesOpen(false)}
formId={formResponsesTarget._id}
formName={formResponsesTarget.name?.trim() || "Form"}
onClose={() => setFormResponsesTarget(null)}
/>
) : null}
{responsesOpen && selectedEventId && !registrationForm?._id ? (
<DefaultRegistrationResponsesPanel formName={formName} onClose={() => setResponsesOpen(false)} />
) : null}
{feedbackEditOpen && selectedEventId ? (
{newFormMode && selectedEventId ? (
<CreateFormPanel
mode="feedback"
mode={newFormMode}
eventId={selectedEventId}
formId={feedbackForm?._id}
defaultFormName={feedbackForm ? undefined : DEFAULT_FEEDBACK_FORM_NAME}
onClose={() => setFeedbackEditOpen(false)}
onSuccess={handleFeedbackEditSuccess}
onClose={() => setNewFormMode(null)}
onSuccess={handleNewFormSuccess}
/>
) : null}
{feedbackResponsesOpen && selectedEventId && feedbackForm?._id ? (
<FormSubmissionsPanel
formId={feedbackForm._id}
formName={feedbackFormName}
onClose={() => setFeedbackResponsesOpen(false)}
/>
) : null}
{feedbackResponsesOpen && selectedEventId && !feedbackForm?._id ? (
<DefaultFeedbackResponsesPanel formName={feedbackFormName} onClose={() => setFeedbackResponsesOpen(false)} />
) : null}
{showAddPoll ? (
<AddQuizPollModal
kind="poll"

View File

@ -1374,7 +1374,7 @@ export function EventsPage({ onNavigateToEvent }: { onNavigateToEvent?: (eventId
if (eid) {
setSelectedEventId(eid);
setOpenAgendaSessionPanelOnce(true);
setActiveNav("dashboard");
setActiveNav("agenda");
} else {
setShowCreatePanel(true);
}

View File

@ -81,7 +81,8 @@ export const ALL_PAGES: SearchPage[] = [
{ id: "p14", navId: "payment", title: "Payment Settings", section: "Portfolio", description: "Configure payment gateways and billing", icon: <CreditCard size={14} /> },
{ id: "p15", navId: "user-management", title: "User Management", section: "Portfolio", description: "Manage team members, roles, and permissions", icon: <Shield size={14} /> },
{ id: "p16", navId: "settings", title: "Settings", section: "General", description: "Organisation, profile, and platform preferences", icon: <Settings size={14} /> },
{ id: "p17", navId: "dashboard", title: "Event Home", section: "Event", description: "Tracks, sessions, and schedule for the event", icon: <LayoutGrid size={14} /> },
{ id: "p17", navId: "dashboard", title: "Event Home", section: "Event", description: "Event overview, modules, and quick actions", icon: <LayoutGrid size={14} /> },
{ id: "p17a", navId: "agenda", title: "Agenda", section: "Event", description: "Tracks, sessions, and schedule for the event", icon: <Calendar size={14} /> },
{ id: "p18", navId: "analytics", title: "Event Analytics", section: "Event", description: "Live stats, charts, and feature overview", icon: <LineChart size={14} /> },
{ id: "p19", navId: "participants", title: "Event Participants", section: "Event", description: "Registrations, check-ins, and attendance", icon: <Users size={14} /> },
{ id: "p20", navId: "permissions", title: "Users & Permissions", section: "Event", description: "Manage event team members, roles, and session access", icon: <Shield size={14} /> },