mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 14:38:12 +00:00
style: invoice
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
import { Badge, Card, Divider, Group, Stack, Text } from "@mantine/core";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
export interface PersonField {
|
||||
label: string;
|
||||
value?: string | null;
|
||||
}
|
||||
|
||||
export interface PersonCardProps {
|
||||
/** OWNER / POA / CONTACT PERSON — the person's role, not their name. */
|
||||
title: string;
|
||||
icon?: ReactNode;
|
||||
/**
|
||||
* Identity state. `undefined` = this person has no identity check at all
|
||||
* (contact person), so no badge is rendered rather than a misleading "not
|
||||
* verified" one.
|
||||
*/
|
||||
verified?: boolean;
|
||||
/** Extra pills after the verification badge (e.g. "Verifies for this company"). */
|
||||
badges?: ReactNode;
|
||||
/** Rendered between the header and the fields — alerts, match warnings. */
|
||||
notice?: ReactNode;
|
||||
fields: PersonField[];
|
||||
/** Shown when the API returned nothing for every field. */
|
||||
emptyMessage: string;
|
||||
/** Attachments or anything else that belongs to this person. */
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* One person in the customer's people column: owner, power of attorney, contact
|
||||
* person. Empty fields are dropped rather than rendered as "—", so a field the
|
||||
* API stops sending simply disappears instead of leaving a dead row behind.
|
||||
*/
|
||||
export function PersonCard({
|
||||
title,
|
||||
icon,
|
||||
verified,
|
||||
badges,
|
||||
notice,
|
||||
fields,
|
||||
emptyMessage,
|
||||
children,
|
||||
}: PersonCardProps) {
|
||||
const filled = fields.filter(
|
||||
(f) => f.value != null && String(f.value).trim(),
|
||||
);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<Stack gap="sm">
|
||||
<Group gap={8} wrap="wrap">
|
||||
{icon}
|
||||
<Text
|
||||
size="xs"
|
||||
fw={700}
|
||||
c="edr-muted"
|
||||
tt="uppercase"
|
||||
style={{ letterSpacing: "0.06em" }}
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
{verified !== undefined &&
|
||||
(verified ? (
|
||||
<Badge size="xs" color="edr-green" variant="light">
|
||||
Fayda verified
|
||||
</Badge>
|
||||
) : (
|
||||
<Badge size="xs" color="gray" variant="light">
|
||||
Not verified
|
||||
</Badge>
|
||||
))}
|
||||
{badges}
|
||||
</Group>
|
||||
|
||||
{notice}
|
||||
|
||||
{filled.length > 0 ? (
|
||||
<Stack gap="xs">
|
||||
{filled.map((f) => (
|
||||
<Stack key={f.label} gap={0}>
|
||||
<Text size="xs" c="edr-muted">
|
||||
{f.label}
|
||||
</Text>
|
||||
<Text
|
||||
size="sm"
|
||||
c="edr-text"
|
||||
style={{ wordBreak: "break-word" }}
|
||||
>
|
||||
{f.value}
|
||||
</Text>
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
) : (
|
||||
<Text size="sm" c="dimmed">
|
||||
{emptyMessage}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
{children && (
|
||||
<>
|
||||
<Divider />
|
||||
{children}
|
||||
</>
|
||||
)}
|
||||
</Stack>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export default PersonCard;
|
||||
@@ -24,4 +24,9 @@ export {
|
||||
type ResetPasswordActionProps,
|
||||
} from "./ResetPasswordAction";
|
||||
export { formatBytes, formatDate, formatMoney, humanize } from "./format";
|
||||
export {
|
||||
PersonCard,
|
||||
type PersonCardProps,
|
||||
type PersonField,
|
||||
} from "./PersonCard";
|
||||
export { TableCard, type TableCardProps } from "./TableCard";
|
||||
|
||||
Reference in New Issue
Block a user