2026-09-15 23:24:34 +03:30
|
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
|
|
import { useEffect, useState } from "react";
|
2026-09-19 22:17:29 +03:30
|
|
|
|
import { StepFooterButton } from "@/components/onboarding/StepFooterButton";
|
2026-09-15 23:24:34 +03:30
|
|
|
|
import { ErrorBanner } from "@/components/ui/ErrorBanner";
|
|
|
|
|
|
import { FullScreenLoader } from "@/components/ui/FullScreenLoader";
|
|
|
|
|
|
import { OptionPicker } from "@/components/ui/OptionPicker";
|
|
|
|
|
|
import { getOptions, submitEducation, Option, FullProfile } from "@/lib/api";
|
|
|
|
|
|
import { formatApiError } from "@/lib/hooks";
|
|
|
|
|
|
|
|
|
|
|
|
function findSelection(profile: FullProfile | null, key: string): number[] {
|
|
|
|
|
|
return profile?.selections.find((s) => s.category_key === key)?.option_ids ?? [];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function EducationStep({
|
|
|
|
|
|
initialProfile,
|
|
|
|
|
|
onNext,
|
|
|
|
|
|
}: {
|
|
|
|
|
|
initialProfile: FullProfile | null;
|
|
|
|
|
|
onNext: () => void;
|
|
|
|
|
|
}) {
|
|
|
|
|
|
const [levelOptions, setLevelOptions] = useState<Option[] | null>(null);
|
|
|
|
|
|
const [fieldOptions, setFieldOptions] = useState<Option[] | null>(null);
|
|
|
|
|
|
const [levelId, setLevelId] = useState<number[]>(
|
|
|
|
|
|
findSelection(initialProfile, "education_level")
|
|
|
|
|
|
);
|
|
|
|
|
|
const [fieldId, setFieldId] = useState<number[]>(
|
|
|
|
|
|
findSelection(initialProfile, "field_of_study")
|
|
|
|
|
|
);
|
|
|
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
Promise.all([getOptions("education_level"), getOptions("field_of_study")])
|
|
|
|
|
|
.then(([lvl, field]) => {
|
|
|
|
|
|
setLevelOptions(lvl);
|
|
|
|
|
|
setFieldOptions(field);
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch((err) => setError(formatApiError(err)));
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
|
|
const isValid = levelId.length === 1 && fieldId.length === 1;
|
|
|
|
|
|
|
|
|
|
|
|
async function handleSubmit() {
|
|
|
|
|
|
if (!isValid) return;
|
|
|
|
|
|
setLoading(true);
|
|
|
|
|
|
setError(null);
|
|
|
|
|
|
try {
|
|
|
|
|
|
await submitEducation({
|
|
|
|
|
|
education_level_option_id: levelId[0],
|
|
|
|
|
|
field_of_study_option_id: fieldId[0],
|
|
|
|
|
|
});
|
|
|
|
|
|
onNext();
|
|
|
|
|
|
} catch (err) {
|
|
|
|
|
|
setError(formatApiError(err));
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
setLoading(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!levelOptions || !fieldOptions) return <FullScreenLoader label="گزینهها رو میاریم..." />;
|
|
|
|
|
|
|
|
|
|
|
|
if (levelOptions.length === 0 || fieldOptions.length === 0) {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<ErrorBanner message="هنوز گزینهای برای تحصیلات توی پنل ادمین ثبت نشده. اول باید ادمین اینها رو اضافه کنه." />
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<div className="flex flex-col gap-7">
|
|
|
|
|
|
<div className="flex flex-col gap-3">
|
|
|
|
|
|
<label className="text-[13px] font-semibold text-(--color-content-secondary) px-1">
|
|
|
|
|
|
سطح تحصیلات
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<OptionPicker options={levelOptions} selectedIds={levelId} onChange={setLevelId} mode="single" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div className="flex flex-col gap-3">
|
|
|
|
|
|
<label className="text-[13px] font-semibold text-(--color-content-secondary) px-1">
|
|
|
|
|
|
رشته تحصیلی
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<OptionPicker options={fieldOptions} selectedIds={fieldId} onChange={setFieldId} mode="single" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<ErrorBanner message={error} />
|
|
|
|
|
|
|
2026-09-19 22:17:29 +03:30
|
|
|
|
<StepFooterButton disabled={!isValid} isLoading={loading} onClick={handleSubmit}>
|
2026-09-15 23:24:34 +03:30
|
|
|
|
بریم مرحله بعد
|
2026-09-19 22:17:29 +03:30
|
|
|
|
</StepFooterButton>
|
2026-09-15 23:24:34 +03:30
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|