fix: the use person x button to checkbox

This commit is contained in:
Nathnael
2026-06-26 12:41:52 +00:00
parent 552e6bcd16
commit f51488e989

View File

@@ -9,6 +9,7 @@ import {
Stack,
Text,
TextInput,
UnstyledButton,
} from "@mantine/core";
import { zodResolver } from "@hookform/resolvers/zod";
import { useQuery } from "@tanstack/react-query";
@@ -16,9 +17,9 @@ import {
AlertCircle,
ArrowLeft,
ArrowRight,
Check,
CheckCircle2,
RotateCw,
ShieldCheck,
Smartphone,
UserCheck,
} from "lucide-react";
@@ -282,6 +283,53 @@ function toFormValues(p: ProfileResponse): FormData {
};
}
/**
* A card styled as a large checkbox: clicking it toggles `checked`, which the
* caller uses to prefill + lock a set of fields (and clear them on uncheck).
*/
function LinkCheckboxCard({
checked,
onToggle,
title,
description,
}: {
checked: boolean;
onToggle: (checked: boolean) => void;
title: string;
description: string;
}) {
return (
<UnstyledButton
onClick={() => onToggle(!checked)}
role="checkbox"
aria-checked={checked}
className={`w-full rounded-lg border! p-3! text-left transition-colors! ${checked
? "border-[var(--mantine-color-edr-green-6)]! bg-[var(--mantine-color-edr-green-0)]!"
: "border-[var(--mantine-color-gray-3)]! hover:border-[var(--mantine-color-edr-green-4)]! hover:bg-[var(--mantine-color-edr-green-0)]!"
}`}
>
<Group gap="sm" wrap="nowrap" align="flex-start">
<div
className={`mt-px flex h-5 w-5 shrink-0 items-center justify-center rounded-[6px] border transition-colors ${checked
? "border-[var(--mantine-color-edr-green-6)] bg-[var(--mantine-color-edr-green-6)] text-white"
: "border-[var(--mantine-color-gray-4)] bg-white"
}`}
>
{checked && <Check size={14} strokeWidth={3} />}
</div>
<div>
<Text fw={600} size="sm" c="edr-text" lh={1.25}>
{title}
</Text>
<Text size="xs" c="dimmed" mt={2}>
{description}
</Text>
</div>
</Group>
</UnstyledButton>
);
}
/** A single read-only registration value rendered as a label/value pair. */
function ReadOnlyField({ label, value }: { label: string; value?: string }) {
return (
@@ -352,7 +400,9 @@ export default function CompanyProfileForm({
* "Continue" action). Resolves to an error message string on failure so the
* step can surface it and hold the user in place.
*/
onUploadDocuments?: () => Promise<{ ok: true } | { ok: false; error: string }>;
onUploadDocuments?: () => Promise<
{ ok: true } | { ok: false; error: string }
>;
}) {
const [step, setStep] = useState<CompanyStep>(initialStep ?? "company");
const [saving, setSaving] = useState(false);
@@ -542,22 +592,54 @@ export default function CompanyProfileForm({
});
};
/** Copy the General Manager into the Contact Person fields (still editable). */
const useGmAsContact = () => {
setValue("contactPersonName", watch("generalManagerName"), {
shouldValidate: true,
});
setValue("contactPersonEmail", watch("generalManagerEmail"));
setValue("contactPersonPhone", watch("generalManagerPhone"), {
shouldValidate: true,
});
// "Same as …" links. A checked card prefills the target step's fields from the
// source step and disables them (kept mirrored while linked); unchecking clears
// them and re-enables editing.
const [contactSameAsGm, setContactSameAsGm] = useState(false);
const [poaSameAsContact, setPoaSameAsContact] = useState(false);
const gmName = watch("generalManagerName");
const gmEmail = watch("generalManagerEmail");
const gmPhone = watch("generalManagerPhone");
const contactName = watch("contactPersonName");
const contactEmail = watch("contactPersonEmail");
const contactPhone = watch("contactPersonPhone");
// While linked, mirror the source values into the (disabled) target fields so
// the copy stays current even if the user goes back and edits the source.
useEffect(() => {
if (!contactSameAsGm) return;
setValue("contactPersonName", gmName ?? "", { shouldValidate: true });
setValue("contactPersonEmail", gmEmail ?? "");
setValue("contactPersonPhone", gmPhone ?? "", { shouldValidate: true });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [contactSameAsGm, gmName, gmEmail, gmPhone]);
useEffect(() => {
if (!poaSameAsContact) return;
setValue("poaName", contactName ?? "");
setValue("poaEmail", contactEmail ?? "");
setValue("poaPhone", contactPhone ?? "");
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [poaSameAsContact, contactName, contactEmail, contactPhone]);
const toggleContactSameAsGm = (checked: boolean) => {
setContactSameAsGm(checked);
// Checked → the mirror effect fills the fields; unchecked → reset them.
if (!checked) {
setValue("contactPersonName", "");
setValue("contactPersonEmail", "");
setValue("contactPersonPhone", "");
}
};
/** Copy the Contact Person into the PoA fields (still editable). */
const useContactAsPoa = () => {
setValue("poaName", watch("contactPersonName"));
setValue("poaEmail", watch("contactPersonEmail"));
setValue("poaPhone", watch("contactPersonPhone"));
const togglePoaSameAsContact = (checked: boolean) => {
setPoaSameAsContact(checked);
if (!checked) {
setValue("poaName", "");
setValue("poaEmail", "");
setValue("poaPhone", "");
}
};
// --- Contact-phone SMS OTP verification -----------------------------------
@@ -950,24 +1032,17 @@ export default function CompanyProfileForm({
{step === "contact" && (
<>
<Group justify="space-between" align="center" wrap="nowrap">
<Text fw={600} size="sm" c="edr-text">
Contact Person
</Text>
<Group gap="xs" wrap="nowrap" style={{ flexShrink: 0 }}>
{watch("generalManagerName") && (
<Button
variant="light"
color="edr-green"
size="xs"
leftSection={<UserCheck size={14} />}
onClick={useGmAsContact}
>
Use General Manager
</Button>
)}
</Group>
</Group>
<Text fw={600} size="sm" c="edr-text">
Contact Person
</Text>
{watch("generalManagerName") && (
<LinkCheckboxCard
checked={contactSameAsGm}
onToggle={toggleContactSameAsGm}
title="Same as General Manager"
description="Reuse the general manager's name, email and phone. Uncheck to enter different details."
/>
)}
<SimpleGrid cols={2} spacing="md">
<TextInput
label="Name"
@@ -1103,24 +1178,18 @@ export default function CompanyProfileForm({
{step === "poa" && (
<>
<Group justify="space-between" align="center" wrap="nowrap">
<Text size="sm" c="edr-muted">
Power of Attorney details are optional. Fill them in if you
have them, or skip to continue.
</Text>
{watch("contactPersonName") && (
<Button
variant="light"
color="edr-green"
size="xs"
leftSection={<UserCheck size={14} />}
onClick={useContactAsPoa}
style={{ flexShrink: 0 }}
>
Use contact person
</Button>
)}
</Group>
<Text size="sm" c="edr-muted">
Power of Attorney details are optional. Fill them in if you have
them, or skip to continue.
</Text>
{watch("contactPersonName") && (
<LinkCheckboxCard
checked={poaSameAsContact}
onToggle={togglePoaSameAsContact}
title="Same as contact person"
description="Reuse the contact person's name, email and phone. Uncheck to enter different details."
/>
)}
<TextInput
label="PoA Name"
placeholder="Authorized Representative Name"