diff --git a/apps/edr-freight-web/portal/src/pages/settings/TabDocuments.tsx b/apps/edr-freight-web/portal/src/pages/settings/TabDocuments.tsx index 4425c513e..a6e48393a 100644 --- a/apps/edr-freight-web/portal/src/pages/settings/TabDocuments.tsx +++ b/apps/edr-freight-web/portal/src/pages/settings/TabDocuments.tsx @@ -1,4 +1,16 @@ -import { useState } from "react"; +import { api } from "@/services/api"; +import { companiesService } from "@/services/companies.service"; +import { getMinFiles } from "@/types/fileUploadSettings"; +import type { ProfileResponse } from "@/types/profile"; +import { SmartFileInput } from "@edr/ui-common"; +import { + Button, + Card, + Center, + Group, + Text, + Title, +} from "@mantine/core"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { ArrowRight, @@ -8,18 +20,7 @@ import { UploadCloud, XCircle, } from "lucide-react"; -import { - Card, - Group, - Title, - Text, - Button, - Center, -} from "@mantine/core"; -import { api } from "@/services/api"; -import { companiesService } from "@/services/companies.service"; -import { SmartFileInput } from "@edr/ui-common"; -import type { ProfileResponse } from "@/types/profile"; +import { useState } from "react"; interface TabDocumentsProps { profile: ProfileResponse; @@ -45,6 +46,42 @@ export default function TabDocuments({ profile, mode = "edit", onContinue }: Tab }, }); + const [fieldErrors, setFieldErrors] = useState>({}); + + const handleFilesChange = (next: Record) => { + setDocumentFiles(next); + // Clear required-field errors for any field that now has a file. + setFieldErrors((prev) => { + if (Object.keys(prev).length === 0) return prev; + const updated = { ...prev }; + for (const key of Object.keys(updated)) { + const v = next[key]; + const hasValue = Array.isArray(v) ? v.length > 0 : v != null; + if (hasValue) delete updated[key]; + } + return updated; + }); + }; + + // Array-aware: an emptied multi-file field is `[]`, which must not count. + const hasFiles = Object.values(documentFiles).some((f) => + Array.isArray(f) ? f.length > 0 : f != null, + ); + + const validateRequired = (): Record => { + const errs: Record = {}; + for (const field of docSettingQuery.data?.fields ?? []) { + const min = getMinFiles(field); + if (min <= 0) continue; + const v = documentFiles[field.fileKey]; + const count = Array.isArray(v) ? v.length : v ? 1 : 0; + if (count < min) { + errs[field.fileKey] = `${field.fileLabel} is required`; + } + } + return errs; + }; + return ( @@ -67,7 +104,8 @@ export default function TabDocuments({ profile, mode = "edit", onContinue }: Tab )} @@ -100,13 +138,14 @@ export default function TabDocuments({ profile, mode = "edit", onContinue }: Tab leftSection={} loading={docUploadMutation.isPending} onClick={() => { - const hasFiles = Object.values(documentFiles).some((f) => f !== null); + const validationErrors = validateRequired(); + if (Object.keys(validationErrors).length > 0) { + setFieldErrors(validationErrors); + return; + } if (hasFiles) { docUploadMutation.mutate(documentFiles, { - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: api.companies.getProfile.queryKey() }); - onContinue?.(); - }, + onSuccess: () => onContinue?.(), }); } else { onContinue?.(); @@ -120,7 +159,11 @@ export default function TabDocuments({ profile, mode = "edit", onContinue }: Tab type="button" leftSection={} loading={docUploadMutation.isPending} - onClick={() => docUploadMutation.mutate(documentFiles)} + disabled={!hasFiles} + onClick={() => { + if (!hasFiles) return; + docUploadMutation.mutate(documentFiles); + }} > Upload Documents