You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

164 lines
5.3 KiB

"use client";
import Image from "next/image";
import { useRouter } from "next/navigation";
import type { ReactNode } from "react";
import { useCallback, useState } from "react";
import { localizePath } from "@/translations/config";
import { useI18n } from "@/translations/provider";
import { useQuestionAnswers } from "./question-answer-storage";
import QuestionProgressTracker, {
useQuestionProgress,
} from "./question-progress-tracker";
import QuestionSnapList from "./question-snap-list";
import type { QuestionField } from "@/lib/schema-adapter";
import NoticeBox from "./notice-box";
import AnswerPaceSheet from "@/app/questions-list/[slug]/answer-pace-sheet";
import { FixToTheEnd } from "./fix-to-the-end";
import Button from "./button";
import { markFirstEntryCompleted } from "@/lib/first-entry-helper";
type QuestionSectionFlowProps = {
children: ReactNode;
continueLabel: string;
exitHref: string;
total: number;
optionalQuestionIndexes: readonly number[];
questions?: readonly QuestionField[];
};
function SectionFlowContent({
children,
continueLabel,
exitHref,
optionalQuestionIndexes,
questions,
}: {
children: ReactNode;
continueLabel: string;
exitHref: string;
optionalQuestionIndexes: readonly number[];
questions?: readonly QuestionField[];
}) {
const router = useRouter();
const { dictionary: t, locale } = useI18n();
const { flushAnswers } = useQuestionAnswers();
const { markQuestionPassed, isCompleted } = useQuestionProgress();
const [activeQuestionIndex, setActiveQuestionIndex] = useState(0);
const [isSubmitting, setIsSubmitting] = useState(false);
const handleQuestionExit = useCallback(() => {
void flushAnswers({ force: true });
}, [flushAnswers]);
const handleSubmit = useCallback(async () => {
if (isSubmitting) {
return;
}
setIsSubmitting(true);
try {
markFirstEntryCompleted();
await flushAnswers({ force: true });
} catch {
// ignore
} finally {
const target = localizePath(exitHref || "/questions-list", locale);
router.push(target);
}
}, [exitHref, flushAnswers, locale, router, isSubmitting]);
const markOptionalQuestionsPassed = useCallback(
(currentIndex: number, nextIndex: number) => {
[currentIndex, nextIndex].forEach((questionIndex) => {
if (optionalQuestionIndexes.includes(questionIndex)) {
markQuestionPassed(questionIndex);
}
});
},
[markQuestionPassed, optionalQuestionIndexes],
);
const activeQuestion = questions?.[activeQuestionIndex];
const showNotice = activeQuestion?.showGuardianNotice;
const isUnder27 = activeQuestion?.required ?? false;
return (
<>
<AnswerPaceSheet
activeQuestionIndex={activeQuestionIndex}
title={t["Answer at Your Own Pace"]}
description={
t[
"You can pause the survey anytime and resume later. Your progress is saved automatically."
]
}
continueLabel={continueLabel || t["Submit"]}
/>
{showNotice && (
<div className="w-full px-[17px] mb-6 shrink-0">
<NoticeBox>
{isUnder27
? t[
"To preserve your peace of mind, security, and dignity, the acquaintance process on our platform follows authentic and respectful family traditions. Having a trusted person (preferably a father or mother) as a representative, in addition to reflecting your noble family background, encourages the other party to step forward with full seriousness, respect, and confidence."
]
: t[
"Our goal is to establish lasting bonds based on mutual trust. Although registering a representative is not mandatory for you, introducing a trusted person (such as a father, mother, or family elder) demonstrates your transparency and serious intent for marriage. Profiles that feature a trusted representative command significantly higher credibility and provide greater peace of mind to the other party's family."
]}
</NoticeBox>
</div>
)}
<QuestionSnapList
alignTop={showNotice}
firstQuestionHint={
<Image
src="/assets/images/Frame 1597880476.svg"
alt=""
aria-hidden="true"
width={31}
height={31}
/>
}
onQuestionExit={handleQuestionExit}
onQuestionTransition={markOptionalQuestionsPassed}
onActiveIndexChange={setActiveQuestionIndex}
>
{children}
</QuestionSnapList>
<FixToTheEnd>
<Button
disabled={!isCompleted || isSubmitting}
isLoading={isSubmitting}
onClick={handleSubmit}
>
{continueLabel || t["Submit"]}
</Button>
</FixToTheEnd>
</>
);
}
export function QuestionSectionFlow({
children,
continueLabel,
exitHref,
total,
optionalQuestionIndexes,
questions,
}: QuestionSectionFlowProps) {
return (
<QuestionProgressTracker total={total}>
<SectionFlowContent
continueLabel={continueLabel}
exitHref={exitHref}
optionalQuestionIndexes={optionalQuestionIndexes}
questions={questions}
>
{children}
</SectionFlowContent>
</QuestionProgressTracker>
);
}
export default QuestionSectionFlow;