ui design for schedule

This commit is contained in:
Marshal
2026-06-10 00:12:52 +00:00
parent 257428be18
commit 2b5a0f4e96
25 changed files with 1687 additions and 611 deletions

View File

@@ -1,20 +1,6 @@
import { useCallback, useMemo, useRef, useState } from "react";
import { useNavigate } from "react-router-dom";
import {
AlertCircle,
ArrowRight,
Calendar,
Clock,
FileText,
Inbox,
LayoutList,
Package,
Plus,
RefreshCw,
Search,
User,
X,
} from "lucide-react";
import { ArrowRight, Calendar, Package, Search, User, X } from "lucide-react";
import {
Container,
Stack,
@@ -33,7 +19,7 @@ import {
BookingStatusTabs,
type BookingStatusTabKey,
} from "@/components/bookings/BookingStatusTabs";
import { BookingStatGrid } from "@/components/bookings/BookingStatGrid";
import { BookingRequestsHeader } from "@/components/bookings/BookingRequestsHeader";
import { BookingStatusBadge } from "@/components/bookings/BookingStatusBadge";
import { BookingApprovalProgressCell } from "@/components/bookings/BookingApprovalProgressCell";
import { AllocateBookingWizard } from "@/components/trainScheduling/AllocateBookingWizard";
@@ -58,8 +44,6 @@ import {
type ColumnDef,
usePagination,
Badge,
Button,
Input,
} from "@edr/ui-common";
function getStatusesForTab(tab: BookingStatusTabKey): string | undefined {
@@ -159,8 +143,6 @@ export default function BookingRequestsPage() {
const metrics = summary?.metrics;
const tabCounts = summary?.tabs;
const statValue = (value: number | undefined) =>
summaryLoading ? "—" : (value ?? 0);
const handleRefresh = useCallback(() => {
void refetch();
@@ -315,88 +297,15 @@ export default function BookingRequestsPage() {
<div style={{ background: "var(--mantine-color-gray-0)", minHeight: "100vh" }}>
<Container size="xxl" py="xl">
<Breadcrumbs items={[{ label: "Operations" }, { label: "Booking requests" }]} />
{/*
<Card
p="lg"
radius="lg"
withBorder
mb="xl"
style={{
background: "white",
border: "1px solid var(--mantine-color-gray-2)",
boxShadow: "0 1px 3px rgba(0, 0, 0, 0.05)",
}}
>
<Group justify="space-between" align="flex-start">
<Group gap="md" align="flex-start">
<ThemeIcon
size="lg"
radius="lg"
color="green"
variant="light"
>
<Inbox size={28} />
</ThemeIcon>
<Stack gap={8}>
<Text size="xs" fw={600} c="dimmed" tt="uppercase">
Operations
</Text>
<Title order={1} size="h2">
Booking Requests
</Title>
<Text size="sm" c="dimmed" maw="500px">
Track bookings from submission through payment and operations. Monitor status, prioritize urgent bookings, and manage approvals.
</Text>
</Stack>
</Group>
<MantineButton
variant="light"
color="green"
leftSection={<RefreshCw size={18} />}
disabled={isFetching}
onClick={handleRefresh}
loading={isFetching}
>
Refresh
</MantineButton>
</Group>
</Card> */}
<div className="mt-6"></div>
<Stack gap="lg">
<BookingStatGrid
items={[
{
label: "In queue",
value: statValue(metrics?.inQueue),
hint: "Total matching filter",
icon: LayoutList,
},
{
label: "On this page",
value: statValue(metrics?.onThisPage),
hint: "Current page",
icon: FileText,
},
{
label: "Needs action",
value: statValue(metrics?.needsAction),
hint: "Submitted or pending approval",
icon: Clock,
accent:
!summaryLoading && (metrics?.needsAction ?? 0) > 0
? "amber"
: "default",
},
{
label: "Urgent",
value: statValue(metrics?.urgent),
hint: "High priority score",
icon: AlertCircle,
accent:
!summaryLoading && (metrics?.urgent ?? 0) > 0 ? "rose" : "default",
},
]}
<Stack gap="lg" mt="md">
<BookingRequestsHeader
metrics={metrics}
tabs={tabCounts}
loading={summaryLoading}
isFetching={isFetching}
onCreate={() => navigate("/dashboard/booking-requests/new")}
onRefresh={handleRefresh}
/>
<Paper
@@ -450,18 +359,9 @@ export default function BookingRequestsPage() {
style={{ flex: 1, minWidth: "200px" }}
radius="lg"
/>
<Group gap="sm">
<Button
variant="filled"
leftSection={<Plus size={16} />}
onClick={() => navigate("/dashboard/booking-requests/new")}
>
Create booking
</Button>
<Text size="sm" c="dimmed">
{total} record{total !== 1 ? "s" : ""}
</Text>
</Group>
<Text size="sm" c="dimmed">
{total} record{total !== 1 ? "s" : ""}
</Text>
</Group>
{isOperationsTab ? (

View File

@@ -22,6 +22,7 @@ import { useQueryClient } from "@tanstack/react-query";
import { OverviewPageHeader } from "@/components/overview/OverviewPageHeader";
import { OverviewQuickLinks } from "@/components/overview/OverviewQuickLinks";
import { OverviewTabContent } from "@/components/overview/OverviewTabContent";
import "@/components/overview/overview.css";
import { QUERY_KEYS } from "@/constants/QUERY_KEYS";
import { useOverview } from "@/hooks/useOverview";
import type { OverviewRange, OverviewTabKey } from "@/types/overview";
@@ -127,60 +128,53 @@ const OverviewPage = () => {
</Alert>
)}
<Paper
radius="lg"
withBorder
p="md"
style={{
background: "white",
border: "1px solid var(--mantine-color-gray-2)",
}}
<Tabs
value={activeTab}
onChange={(value) => setActiveTab((value as OverviewTabKey) ?? "bookings")}
variant="pills"
color="green"
keepMounted={false}
classNames={{ list: "ov-tablist", tab: "ov-tab" }}
>
<Tabs
value={activeTab}
onChange={(value) => setActiveTab((value as OverviewTabKey) ?? "bookings")}
variant="pills"
color="green"
keepMounted={false}
>
<Tabs.List
style={{
flexWrap: "wrap",
gap: 8,
background: "var(--freight-brand-muted, #f0fdf4)",
padding: 8,
borderRadius: 12,
}}
>
{TAB_ITEMS.map((tab) => {
const Icon = tab.icon;
return (
<Tabs.Tab
key={tab.value}
value={tab.value}
leftSection={<Icon size={16} />}
rightSection={
summary ? (
<Badge size="sm" variant="light" color="green">
{getTabBadge(tab)}
</Badge>
) : undefined
}
style={{ fontWeight: 600 }}
>
{tab.label}
</Tabs.Tab>
);
})}
</Tabs.List>
<Tabs.List>
{TAB_ITEMS.map((tab) => {
const Icon = tab.icon;
const isActive = activeTab === tab.value;
return (
<Tabs.Tab
key={tab.value}
value={tab.value}
leftSection={<Icon size={17} />}
rightSection={
summary ? (
<Badge
size="sm"
radius="sm"
variant={isActive ? "white" : "light"}
color={isActive ? "green" : "gray"}
styles={
isActive
? { root: { background: "rgba(255,255,255,0.9)", color: "#15803d" } }
: undefined
}
>
{getTabBadge(tab)}
</Badge>
) : undefined
}
>
{tab.label}
</Tabs.Tab>
);
})}
</Tabs.List>
{TAB_ITEMS.map((tab) => (
<Tabs.Panel key={tab.value} value={tab.value} pt="lg">
<OverviewTabContent tab={tab.value} range={range} />
</Tabs.Panel>
))}
</Tabs>
</Paper>
{TAB_ITEMS.map((tab) => (
<Tabs.Panel key={tab.value} value={tab.value} pt="lg">
<OverviewTabContent tab={tab.value} range={range} />
</Tabs.Panel>
))}
</Tabs>
<Paper p="lg" radius="lg" withBorder>
<OverviewQuickLinks />