style: use the proper primary color

This commit is contained in:
Nathnael
2026-06-22 08:11:11 +00:00
parent ec708d85b3
commit feddce8a0c
62 changed files with 182 additions and 200 deletions

View File

@@ -68,7 +68,7 @@ export function ApprovalStepsCard({ booking, mutations }: ApprovalStepsCardProps
icon={ShieldCheck} icon={ShieldCheck}
title="Approval chain" title="Approval chain"
extra={ extra={
<Badge color="green" variant="light" radius="sm"> <Badge color="edr-green" variant="light" radius="sm">
{steps.filter((s) => s.status === "APPROVED").length}/{steps.length} {steps.filter((s) => s.status === "APPROVED").length}/{steps.length}
</Badge> </Badge>
} }
@@ -144,11 +144,11 @@ function StepRow({
const canApprove = canActOnApprovalStep(user, step, steps); const canApprove = canActOnApprovalStep(user, step, steps);
const statusColor = const statusColor =
step.status === "APPROVED" step.status === "APPROVED"
? "green" ? "edr-green"
: step.status === "REJECTED" : step.status === "REJECTED"
? "red" ? "red"
: isNext : isNext
? "green" ? "edr-green"
: "gray"; : "gray";
return ( return (
@@ -200,7 +200,7 @@ function StepRow({
{canApprove && ( {canApprove && (
<Button <Button
size="compact-sm" size="compact-sm"
color="green" color="edr-green"
leftSection={<Check size={14} />} leftSection={<Check size={14} />}
disabled={isPending} disabled={isPending}
onClick={() => onApprove(step)} onClick={() => onApprove(step)}

View File

@@ -86,7 +86,7 @@ export function BookingActionsMenu({
key={action.id} key={action.id}
size="sm" size="sm"
variant={action.primary && !destructive ? "filled" : "default"} variant={action.primary && !destructive ? "filled" : "default"}
color={destructive ? "red" : action.primary ? "green" : "gray"} color={destructive ? "red" : action.primary ? "edr-green" : "gray"}
leftSection={<Icon size={16} />} leftSection={<Icon size={16} />}
disabled={mutations.isPending} disabled={mutations.isPending}
onClick={() => handleAction(action)} onClick={() => handleAction(action)}
@@ -113,7 +113,7 @@ export function BookingActionsMenu({
{variant === "table" && primary && ( {variant === "table" && primary && (
<Button <Button
size="compact-sm" size="compact-sm"
color="green" color="edr-green"
visibleFrom="lg" visibleFrom="lg"
leftSection={<primary.icon size={14} />} leftSection={<primary.icon size={14} />}
disabled={mutations.isPending} disabled={mutations.isPending}

View File

@@ -49,7 +49,7 @@ export function BookingConfirmDialog({
const inputMissing = const inputMissing =
(needsTextInput && !inputValue.trim()) || (needsFileInput && !selectedFile); (needsTextInput && !inputValue.trim()) || (needsFileInput && !selectedFile);
const isDestructive = action.variant === "destructive"; const isDestructive = action.variant === "destructive";
const accent = isDestructive ? "red" : "green"; const accent = isDestructive ? "red" : "edr-green";
return ( return (
<Modal <Modal

View File

@@ -20,7 +20,7 @@ export function BookingPricingSummary({ booking }: { booking: BookingDetail }) {
<Text <Text
size="xl" size="xl"
fw={700} fw={700}
c="green.9" c="edr-green.9"
mt={4} mt={4}
style={{ fontVariantNumeric: "tabular-nums", letterSpacing: "-0.5px" }} style={{ fontVariantNumeric: "tabular-nums", letterSpacing: "-0.5px" }}
> >

View File

@@ -62,7 +62,7 @@ export function BookingRequestsHeader({
return ( return (
<Stack gap="lg"> <Stack gap="lg">
<Group justify="flex-end" gap="sm"> <Group justify="flex-end" gap="sm">
<Button color="green" radius="lg" leftSection={<Plus size={18} />} onClick={onCreate}> <Button color="edr-green" radius="lg" leftSection={<Plus size={18} />} onClick={onCreate}>
Create booking Create booking
</Button> </Button>
<Button <Button

View File

@@ -8,7 +8,7 @@ const statusColorMap: Record<string, string> = {
CHANGES_REQUESTED: "orange", CHANGES_REQUESTED: "orange",
PENDING_APPROVAL: "yellow", PENDING_APPROVAL: "yellow",
APPROVED_PENDING_SIGNATURE: "cyan", APPROVED_PENDING_SIGNATURE: "cyan",
APPROVED: "green", APPROVED: "edr-green",
CONTRACT_READY: "indigo", CONTRACT_READY: "indigo",
SIGNED_CUSTOMER: "cyan", SIGNED_CUSTOMER: "cyan",
FULLY_EXECUTED: "indigo", FULLY_EXECUTED: "indigo",
@@ -16,7 +16,7 @@ const statusColorMap: Record<string, string> = {
PAYMENT_VERIFICATION_IN_PROGRESS: "yellow", PAYMENT_VERIFICATION_IN_PROGRESS: "yellow",
SELECTED_FOR_BATCH: "orange", SELECTED_FOR_BATCH: "orange",
EXPIRED: "red", EXPIRED: "red",
PAID: "green", PAID: "edr-green",
IN_TRANSIT: "cyan", IN_TRANSIT: "cyan",
COMPLETED: "indigo", COMPLETED: "indigo",
REJECTED: "red", REJECTED: "red",

View File

@@ -43,7 +43,7 @@ export function BookingStatusTabs({
value={active} value={active}
onChange={(value) => onChange((value as BookingStatusTabKey) ?? "all")} onChange={(value) => onChange((value as BookingStatusTabKey) ?? "all")}
variant="pills" variant="pills"
color="green" color="edr-green"
keepMounted={false} keepMounted={false}
classNames={{ list: "ov-tablist", tab: "ov-tab" }} classNames={{ list: "ov-tablist", tab: "ov-tab" }}
> >
@@ -62,7 +62,7 @@ export function BookingStatusTabs({
size="sm" size="sm"
radius="sm" radius="sm"
variant={isActive ? "white" : "light"} variant={isActive ? "white" : "light"}
color={isActive ? "green" : "gray"} color={isActive ? "edr-green" : "gray"}
styles={ styles={
isActive isActive
? { root: { background: "rgba(255,255,255,0.9)", color: "#15805f" } } ? { root: { background: "rgba(255,255,255,0.9)", color: "#15805f" } }

View File

@@ -83,7 +83,7 @@ export function BookingWorkflowStepper({
<Text <Text
size="xs" size="xs"
fw={isActive ? 600 : 500} fw={isActive ? 600 : 500}
c={isActive ? "green.7" : isComplete ? "dark" : "dimmed"} c={isActive ? "edr-green.7" : isComplete ? "dark" : "dimmed"}
ta="center" ta="center"
style={{ whiteSpace: "nowrap" }} style={{ whiteSpace: "nowrap" }}
> >

View File

@@ -190,7 +190,7 @@ export function OperationsBookingQueue({
<Badge variant="light">{selected.length} selected</Badge> <Badge variant="light">{selected.length} selected</Badge>
<Button <Button
size="compact-sm" size="compact-sm"
color="green" color="edr-green"
disabled={!selected.length} disabled={!selected.length}
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();

View File

@@ -19,14 +19,14 @@ export function BookingApprovalCard({ steps, approvedCount }: BookingApprovalCar
<SectionCard <SectionCard
icon={CheckCircle} icon={CheckCircle}
title="Approval Workflow" title="Approval Workflow"
accent="green" accent="edr-green"
extra={ extra={
<Badge color="green" variant="light" radius="sm"> <Badge color="edr-green" variant="light" radius="sm">
{approvedCount} / {steps.length} approved {approvedCount} / {steps.length} approved
</Badge> </Badge>
} }
> >
<Timeline active={approvedCount - 1} bulletSize={26} lineWidth={2} color="green"> <Timeline active={approvedCount - 1} bulletSize={26} lineWidth={2} color="edr-green">
{steps.map((step) => ( {steps.map((step) => (
<Timeline.Item <Timeline.Item
key={step.id} key={step.id}

View File

@@ -28,7 +28,7 @@ export function BookingDetailToolbar({
<Button variant="default" leftSection={<Download size={16} />} onClick={onExport}> <Button variant="default" leftSection={<Download size={16} />} onClick={onExport}>
Export Export
</Button> </Button>
<Button color="green" leftSection={<CheckCircle size={16} />} onClick={onAction}> <Button color="edr-green" leftSection={<CheckCircle size={16} />} onClick={onAction}>
Take Action Take Action
</Button> </Button>
</Group> </Group>

View File

@@ -68,7 +68,7 @@ export function BookingLifecycleStepper({ status }: BookingLifecycleStepperProps
<Text <Text
size="xs" size="xs"
fw={isActive ? 600 : 500} fw={isActive ? 600 : 500}
c={isActive ? "green.7" : isComplete ? "dark" : "dimmed"} c={isActive ? "edr-green.7" : isComplete ? "dark" : "dimmed"}
ta="center" ta="center"
style={{ whiteSpace: "nowrap" }} style={{ whiteSpace: "nowrap" }}
> >

View File

@@ -29,7 +29,7 @@ export function BookingPaymentCard({
</Text> </Text>
</Group> </Group>
<Badge <Badge
color={paymentStatus === "PAID" ? "green" : "yellow"} color={paymentStatus === "PAID" ? "edr-green" : "yellow"}
variant="light" variant="light"
radius="sm" radius="sm"
mt="xs" mt="xs"

View File

@@ -49,13 +49,7 @@ export function BookingRequestHero({
<Paper <Paper
radius="xl" radius="xl"
p="xl" p="xl"
style={{ style={{ position: "relative", overflow: "hidden" }}
position: "relative",
overflow: "hidden",
background: "#ffffff",
border: "1px solid var(--mantine-color-gray-2)",
boxShadow: "0 1px 3px rgba(15,23,42,0.04)",
}}
> >
<Stack gap="lg" style={{ position: "relative" }}> <Stack gap="lg" style={{ position: "relative" }}>
<Group justify="space-between" align="flex-start" wrap="wrap"> <Group justify="space-between" align="flex-start" wrap="wrap">
@@ -70,7 +64,7 @@ export function BookingRequestHero({
</Button> </Button>
<Button <Button
variant="light" variant="light"
color="green" color="edr-green"
size="compact-sm" size="compact-sm"
radius="lg" radius="lg"
leftSection={<RefreshCw size={15} />} leftSection={<RefreshCw size={15} />}
@@ -87,7 +81,7 @@ export function BookingRequestHero({
Booking reference Booking reference
</Text> </Text>
<Group gap="sm" align="center" wrap="wrap"> <Group gap="sm" align="center" wrap="wrap">
<Title order={2} fw={700} style={{ letterSpacing: "-0.4px", color: "#0f172a" }}> <Title order={2} fw={700} style={{ letterSpacing: "-0.4px" }}>
{booking.reference} {booking.reference}
</Title> </Title>
<BookingStatusBadge status={booking.status} /> <BookingStatusBadge status={booking.status} />
@@ -130,7 +124,7 @@ export function BookingRequestHero({
minimumFractionDigits: 2, minimumFractionDigits: 2,
})}`} })}`}
hint={booking.paymentStatus} hint={booking.paymentStatus}
accent="green" accent="edr-green"
/> />
<HeroTile icon={Weight} label="Cargo weight" value={`${weight} T`} hint="VGM total" accent="blue" /> <HeroTile icon={Weight} label="Cargo weight" value={`${weight} T`} hint="VGM total" accent="blue" />
<HeroTile <HeroTile
@@ -177,7 +171,7 @@ function HeroTile({
label, label,
value, value,
hint, hint,
accent = "green", accent = "edr-green",
}: { }: {
icon: LucideIcon; icon: LucideIcon;
label: string; label: string;
@@ -204,7 +198,7 @@ function HeroTile({
<Text size="xs" fw={600} tt="uppercase" c="dimmed" style={{ letterSpacing: 0.4 }}> <Text size="xs" fw={600} tt="uppercase" c="dimmed" style={{ letterSpacing: 0.4 }}>
{label} {label}
</Text> </Text>
<Text fw={700} size="lg" lh={1.1} style={{ whiteSpace: "nowrap", color: "#0f172a" }}> <Text fw={700} size="lg" lh={1.1} style={{ whiteSpace: "nowrap" }}>
{value} {value}
</Text> </Text>
{hint ? ( {hint ? (

View File

@@ -30,7 +30,7 @@ export function BookingReviewNotesCard({ notes }: BookingReviewNotesCardProps) {
</ThemeIcon> </ThemeIcon>
<Stack gap={2} style={{ flex: 1 }}> <Stack gap={2} style={{ flex: 1 }}>
<Group justify="space-between"> <Group justify="space-between">
<Badge color="green" variant="light" size="sm" radius="sm"> <Badge color="edr-green" variant="light" size="sm" radius="sm">
{note.type} {note.type}
</Badge> </Badge>
<Text size="xs" c="dimmed"> <Text size="xs" c="dimmed">

View File

@@ -9,38 +9,29 @@ export interface SectionCardProps {
title: string; title: string;
/** Optional one-line context shown under the title. */ /** Optional one-line context shown under the title. */
subtitle?: string; subtitle?: string;
/** Mantine palette key used to tint the icon chip + top accent (default green). */ /** Mantine palette key used to tint the icon chip (default brand green). */
accent?: string; accent?: string;
extra?: ReactNode; extra?: ReactNode;
children: ReactNode; children: ReactNode;
} }
/** Consistent card with a colored icon chip + accent stripe header used by every detail section. */ /** Consistent card with a colored icon chip header used by every detail section. */
export function SectionCard({ export function SectionCard({
icon: Icon, icon: Icon,
title, title,
subtitle, subtitle,
accent = "green", accent = "edr-green",
extra, extra,
children, children,
}: SectionCardProps) { }: SectionCardProps) {
return ( return (
<Paper radius="md" withBorder style={{ ...detailStyles.card, overflow: "hidden" }}> <Paper radius="md" withBorder style={{ ...detailStyles.card, overflow: "hidden" }}>
<Box
style={{
height: 3,
background: `linear-gradient(90deg, var(--mantine-color-${accent}-5) 0%, var(--mantine-color-${accent}-7) 100%)`,
}}
/>
<Group <Group
justify="space-between" justify="space-between"
px="xl" px="xl"
py="md" py="md"
wrap="nowrap" wrap="nowrap"
style={{ style={detailStyles.cardHeader}
...detailStyles.cardHeader,
background: `linear-gradient(180deg, var(--mantine-color-${accent}-0) 0%, white 100%)`,
}}
> >
<Group gap="sm" wrap="nowrap" style={{ minWidth: 0 }}> <Group gap="sm" wrap="nowrap" style={{ minWidth: 0 }}>
<Box <Box

View File

@@ -94,8 +94,8 @@ const FleetCardGrid = ({
width: 40, width: 40,
height: 40, height: 40,
borderRadius: 10, borderRadius: 10,
background: "var(--mantine-color-green-0)", background: "var(--mantine-color-edr-green-0)",
color: "var(--mantine-color-green-7)", color: "var(--mantine-color-edr-green-7)",
display: "flex", display: "flex",
alignItems: "center", alignItems: "center",
justifyContent: "center", justifyContent: "center",

View File

@@ -195,7 +195,7 @@ const FleetFormDialog = ({
<Button variant="default" onClick={() => onOpenChange(false)}> <Button variant="default" onClick={() => onOpenChange(false)}>
Cancel Cancel
</Button> </Button>
<Button color="green" loading={isSubmitting} onClick={handleSubmit}> <Button color="edr-green" loading={isSubmitting} onClick={handleSubmit}>
Save Save
</Button> </Button>
</Group> </Group>

View File

@@ -35,7 +35,7 @@ const FleetRecordActions = ({
{showDetail ? ( {showDetail ? (
<Button <Button
variant="light" variant="light"
color="green" color="edr-green"
size="compact-sm" size="compact-sm"
radius="md" radius="md"
onClick={handleDetail} onClick={handleDetail}
@@ -72,7 +72,7 @@ const FleetRecordActions = ({
<Group gap={4} wrap="nowrap" justify="flex-end"> <Group gap={4} wrap="nowrap" justify="flex-end">
{showDetail ? ( {showDetail ? (
<Tooltip label="Manage wagons"> <Tooltip label="Manage wagons">
<ActionIcon variant="subtle" color="green" size="md" radius="md" onClick={handleDetail}> <ActionIcon variant="subtle" color="edr-green" size="md" radius="md" onClick={handleDetail}>
<Truck size={16} /> <Truck size={16} />
</ActionIcon> </ActionIcon>
</Tooltip> </Tooltip>

View File

@@ -93,7 +93,7 @@ const FleetToolbar = ({
/> />
{onAdd ? ( {onAdd ? (
<Button <Button
color="green" color="edr-green"
radius="lg" radius="lg"
size="sm" size="sm"
fw={600} fw={600}

View File

@@ -49,7 +49,7 @@ export function OverviewQuickLinks() {
> >
<Group justify="space-between" align="flex-start" wrap="nowrap"> <Group justify="space-between" align="flex-start" wrap="nowrap">
<Group align="flex-start" gap="sm" wrap="nowrap"> <Group align="flex-start" gap="sm" wrap="nowrap">
<ThemeIcon variant="light" color="green" size="lg" radius="md"> <ThemeIcon variant="light" color="edr-green" size="lg" radius="md">
<Icon size={18} /> <Icon size={18} />
</ThemeIcon> </ThemeIcon>
<Stack gap={2}> <Stack gap={2}>

View File

@@ -333,7 +333,7 @@ const ManageRuleEngineOrderDialog = ({
Cancel Cancel
</Button> </Button>
<Button <Button
color="green" color="edr-green"
onClick={handleSave} onClick={handleSave}
disabled={isLoading || isSaving} disabled={isLoading || isSaving}
leftSection={ leftSection={

View File

@@ -240,7 +240,7 @@ const RuleEngineFormDialog = ({
checked={Boolean(values[field.name])} checked={Boolean(values[field.name])}
onChange={(e) => setField(field.name, e.currentTarget.checked)} onChange={(e) => setField(field.name, e.currentTarget.checked)}
size="md" size="md"
color="green" color="edr-green"
/> />
</Group> </Group>
); );
@@ -387,7 +387,7 @@ const RuleEngineFormDialog = ({
) : undefined ) : undefined
} }
radius="md" radius="md"
color="green" color="edr-green"
variant="filled" variant="filled"
fw={600} fw={600}
size="md" size="md"

View File

@@ -52,7 +52,7 @@ const RuleEngineToolbar = ({
onChange={(value) => onViewModeChange(value as RuleEngineViewMode)} onChange={(value) => onViewModeChange(value as RuleEngineViewMode)}
size="sm" size="sm"
radius="lg" radius="lg"
color="green" color="edr-green"
data={[ data={[
{ {
value: "table", value: "table",
@@ -101,7 +101,7 @@ const RuleEngineToolbar = ({
leftSection={<Plus size={18} />} leftSection={<Plus size={18} />}
size="sm" size="sm"
radius="lg" radius="lg"
color="green" color="edr-green"
variant="filled" variant="filled"
fw={600} fw={600}
style={{ whiteSpace: "nowrap" }} style={{ whiteSpace: "nowrap" }}

View File

@@ -39,7 +39,7 @@ export const formatCell = (value: unknown, format?: ColumnFormat): ReactNode =>
const active = Boolean(value); const active = Boolean(value);
return ( return (
<Badge <Badge
color={active ? "green" : "gray"} color={active ? "edr-green" : "gray"}
variant={active ? "filled" : "light"} variant={active ? "filled" : "light"}
size="sm" size="sm"
radius="md" radius="md"
@@ -53,7 +53,7 @@ export const formatCell = (value: unknown, format?: ColumnFormat): ReactNode =>
const status = String(value); const status = String(value);
const color = const color =
status === "LIVE" status === "LIVE"
? "green" ? "edr-green"
: status === "DRAFT" : status === "DRAFT"
? "yellow" ? "yellow"
: status === "PENDING_APPROVAL" : status === "PENDING_APPROVAL"

View File

@@ -447,27 +447,27 @@ export function AllocateBookingWizard({
if (key === "bookings") { if (key === "bookings") {
if (previewResult) { if (previewResult) {
return ( return (
<Badge variant="light" color={previewResult.valid ? "green" : "red"} radius="sm"> <Badge variant="light" color={previewResult.valid ? "edr-green" : "red"} radius="sm">
{previewResult.valid ? "Plan valid" : "Has issues"} {previewResult.valid ? "Plan valid" : "Has issues"}
</Badge> </Badge>
); );
} }
return allBookingIds.length ? ( return allBookingIds.length ? (
<Badge variant="light" color="green" radius="sm"> <Badge variant="light" color="edr-green" radius="sm">
{allBookingIds.length} selected {allBookingIds.length} selected
</Badge> </Badge>
) : null; ) : null;
} }
if (key === "wagon" && displayWagonPlan.length) { if (key === "wagon" && displayWagonPlan.length) {
return ( return (
<Badge variant="light" color="green" radius="sm"> <Badge variant="light" color="edr-green" radius="sm">
{displayWagonPlan.length} wagons {displayWagonPlan.length} wagons
</Badge> </Badge>
); );
} }
if (key === "container" && containerUnits.length) { if (key === "container" && containerUnits.length) {
return ( return (
<Badge variant="light" color={containerComplete ? "green" : "yellow"} radius="sm"> <Badge variant="light" color={containerComplete ? "edr-green" : "yellow"} radius="sm">
{containerUnits.length} units {containerUnits.length} units
</Badge> </Badge>
); );
@@ -577,7 +577,7 @@ export function AllocateBookingWizard({
size="sm" size="sm"
/> />
<Button <Button
color="green" color="edr-green"
radius="md" radius="md"
leftSection={<Eye size={16} />} leftSection={<Eye size={16} />}
loading={preview.isPending} loading={preview.isPending}
@@ -648,7 +648,7 @@ export function AllocateBookingWizard({
<Group> <Group>
{!hasContainerStep ? ( {!hasContainerStep ? (
<Button <Button
color="green" color="edr-green"
radius="md" radius="md"
loading={assign.isPending || create.isPending} loading={assign.isPending || create.isPending}
onClick={handleAssign} onClick={handleAssign}
@@ -657,7 +657,7 @@ export function AllocateBookingWizard({
</Button> </Button>
) : ( ) : (
<Button <Button
color="green" color="edr-green"
radius="md" radius="md"
rightSection={<ContainerIcon size={16} />} rightSection={<ContainerIcon size={16} />}
onClick={() => setActiveStep(2)} onClick={() => setActiveStep(2)}
@@ -692,7 +692,7 @@ export function AllocateBookingWizard({
)} )}
<Group> <Group>
<Button <Button
color="green" color="edr-green"
radius="md" radius="md"
loading={assign.isPending || create.isPending} loading={assign.isPending || create.isPending}
onClick={handleAssign} onClick={handleAssign}
@@ -732,7 +732,7 @@ export function AllocateBookingWizard({
style={{ background: scheduleBrand.softSurface, borderColor: scheduleBrand.mutedBorder }} style={{ background: scheduleBrand.softSurface, borderColor: scheduleBrand.mutedBorder }}
> >
<Group gap="md" align="flex-start" wrap="nowrap"> <Group gap="md" align="flex-start" wrap="nowrap">
<ThemeIcon size={44} radius="md" variant="light" color="green"> <ThemeIcon size={44} radius="md" variant="light" color="edr-green">
<CheckCircle2 size={22} /> <CheckCircle2 size={22} />
</ThemeIcon> </ThemeIcon>
<Stack gap={2} style={{ flex: 1 }}> <Stack gap={2} style={{ flex: 1 }}>
@@ -741,14 +741,14 @@ export function AllocateBookingWizard({
</Text> </Text>
<Text size="sm" c="dimmed"> <Text size="sm" c="dimmed">
Booking {booking.reference} is scheduled on train{" "} Booking {booking.reference} is scheduled on train{" "}
<Text span fw={600} c="green.7"> <Text span fw={600} c="edr-green.7">
{assignedSchedule?.trainSet?.locomotive?.code ?? "—"} {assignedSchedule?.trainSet?.locomotive?.code ?? "—"}
</Text> </Text>
. .
</Text> </Text>
<Group mt="sm"> <Group mt="sm">
<Button <Button
color="green" color="edr-green"
radius="md" radius="md"
onClick={() => { onClick={() => {
onClose(); onClose();
@@ -777,14 +777,14 @@ export function AllocateBookingWizard({
style={{ background: scheduleBrand.softSurface, borderColor: scheduleBrand.mutedBorder }} style={{ background: scheduleBrand.softSurface, borderColor: scheduleBrand.mutedBorder }}
> >
<Group gap="md" align="flex-start" wrap="nowrap"> <Group gap="md" align="flex-start" wrap="nowrap">
<ThemeIcon size={44} radius="md" variant="light" color="green"> <ThemeIcon size={44} radius="md" variant="light" color="edr-green">
<CheckCircle2 size={22} /> <CheckCircle2 size={22} />
</ThemeIcon> </ThemeIcon>
<Stack gap={2}> <Stack gap={2}>
<Text fw={600}>Ready to finalize</Text> <Text fw={600}>Ready to finalize</Text>
<Text size="sm" c="dimmed"> <Text size="sm" c="dimmed">
Finalizing locks the plan, moves the schedule to{" "} Finalizing locks the plan, moves the schedule to{" "}
<Text span fw={600} c="green.7"> <Text span fw={600} c="edr-green.7">
SCHEDULED SCHEDULED
</Text> </Text>
, and completes the booking allocation. , and completes the booking allocation.
@@ -794,7 +794,7 @@ export function AllocateBookingWizard({
</Paper> </Paper>
<Group> <Group>
<Button <Button
color="green" color="edr-green"
size="md" size="md"
radius="md" radius="md"
leftSection={<CheckCircle2 size={18} />} leftSection={<CheckCircle2 size={18} />}
@@ -852,7 +852,7 @@ export function AllocateBookingWizard({
size={56} size={56}
radius="lg" radius="lg"
variant="white" variant="white"
style={{ color: "var(--mantine-color-green-7)" }} style={{ color: "var(--mantine-color-edr-green-7)" }}
> >
<Train size={28} /> <Train size={28} />
</ThemeIcon> </ThemeIcon>
@@ -884,7 +884,7 @@ export function AllocateBookingWizard({
size="lg" size="lg"
radius="sm" radius="sm"
variant="white" variant="white"
c={previewResult.valid ? "green.8" : "red.7"} c={previewResult.valid ? "edr-green.8" : "red.7"}
leftSection={ leftSection={
<Box <Box
w={8} w={8}
@@ -892,7 +892,7 @@ export function AllocateBookingWizard({
style={{ style={{
borderRadius: 999, borderRadius: 999,
background: previewResult.valid background: previewResult.valid
? "var(--mantine-color-green-6)" ? "var(--mantine-color-edr-green-6)"
: "var(--mantine-color-red-6)", : "var(--mantine-color-red-6)",
}} }}
/> />
@@ -941,7 +941,7 @@ export function AllocateBookingWizard({
size={44} size={44}
radius="md" radius="md"
variant="gradient" variant="gradient"
gradient={{ from: "green", to: "teal", deg: 135 }} gradient={{ from: "edr-green", to: "teal", deg: 135 }}
> >
<RouteIcon size={22} /> <RouteIcon size={22} />
</ThemeIcon> </ThemeIcon>
@@ -959,9 +959,9 @@ export function AllocateBookingWizard({
size={64} size={64}
thickness={6} thickness={6}
roundCaps roundCaps
sections={[{ value: progressPct, color: "green" }]} sections={[{ value: progressPct, color: "edr-green" }]}
label={ label={
<Text ta="center" size="xs" fw={700} c="green.7"> <Text ta="center" size="xs" fw={700} c="edr-green.7">
{progressPct}% {progressPct}%
</Text> </Text>
} }

View File

@@ -120,7 +120,7 @@ export function ContainerPlacementGrid({
value={progress} value={progress}
size="sm" size="sm"
radius="xl" radius="xl"
color={issues.length ? "yellow" : "green"} color={issues.length ? "yellow" : "edr-green"}
/> />
</Stack> </Stack>
</Paper> </Paper>
@@ -135,7 +135,7 @@ export function ContainerPlacementGrid({
</Stack> </Stack>
) : ( ) : (
<Badge <Badge
color="green" color="edr-green"
variant="light" variant="light"
size="sm" size="sm"
w="fit-content" w="fit-content"
@@ -163,7 +163,7 @@ export function ContainerPlacementGrid({
{unit.label} · {unit.containerTypeCode} · {unit.grossWeightTons}T {unit.label} · {unit.containerTypeCode} · {unit.grossWeightTons}T
</Text> </Text>
</Stack> </Stack>
<Badge size="sm" variant="light" color={isComplete ? "green" : "gray"}> <Badge size="sm" variant="light" color={isComplete ? "edr-green" : "gray"}>
{isComplete ? "Ready" : "Pending"} {isComplete ? "Ready" : "Pending"}
</Badge> </Badge>
</Group> </Group>

View File

@@ -37,14 +37,14 @@ function EligibleBookingRow({
p="sm" p="sm"
style={{ style={{
border: `1px solid ${ border: `1px solid ${
selected ? "var(--mantine-color-green-3)" : "var(--mantine-color-gray-2)" selected ? "var(--mantine-color-edr-green-3)" : "var(--mantine-color-gray-2)"
}`, }`,
borderRadius: 12, borderRadius: 12,
background: selected ? "var(--mantine-color-green-0)" : "white", background: selected ? "var(--mantine-color-edr-green-0)" : "white",
transition: "border-color 120ms ease, background 120ms ease", transition: "border-color 120ms ease, background 120ms ease",
}} }}
> >
<Checkbox checked={selected} onChange={onToggle} mt={4} color="green" /> <Checkbox checked={selected} onChange={onToggle} mt={4} color="edr-green" />
<Stack gap={4} style={{ flex: 1 }}> <Stack gap={4} style={{ flex: 1 }}>
<Group gap="xs" wrap="wrap"> <Group gap="xs" wrap="wrap">
<Package size={14} /> <Package size={14} />
@@ -205,7 +205,7 @@ export function EligibleBookingsPanel({
</Text> </Text>
</Stack> </Stack>
<Group gap="xs" onClick={(e) => e.stopPropagation()}> <Group gap="xs" onClick={(e) => e.stopPropagation()}>
<Badge variant="light" color="green"> <Badge variant="light" color="edr-green">
{selectedInBucket.length} selected {selectedInBucket.length} selected
</Badge> </Badge>
<Button <Button

View File

@@ -43,7 +43,7 @@ export function FleetAvailabilitySummary({
</Text> </Text>
</Stack> </Stack>
</Group> </Group>
<Badge variant="light" color={totalShortfall > 0 ? "yellow" : "green"}> <Badge variant="light" color={totalShortfall > 0 ? "yellow" : "edr-green"}>
{fillRate}% fleet coverage {fillRate}% fleet coverage
</Badge> </Badge>
</Group> </Group>
@@ -59,7 +59,7 @@ export function FleetAvailabilitySummary({
value={fillRate} value={fillRate}
size="sm" size="sm"
radius="xl" radius="xl"
color={totalShortfall > 0 ? "yellow" : "green"} color={totalShortfall > 0 ? "yellow" : "edr-green"}
/> />
</Stack> </Stack>
) : null} ) : null}
@@ -86,7 +86,7 @@ export function FleetAvailabilitySummary({
{row.shortfall} {row.shortfall}
</Badge> </Badge>
) : ( ) : (
<Text size="sm" c="green"> <Text size="sm" c="edr-green">
0 0
</Text> </Text>
)} )}

View File

@@ -143,7 +143,7 @@ export function RouteCorridorTrack({
fw={passed ? 700 : 600} fw={passed ? 700 : 600}
ta="center" ta="center"
lineClamp={2} lineClamp={2}
c={passed ? "green.8" : "dimmed"} c={passed ? "edr-green.8" : "dimmed"}
> >
{station.label} {station.label}
</Text> </Text>
@@ -172,7 +172,7 @@ export function RouteCorridorTrack({
<Button <Button
size="compact-xs" size="compact-xs"
radius="md" radius="md"
color={isFinal ? "teal" : "green"} color={isFinal ? "teal" : "edr-green"}
variant={isFinal ? "filled" : "light"} variant={isFinal ? "filled" : "light"}
loading={loggingSeq === station.sequenceNo} loading={loggingSeq === station.sequenceNo}
onClick={() => onLogCheckpoint?.(station.sequenceNo)} onClick={() => onLogCheckpoint?.(station.sequenceNo)}

View File

@@ -26,7 +26,7 @@ interface ScheduleBatchPanelProps {
} }
const windowColor: Record<string, string> = { const windowColor: Record<string, string> = {
OPEN: "green", OPEN: "edr-green",
FULL: "orange", FULL: "orange",
CLOSED: "gray", CLOSED: "gray",
}; };
@@ -68,7 +68,7 @@ export function ScheduleBatchPanel({ schedule }: ScheduleBatchPanelProps) {
<Paper radius="lg" withBorder p="lg" style={{ borderColor: "var(--mantine-color-gray-2)" }}> <Paper radius="lg" withBorder p="lg" style={{ borderColor: "var(--mantine-color-gray-2)" }}>
<Group justify="space-between" align="center" mb="md" wrap="wrap"> <Group justify="space-between" align="center" mb="md" wrap="wrap">
<Group gap="sm"> <Group gap="sm">
<ThemeIcon size={36} radius="md" variant="light" color="green"> <ThemeIcon size={36} radius="md" variant="light" color="edr-green">
<Layers size={18} /> <Layers size={18} />
</ThemeIcon> </ThemeIcon>
<div> <div>
@@ -90,7 +90,7 @@ export function ScheduleBatchPanel({ schedule }: ScheduleBatchPanelProps) {
<Button <Button
size="compact-sm" size="compact-sm"
variant="light" variant="light"
color="green" color="edr-green"
leftSection={<PlayCircle size={15} />} leftSection={<PlayCircle size={15} />}
loading={actions.runBatch.isPending} loading={actions.runBatch.isPending}
onClick={() => run(actions.runBatch.mutateAsync(schedule.id), "Batch fill run")} onClick={() => run(actions.runBatch.mutateAsync(schedule.id), "Batch fill run")}
@@ -169,7 +169,7 @@ export function ScheduleBatchPanel({ schedule }: ScheduleBatchPanelProps) {
<Button <Button
size="compact-xs" size="compact-xs"
variant="light" variant="light"
color="green" color="edr-green"
leftSection={<CheckCircle2 size={13} />} leftSection={<CheckCircle2 size={13} />}
onClick={() => run(actions.markPaid.mutateAsync(b.id), "Marked paid")} onClick={() => run(actions.markPaid.mutateAsync(b.id), "Marked paid")}
> >
@@ -228,7 +228,7 @@ export function ScheduleBatchPanel({ schedule }: ScheduleBatchPanelProps) {
Cancel Cancel
</Button> </Button>
<Button <Button
color="green" color="edr-green"
disabled={!moveTarget} disabled={!moveTarget}
loading={actions.moveSchedule.isPending} loading={actions.moveSchedule.isPending}
onClick={() => { onClick={() => {

View File

@@ -46,7 +46,7 @@ export function ScheduleBookingsStep({
defaultValue={assignedBookings.length ? "on-train" : "add"} defaultValue={assignedBookings.length ? "on-train" : "add"}
radius="md" radius="md"
variant="pills" variant="pills"
color="green" color="edr-green"
> >
<Tabs.List mb="md"> <Tabs.List mb="md">
<Tabs.Tab <Tabs.Tab
@@ -54,7 +54,7 @@ export function ScheduleBookingsStep({
leftSection={<Train size={14} />} leftSection={<Train size={14} />}
rightSection={ rightSection={
assignedBookings.length ? ( assignedBookings.length ? (
<Badge size="xs" variant="light" color="green" circle> <Badge size="xs" variant="light" color="edr-green" circle>
{assignedBookings.length} {assignedBookings.length}
</Badge> </Badge>
) : undefined ) : undefined
@@ -76,9 +76,9 @@ export function ScheduleBookingsStep({
justify="space-between" justify="space-between"
p="sm" p="sm"
style={{ style={{
border: "1px solid var(--mantine-color-green-2)", border: "1px solid var(--mantine-color-edr-green-2)",
borderRadius: 12, borderRadius: 12,
background: "var(--mantine-color-green-0)", background: "var(--mantine-color-edr-green-0)",
}} }}
> >
<Stack gap={4}> <Stack gap={4}>
@@ -87,7 +87,7 @@ export function ScheduleBookingsStep({
{booking.reference} {booking.reference}
</Text> </Text>
{booking.weightTons != null ? ( {booking.weightTons != null ? (
<Badge variant="outline" size="xs" color="green"> <Badge variant="outline" size="xs" color="edr-green">
{booking.weightTons}T {booking.weightTons}T
</Badge> </Badge>
) : null} ) : null}
@@ -97,7 +97,7 @@ export function ScheduleBookingsStep({
Assigned to this consist Assigned to this consist
</Text> </Text>
<ArrowRight size={12} /> <ArrowRight size={12} />
<Text size="xs" c="green.7" fw={500}> <Text size="xs" c="edr-green.7" fw={500}>
Ready for wagon plan Ready for wagon plan
</Text> </Text>
</Group> </Group>

View File

@@ -54,7 +54,7 @@ export function PreviewSummary({
{ label: "Train length", value: `${summary.totalLengthMeters}m` }, { label: "Train length", value: `${summary.totalLengthMeters}m` },
]; ];
return ( return (
<Paper p="md" radius="xl" withBorder bg="green.0"> <Paper p="md" radius="xl" withBorder bg="edr-green.0">
<Text size="sm" fw={600} mb="sm"> <Text size="sm" fw={600} mb="sm">
Plan summary Plan summary
</Text> </Text>

View File

@@ -49,7 +49,7 @@ export function SchedulingWorkflowHeader({
> >
<Group justify="space-between" align="flex-start" wrap="wrap" gap="md"> <Group justify="space-between" align="flex-start" wrap="wrap" gap="md">
<Group gap="md" align="flex-start"> <Group gap="md" align="flex-start">
<ThemeIcon size={42} radius="xl" variant="gradient" gradient={{ from: "green", to: "teal", deg: 135 }}> <ThemeIcon size={42} radius="xl" variant="gradient" gradient={{ from: "edr-green", to: "teal", deg: 135 }}>
<Icon size={20} /> <Icon size={20} />
</ThemeIcon> </ThemeIcon>
<Stack gap={4}> <Stack gap={4}>
@@ -63,7 +63,7 @@ export function SchedulingWorkflowHeader({
) : null} ) : null}
</Stack> </Stack>
</Group> </Group>
<Badge size="lg" variant="light" color="green"> <Badge size="lg" variant="light" color="edr-green">
Step {activeStep + 1} of {totalSteps} Step {activeStep + 1} of {totalSteps}
</Badge> </Badge>
</Group> </Group>
@@ -83,7 +83,7 @@ export function SchedulingWorkflowHeader({
{progress}% {progress}%
</Text> </Text>
</Group> </Group>
<Progress value={progress} size="sm" radius="xl" color="green" /> <Progress value={progress} size="sm" radius="xl" color="edr-green" />
</Stack> </Stack>
</Paper> </Paper>
); );

View File

@@ -618,18 +618,18 @@ export function TrainCompositionDiagram({
p="sm" p="sm"
style={{ style={{
borderRadius: 12, borderRadius: 12,
background: "linear-gradient(135deg, var(--mantine-color-green-0), #F2FBF7)", background: "linear-gradient(135deg, var(--mantine-color-edr-green-0), #F2FBF7)",
border: "1px solid var(--mantine-color-green-1)", border: "1px solid var(--mantine-color-edr-green-1)",
}} }}
> >
<Group justify="space-between" mb={6}> <Group justify="space-between" mb={6}>
<Group gap={6} wrap="nowrap"> <Group gap={6} wrap="nowrap">
<Gauge size={14} color={freightBrand.primary} /> <Gauge size={14} color={freightBrand.primary} />
<Text size="xs" fw={700} c="green.8"> <Text size="xs" fw={700} c="edr-green.8">
Locomotive load · {stats.totalWeight}T of {locomotive?.maxPullWeightTons}T Locomotive load · {stats.totalWeight}T of {locomotive?.maxPullWeightTons}T
</Text> </Text>
</Group> </Group>
<Text size="sm" fw={800} c={stats.pullUtil > 95 ? "red.7" : "green.7"}> <Text size="sm" fw={800} c={stats.pullUtil > 95 ? "red.7" : "edr-green.7"}>
{stats.pullUtil}% {stats.pullUtil}%
</Text> </Text>
</Group> </Group>
@@ -639,7 +639,7 @@ export function TrainCompositionDiagram({
radius="xl" radius="xl"
striped={stats.pullUtil > 95} striped={stats.pullUtil > 95}
animated={stats.pullUtil > 95} animated={stats.pullUtil > 95}
color={stats.pullUtil > 95 ? "red" : stats.pullUtil > 80 ? "yellow" : "green"} color={stats.pullUtil > 95 ? "red" : stats.pullUtil > 80 ? "yellow" : "edr-green"}
/> />
</Box> </Box>
) : null} ) : null}

View File

@@ -133,7 +133,7 @@ export function WagonPlanGrid({
value={utilization} value={utilization}
size="sm" size="sm"
radius="xl" radius="xl"
color={utilization > 95 ? "red" : utilization > 80 ? "yellow" : "green"} color={utilization > 95 ? "red" : utilization > 80 ? "yellow" : "edr-green"}
/> />
</Stack> </Stack>
) : null} ) : null}

View File

@@ -123,13 +123,13 @@ export function WorkflowStep({
<Text <Text
size="xs" size="xs"
fw={700} fw={700}
c={isComplete || isActive ? "green.7" : "dimmed"} c={isComplete || isActive ? "edr-green.7" : "dimmed"}
style={{ letterSpacing: 0.6 }} style={{ letterSpacing: 0.6 }}
> >
STEP {index + 1} STEP {index + 1}
</Text> </Text>
{isComplete ? ( {isComplete ? (
<Badge size="xs" variant="light" color="green" radius="sm"> <Badge size="xs" variant="light" color="edr-green" radius="sm">
Done Done
</Badge> </Badge>
) : null} ) : null}
@@ -155,10 +155,10 @@ export function WorkflowStep({
height: 28, height: 28,
borderRadius: 8, borderRadius: 8,
background: open background: open
? "var(--mantine-color-green-0)" ? "var(--mantine-color-edr-green-0)"
: "var(--mantine-color-gray-1)", : "var(--mantine-color-gray-1)",
color: open color: open
? "var(--mantine-color-green-7)" ? "var(--mantine-color-edr-green-7)"
: "var(--mantine-color-gray-6)", : "var(--mantine-color-gray-6)",
}} }}
> >
@@ -209,7 +209,7 @@ export function WorkflowRail({ children }: { children: ReactNode }) {
bottom: 24, bottom: 24,
width: 2, width: 2,
background: background:
"linear-gradient(180deg, var(--mantine-color-green-3) 0%, var(--mantine-color-gray-3) 100%)", "linear-gradient(180deg, var(--mantine-color-edr-green-3) 0%, var(--mantine-color-gray-3) 100%)",
borderRadius: 2, borderRadius: 2,
pointerEvents: "none", pointerEvents: "none",
}} }}

View File

@@ -27,7 +27,7 @@ export const PIPELINE_STAGES: ReadonlyArray<{
{ {
key: "allocated", key: "allocated",
label: "Allocated", label: "Allocated",
color: "green", color: "edr-green",
hint: "Assigned to wagons on the train", hint: "Assigned to wagons on the train",
}, },
{ {
@@ -137,7 +137,7 @@ export function BookingPipeline({
} }
const WINDOW_META: Record<string, { color: string; label: string; pulse: boolean }> = { const WINDOW_META: Record<string, { color: string; label: string; pulse: boolean }> = {
OPEN: { color: "green", label: "Window open", pulse: true }, OPEN: { color: "edr-green", label: "Window open", pulse: true },
FULL: { color: "orange", label: "Full", pulse: false }, FULL: { color: "orange", label: "Full", pulse: false },
CLOSED: { color: "gray", label: "Closed", pulse: false }, CLOSED: { color: "gray", label: "Closed", pulse: false },
}; };

View File

@@ -95,7 +95,7 @@ export const AssignedBookingsPanel = ({
}} }}
> >
<Group gap={8} wrap="nowrap" align="flex-start"> <Group gap={8} wrap="nowrap" align="flex-start">
<ThemeIcon size={30} radius="md" variant="light" color="green"> <ThemeIcon size={30} radius="md" variant="light" color="edr-green">
<Package size={16} /> <Package size={16} />
</ThemeIcon> </ThemeIcon>
<Box style={{ flex: 1, minWidth: 0 }}> <Box style={{ flex: 1, minWidth: 0 }}>
@@ -107,7 +107,7 @@ export const AssignedBookingsPanel = ({
<Badge <Badge
size="xs" size="xs"
variant="light" variant="light"
color="green" color="edr-green"
leftSection={<TrainFront size={9} />} leftSection={<TrainFront size={9} />}
> >
{wagonCountByBooking.get(booking.id)} {wagonCountByBooking.get(booking.id)}

View File

@@ -43,7 +43,7 @@ function InfoRow({
return ( return (
<Group justify="space-between" wrap="nowrap" gap="md"> <Group justify="space-between" wrap="nowrap" gap="md">
<Group gap={8} wrap="nowrap"> <Group gap={8} wrap="nowrap">
<ThemeIcon size={28} radius="md" variant="light" color="green"> <ThemeIcon size={28} radius="md" variant="light" color="edr-green">
{icon} {icon}
</ThemeIcon> </ThemeIcon>
<Text size="sm" c="dimmed"> <Text size="sm" c="dimmed">
@@ -146,7 +146,7 @@ export const BookingDetailModal = ({
bookingWagons.length ? ( bookingWagons.length ? (
<Group gap={4} justify="flex-end"> <Group gap={4} justify="flex-end">
{bookingWagons.map((w) => ( {bookingWagons.map((w) => (
<Badge key={w.id} size="sm" variant="outline" color="green" radius="sm"> <Badge key={w.id} size="sm" variant="outline" color="edr-green" radius="sm">
#{w.sequenceNo} #{w.sequenceNo}
</Badge> </Badge>
))} ))}

View File

@@ -29,7 +29,7 @@ interface CompositionBookingTabsProps {
type TabKey = "assigned" | "unassigned" | "payment" | "expired" | "removed"; type TabKey = "assigned" | "unassigned" | "payment" | "expired" | "removed";
const TAB_META: Record<TabKey, { label: string; icon: LucideIcon; color: string }> = { const TAB_META: Record<TabKey, { label: string; icon: LucideIcon; color: string }> = {
assigned: { label: "Assigned to train", icon: PackageCheck, color: "green" }, assigned: { label: "Assigned to train", icon: PackageCheck, color: "edr-green" },
unassigned: { label: "Unassigned (ready to load)", icon: PackagePlus, color: "orange" }, unassigned: { label: "Unassigned (ready to load)", icon: PackagePlus, color: "orange" },
payment: { label: "Awaiting payment", icon: CreditCard, color: "orange" }, payment: { label: "Awaiting payment", icon: CreditCard, color: "orange" },
expired: { label: "Expired bookings", icon: XCircle, color: "red" }, expired: { label: "Expired bookings", icon: XCircle, color: "red" },
@@ -152,7 +152,7 @@ export const CompositionBookingTabs = ({
value={tab} value={tab}
onChange={(v) => v && setTab(v as TabKey)} onChange={(v) => v && setTab(v as TabKey)}
variant="default" variant="default"
color="green" color="edr-green"
style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }} style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}
> >
<Tabs.List grow> <Tabs.List grow>
@@ -220,7 +220,7 @@ export const CompositionBookingTabs = ({
}} }}
> >
<Group gap={5} wrap="nowrap"> <Group gap={5} wrap="nowrap">
<PackageCheck size={13} color="var(--mantine-color-green-7)" /> <PackageCheck size={13} color="var(--mantine-color-edr-green-7)" />
<Text size="xs" c="dimmed"> <Text size="xs" c="dimmed">
{assignedCount} on train {assignedCount} on train
</Text> </Text>

View File

@@ -60,7 +60,7 @@ export const RemoveBookingConfirmModal = ({
<Text fw={800} size="sm"> <Text fw={800} size="sm">
{target?.reference ?? "Booking"} {target?.reference ?? "Booking"}
</Text> </Text>
<Badge variant="light" color="green" leftSection={<TrainFront size={10} />}> <Badge variant="light" color="edr-green" leftSection={<TrainFront size={10} />}>
{target?.wagonCount ?? 0} wagon{target?.wagonCount === 1 ? "" : "s"} {target?.wagonCount ?? 0} wagon{target?.wagonCount === 1 ? "" : "s"}
</Badge> </Badge>
</Group> </Group>

View File

@@ -165,7 +165,7 @@ export const TrainConsistView = ({
{selectedWagon ? ( {selectedWagon ? (
<Box> <Box>
<Group gap={6} mb={6} wrap="nowrap"> <Group gap={6} mb={6} wrap="nowrap">
<Badge variant="light" color="green" radius="sm"> <Badge variant="light" color="edr-green" radius="sm">
Editing wagon #{selectedWagon.sequenceNo} Editing wagon #{selectedWagon.sequenceNo}
</Badge> </Badge>
<Text size="xs" c="dimmed"> <Text size="xs" c="dimmed">

View File

@@ -48,18 +48,18 @@ const YardFleetBanner = ({ fleetAtOrigin }: { fleetAtOrigin: FleetAvailabilityRo
py={6} py={6}
style={{ style={{
borderRadius: 8, borderRadius: 8,
background: "var(--mantine-color-green-0)", background: "var(--mantine-color-edr-green-0)",
border: "1px solid var(--mantine-color-green-1)", border: "1px solid var(--mantine-color-edr-green-1)",
}} }}
> >
<Group gap={5} wrap="nowrap"> <Group gap={5} wrap="nowrap">
<MapPin size={13} color="var(--mantine-color-green-7)" /> <MapPin size={13} color="var(--mantine-color-edr-green-7)" />
<Text size="xs" fw={700} c="green.8"> <Text size="xs" fw={700} c="edr-green.8">
Origin yard Origin yard
</Text> </Text>
</Group> </Group>
{fleetAtOrigin.map((row) => ( {fleetAtOrigin.map((row) => (
<Badge key={row.wagonTypeId} size="sm" variant="light" color="green"> <Badge key={row.wagonTypeId} size="sm" variant="light" color="edr-green">
{row.wagonTypeCode}: {row.available} {row.wagonTypeCode}: {row.available}
</Badge> </Badge>
))} ))}
@@ -148,7 +148,7 @@ export const UnassignedBookingsPanel = ({
} }
style={{ style={{
cursor: "pointer", cursor: "pointer",
borderColor: isActive ? "var(--mantine-color-green-5)" : undefined, borderColor: isActive ? "var(--mantine-color-edr-green-5)" : undefined,
}} }}
> >
<Stack gap={6}> <Stack gap={6}>
@@ -162,7 +162,7 @@ export const UnassignedBookingsPanel = ({
{booking.reference} {booking.reference}
</Text> </Text>
{booking.priorityScore ? ( {booking.priorityScore ? (
<Badge size="xs" color="green"> <Badge size="xs" color="edr-green">
P{booking.priorityScore} P{booking.priorityScore}
</Badge> </Badge>
) : null} ) : null}
@@ -194,7 +194,7 @@ export const UnassignedBookingsPanel = ({
<Button <Button
size="xs" size="xs"
variant="light" variant="light"
color="green" color="edr-green"
disabled={!fits} disabled={!fits}
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();

View File

@@ -47,7 +47,7 @@ export const WagonCard = ({
<Card.Section withBorder inheritPadding py="xs" style={{ background: freightBrand.mutedBg }}> <Card.Section withBorder inheritPadding py="xs" style={{ background: freightBrand.mutedBg }}>
<Group justify="space-between"> <Group justify="space-between">
<Group gap={6}> <Group gap={6}>
<ThemeIcon size={28} radius="md" variant="white" color="green"> <ThemeIcon size={28} radius="md" variant="white" color="edr-green">
<TrainFront size={16} /> <TrainFront size={16} />
</ThemeIcon> </ThemeIcon>
<div> <div>
@@ -55,7 +55,7 @@ export const WagonCard = ({
<Text size="sm" fw={800}> <Text size="sm" fw={800}>
Wagon #{wagon.sequenceNo} Wagon #{wagon.sequenceNo}
</Text> </Text>
<Badge size="xs" variant="light" color="green"> <Badge size="xs" variant="light" color="edr-green">
{wagonType} {wagonType}
</Badge> </Badge>
</Group> </Group>
@@ -142,7 +142,7 @@ export const WagonCard = ({
</Group> </Group>
<Progress <Progress
value={Math.min(weightPercent, 100)} value={Math.min(weightPercent, 100)}
color={weightPercent > 90 ? "red" : weightPercent > 75 ? "orange" : "green"} color={weightPercent > 90 ? "red" : weightPercent > 75 ? "orange" : "edr-green"}
size="sm" size="sm"
radius="xl" radius="xl"
/> />

View File

@@ -2,7 +2,7 @@ import type { MantineTheme } from "@mantine/core";
export const schedulingWorkflow = { export const schedulingWorkflow = {
stepper: { stepper: {
color: "green" as const, color: "edr-green" as const,
iconSize: 32, iconSize: 32,
size: "sm" as const, size: "sm" as const,
}, },
@@ -12,11 +12,11 @@ export const schedulingWorkflow = {
withBorder: true, withBorder: true,
}, },
heroGradient: (theme: MantineTheme) => heroGradient: (theme: MantineTheme) =>
`linear-gradient(135deg, ${theme.colors.green[0]} 0%, ${theme.white} 55%, ${theme.colors.gray[0]} 100%)`, `linear-gradient(135deg, ${theme.colors["edr-green"][0]} 0%, ${theme.white} 55%, ${theme.colors.gray[0]} 100%)`,
workflowGradient: (theme: MantineTheme) => workflowGradient: (theme: MantineTheme) =>
`linear-gradient(180deg, ${theme.white} 0%, ${theme.colors.gray[0]} 100%)`, `linear-gradient(180deg, ${theme.white} 0%, ${theme.colors.gray[0]} 100%)`,
accentColor: "green" as const, accentColor: "edr-green" as const,
successColor: "green" as const, successColor: "edr-green" as const,
warningColor: "yellow" as const, warningColor: "yellow" as const,
}; };

View File

@@ -56,7 +56,7 @@ export function AssignWagonDialog({ trainId }: { trainId: string }) {
return ( return (
<> <>
<Button <Button
color="green" color="edr-green"
size="sm" size="sm"
radius="lg" radius="lg"
leftSection={<Plus size={16} />} leftSection={<Plus size={16} />}
@@ -91,7 +91,7 @@ export function AssignWagonDialog({ trainId }: { trainId: string }) {
<Button variant="default" onClick={() => setOpen(false)}> <Button variant="default" onClick={() => setOpen(false)}>
Cancel Cancel
</Button> </Button>
<Button color="green" loading={assign.isPending} onClick={handleAssign}> <Button color="edr-green" loading={assign.isPending} onClick={handleAssign}>
Assign Assign
</Button> </Button>
</Group> </Group>

View File

@@ -15,7 +15,7 @@ const INVOICE_STATUS_COLOR: Record<WarehouseInvoiceStatus, string> = {
DRAFT: 'gray', DRAFT: 'gray',
ISSUED: 'orange', ISSUED: 'orange',
PARTIALLY_PAID: 'yellow', PARTIALLY_PAID: 'yellow',
PAID: 'green', PAID: 'edr-green',
CANCELLED: 'gray', CANCELLED: 'gray',
}; };
@@ -175,7 +175,7 @@ export function FeePreviewModal({ opened, onClose, inventoryId }: FeePreviewModa
<Button <Button
variant="light" variant="light"
color="green" color="edr-green"
leftSection={<DoorOpen size={16} />} leftSection={<DoorOpen size={16} />}
loading={gateClear.isPending} loading={gateClear.isPending}
onClick={handleGateClearance} onClick={handleGateClearance}

View File

@@ -205,7 +205,7 @@ export function InspectionReportModal({ opened, onClose, inventoryId }: Inspecti
<Button variant="default" onClick={onClose} disabled={submitting}> <Button variant="default" onClick={onClose} disabled={submitting}>
Cancel Cancel
</Button> </Button>
<Button color="green" onClick={handleSubmit} loading={submitting} disabled={!inventoryId}> <Button color="edr-green" onClick={handleSubmit} loading={submitting} disabled={!inventoryId}>
Save report Save report
</Button> </Button>
</Group> </Group>

View File

@@ -30,7 +30,7 @@ const actionColor: Record<InventoryAction, string> = {
reserve: 'grape', reserve: 'grape',
'ready-for-loading': 'cyan', 'ready-for-loading': 'cyan',
load: 'teal', load: 'teal',
dispatch: 'green', dispatch: 'edr-green',
}; };
export function WarehouseInventoryTable({ export function WarehouseInventoryTable({

View File

@@ -25,7 +25,7 @@ export function WarehouseTypeBadge({ type }: { type: WarehouseType }) {
} }
export function WarehouseStatusBadge({ status }: { status: WarehouseStatus }) { export function WarehouseStatusBadge({ status }: { status: WarehouseStatus }) {
const color = status === 'ACTIVE' ? 'green' : 'gray'; const color = status === 'ACTIVE' ? 'edr-green' : 'gray';
return ( return (
<Badge color={color} variant="light" size="sm" radius="md" tt="uppercase" fw={600} style={badgeStyle}> <Badge color={color} variant="light" size="sm" radius="md" tt="uppercase" fw={600} style={badgeStyle}>
{status} {status}
@@ -39,7 +39,7 @@ const inventoryStatusColor: Record<InventoryStatus, string> = {
RESERVED: 'grape', RESERVED: 'grape',
READY_FOR_LOADING: 'cyan', READY_FOR_LOADING: 'cyan',
LOADED: 'teal', LOADED: 'teal',
DISPATCHED: 'green', DISPATCHED: 'edr-green',
}; };
export function InventoryStatusBadge({ status }: { status: InventoryStatus }) { export function InventoryStatusBadge({ status }: { status: InventoryStatus }) {

View File

@@ -1,32 +1,31 @@
import {
ActionIcon,
Card,
Group,
Stack,
Tabs,
Text,
TextInput,
} from "@mantine/core";
import { ArrowRight, Calendar, Package, Search, User, X } from "lucide-react";
import { useCallback, useMemo, useRef, useState } from "react"; import { useCallback, useMemo, useRef, useState } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { ArrowRight, Calendar, Package, Search, User, X } from "lucide-react";
import {
Stack,
Group,
Text,
Card,
TextInput,
ActionIcon,
Tabs,
} from "@mantine/core";
import { PageContainer } from "@/components/page"; import { BookingActionsMenu } from "@/components/bookings/BookingActionsMenu";
import Breadcrumbs from "@/components/ui/Breadcrumbs"; import { BookingApprovalProgressCell } from "@/components/bookings/BookingApprovalProgressCell";
import { BookingPriorityBadge } from "@/components/bookings/BookingPriorityBadge"; import { BookingPriorityBadge } from "@/components/bookings/BookingPriorityBadge";
import { BookingRequestsHeader } from "@/components/bookings/BookingRequestsHeader";
import { BookingStatusBadge } from "@/components/bookings/BookingStatusBadge";
import { import {
BookingStatusTabs, BookingStatusTabs,
type BookingStatusTabKey, type BookingStatusTabKey,
} from "@/components/bookings/BookingStatusTabs"; } from "@/components/bookings/BookingStatusTabs";
import { BookingRequestsHeader } from "@/components/bookings/BookingRequestsHeader"; import { BookingTableEmpty } from "@/components/bookings/BookingTableEmpty";
import { BookingStatusBadge } from "@/components/bookings/BookingStatusBadge";
import { BookingApprovalProgressCell } from "@/components/bookings/BookingApprovalProgressCell";
import { AllocateBookingWizard } from "@/components/trainScheduling/AllocateBookingWizard";
import { BookingActionsMenu } from "@/components/bookings/BookingActionsMenu";
import { OperationsBookingQueue } from "@/components/bookings/OperationsBookingQueue"; import { OperationsBookingQueue } from "@/components/bookings/OperationsBookingQueue";
import { OperationsScheduledBookings } from "@/components/bookings/OperationsScheduledBookings"; import { OperationsScheduledBookings } from "@/components/bookings/OperationsScheduledBookings";
import { BookingTableEmpty } from "@/components/bookings/BookingTableEmpty";
import { bookingTable } from "@/components/bookings/booking-ui.styles"; import { bookingTable } from "@/components/bookings/booking-ui.styles";
import { PageContainer } from "@/components/page";
import { AllocateBookingWizard } from "@/components/trainScheduling/AllocateBookingWizard";
import { BOOKING_LIST_TABS } from "@/features/bookings/booking-status.config"; import { BOOKING_LIST_TABS } from "@/features/bookings/booking-status.config";
import { toBookingListRow } from "@/features/bookings/mapBookingListRow"; import { toBookingListRow } from "@/features/bookings/mapBookingListRow";
import { import {
@@ -34,15 +33,15 @@ import {
useBookingList, useBookingList,
useBookingListSummary, useBookingListSummary,
} from "@/hooks/bookings/useBookings"; } from "@/hooks/bookings/useBookings";
import { cn } from "@/lib/utils";
import type { BookingListFilter } from "@/services/bookings.service"; import type { BookingListFilter } from "@/services/bookings.service";
import type { BookingListRow } from "@/types/booking"; import type { BookingListRow } from "@/types/booking";
import { cn } from "@/lib/utils";
import { import {
Badge,
DataTable, DataTable,
DataTableFooter, DataTableFooter,
type ColumnDef,
usePagination, usePagination,
Badge, type ColumnDef,
} from "@edr/ui-common"; } from "@edr/ui-common";
function getStatusesForTab(tab: BookingStatusTabKey): string | undefined { function getStatusesForTab(tab: BookingStatusTabKey): string | undefined {
@@ -298,8 +297,6 @@ export default function BookingRequestsPage() {
return ( return (
<PageContainer> <PageContainer>
<Breadcrumbs items={[{ label: "Operations" }, { label: "Booking requests" }]} />
<Stack gap="lg"> <Stack gap="lg">
<BookingRequestsHeader <BookingRequestsHeader
metrics={metrics} metrics={metrics}

View File

@@ -147,7 +147,7 @@ function FormSection({
icon: Icon, icon: Icon,
title, title,
subtitle, subtitle,
accent = "green", accent = "edr-green",
right, right,
children, children,
}: { }: {
@@ -394,7 +394,7 @@ export default function NewBookingPage() {
{/* LEFT — form */} {/* LEFT — form */}
<Grid.Col span={{ base: 12, lg: 8 }}> <Grid.Col span={{ base: 12, lg: 8 }}>
<Stack gap="lg"> <Stack gap="lg">
<FormSection icon={Layers} title="Booking type" subtitle="Who is booking and what kind of freight" accent="green"> <FormSection icon={Layers} title="Booking type" subtitle="Who is booking and what kind of freight" accent="edr-green">
<Stack gap="md"> <Stack gap="md">
<Switch <Switch
label="Government booking" label="Government booking"
@@ -745,7 +745,7 @@ export default function NewBookingPage() {
<Box style={{ position: "sticky", top: 16 }}> <Box style={{ position: "sticky", top: 16 }}>
<Paper radius="lg" withBorder p="lg" style={{ borderColor: "var(--mantine-color-gray-2)" }}> <Paper radius="lg" withBorder p="lg" style={{ borderColor: "var(--mantine-color-gray-2)" }}>
<Group gap="sm" mb="md"> <Group gap="sm" mb="md">
<ThemeIcon size={34} radius="md" variant="light" color="green"> <ThemeIcon size={34} radius="md" variant="light" color="edr-green">
<Weight size={17} /> <Weight size={17} />
</ThemeIcon> </ThemeIcon>
<Text fw={700}>Summary</Text> <Text fw={700}>Summary</Text>

View File

@@ -751,7 +751,7 @@ export function WagonTypesCrudPage() {
<MantineTable.Td>{type.lengthMeters}</MantineTable.Td> <MantineTable.Td>{type.lengthMeters}</MantineTable.Td>
<MantineTable.Td>{type.supportedLoadTypes?.join(', ') || '-'}</MantineTable.Td> <MantineTable.Td>{type.supportedLoadTypes?.join(', ') || '-'}</MantineTable.Td>
<MantineTable.Td> <MantineTable.Td>
<MantineBadge color={type.isActive === false ? 'gray' : 'green'} variant="light"> <MantineBadge color={type.isActive === false ? 'gray' : 'edr-green'} variant="light">
{type.isActive === false ? 'Inactive' : 'Active'} {type.isActive === false ? 'Inactive' : 'Active'}
</MantineBadge> </MantineBadge>
</MantineTable.Td> </MantineTable.Td>

View File

@@ -58,7 +58,7 @@ const METHOD_OPTIONS: { value: PaymentMethod; label: string }[] = [
]; ];
const STATUS_COLORS: Record<string, string> = { const STATUS_COLORS: Record<string, string> = {
success: "green", success: "edr-green",
processing: "yellow", processing: "yellow",
"action-required": "yellow", "action-required": "yellow",
failed: "red", failed: "red",
@@ -205,7 +205,7 @@ export default function PaymentsPage() {
label: "Successful", label: "Successful",
value: summary?.success ?? 0, value: summary?.success ?? 0,
icon: CheckCircle2, icon: CheckCircle2,
color: "green", color: "edr-green",
}, },
{ {
label: "Processing", label: "Processing",

View File

@@ -516,12 +516,12 @@ export default function BatchBoardPage() {
style={{ style={{
padding: "2px 8px", padding: "2px 8px",
borderRadius: 8, borderRadius: 8,
background: "var(--mantine-color-green-0)", background: "var(--mantine-color-edr-green-0)",
border: "1px solid var(--mantine-color-green-1)", border: "1px solid var(--mantine-color-edr-green-1)",
}} }}
> >
<Package size={12} color="var(--mantine-color-green-7)" /> <Package size={12} color="var(--mantine-color-edr-green-7)" />
<Text size="xs" fw={700} c="green.8" lh={1.2}> <Text size="xs" fw={700} c="edr-green.8" lh={1.2}>
{row.original.capacity.allocatedWagons} {row.original.capacity.allocatedWagons}
</Text> </Text>
<Text size="10px" c="dimmed" lh={1.2}> <Text size="10px" c="dimmed" lh={1.2}>

View File

@@ -180,8 +180,8 @@ export default function TrainScheduleV2ListPage() {
width: 34, width: 34,
height: 34, height: 34,
borderRadius: 9, borderRadius: 9,
background: "var(--mantine-color-green-0)", background: "var(--mantine-color-edr-green-0)",
color: "var(--mantine-color-green-7)", color: "var(--mantine-color-edr-green-7)",
flexShrink: 0, flexShrink: 0,
}} }}
> >
@@ -576,13 +576,13 @@ function MetricChip({
borderRadius: 8, borderRadius: 8,
background: subtle background: subtle
? "var(--mantine-color-gray-1)" ? "var(--mantine-color-gray-1)"
: "var(--mantine-color-green-0)", : "var(--mantine-color-edr-green-0)",
border: `1px solid ${ border: `1px solid ${
subtle ? "var(--mantine-color-gray-2)" : "var(--mantine-color-green-1)" subtle ? "var(--mantine-color-gray-2)" : "var(--mantine-color-edr-green-1)"
}`, }`,
}} }}
> >
<Text size="sm" fw={700} c={subtle ? "gray.7" : "green.8"} lh={1.2}> <Text size="sm" fw={700} c={subtle ? "gray.7" : "edr-green.8"} lh={1.2}>
{value} {value}
</Text> </Text>
{label ? ( {label ? (
@@ -653,7 +653,7 @@ function ScheduleCard({
<Group gap="xs" wrap="nowrap"> <Group gap="xs" wrap="nowrap">
<Button <Button
variant="light" variant="light"
color="green" color="edr-green"
size="sm" size="sm"
radius="md" radius="md"
style={{ flex: 1 }} style={{ flex: 1 }}

View File

@@ -22,7 +22,7 @@ import type { ArrivalQueueItem } from '@/types/warehouse';
function inspectionBadge(status: string | null) { function inspectionBadge(status: string | null) {
if (!status) return <Badge variant="light" color="gray" size="sm">Not inspected</Badge>; if (!status) return <Badge variant="light" color="gray" size="sm">Not inspected</Badge>;
const color = status === 'PASSED' ? 'green' : status === 'FAILED' ? 'red' : 'orange'; const color = status === 'PASSED' ? 'edr-green' : status === 'FAILED' ? 'red' : 'orange';
return <Badge variant="light" color={color} size="sm">{status.replace(/_/g, ' ')}</Badge>; return <Badge variant="light" color={color} size="sm">{status.replace(/_/g, ' ')}</Badge>;
} }
@@ -89,7 +89,7 @@ export default function ArrivalQueuePage() {
header: 'Status', header: 'Status',
cell: ({ row }) => cell: ({ row }) =>
row.original.unloaded ? ( row.original.unloaded ? (
<Badge variant="light" color="green" size="sm"> <Badge variant="light" color="edr-green" size="sm">
{row.original.currentStatus ?? 'RECEIVED'} {row.original.currentStatus ?? 'RECEIVED'}
</Badge> </Badge>
) : ( ) : (
@@ -125,7 +125,7 @@ export default function ArrivalQueuePage() {
<Button <Button
size="compact-xs" size="compact-xs"
variant="light" variant="light"
color="green" color="edr-green"
leftSection={<ClipboardList size={14} />} leftSection={<ClipboardList size={14} />}
onClick={() => setInspectInventoryId(item.inventoryId)} onClick={() => setInspectInventoryId(item.inventoryId)}
> >

View File

@@ -49,7 +49,7 @@ const columns: ColumnDef<Loading>[] = [
cell: ({ row }) => ( cell: ({ row }) => (
<Badge <Badge
variant="light" variant="light"
color={row.original.inventory?.status === 'DISPATCHED' ? 'green' : 'teal'} color={row.original.inventory?.status === 'DISPATCHED' ? 'edr-green' : 'teal'}
size="sm" size="sm"
> >
{row.original.inventory?.status ?? 'LOADED'} {row.original.inventory?.status ?? 'LOADED'}

View File

@@ -74,7 +74,7 @@ export default function LoadingQueuePage() {
<Tabs.Tab <Tabs.Tab
value="ready" value="ready"
leftSection={ leftSection={
<Badge size="xs" color="green"> <Badge size="xs" color="edr-green">
{paidItems.length} {paidItems.length}
</Badge> </Badge>
} }

View File

@@ -36,7 +36,7 @@ const STATUS_COLOR: Record<WarehouseInvoiceStatus, string> = {
DRAFT: 'gray', DRAFT: 'gray',
ISSUED: 'orange', ISSUED: 'orange',
PARTIALLY_PAID: 'yellow', PARTIALLY_PAID: 'yellow',
PAID: 'green', PAID: 'edr-green',
CANCELLED: 'gray', CANCELLED: 'gray',
}; };

View File

@@ -119,7 +119,7 @@ function AllocationRules() {
id: 'active', id: 'active',
header: 'Active', header: 'Active',
cell: ({ row }) => ( cell: ({ row }) => (
<Badge color={row.original.isActive ? 'green' : 'gray'} variant="light"> <Badge color={row.original.isActive ? 'edr-green' : 'gray'} variant="light">
{row.original.isActive ? 'Yes' : 'No'} {row.original.isActive ? 'Yes' : 'No'}
</Badge> </Badge>
), ),
@@ -240,7 +240,7 @@ function FeeRules() {
id: 'active', id: 'active',
header: 'Active', header: 'Active',
cell: ({ row }) => ( cell: ({ row }) => (
<Badge color={row.original.isActive ? 'green' : 'gray'} variant="light"> <Badge color={row.original.isActive ? 'edr-green' : 'gray'} variant="light">
{row.original.isActive ? 'Yes' : 'No'} {row.original.isActive ? 'Yes' : 'No'}
</Badge> </Badge>
), ),