124 lines
3.9 KiB
TypeScript
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>
|
|
);
|
|
}
|