184 lines
5.8 KiB
TypeScript
184 lines
5.8 KiB
TypeScript
import { useCallback, useEffect, useState } from "react";
|
|
import { Link } from "react-router-dom";
|
|
import { ChevronLeft, ChevronRight } from "lucide-react";
|
|
import { useSessionQuestionsRtdb } from "../hooks/useSessionQuestionsRtdb";
|
|
import { AudienceQuestionCard, type AudienceQuestionItem } from "./AudienceQuestionCard";
|
|
import { AskQuestionModal } from "./AskQuestionModal";
|
|
|
|
type QuestionItem = AudienceQuestionItem & { _id?: string };
|
|
|
|
const sample: QuestionItem[] = [
|
|
{
|
|
author: "Ashok Kuwal",
|
|
text: "Role of GINA Guidelines for Iniang and Monitoring Asthma Treatment?",
|
|
up: 2,
|
|
down: 3,
|
|
},
|
|
{
|
|
author: "Ashok Kuwal",
|
|
text: "Role of GINA Guidelines for Iniang and Monitoring Asthma Treatment?",
|
|
up: 2,
|
|
down: 3,
|
|
},
|
|
{
|
|
author: "Ashok Kuwal",
|
|
text: "Role of GINA Guidelines for Iniang and Monitoring Asthma Treatment?",
|
|
up: 2,
|
|
down: 3,
|
|
},
|
|
];
|
|
|
|
type SessionQuestionsCardProps = {
|
|
title?: string;
|
|
showQuestionNav?: boolean;
|
|
eventId?: string;
|
|
sessionId?: string;
|
|
};
|
|
|
|
export function SessionQuestionsCard({
|
|
title = "Session Questions",
|
|
showQuestionNav = false,
|
|
eventId,
|
|
sessionId,
|
|
}: SessionQuestionsCardProps) {
|
|
const live = Boolean(eventId?.trim() && sessionId?.trim());
|
|
const eid = eventId?.trim() ?? "";
|
|
const sid = sessionId?.trim() ?? "";
|
|
|
|
const { items: rtdbItems, loading, error } = useSessionQuestionsRtdb(
|
|
live ? sid : null,
|
|
live ? eid : null,
|
|
);
|
|
|
|
const items: QuestionItem[] = live
|
|
? rtdbItems.map((r) => ({
|
|
_id: r._id,
|
|
author: r.author,
|
|
text: r.text,
|
|
up: r.up,
|
|
down: r.down,
|
|
}))
|
|
: sample;
|
|
|
|
const total = items.length;
|
|
const [index, setIndex] = useState(0);
|
|
const [askModalOpen, setAskModalOpen] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (index >= total && total > 0) setIndex(0);
|
|
else if (total === 0) setIndex(0);
|
|
}, [total, index]);
|
|
|
|
const goNext = useCallback(() => {
|
|
if (total <= 0) return;
|
|
setIndex((i) => (i + 1) % total);
|
|
}, [total]);
|
|
|
|
const goPrev = useCallback(() => {
|
|
if (total <= 0) return;
|
|
setIndex((i) => (i - 1 + total) % total);
|
|
}, [total]);
|
|
|
|
useEffect(() => {
|
|
if (total <= 1) return;
|
|
const id = window.setInterval(goNext, 2000);
|
|
return () => window.clearInterval(id);
|
|
}, [total, goNext]);
|
|
|
|
const safeIndex = total > 0 ? Math.min(index, total - 1) : 0;
|
|
const current = total > 0 ? items[safeIndex] : null;
|
|
|
|
const viewAllTo =
|
|
live ? `/questions?event_id=${encodeURIComponent(eid)}&session_id=${encodeURIComponent(sid)}` : null;
|
|
|
|
return (
|
|
<section
|
|
className="relative z-10 flex w-full max-w-none flex-col gap-4 rounded-lg border border-[rgba(116,112,112,0.2)] bg-whit card-bg py-4 shadow-sm"
|
|
data-name="Session Questions"
|
|
>
|
|
<div className="flex h-8 items-center justify-between gap-2 px-4">
|
|
<div className="flex min-w-0 flex-1 items-center gap-2">
|
|
<h2 className="truncate text-lg font-semibold tracking-wide text-[#24282f]">
|
|
{title}
|
|
</h2>
|
|
{total > 0 ? (
|
|
<span className="shrink-0 rounded bg-[#e5e5ea] px-2 py-0.5 text-[10px] tracking-wide text-[#24282f]">
|
|
{safeIndex + 1}/{total}
|
|
</span>
|
|
) : null}
|
|
</div>
|
|
{showQuestionNav && total > 1 ? (
|
|
<div className="flex shrink-0 gap-1">
|
|
<button
|
|
type="button"
|
|
className="rounded-full bg-[#f2f2f7] p-1"
|
|
aria-label="Previous question"
|
|
onClick={goPrev}
|
|
>
|
|
<ChevronLeft className="size-4 text-[#24282f]" />
|
|
</button>
|
|
<button
|
|
type="button"
|
|
className="rounded-full bg-[#f2f2f7] p-1"
|
|
aria-label="Next question"
|
|
onClick={goNext}
|
|
>
|
|
<ChevronRight className="size-4 text-[#24282f]" />
|
|
</button>
|
|
</div>
|
|
) : null}
|
|
</div>
|
|
<div className="border-t border-[#f2f2f7]">
|
|
{live && loading ? (
|
|
<p className="px-4 py-6 text-center text-sm text-[rgba(36,40,47,0.55)]">Loading questions…</p>
|
|
) : live && error ? (
|
|
<p className="px-4 py-6 text-center text-sm text-red-600">{error}</p>
|
|
) : current ? (
|
|
<div className="p-0">
|
|
<AudienceQuestionCard
|
|
key={current._id ?? `${safeIndex}-${current.text.slice(0, 24)}`}
|
|
item={current}
|
|
variant="embedded"
|
|
voteContext={live ? { eventId: eid, sessionId: sid } : undefined}
|
|
/>
|
|
</div>
|
|
) : (
|
|
<p className="px-4 py-6 text-center text-sm text-[rgba(36,40,47,0.55)]">No questions yet.</p>
|
|
)}
|
|
</div>
|
|
<div className="flex items-center justify-between gap-3 px-4">
|
|
{viewAllTo ? (
|
|
<Link
|
|
to={viewAllTo}
|
|
className="font-inter text-xs font-semibold uppercase tracking-wider text-[#1e72e theme-btn-link"
|
|
>
|
|
View All
|
|
</Link>
|
|
) : (
|
|
<span className="font-inter text-xs font-semibold uppercase tracking-wider text-[rgba(36,40,47,0.35)]">
|
|
View All
|
|
</span>
|
|
)}
|
|
<button
|
|
type="button"
|
|
onClick={() => live && setAskModalOpen(true)}
|
|
disabled={!live}
|
|
className="shrink-0 rounded-lg bg-[#ef8d1 bg-[var(--theme-button-color)] px-3 py-2 text-xs font-semibold text-white shadow-[0_2px_4px_rgba(0,0,0,0.1)] transition-all duration-300 ease-in-out hover:bg-[#e0800c] transition hover:bg-[var(--theme-button-color)]/90 disabled:opacity-50"
|
|
>
|
|
Ask your Question
|
|
</button>
|
|
</div>
|
|
|
|
{live ? (
|
|
<AskQuestionModal
|
|
open={askModalOpen}
|
|
onClose={() => setAskModalOpen(false)}
|
|
eventId={eid}
|
|
sessionId={sid}
|
|
idSuffix="-card"
|
|
/>
|
|
) : null}
|
|
</section>
|
|
);
|
|
}
|