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
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;
|