mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 12:18:11 +00:00
fix: onboarding back and contract blocking
This commit is contained in:
@@ -286,9 +286,13 @@ export default function OnboardingWizardDialog({
|
|||||||
});
|
});
|
||||||
}, [roles, nationality, startMutation]);
|
}, [roles, nationality, startMutation]);
|
||||||
|
|
||||||
// Note: no "back to role selection" — once the draft is created the role(s)
|
// Back from the form's first step returns to nationality/role selection.
|
||||||
// are fixed; the form's first-step Back is a no-op so progress never resets.
|
// Safe to re-enter: startOnboarding is idempotent — it reuses the existing
|
||||||
const handleBackToRoles = useCallback(() => { }, []);
|
// draft, refreshes the nationality and creates only roles that don't exist yet.
|
||||||
|
const handleBackToRoles = useCallback(() => {
|
||||||
|
setStartError(null);
|
||||||
|
setPhase("nationality-role");
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Save the current step's fields to the draft (PATCH /profile). Returns the
|
// Save the current step's fields to the draft (PATCH /profile). Returns the
|
||||||
// server error message on failure so the form can show it (e.g. duplicate TIN).
|
// server error message on failure so the form can show it (e.g. duplicate TIN).
|
||||||
@@ -359,7 +363,6 @@ export default function OnboardingWizardDialog({
|
|||||||
// The active step across the whole journey, driving the header + progress pill.
|
// The active step across the whole journey, driving the header + progress pill.
|
||||||
const activeStep: WizardStep = phase === "form" ? formStep : phase;
|
const activeStep: WizardStep = phase === "form" ? formStep : phase;
|
||||||
const stepMeta = STEP_META[activeStep];
|
const stepMeta = STEP_META[activeStep];
|
||||||
console.log({ stepMeta, activeStep, STEP_META });
|
|
||||||
const activeIdx = WIZARD_STEPS.indexOf(activeStep);
|
const activeIdx = WIZARD_STEPS.indexOf(activeStep);
|
||||||
|
|
||||||
// Closing from the congratulations panel also clears the completed flag so a
|
// Closing from the congratulations panel also clears the completed flag so a
|
||||||
@@ -403,7 +406,6 @@ export default function OnboardingWizardDialog({
|
|||||||
onSubmit: handleSubmit,
|
onSubmit: handleSubmit,
|
||||||
isPending: finishMutation.isPending,
|
isPending: finishMutation.isPending,
|
||||||
onBack: handleBackToRoles,
|
onBack: handleBackToRoles,
|
||||||
hideFirstStepBack: true,
|
|
||||||
initialStep: effectiveResumeStep,
|
initialStep: effectiveResumeStep,
|
||||||
resyncOpen: opened,
|
resyncOpen: opened,
|
||||||
onStepChange: handleStepChange,
|
onStepChange: handleStepChange,
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ export default function CompanyProfileForm({
|
|||||||
onBack,
|
onBack,
|
||||||
initialStep,
|
initialStep,
|
||||||
resyncOpen,
|
resyncOpen,
|
||||||
hideFirstStepBack,
|
|
||||||
onStepChange,
|
onStepChange,
|
||||||
onSaveStep,
|
onSaveStep,
|
||||||
rehydrate,
|
rehydrate,
|
||||||
@@ -73,8 +72,6 @@ export default function CompanyProfileForm({
|
|||||||
initialStep?: CompanyStep;
|
initialStep?: CompanyStep;
|
||||||
/** When this flips true (dialog reopened), jump back to initialStep (furthest reached). */
|
/** When this flips true (dialog reopened), jump back to initialStep (furthest reached). */
|
||||||
resyncOpen?: boolean;
|
resyncOpen?: boolean;
|
||||||
/** Hide the Back button on the first step (onboarding can't go back to role pick). */
|
|
||||||
hideFirstStepBack?: boolean;
|
|
||||||
/** Reports the active step so the parent can persist resume progress. */
|
/** Reports the active step so the parent can persist resume progress. */
|
||||||
onStepChange?: (step: CompanyStep) => void;
|
onStepChange?: (step: CompanyStep) => void;
|
||||||
/** Persist the current step's data before advancing; returns an error to show. */
|
/** Persist the current step's data before advancing; returns an error to show. */
|
||||||
@@ -514,10 +511,6 @@ export default function CompanyProfileForm({
|
|||||||
else setStep(stepOrder[currentIdx - 1]);
|
else setStep(stepOrder[currentIdx - 1]);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Back is hidden on the first step during onboarding (can't return to role
|
|
||||||
// selection); otherwise always available.
|
|
||||||
const showBack = !(hideFirstStepBack && step === "company");
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<form onSubmit={(e) => e.preventDefault()}>
|
<form onSubmit={(e) => e.preventDefault()}>
|
||||||
@@ -851,17 +844,13 @@ export default function CompanyProfileForm({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<Group justify="space-between" pt="xs">
|
<Group justify="space-between" pt="xs">
|
||||||
{showBack ? (
|
<Button
|
||||||
<Button
|
variant="default"
|
||||||
variant="default"
|
onClick={prevStep}
|
||||||
onClick={prevStep}
|
leftSection={<ArrowLeft size={16} />}
|
||||||
leftSection={<ArrowLeft size={16} />}
|
>
|
||||||
>
|
Back
|
||||||
Back
|
</Button>
|
||||||
</Button>
|
|
||||||
) : (
|
|
||||||
<span />
|
|
||||||
)}
|
|
||||||
<Button
|
<Button
|
||||||
color="edr-green"
|
color="edr-green"
|
||||||
onClick={nextStep}
|
onClick={nextStep}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
Group,
|
Group,
|
||||||
Loader,
|
Loader,
|
||||||
Paper,
|
Paper,
|
||||||
|
Popover,
|
||||||
Select,
|
Select,
|
||||||
Stack,
|
Stack,
|
||||||
Table,
|
Table,
|
||||||
@@ -17,6 +18,7 @@ import {
|
|||||||
Title,
|
Title,
|
||||||
} from "@mantine/core";
|
} from "@mantine/core";
|
||||||
import {
|
import {
|
||||||
|
AlertTriangle,
|
||||||
CheckCircle2,
|
CheckCircle2,
|
||||||
ChevronDown,
|
ChevronDown,
|
||||||
ChevronLeft,
|
ChevronLeft,
|
||||||
@@ -31,6 +33,8 @@ import {
|
|||||||
X,
|
X,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
||||||
|
import { PROFILE_TYPE_LABELS } from "@/constants/profileMode";
|
||||||
|
import useAuth from "@/hooks/useAuth";
|
||||||
import { api } from "@/services/api";
|
import { api } from "@/services/api";
|
||||||
import { ContractCustomerAction } from "@/components/customer-actions/ContractCustomerAction";
|
import { ContractCustomerAction } from "@/components/customer-actions/ContractCustomerAction";
|
||||||
import type { ContractListFilter } from "@/services/contracts.service";
|
import type { ContractListFilter } from "@/services/contracts.service";
|
||||||
@@ -58,14 +62,26 @@ function primaryRoute(contract: Freight.IContract) {
|
|||||||
|
|
||||||
export default function ContractsList() {
|
export default function ContractsList() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { company } = useAuth();
|
||||||
const { pagination, setPagination } = usePagination({ pageSize: 10 });
|
const { pagination, setPagination } = usePagination({ pageSize: 10 });
|
||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
|
const [disclaimerOpen, setDisclaimerOpen] = useState(false);
|
||||||
const [freightFilter, setFreightFilter] = useState<string | null>(null);
|
const [freightFilter, setFreightFilter] = useState<string | null>(null);
|
||||||
const [kindFilter, setKindFilter] = useState<string | null>(null);
|
const [kindFilter, setKindFilter] = useState<string | null>(null);
|
||||||
const [createdFrom, setCreatedFrom] = useState<string>("");
|
const [createdFrom, setCreatedFrom] = useState<string>("");
|
||||||
const [createdTo, setCreatedTo] = useState<string>("");
|
const [createdTo, setCreatedTo] = useState<string>("");
|
||||||
const [expanded, setExpanded] = useState<Set<string>>(new Set());
|
const [expanded, setExpanded] = useState<Set<string>>(new Set());
|
||||||
|
|
||||||
|
// A contract can only be created under an approved profile — NewContractPage
|
||||||
|
// blocks every operation whose profile isn't "active". With none approved the
|
||||||
|
// page is reachable but unusable, so warn before sending the user there.
|
||||||
|
const profiles = company?.company?.companyProfiles ?? [];
|
||||||
|
const noActiveProfile =
|
||||||
|
profiles.length > 0 && !profiles.some((p) => p.status === "active");
|
||||||
|
|
||||||
|
const openNewContract = () =>
|
||||||
|
navigate("/contracts/new", { state: { fresh: true } });
|
||||||
|
|
||||||
const toggleExpanded = (id: string) =>
|
const toggleExpanded = (id: string) =>
|
||||||
setExpanded((prev) => {
|
setExpanded((prev) => {
|
||||||
const nextSet = new Set(prev);
|
const nextSet = new Set(prev);
|
||||||
@@ -137,9 +153,11 @@ export default function ContractsList() {
|
|||||||
const stats = useMemo(() => {
|
const stats = useMemo(() => {
|
||||||
const items = data?.items ?? [];
|
const items = data?.items ?? [];
|
||||||
const active = items.filter((c) =>
|
const active = items.filter((c) =>
|
||||||
["CONTRACT_ACTIVE", "FULLY_EXECUTED", "ACTIVE_SHIPMENT_IN_PROGRESS"].includes(
|
[
|
||||||
c.status,
|
"CONTRACT_ACTIVE",
|
||||||
),
|
"FULLY_EXECUTED",
|
||||||
|
"ACTIVE_SHIPMENT_IN_PROGRESS",
|
||||||
|
].includes(c.status),
|
||||||
).length;
|
).length;
|
||||||
const pending = items.filter((c) =>
|
const pending = items.filter((c) =>
|
||||||
[
|
[
|
||||||
@@ -158,7 +176,7 @@ export default function ContractsList() {
|
|||||||
return { active, pending, total };
|
return { active, pending, total };
|
||||||
}, [data]);
|
}, [data]);
|
||||||
|
|
||||||
const total = data?.meta?.total ?? (data?.items?.length ?? 0);
|
const total = data?.meta?.total ?? data?.items?.length ?? 0;
|
||||||
const pageCount = Math.max(1, Math.ceil(total / pagination.pageSize));
|
const pageCount = Math.max(1, Math.ceil(total / pagination.pageSize));
|
||||||
const pageIndex = pagination.pageIndex;
|
const pageIndex = pagination.pageIndex;
|
||||||
const start = total === 0 ? 0 : pageIndex * pagination.pageSize + 1;
|
const start = total === 0 ? 0 : pageIndex * pagination.pageSize + 1;
|
||||||
@@ -175,19 +193,63 @@ export default function ContractsList() {
|
|||||||
<Stack gap="lg">
|
<Stack gap="lg">
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<Group justify="space-between" align="center" wrap="wrap" gap="md">
|
<Group justify="space-between" align="center" wrap="wrap" gap="md">
|
||||||
<Title order={1} fw={800} fz={26} style={{ letterSpacing: "-0.01em" }}>
|
<Title
|
||||||
|
order={1}
|
||||||
|
fw={800}
|
||||||
|
fz={26}
|
||||||
|
style={{ letterSpacing: "-0.01em" }}
|
||||||
|
>
|
||||||
Contracts
|
Contracts
|
||||||
</Title>
|
</Title>
|
||||||
<Button
|
<Popover
|
||||||
color="edr-green"
|
opened={disclaimerOpen}
|
||||||
|
onChange={setDisclaimerOpen}
|
||||||
|
position="bottom-end"
|
||||||
|
width={340}
|
||||||
radius="md"
|
radius="md"
|
||||||
size="md"
|
shadow="md"
|
||||||
leftSection={<Plus size={16} />}
|
withArrow
|
||||||
onClick={() => navigate("/contracts/new", { state: { fresh: true } })}
|
trapFocus
|
||||||
styles={{ root: { fontWeight: 600, height: 42, paddingInline: 18 } }}
|
|
||||||
>
|
>
|
||||||
New Contract
|
<Popover.Target>
|
||||||
</Button>
|
<Button
|
||||||
|
color="edr-green"
|
||||||
|
radius="md"
|
||||||
|
size="md"
|
||||||
|
leftSection={<Plus size={16} />}
|
||||||
|
onClick={() =>
|
||||||
|
noActiveProfile
|
||||||
|
? setDisclaimerOpen((o) => !o)
|
||||||
|
: openNewContract()
|
||||||
|
}
|
||||||
|
styles={{
|
||||||
|
root: { fontWeight: 600, height: 42, paddingInline: 18 },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
New Contract
|
||||||
|
</Button>
|
||||||
|
</Popover.Target>
|
||||||
|
<Popover.Dropdown>
|
||||||
|
<Stack gap="sm">
|
||||||
|
<Group gap={8} wrap="nowrap" align="flex-start">
|
||||||
|
<AlertTriangle
|
||||||
|
size={18}
|
||||||
|
color="var(--mantine-color-edr-accent-6)"
|
||||||
|
style={{ flexShrink: 0, marginTop: 1 }}
|
||||||
|
/>
|
||||||
|
<Text fz={14} fw={700} style={{ color: INK }}>
|
||||||
|
None of your profiles are active yet
|
||||||
|
</Text>
|
||||||
|
</Group>
|
||||||
|
|
||||||
|
<Text fz={13} c="dimmed">
|
||||||
|
Contracts can only be created under a profile EDR has
|
||||||
|
approved. You can continue, but every operation stays locked
|
||||||
|
until at least one profile is approved.
|
||||||
|
</Text>
|
||||||
|
</Stack>
|
||||||
|
</Popover.Dropdown>
|
||||||
|
</Popover>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
{/* Summary strip */}
|
{/* Summary strip */}
|
||||||
@@ -378,7 +440,11 @@ export default function ContractsList() {
|
|||||||
<Table.Tr>
|
<Table.Tr>
|
||||||
<Table.Td colSpan={11}>
|
<Table.Td colSpan={11}>
|
||||||
<Stack align="center" gap={8} py={48}>
|
<Stack align="center" gap={8} py={48}>
|
||||||
<Inbox size={26} color={MUTED} style={{ opacity: 0.5 }} />
|
<Inbox
|
||||||
|
size={26}
|
||||||
|
color={MUTED}
|
||||||
|
style={{ opacity: 0.5 }}
|
||||||
|
/>
|
||||||
<Text fz={13} c="dimmed">
|
<Text fz={13} c="dimmed">
|
||||||
No contracts yet. Create one from New Contract.
|
No contracts yet. Create one from New Contract.
|
||||||
</Text>
|
</Text>
|
||||||
@@ -400,154 +466,159 @@ export default function ContractsList() {
|
|||||||
const isOpen = expanded.has(c.id);
|
const isOpen = expanded.has(c.id);
|
||||||
return (
|
return (
|
||||||
<Fragment key={c.id}>
|
<Fragment key={c.id}>
|
||||||
<Table.Tr
|
<Table.Tr
|
||||||
style={{
|
style={{
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
background: isOpen ? "#F4FBF8" : undefined,
|
background: isOpen ? "#F4FBF8" : undefined,
|
||||||
}}
|
}}
|
||||||
onClick={() => navigate(`/contracts/${c.id}`)}
|
onClick={() => navigate(`/contracts/${c.id}`)}
|
||||||
>
|
>
|
||||||
<Table.Td>
|
<Table.Td>
|
||||||
<Box
|
<Box
|
||||||
component="button"
|
component="button"
|
||||||
aria-label={isOpen ? "Hide progress" : "Show progress"}
|
aria-label={
|
||||||
aria-expanded={isOpen}
|
isOpen ? "Hide progress" : "Show progress"
|
||||||
onClick={(e) => {
|
}
|
||||||
e.stopPropagation();
|
aria-expanded={isOpen}
|
||||||
toggleExpanded(c.id);
|
onClick={(e) => {
|
||||||
}}
|
e.stopPropagation();
|
||||||
style={{
|
toggleExpanded(c.id);
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
width: 28,
|
|
||||||
height: 28,
|
|
||||||
borderRadius: 8,
|
|
||||||
border: `1px solid ${BORDER}`,
|
|
||||||
background: isOpen ? GREEN : "#FFFFFF",
|
|
||||||
color: isOpen ? "#FFFFFF" : MUTED,
|
|
||||||
cursor: "pointer",
|
|
||||||
transition: "all 140ms ease",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<ChevronDown
|
|
||||||
size={16}
|
|
||||||
style={{
|
|
||||||
transform: isOpen ? "rotate(180deg)" : "none",
|
|
||||||
transition: "transform 160ms ease",
|
|
||||||
}}
|
}}
|
||||||
/>
|
style={{
|
||||||
</Box>
|
display: "flex",
|
||||||
</Table.Td>
|
alignItems: "center",
|
||||||
<Table.Td>
|
justifyContent: "center",
|
||||||
<Text fz={14} fw={700} style={{ color: INK }}>
|
width: 28,
|
||||||
{c.reference}
|
height: 28,
|
||||||
</Text>
|
borderRadius: 8,
|
||||||
<Text fz={12} c="dimmed">
|
border: `1px solid ${BORDER}`,
|
||||||
{isContainer ? "Containerised" : "Bulk"}
|
background: isOpen ? GREEN : "#FFFFFF",
|
||||||
</Text>
|
color: isOpen ? "#FFFFFF" : MUTED,
|
||||||
</Table.Td>
|
cursor: "pointer",
|
||||||
<Table.Td>
|
transition: "all 140ms ease",
|
||||||
<Badge
|
}}
|
||||||
variant="light"
|
>
|
||||||
color={isGeneral ? "edr-green" : "gray"}
|
<ChevronDown
|
||||||
radius="sm"
|
size={16}
|
||||||
>
|
style={{
|
||||||
{isGeneral ? "General" : "One-Time"}
|
transform: isOpen ? "rotate(180deg)" : "none",
|
||||||
</Badge>
|
transition: "transform 160ms ease",
|
||||||
</Table.Td>
|
}}
|
||||||
<Table.Td>
|
/>
|
||||||
<Group gap={7} wrap="nowrap" align="center">
|
</Box>
|
||||||
{isContainer ? (
|
</Table.Td>
|
||||||
<Package size={15} color={MUTED} />
|
<Table.Td>
|
||||||
) : (
|
<Text fz={14} fw={700} style={{ color: INK }}>
|
||||||
<Weight size={15} color={MUTED} />
|
{c.reference}
|
||||||
)}
|
|
||||||
<Text fz={13} style={{ color: INK }}>
|
|
||||||
{isContainer ? "Container" : "Bulk"}
|
|
||||||
</Text>
|
</Text>
|
||||||
</Group>
|
<Text fz={12} c="dimmed">
|
||||||
</Table.Td>
|
{isContainer ? "Containerised" : "Bulk"}
|
||||||
<Table.Td>
|
</Text>
|
||||||
<Text fz={13} style={{ color: INK }}>
|
</Table.Td>
|
||||||
{origin}{" "}
|
<Table.Td>
|
||||||
<Text span c="dimmed">
|
<Badge
|
||||||
→
|
variant="light"
|
||||||
</Text>{" "}
|
color={isGeneral ? "edr-green" : "gray"}
|
||||||
{destination}
|
radius="sm"
|
||||||
{count > 1 && (
|
>
|
||||||
<Text span c="dimmed" fz={12}>
|
{isGeneral ? "General" : "One-Time"}
|
||||||
{" "}
|
</Badge>
|
||||||
+{count - 1}
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
<Group gap={7} wrap="nowrap" align="center">
|
||||||
|
{isContainer ? (
|
||||||
|
<Package size={15} color={MUTED} />
|
||||||
|
) : (
|
||||||
|
<Weight size={15} color={MUTED} />
|
||||||
|
)}
|
||||||
|
<Text fz={13} style={{ color: INK }}>
|
||||||
|
{isContainer ? "Container" : "Bulk"}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
</Group>
|
||||||
</Text>
|
</Table.Td>
|
||||||
</Table.Td>
|
<Table.Td>
|
||||||
<Table.Td>
|
<Text fz={13} style={{ color: INK }}>
|
||||||
<Text
|
{origin}{" "}
|
||||||
fz={13}
|
<Text span c="dimmed">
|
||||||
c={dir ? undefined : "dimmed"}
|
→
|
||||||
style={{ color: dir ? INK : undefined }}
|
</Text>{" "}
|
||||||
>
|
{destination}
|
||||||
{tradeLabel}
|
{count > 1 && (
|
||||||
</Text>
|
<Text span c="dimmed" fz={12}>
|
||||||
</Table.Td>
|
{" "}
|
||||||
<Table.Td>
|
+{count - 1}
|
||||||
<Text fz={13} style={{ color: INK }}>
|
</Text>
|
||||||
{c.paymentCurrency ?? "—"}
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
<Table.Td>
|
<Table.Td>
|
||||||
<Text
|
<Text
|
||||||
fz={13}
|
fz={13}
|
||||||
c={c.createdAt ? undefined : "dimmed"}
|
c={dir ? undefined : "dimmed"}
|
||||||
style={{ color: c.createdAt ? INK : undefined }}
|
style={{ color: dir ? INK : undefined }}
|
||||||
>
|
>
|
||||||
{c.createdAt
|
{tradeLabel}
|
||||||
? new Date(c.createdAt).toLocaleDateString()
|
</Text>
|
||||||
: "—"}
|
</Table.Td>
|
||||||
</Text>
|
<Table.Td>
|
||||||
</Table.Td>
|
<Text fz={13} style={{ color: INK }}>
|
||||||
<Table.Td>
|
{c.paymentCurrency ?? "—"}
|
||||||
<Text
|
</Text>
|
||||||
fz={13}
|
</Table.Td>
|
||||||
c={c.contractValidUntil ? undefined : "dimmed"}
|
<Table.Td>
|
||||||
style={{
|
<Text
|
||||||
color: c.contractValidUntil ? INK : undefined,
|
fz={13}
|
||||||
}}
|
c={c.createdAt ? undefined : "dimmed"}
|
||||||
>
|
style={{ color: c.createdAt ? INK : undefined }}
|
||||||
{c.contractValidUntil
|
>
|
||||||
? new Date(
|
{c.createdAt
|
||||||
|
? new Date(c.createdAt).toLocaleDateString()
|
||||||
|
: "—"}
|
||||||
|
</Text>
|
||||||
|
</Table.Td>
|
||||||
|
<Table.Td>
|
||||||
|
<Text
|
||||||
|
fz={13}
|
||||||
|
c={c.contractValidUntil ? undefined : "dimmed"}
|
||||||
|
style={{
|
||||||
|
color: c.contractValidUntil ? INK : undefined,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{c.contractValidUntil
|
||||||
|
? new Date(
|
||||||
c.contractValidUntil,
|
c.contractValidUntil,
|
||||||
).toLocaleDateString()
|
).toLocaleDateString()
|
||||||
: "—"}
|
: "—"}
|
||||||
</Text>
|
</Text>
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
<Table.Td>
|
<Table.Td>
|
||||||
<ContractStatusBadge status={c.status} />
|
<ContractStatusBadge status={c.status} />
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
<Table.Td>
|
<Table.Td>
|
||||||
<Group justify="flex-end" gap={8} wrap="nowrap">
|
<Group justify="flex-end" gap={8} wrap="nowrap">
|
||||||
<ContractDocButton
|
<ContractDocButton
|
||||||
contract={c}
|
contract={c}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
/>
|
/>
|
||||||
<ContractCustomerAction
|
<ContractCustomerAction
|
||||||
contract={c}
|
contract={c}
|
||||||
bookings={bookings}
|
bookings={bookings}
|
||||||
size="sm"
|
size="sm"
|
||||||
listStyle
|
listStyle
|
||||||
/>
|
/>
|
||||||
</Group>
|
</Group>
|
||||||
</Table.Td>
|
|
||||||
</Table.Tr>
|
|
||||||
{isOpen && (
|
|
||||||
<Table.Tr style={{ background: "#F4FBF8" }}>
|
|
||||||
<Table.Td colSpan={11} style={{ padding: "6px 20px 18px" }}>
|
|
||||||
<ContractStepBanner contract={c} />
|
|
||||||
</Table.Td>
|
</Table.Td>
|
||||||
</Table.Tr>
|
</Table.Tr>
|
||||||
)}
|
{isOpen && (
|
||||||
|
<Table.Tr style={{ background: "#F4FBF8" }}>
|
||||||
|
<Table.Td
|
||||||
|
colSpan={11}
|
||||||
|
style={{ padding: "6px 20px 18px" }}
|
||||||
|
>
|
||||||
|
<ContractStepBanner contract={c} />
|
||||||
|
</Table.Td>
|
||||||
|
</Table.Tr>
|
||||||
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -564,7 +635,10 @@ export default function ContractsList() {
|
|||||||
gap="md"
|
gap="md"
|
||||||
px={20}
|
px={20}
|
||||||
py={14}
|
py={14}
|
||||||
style={{ borderTop: `1px solid ${BORDER}`, background: "#FCFDFE" }}
|
style={{
|
||||||
|
borderTop: `1px solid ${BORDER}`,
|
||||||
|
background: "#FCFDFE",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Group gap={10} align="center">
|
<Group gap={10} align="center">
|
||||||
<Text fz={13} c="dimmed">
|
<Text fz={13} c="dimmed">
|
||||||
@@ -574,8 +648,7 @@ export default function ContractsList() {
|
|||||||
data={["10", "25", "50"]}
|
data={["10", "25", "50"]}
|
||||||
value={String(pagination.pageSize)}
|
value={String(pagination.pageSize)}
|
||||||
onChange={(v) =>
|
onChange={(v) =>
|
||||||
v &&
|
v && setPagination({ pageIndex: 0, pageSize: Number(v) })
|
||||||
setPagination({ pageIndex: 0, pageSize: Number(v) })
|
|
||||||
}
|
}
|
||||||
radius="md"
|
radius="md"
|
||||||
size="xs"
|
size="xs"
|
||||||
|
|||||||
Reference in New Issue
Block a user