fix: add vat to the settings, and docs to the profile

This commit is contained in:
Nathnael
2026-07-08 10:51:22 +00:00
parent 8947ab8614
commit 9e98600a5f
2 changed files with 112 additions and 32 deletions

View File

@@ -164,25 +164,85 @@ export default function CustomerDetailPage() {
{
id: "type",
header: "Role",
cell: ({ row }) => <ProfileTypeBadge type={row.original.type} />,
},
{
id: "reference",
header: "Reference",
cell: ({ row }) => (
<Text size="sm" fw={600} c="edr-text">
{row.original.reference}
</Text>
<div className="space-y-2">
<ProfileTypeBadge type={row.original.type} />
<Text size="sm" fw={600} c="edr-text">
{row.original.reference}
</Text>
</div>
),
},
{
id: "businessLicense",
header: "Business license",
cell: ({ row }) => (
<Text size="sm" c="dimmed">
{row.original.businessLicense || "—"}
</Text>
),
id: "licenseFiles",
header: "License documents",
cell: ({ row }) => {
const files = row.original.licenseFiles ?? [];
if (files.length === 0) {
return (
<Text size="sm" c="dimmed">
</Text>
);
}
return (
<Stack gap={4}>
{files.map((f) => (
<Group key={f.id} gap={6} wrap="nowrap">
<ActionIcon
size="sm"
variant="subtle"
color="gray"
aria-label={`View ${f.name}`}
onClick={() =>
view({
name: f.name,
url: fileViewUrl(f.id),
mimeType: f.mimeType,
})
}
>
<Eye size={14} />
</ActionIcon>
<Anchor
component="button"
type="button"
size="xs"
lineClamp={1}
onClick={() =>
view({
name: f.name,
url: fileViewUrl(f.id),
mimeType: f.mimeType,
})
}
style={{
maxWidth: 170,
textAlign: "left",
textDecoration:
f.status === "pending_remove"
? "line-through"
: undefined,
}}
>
{f.name}
</Anchor>
{f.status === "pending_add" && (
<Badge size="xs" color="yellow" variant="light">
Pending
</Badge>
)}
{f.status === "pending_remove" && (
<Badge size="xs" color="red" variant="light">
Removing
</Badge>
)}
</Group>
))}
</Stack>
);
},
},
{
id: "status",
@@ -210,7 +270,7 @@ export default function CustomerDetailPage() {
),
},
],
[],
[view],
);
const bookingColumns: ColumnDef<CustomerBooking>[] = useMemo(
@@ -504,9 +564,8 @@ export default function CustomerDetailPage() {
]}
backTo="/dashboard/customers"
title={company.name}
subtitle={`TIN ${company.tin}${
company.country ? ` · ${company.country}` : ""
}`}
subtitle={`TIN ${company.tin}${company.country ? ` · ${company.country}` : ""
}`}
meta={
<Group gap="xs" wrap="nowrap">
<CompanyTypeBadge type={company.type} />
@@ -620,7 +679,7 @@ export default function CustomerDetailPage() {
<ProfileChips profiles={company.companyProfiles} />
</Group>
<Box style={{ overflowX: "auto" }} w="100%">
<Box miw={860}>
<Box miw={1040}>
<DataTable
columns={profileColumns}
data={company.companyProfiles}
@@ -647,9 +706,9 @@ export default function CustomerDetailPage() {
error={
bookingsQuery.isError
? {
message: "Failed to load bookings.",
onRetry: () => void bookingsQuery.refetch(),
}
message: "Failed to load bookings.",
onRetry: () => void bookingsQuery.refetch(),
}
: undefined
}
/>
@@ -669,9 +728,9 @@ export default function CustomerDetailPage() {
error={
documentsQuery.isError
? {
message: "Failed to load documents.",
onRetry: () => void documentsQuery.refetch(),
}
message: "Failed to load documents.",
onRetry: () => void documentsQuery.refetch(),
}
: undefined
}
/>
@@ -750,9 +809,9 @@ export default function CustomerDetailPage() {
error={
paymentsQuery.isError
? {
message: "Failed to load payments.",
onRetry: () => void paymentsQuery.refetch(),
}
message: "Failed to load payments.",
onRetry: () => void paymentsQuery.refetch(),
}
: undefined
}
/>
@@ -773,9 +832,9 @@ export default function CustomerDetailPage() {
error={
invoicesQuery.isError
? {
message: "Failed to load invoices.",
onRetry: () => void invoicesQuery.refetch(),
}
message: "Failed to load invoices.",
onRetry: () => void invoicesQuery.refetch(),
}
: undefined
}
pagination={{

View File

@@ -34,6 +34,12 @@ export const COMPANY_PROFILE_SCHEMA = z.object({
companyAddress: z.string().min(1, "Address is required"),
tinNumber: z.string().length(10, "TIN must be exactly 10 digits"),
fanNumber: z.string().length(16, "FAN must be exactly 16 digits"),
vatNumber: z
.string()
.trim()
.max(20, "VAT number is too long")
.optional()
.or(z.literal("")),
});
export type CompanyProfileFormData = z.infer<typeof COMPANY_PROFILE_SCHEMA>;
@@ -63,6 +69,7 @@ export default function TabCompanyProfile({
companyAddress: profile.companyAddress ?? "",
tinNumber: profile.tinNumber,
fanNumber: profile.fanNumber ?? "",
vatNumber: profile.vatNumber ?? "",
};
}
return {
@@ -73,6 +80,7 @@ export default function TabCompanyProfile({
companyAddress: "",
tinNumber: "",
fanNumber: "",
vatNumber: "",
};
}, [profile]);
@@ -97,6 +105,7 @@ export default function TabCompanyProfile({
companyAddress: data.companyAddress,
tin: data.tinNumber,
fanNumber: data.fanNumber,
vatNumber: data.vatNumber ?? "",
};
if (isCreate) {
@@ -223,6 +232,18 @@ export default function TabCompanyProfile({
/>
</Grid.Col>
</Grid>
<Grid>
<Grid.Col span={6}>
<TextInput
label="VAT Number (optional)"
placeholder="e.g. 0012345678"
maxLength={20}
error={errors.vatNumber?.message}
{...register("vatNumber")}
/>
</Grid.Col>
</Grid>
</Stack>
<Group