2 Commits

  1. 6
      src/app/questions-list/page.tsx
  2. 76
      src/components/Componentes/button.tsx
  3. 7
      src/components/Componentes/question-answer-storage.tsx
  4. 2
      src/hooks/marriage/types.ts
  5. 2
      src/hooks/marriage/use-form-schema.ts
  6. 6
      src/hooks/marriage/use-section-data.ts

6
src/app/questions-list/page.tsx

@ -284,6 +284,7 @@ export default function QuestionsListPage() {
const result = await updateMarriageSectionData(pendingSections[0].slug, { const result = await updateMarriageSectionData(pendingSections[0].slug, {
current_step: pendingSections[0].storedValue.current_step, current_step: pendingSections[0].storedValue.current_step,
fields: pendingSections.flatMap((section) => section.fields), fields: pendingSections.flatMap((section) => section.fields),
version: overview.version,
}); });
applyProfilePatchResultToCache(queryClient, locale, result); applyProfilePatchResultToCache(queryClient, locale, result);
const cleared = new Set(result.cleared_answer_ids ?? []); const cleared = new Set(result.cleared_answer_ids ?? []);
@ -452,6 +453,11 @@ export default function QuestionsListPage() {
} catch (err) { } catch (err) {
console.error("Failed to sync pending sections:", err); console.error("Failed to sync pending sections:", err);
setIsSyncError(true); setIsSyncError(true);
setToastMessage(
t[
"Sending the match request failed. Please check your connection and try again."
] ?? "Sending the match request failed. Please check your connection and try again."
);
} finally { } finally {
setIsSyncing(false); setIsSyncing(false);
} }

76
src/components/Componentes/button.tsx

@ -153,7 +153,47 @@ export function Button({
); );
}; };
const button = (
const content = isLoading ? (
<LoadingThreeDot />
) : (
<span className="flex w-full items-center justify-center gap-2">
{renderArrow("left")}
<span className="flex min-w-0 flex-col items-center justify-center">
<span className="flex items-center justify-center gap-2 text-center group-16 font-semibold leading-none">
{children}
</span>
{description && !isOutlined ? (
<span
id={countdownId}
className="mt-1 text-center group-10 font-semibold leading-none text-white"
>
{description}
</span>
) : null}
</span>
{countdownLocked ? (
<span className="shrink-0">
<CountdownProgress value={remainingSeconds} progress={progress} />
</span>
) : (
renderArrow("right")
)}
</span>
);
if (href) {
return (
<Link
href={localizePath(href, locale)}
aria-disabled={isDisabled}
className={`${baseClassName} ${isDisabled ? "pointer-events-none" : ""}`}
>
{content}
</Link>
);
}
return (
<button <button
{...props} {...props}
type={type} type={type}
@ -161,41 +201,9 @@ export function Button({
aria-describedby={description && !isOutlined ? countdownId : undefined} aria-describedby={description && !isOutlined ? countdownId : undefined}
className={baseClassName} className={baseClassName}
> >
{isLoading ? (
<LoadingThreeDot />
) : (
<span className="flex w-full items-center justify-center gap-2">
{renderArrow("left")}
<span className="flex min-w-0 flex-col items-center justify-center">
<span className="flex items-center justify-center gap-2 text-center group-16 font-semibold leading-none">
{children}
</span>
{description && !isOutlined ? (
<span
id={countdownId}
className="mt-1 text-center group-10 font-semibold leading-none text-white"
>
{description}
</span>
) : null}
</span>
{countdownLocked ? (
<span className="shrink-0">
<CountdownProgress value={remainingSeconds} progress={progress} />
</span>
) : (
renderArrow("right")
)}
</span>
)}
{content}
</button> </button>
); );
return href ? (
<Link href={localizePath(href, locale)}>{button}</Link>
) : (
button
);
} }
type CountdownProgressProps = { type CountdownProgressProps = {

7
src/components/Componentes/question-answer-storage.tsx

@ -317,6 +317,7 @@ export function QuestionAnswersProvider({
const storageKeyRef = useRef(storageKey); const storageKeyRef = useRef(storageKey);
const slugRef = useRef(slug); const slugRef = useRef(slug);
const backendFieldsRef = useRef<MarriageField[]>([]); const backendFieldsRef = useRef<MarriageField[]>([]);
const versionRef = useRef<number | undefined>(undefined);
const dirtyKeysRef = useRef(new Set<string>()); const dirtyKeysRef = useRef(new Set<string>());
const { data: profile } = useMarriageProfileQuery(); const { data: profile } = useMarriageProfileQuery();
@ -331,12 +332,14 @@ export function QuestionAnswersProvider({
slugRef.current = slug; slugRef.current = slug;
questionsRef.current = questions; questionsRef.current = questions;
backendFieldsRef.current = serverSectionData?.data || []; backendFieldsRef.current = serverSectionData?.data || [];
versionRef.current = serverSectionData?.version;
}, [ }, [
answers, answers,
hasPendingSync, hasPendingSync,
slug, slug,
questions, questions,
serverSectionData?.data, serverSectionData?.data,
serverSectionData?.version,
]); ]);
useEffect(() => { useEffect(() => {
@ -491,6 +494,7 @@ export function QuestionAnswersProvider({
fields: nextDirtyKey fields: nextDirtyKey
? fullPayload.fields.filter((field) => field.key === nextDirtyKey) ? fullPayload.fields.filter((field) => field.key === nextDirtyKey)
: [], : [],
version: versionRef.current,
}; };
const revision = answersRevisionRef.current; const revision = answersRevisionRef.current;
@ -591,7 +595,7 @@ export function QuestionAnswersProvider({
const pendingFields = fullPayload.fields.filter((field) => const pendingFields = fullPayload.fields.filter((field) =>
dirtyKeysRef.current.has(field.key), dirtyKeysRef.current.has(field.key),
); );
const payload = { ...fullPayload, fields: pendingFields };
const payload = { ...fullPayload, fields: pendingFields, version: versionRef.current };
const revision = answersRevisionRef.current; const revision = answersRevisionRef.current;
if (payload.fields.length === 0) { if (payload.fields.length === 0) {
@ -616,6 +620,7 @@ export function QuestionAnswersProvider({
fetch(getKeepalivePatchUrl(slugRef.current), { fetch(getKeepalivePatchUrl(slugRef.current), {
body: JSON.stringify({ body: JSON.stringify({
answers: answersPayload, answers: answersPayload,
version: payload.version,
}), }),
credentials: "include", credentials: "include",
headers, headers,

2
src/hooks/marriage/types.ts

@ -148,12 +148,14 @@ export type MarriageSectionData = {
total_steps: number; total_steps: number;
completion_percent: number; completion_percent: number;
updated_at: string | null; updated_at: string | null;
version?: number;
}; };
export type UpdateMarriageSectionDataPayload = { export type UpdateMarriageSectionDataPayload = {
current_step: number; current_step: number;
total_steps?: number; total_steps?: number;
fields: MarriageField[]; fields: MarriageField[];
version?: number;
}; };
export type MarriageQuestionState = { export type MarriageQuestionState = {

2
src/hooks/marriage/use-form-schema.ts

@ -77,12 +77,14 @@ export interface FormOverviewSection extends Omit<FormSection, "cards"> {
export interface FormOverviewResponse { export interface FormOverviewResponse {
form_id: string; form_id: string;
version: number;
sections: FormOverviewSection[]; sections: FormOverviewSection[];
progress: FormSchemaResponse["progress"]; progress: FormSchemaResponse["progress"];
} }
export interface FormSectionResponse { export interface FormSectionResponse {
form_id: string; form_id: string;
version: number;
section: FormSection; section: FormSection;
answers: FormSchemaResponse["answers"]; answers: FormSchemaResponse["answers"];
progress: FormSchemaResponse["progress"]; progress: FormSchemaResponse["progress"];

6
src/hooks/marriage/use-section-data.ts

@ -25,10 +25,11 @@ type AnswersPayloadItem = {
async function patchAnswers( async function patchAnswers(
answersPayload: AnswersPayloadItem[], answersPayload: AnswersPayloadItem[],
version?: number,
): Promise<ProfileAnswersPatchResult> { ): Promise<ProfileAnswersPatchResult> {
const response = await http.patch<ProfileAnswersPatchResult>( const response = await http.patch<ProfileAnswersPatchResult>(
ANSWERS_ENDPOINT, ANSWERS_ENDPOINT,
{ answers: answersPayload },
{ answers: answersPayload, version },
); );
return response.data; return response.data;
} }
@ -43,7 +44,7 @@ export async function updateMarriageSectionData(
option_id: f.option_id || undefined, option_id: f.option_id || undefined,
})); }));
const data = await patchAnswers(answersPayload);
const data = await patchAnswers(answersPayload, payload.version);
const prog = data.affected_sections[slug] || const prog = data.affected_sections[slug] ||
data.progress.sections_progress[slug] || { data.progress.sections_progress[slug] || {
@ -204,6 +205,7 @@ export function useMarriageSectionDataQuery(
data: fields, data: fields,
...progress, ...progress,
updated_at: null, updated_at: null,
version: query.data.version,
}; };
})() })()
: undefined, : undefined,

Loading…
Cancel
Save