137 lines
4.3 KiB
TypeScript
137 lines
4.3 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";
|
||
import { createTemplateLayoutProps } from "@/lib/funnel/templateHelpers";
|
||
|
||
export interface ListTemplateProps {
|
||
screen: ListScreenDefinition;
|
||
selectedOptionIds: string[];
|
||
onSelectionChange: (
|
||
selectedIds: string[],
|
||
skipCheckChanges?: boolean
|
||
) => 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 handleRadioAnswerClick: RadioAnswersListProps["onAnswerClick"] = (
|
||
answer
|
||
) => {
|
||
const id = stringId(answer?.id);
|
||
onSelectionChange(id ? [id] : [], true);
|
||
};
|
||
|
||
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 чтобы избежать двойного вызова при клике
|
||
// onAnswerClick достаточно для обработки выбора
|
||
onAnswerClick: handleRadioAnswerClick,
|
||
};
|
||
|
||
const selectContent: SelectAnswersListProps = {
|
||
answers: buttons,
|
||
activeAnswers,
|
||
onChangeSelectedAnswers: handleSelectChange,
|
||
};
|
||
|
||
const actionButtonOptions = actionButtonProps
|
||
? {
|
||
defaultText: (actionButtonProps.children as string) || "Next",
|
||
// Кнопка неактивна если: 1) disabled из props ИЛИ 2) ничего не выбрано
|
||
disabled: actionButtonProps.disabled || selectedOptionIds.length === 0,
|
||
onClick: () => {
|
||
if (actionButtonProps.onClick) {
|
||
actionButtonProps.onClick(
|
||
{} as React.MouseEvent<HTMLButtonElement>
|
||
);
|
||
}
|
||
},
|
||
}
|
||
: undefined;
|
||
|
||
const layoutProps = createTemplateLayoutProps(
|
||
screen,
|
||
{ canGoBack, onBack },
|
||
screenProgress,
|
||
{
|
||
preset: "left",
|
||
actionButton: actionButtonOptions,
|
||
}
|
||
);
|
||
|
||
return (
|
||
<TemplateLayout {...layoutProps}>
|
||
<div className="w-full mt-[22px]">
|
||
{contentType === "radio-answers-list" ? (
|
||
<RadioAnswersList {...radioContent} />
|
||
) : (
|
||
<SelectAnswersList {...selectContent} />
|
||
)}
|
||
</div>
|
||
</TemplateLayout>
|
||
);
|
||
}
|