w-funnel/src/components/funnel/templates/interactive/ListTemplate.tsx
dev.daminik00 e98b1bfc05 fix
2025-09-28 15:59:45 +02:00

124 lines
3.9 KiB
TypeScript

"use client";
import { useMemo } from "react";
import { RadioAnswersList } from "@/components/widgets/RadioAnswersList/RadioAnswersList";
import { SelectAnswersList } from "@/components/widgets/SelectAnswersList/SelectAnswersList";
import type { ActionButtonProps } from "@/components/ui/ActionButton/ActionButton";
import type { MainButtonProps } from "@/components/ui/MainButton/MainButton";
import type { RadioAnswersListProps } from "@/components/widgets/RadioAnswersList/RadioAnswersList";
import type { SelectAnswersListProps } from "@/components/widgets/SelectAnswersList/SelectAnswersList";
import { mapListOptionsToButtons } from "@/lib/funnel/mappers";
import type { ListScreenDefinition } from "@/lib/funnel/types";
import { TemplateLayout } from "../layouts/TemplateLayout";
interface ListTemplateProps {
screen: ListScreenDefinition;
selectedOptionIds: string[];
onSelectionChange: (selectedIds: string[]) => void;
actionButtonProps?: ActionButtonProps;
canGoBack: boolean;
onBack: () => void;
screenProgress?: { current: number; total: number };
}
function stringId(value: MainButtonProps["id"]): string | null {
if (value === undefined || value === null) {
return null;
}
return String(value);
}
export function ListTemplate({
screen,
selectedOptionIds,
onSelectionChange,
actionButtonProps,
canGoBack,
onBack,
screenProgress,
}: ListTemplateProps) {
const buttons = useMemo(
() => mapListOptionsToButtons(screen.list.options, screen.list.selectionType),
[screen.list.options, screen.list.selectionType]
);
const selectionSet = useMemo(
() => new Set(selectedOptionIds.map((id) => String(id))),
[selectedOptionIds]
);
const contentType: "radio-answers-list" | "select-answers-list" =
screen.list.selectionType === "multi"
? "select-answers-list"
: "radio-answers-list";
const activeAnswer: MainButtonProps | null =
contentType === "radio-answers-list"
? buttons.find((button) => selectionSet.has(String(button.id))) ?? null
: null;
const activeAnswers: MainButtonProps[] | null =
contentType === "select-answers-list"
? buttons.filter((button) => selectionSet.has(String(button.id)))
: null;
const handleRadioChange: RadioAnswersListProps["onChangeSelectedAnswer"] = (
answer
) => {
const id = stringId(answer?.id);
onSelectionChange(id ? [id] : []);
};
const handleSelectChange: SelectAnswersListProps["onChangeSelectedAnswers"] = (
answers
) => {
const ids = answers
?.map((answer) => stringId(answer.id))
.filter((value): value is string => Boolean(value));
onSelectionChange(ids ?? []);
};
const radioContent: RadioAnswersListProps = {
answers: buttons,
activeAnswer,
onChangeSelectedAnswer: handleRadioChange,
};
const selectContent: SelectAnswersListProps = {
answers: buttons,
activeAnswers,
onChangeSelectedAnswers: handleSelectChange,
};
const actionButtonOptions = actionButtonProps ? {
defaultText: actionButtonProps.children as string || "Next",
disabled: actionButtonProps.disabled || false,
onClick: () => {
if (actionButtonProps.onClick) {
actionButtonProps.onClick({} as React.MouseEvent<HTMLButtonElement>);
}
},
} : undefined;
return (
<TemplateLayout
screen={screen}
canGoBack={canGoBack}
onBack={onBack}
screenProgress={screenProgress}
titleDefaults={{ font: "manrope", weight: "bold", align: "left", size: "2xl", color: "default" }}
subtitleDefaults={{ font: "manrope", weight: "medium", color: "default", align: "left", size: "lg" }}
actionButtonOptions={actionButtonOptions}
>
<div className="w-full mt-[22px]">
{contentType === "radio-answers-list" ? (
<RadioAnswersList {...radioContent} />
) : (
<SelectAnswersList {...selectContent} />
)}
</div>
</TemplateLayout>
);
}