mirror of
https://github.com/Tria-plc/emaui.git
synced 2026-08-26 13:02:50 +00:00
fix(exam): step the exam form instead of validating hidden tabs
Submitting from Basic Info complained that required fields on the Settings tab were empty — a correct error the user could not act on, since Settings had not been shown yet. The primary action now reads "Next" while Basic Info is open and validates only that tab before moving on; Create/Update appears on Settings, the final step, alongside a Back button. Submit still checks both tabs, since the tab headers stay clickable and a user can reach Settings without going through Next.
This commit is contained in:
@@ -79,21 +79,44 @@ function ExamForm({
|
|||||||
const [status, setStatus] = useState<string | null>(editing?.status ?? null);
|
const [status, setStatus] = useState<string | null>(editing?.status ?? null);
|
||||||
const [activeTab, setActiveTab] = useState<string | null>("basic");
|
const [activeTab, setActiveTab] = useState<string | null>("basic");
|
||||||
|
|
||||||
const handleSubmit = (e: React.FormEvent) => {
|
/**
|
||||||
e.preventDefault();
|
* Split per tab so "Next" can check just the tab in front of the user.
|
||||||
|
* Submitting from Basic Info used to complain about Settings fields the
|
||||||
|
* user had not been shown yet — the error was correct and unactionable at
|
||||||
|
* the same time. Each returns the message key for what is missing, or null.
|
||||||
|
*/
|
||||||
|
const validateBasic = (): string | null => {
|
||||||
if (!certificationId || !titleEn || !titleAm || !date || !venue) {
|
if (!certificationId || !titleEn || !titleAm || !date || !venue) {
|
||||||
setActiveTab("basic");
|
return "exam.form.fillRequiredBasic";
|
||||||
notify.error(t("exam.form.fillRequiredBasic"));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if ((directionEn || directionAm) && !(directionEn && directionAm)) {
|
if ((directionEn || directionAm) && !(directionEn && directionAm)) {
|
||||||
setActiveTab("basic");
|
return "exam.form.directionBothLanguages";
|
||||||
notify.error(t("exam.form.directionBothLanguages"));
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateSettings = (): string | null =>
|
||||||
|
!type || !form || !adminMethod || !evalMethod || !cuttingPoint
|
||||||
|
? "exam.form.fillRequiredSettings"
|
||||||
|
: null;
|
||||||
|
|
||||||
|
const goNext = () => {
|
||||||
|
const error = validateBasic();
|
||||||
|
if (error) {
|
||||||
|
notify.error(t(error));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!type || !form || !adminMethod || !evalMethod || !cuttingPoint) {
|
setActiveTab("settings");
|
||||||
setActiveTab("settings");
|
};
|
||||||
notify.error(t("exam.form.fillRequiredSettings"));
|
|
||||||
|
const handleSubmit = (e: React.FormEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
// Still checks both: the tabs are clickable, so a user can reach Settings
|
||||||
|
// without going through Next.
|
||||||
|
const error = validateBasic() ?? validateSettings();
|
||||||
|
if (error) {
|
||||||
|
setActiveTab(error === "exam.form.fillRequiredSettings" ? "settings" : "basic");
|
||||||
|
notify.error(t(error));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
onSubmit(
|
onSubmit(
|
||||||
@@ -337,9 +360,26 @@ function ExamForm({
|
|||||||
<Button variant="default" onClick={onCancel} size="sm">
|
<Button variant="default" onClick={onCancel} size="sm">
|
||||||
{t("exam.cancel")}
|
{t("exam.cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="submit" size="sm" loading={isSubmitting}>
|
{activeTab === "basic" ? (
|
||||||
{editing ? t("exam.update") : t("exam.create")}
|
/* Not type="submit": Basic Info is not the last step, so the
|
||||||
</Button>
|
primary action advances rather than saves. */
|
||||||
|
<Button size="sm" onClick={goNext}>
|
||||||
|
{t("exam.form.next")}
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
variant="default"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => setActiveTab("basic")}
|
||||||
|
>
|
||||||
|
{t("exam.form.back")}
|
||||||
|
</Button>
|
||||||
|
<Button type="submit" size="sm" loading={isSubmitting}>
|
||||||
|
{editing ? t("exam.update") : t("exam.create")}
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
</form>
|
</form>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
@@ -271,6 +271,8 @@ export const am: Translations = {
|
|||||||
cuttingPointPercentageHint: "የመቶኛ ግምገማ — ከ100 አይበልጥም።",
|
cuttingPointPercentageHint: "የመቶኛ ግምገማ — ከ100 አይበልጥም።",
|
||||||
fillRequiredBasic: "በመሠረታዊ መረጃ ውስጥ ያሉ አስፈላጊ መስኮችን ይሙሉ።",
|
fillRequiredBasic: "በመሠረታዊ መረጃ ውስጥ ያሉ አስፈላጊ መስኮችን ይሙሉ።",
|
||||||
fillRequiredSettings: "በቅንብሮች ውስጥ ያሉ አስፈላጊ መስኮችን ይሙሉ — ዓይነት፣ ቅጽ፣ የአስተዳደር ዘዴ፣ የግምገማ ዘዴ እና የማለፊያ ነጥብ።",
|
fillRequiredSettings: "በቅንብሮች ውስጥ ያሉ አስፈላጊ መስኮችን ይሙሉ — ዓይነት፣ ቅጽ፣ የአስተዳደር ዘዴ፣ የግምገማ ዘዴ እና የማለፊያ ነጥብ።",
|
||||||
|
next: "ቀጣይ",
|
||||||
|
back: "ተመለስ",
|
||||||
directionBothLanguages: "መመሪያ በሁለቱም እንግሊዝኛ እና አማርኛ ጽሑፍ ያስፈልገዋል፣ ወይም ሁለቱንም ባዶ ይተዉ።",
|
directionBothLanguages: "መመሪያ በሁለቱም እንግሊዝኛ እና አማርኛ ጽሑፍ ያስፈልገዋል፣ ወይም ሁለቱንም ባዶ ይተዉ።",
|
||||||
status: "ሁኔታ",
|
status: "ሁኔታ",
|
||||||
statusPlaceholder: "የፈተና ሁኔታ",
|
statusPlaceholder: "የፈተና ሁኔታ",
|
||||||
|
|||||||
@@ -271,6 +271,8 @@ export const en = {
|
|||||||
fillRequiredBasic: 'Please fill all required fields in Basic Info.',
|
fillRequiredBasic: 'Please fill all required fields in Basic Info.',
|
||||||
fillRequiredSettings: 'Please fill all required fields in Settings — type, form, administration method, evaluation method, and cutting point.',
|
fillRequiredSettings: 'Please fill all required fields in Settings — type, form, administration method, evaluation method, and cutting point.',
|
||||||
directionBothLanguages: 'Direction needs text in both English and Amharic, or leave both empty.',
|
directionBothLanguages: 'Direction needs text in both English and Amharic, or leave both empty.',
|
||||||
|
next: 'Next',
|
||||||
|
back: 'Back',
|
||||||
status: 'Status',
|
status: 'Status',
|
||||||
statusPlaceholder: 'Exam status',
|
statusPlaceholder: 'Exam status',
|
||||||
pending: 'Pending',
|
pending: 'Pending',
|
||||||
|
|||||||
Reference in New Issue
Block a user