Merge pull request #829 from Tria-plc/freight_feature/usermanagement

changes
This commit is contained in:
marshal
2026-07-20 08:54:09 +03:00
committed by GitHub
2 changed files with 13 additions and 125 deletions

View File

@@ -39,11 +39,9 @@ import {
import useAuth from "@/hooks/useAuth";
import {
CONTRACT_STEPS,
EDIT_CONTRACT_STEPS,
ContractFormInputValues,
contractFormSchema,
contractStepFields,
editContractStepFields,
initialContractFormValues,
OPERATION_TYPES,
type ContractFormValues,
@@ -55,12 +53,6 @@ import {
operationToTradeDirection,
} from "./new-contract-form/helpers";
import { contractToFormValues } from "./new-contract-form/contractToForm";
import {
ContractDocsEditor,
documentSettingCode,
missingRequiredDocKeys,
useCompanyDocuments,
} from "./new-contract-form/ContractDocsEditor";
import { PROFILE_TYPE_LABELS } from "@/constants/profileMode";
import type { ProfileTypeValue } from "@/services/companies.service";
import { StepIndicator } from "./new-contract-form/StepIndicator";
@@ -84,8 +76,8 @@ type PriceModalMode = "submit" | "draft";
* The contract wizard, used both to create a new contract and — in `edit` mode —
* to continue an unsubmitted DRAFT or edit & resubmit a contract staff returned
* with CHANGES_REQUESTED. Edit mode hydrates the form from the saved contract,
* lets the customer change any term and replace documents, then runs the same
* update → price → submit flow.
* lets the customer change any term, then runs the same update → price →
* submit flow. Same 3 steps as create — there is no separate documents step.
*/
export default function NewContractPage({
mode = "create",
@@ -105,22 +97,6 @@ export default function NewContractPage({
...api.contracts.get.queryOptions({ input: { id: editId ?? "" } }),
enabled: isEdit,
});
// Onboarding document requirements — used in edit mode to block resubmit until
// every required document is on file (existing or freshly attached).
const editDocSettingQuery = useQuery({
...api.fileUploadSettings.getByCode.queryOptions({
input: {
code: documentSettingCode(
auth.company?.company?.nationality as string | null | undefined,
),
},
}),
enabled: isEdit,
});
// Profile documents (TIN, licenses, IDs) satisfy requirements too — the API
// carries them onto the contract on save.
const companyDocs = useCompanyDocuments();
// Contract creation is gated on profile approval, same as bookings.
if (!auth.isPending && auth.company && !auth.canBook) {
return <Navigate to="/contracts" replace />;
@@ -167,12 +143,6 @@ export default function NewContractPage({
const [priceContractId, setPriceContractId] = useState<string | null>(
isEdit ? (editId ?? null) : null,
);
// Documents freshly attached on the review step (edit mode only). Merged into
// the form's `documents` map before the contract is updated.
const [editDocuments, setEditDocuments] = useState<
Record<string, File | File[] | null>
>({});
const [showDocErrors, setShowDocErrors] = useState(false);
const [priceModalMode, setPriceModalMode] = useState<PriceModalMode | null>(
null,
);
@@ -311,10 +281,9 @@ export default function NewContractPage({
const destinationYard = form.watch("destinationYard");
const operationType = form.watch("operationType");
const visibleSteps = useMemo(
() => (isEdit ? EDIT_CONTRACT_STEPS : CONTRACT_STEPS),
[isEdit],
);
// Create and edit share the same 3 steps — documents come along automatically
// (company profile docs are carried onto the contract by the API on save).
const visibleSteps = CONTRACT_STEPS;
const visibleStepIds = useMemo<number[]>(
() => visibleSteps.map((s) => s.id),
[visibleSteps],
@@ -519,25 +488,11 @@ export default function NewContractPage({
}, [auth.company, auth.activeCompanyProfileId]);
async function handleContinue() {
const stepFields = isEdit ? editContractStepFields : contractStepFields;
const fields = stepFields[step];
const fields = contractStepFields[step];
if (fields.length > 0) {
const valid = await form.trigger(fields, { shouldFocus: true });
if (!valid) return;
}
if (isEdit && step === 2 && editContract) {
const missing = missingRequiredDocKeys(
editDocSettingQuery.data,
editContract,
editDocuments,
companyDocs,
);
if (missing.length > 0) {
setShowDocErrors(true);
return;
}
setShowDocErrors(false);
}
goToStep(1);
}
@@ -649,26 +604,6 @@ export default function NewContractPage({
const handleSubmitContract = form.handleSubmit((data) => {
try {
// Edit mode: all required documents must be on file (already uploaded or
// freshly attached) before resubmitting, and freshly attached files are
// merged into the form's documents map so the update sends them.
if (isEdit && editContract) {
const missing = missingRequiredDocKeys(
editDocSettingQuery.data,
editContract,
editDocuments,
companyDocs,
);
if (missing.length > 0) {
setShowDocErrors(true);
return;
}
setShowDocErrors(false);
form.setValue("documents", {
...(form.getValues("documents") ?? {}),
...editDocuments,
});
}
const apiPayload = buildApiPayload(data);
persistAndPriceMutation.mutate({
payload: apiPayload,
@@ -724,8 +659,8 @@ export default function NewContractPage({
<Text size="sm" c="edr-muted" mt={4}>
{isEdit
? editContract?.status === "CHANGES_REQUESTED"
? "Update your contract details and documents, then resubmit it for EDR staff review."
: "Update your draft contract details and documents, then submit it for EDR staff review."
? "Update your contract details, then resubmit it for EDR staff review."
: "Update your draft contract details, then submit it for EDR staff review."
: "Define your freight contract — scope, routes, and unit rates. Book shipments against it after signing."}
</Text>
</Box>
@@ -769,12 +704,12 @@ export default function NewContractPage({
{editContract.latestChangeRequestNote}
</Text>
<Text size="sm" c="dimmed" mt={2}>
Update the details or documents below, then resubmit the
contract for review.
Update the details below, then resubmit the contract for
review.
</Text>
</Stack>
) : (
"Update any contract detail or document that needs to change, then resubmit the contract for review."
"Update any contract detail that needs to change, then resubmit the contract for review."
)}
</Alert>
)}
@@ -843,35 +778,8 @@ export default function NewContractPage({
</StepCard>
)}
{/* Step 2 (edit) — Documents. */}
{step === 2 && isEdit && editContract && (
<StepCard>
<StepHeader
title="Contract Documents"
description="Upload or replace the documents required for this contract before resubmitting."
/>
<ContractDocsEditor
contract={editContract}
value={editDocuments}
onChange={setEditDocuments}
errors={
showDocErrors
? Object.fromEntries(
missingRequiredDocKeys(
editDocSettingQuery.data,
editContract,
editDocuments,
companyDocs,
).map((k) => [k, "Required"]),
)
: {}
}
/>
</StepCard>
)}
{/* Step 2 (create) / Step 3 (edit) — Review & Submit. */}
{((step === 2 && !isEdit) || (step === 3 && isEdit)) && (
{/* Step 2 — Review & Submit. */}
{step === 2 && (
<Step8Review
form={form}
setStep={setStep}

View File

@@ -11,14 +11,6 @@ export const CONTRACT_STEPS = [
{ id: 2, label: "Review & Submit", short: "Review" },
] as const;
/** Edit flow (CHANGES_REQUESTED): documents on step 2, review on step 3. */
export const EDIT_CONTRACT_STEPS = [
{ id: 0, label: "Setup", short: "Setup" },
{ id: 1, label: "Cargo & Route", short: "Cargo & Route" },
{ id: 2, label: "Documents", short: "Documents" },
{ id: 3, label: "Review & Submit", short: "Review" },
] as const;
export const OPERATION_TYPES = [
"import",
"export",
@@ -330,15 +322,3 @@ export const contractStepFields: Record<
// company profile documents are attached to the contract automatically.)
2: ["notes"],
};
/** Field validation per step when editing a CHANGES_REQUESTED contract. */
export const editContractStepFields: Record<
number,
Array<Path<ContractFormValues>>
> = {
0: contractStepFields[0],
1: contractStepFields[1],
// Step 2 — Documents: validated via missingRequiredDocKeys in the wizard.
2: [],
3: ["notes"],
};