Prelegent widzi zadania i banery na sali

`PublicTaskOfferController` szukal tokenu wylacznie w `registrations`,
a prelegent tam nie istnieje: nie przechodzi przez formularz zapisu i ma
wlasny token w `webinar_speakers`. Kazdy endpoint sali odpowiadal mu 404.

Objawialo sie to tym, ze prowadzacy **nie widzial wlasnych zadan**: panel
pokazywal "Nie znaleziono zapisu" przy zadaniu ogloszonym minute wczesniej
i widocznym w panelu prowadzenia. Tak samo znikaly banery i nie liczyly sie
ich wyswietlenia. Zdarzylo sie to na zywo, w trakcie spotkania.

Nowa metoda `TaskService.viewer` obsluguje oba rodzaje tokenu, wzorowana na
`PublicInteractionController`, ktory robil to juz przy historii czatu.
Przelaczone sa WYLACZNIE odczyty: lista zadan, banery i ich zdarzenia.
Zapisy (zgloszenie do zadania, wyslanie oferty) zostaja przy `participant`,
bo prelegent nie zapisuje sie na wlasne zadanie.

`registrationId` rowne null jest tu poprawna wartoscia, nie brakiem danych:
`listViews` przewidywalo to od poczatku, a `banner_events.registration_id`
jest nullowalne wlasnie dla zdarzen od osob bez zapisu.

Front: `TasksTab` dostaje tryb `readOnly`, wiec prowadzacy widzi zadania
i liczbe zapisanych, ale bez przycisku zgloszenia.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-04 09:44:28 +02:00
parent 5138268b6d
commit 2bc2e6525c
4 changed files with 79 additions and 17 deletions
@@ -161,7 +161,9 @@ export function InteractionPanel({
</div>
)}
{tab === 'tasks' && <TasksTab token={token} webinarId={history.webinarId} />}
{tab === 'tasks' && (
<TasksTab token={token} webinarId={history.webinarId} readOnly={history.speaker} />
)}
{tab === 'offer' && !history.speaker && <OfferTab token={token} />}
{tab === 'chat' ? (
+27 -11
View File
@@ -25,7 +25,21 @@ export type TaskView = {
createdAt: string
}
export function TasksTab({ token, webinarId }: { token: string; webinarId: number }) {
export function TasksTab({
token,
webinarId,
readOnly = false,
}: {
token: string
webinarId: number
/**
* Podglad bez mozliwosci zapisu.
*
* Prowadzacy widzi zadania, ktore sam oglosil, ale nie zapisuje sie na nie:
* nie ma wiersza w `registrations`, wiec backend i tak odrzucilby zgloszenie.
*/
readOnly?: boolean
}) {
const [tasks, setTasks] = useState<TaskView[]>([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
@@ -129,16 +143,18 @@ export function TasksTab({ token, webinarId }: { token: string; webinarId: numbe
)}
{!task.open && <span className="text-xs text-warn-600">zapisy zamknięte</span>}
<Button
type="button"
size="sm"
variant={task.signedUp ? 'secondary' : 'primary'}
className="ml-auto"
disabled={busy === task.id || (blocked && !task.signedUp)}
onClick={() => toggle(task)}
>
{task.signedUp ? 'Wycofaj się' : task.full ? 'Brak miejsc' : 'Zgłaszam się'}
</Button>
{!readOnly && (
<Button
type="button"
size="sm"
variant={task.signedUp ? 'secondary' : 'primary'}
className="ml-auto"
disabled={busy === task.id || (blocked && !task.signedUp)}
onClick={() => toggle(task)}
>
{task.signedUp ? 'Wycofaj się' : task.full ? 'Brak miejsc' : 'Zgłaszam się'}
</Button>
)}
</div>
{task.signedUp && (