mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
changes
This commit is contained in:
@@ -16,6 +16,8 @@ export interface OperationDatePickerProps {
|
||||
value: string;
|
||||
/** Called with the picked `yyyy-MM-dd` day. */
|
||||
onChange: (date: string) => void;
|
||||
/** Stretch to the full width of the parent container. */
|
||||
fullWidth?: boolean;
|
||||
}
|
||||
|
||||
/** `yyyy-MM-dd` for a local date. */
|
||||
@@ -41,6 +43,8 @@ const MONTH_NAMES = [
|
||||
"December",
|
||||
];
|
||||
|
||||
const WEEKDAY_LABELS = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"];
|
||||
|
||||
/**
|
||||
* Presentational month calendar for picking a binding shipment day. Only the
|
||||
* `availableDays` (passed in by the caller, which owns the query) are
|
||||
@@ -53,8 +57,8 @@ export function OperationDatePicker({
|
||||
isLoading = false,
|
||||
value,
|
||||
onChange,
|
||||
fullWidth = false,
|
||||
}: OperationDatePickerProps) {
|
||||
// First-of-month for the visible month; defaults to the current month.
|
||||
const [month, setMonth] = useState(() => {
|
||||
const now = new Date();
|
||||
return new Date(now.getFullYear(), now.getMonth(), 1);
|
||||
@@ -67,7 +71,6 @@ export function OperationDatePicker({
|
||||
|
||||
const cells = useMemo(() => {
|
||||
const first = new Date(month.getFullYear(), month.getMonth(), 1);
|
||||
// Monday-first grid: JS getDay() Sun=0..Sat=6 → shift so Mon=0.
|
||||
const lead = (first.getDay() + 6) % 7;
|
||||
const start = new Date(first);
|
||||
start.setDate(first.getDate() - lead);
|
||||
@@ -90,6 +93,11 @@ export function OperationDatePicker({
|
||||
});
|
||||
}, [month, departureDays, value]);
|
||||
|
||||
const availableInMonth = useMemo(
|
||||
() => cells.filter((c) => c.inMonth && c.hasDeparture).length,
|
||||
[cells],
|
||||
);
|
||||
|
||||
const shiftMonth = (delta: number) =>
|
||||
setMonth((m) => new Date(m.getFullYear(), m.getMonth() + delta, 1));
|
||||
|
||||
@@ -98,11 +106,25 @@ export function OperationDatePicker({
|
||||
style={{
|
||||
border: "1px solid #E6ECF2",
|
||||
borderRadius: 12,
|
||||
padding: 14,
|
||||
maxWidth: 340,
|
||||
padding: fullWidth ? "12px 16px" : 14,
|
||||
width: fullWidth ? "100%" : undefined,
|
||||
maxWidth: fullWidth ? undefined : 340,
|
||||
}}
|
||||
>
|
||||
<Group justify="space-between" align="center" mb="sm">
|
||||
<Group
|
||||
justify="space-between"
|
||||
align="center"
|
||||
mb="sm"
|
||||
px={fullWidth ? 4 : 0}
|
||||
style={
|
||||
fullWidth
|
||||
? {
|
||||
borderBottom: "1px solid #EEF2F6",
|
||||
paddingBottom: 10,
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<Button
|
||||
variant="default"
|
||||
size="xs"
|
||||
@@ -112,9 +134,7 @@ export function OperationDatePicker({
|
||||
>
|
||||
<ChevronLeft size={15} />
|
||||
</Button>
|
||||
<Text fz="13px" fw={700} c="#10202F">
|
||||
{MONTH_NAMES[month.getMonth()]} {month.getFullYear()}
|
||||
</Text>
|
||||
<StackedMonthHeader month={month} availableCount={availableInMonth} />
|
||||
<Button
|
||||
variant="default"
|
||||
size="xs"
|
||||
@@ -143,8 +163,8 @@ export function OperationDatePicker({
|
||||
marginBottom: 6,
|
||||
}}
|
||||
>
|
||||
{["M", "T", "W", "T", "F", "S", "S"].map((d, i) => (
|
||||
<Text key={i} ta="center" fz="10px" fw={700} c="#9AA8B5">
|
||||
{WEEKDAY_LABELS.map((d) => (
|
||||
<Text key={d} ta="center" fz="10px" fw={700} c="#9AA8B5">
|
||||
{d}
|
||||
</Text>
|
||||
))}
|
||||
@@ -173,9 +193,11 @@ export function OperationDatePicker({
|
||||
cursor: clickable ? "pointer" : "default",
|
||||
border: c.selected
|
||||
? "1.5px solid #12B981"
|
||||
: clickable
|
||||
? "1px solid #CDEBDD"
|
||||
: "1px solid transparent",
|
||||
: c.today
|
||||
? "1.5px solid #94A3B8"
|
||||
: clickable
|
||||
? "1px solid #CDEBDD"
|
||||
: "1px solid transparent",
|
||||
background: c.selected
|
||||
? "#12B981"
|
||||
: clickable
|
||||
@@ -224,18 +246,30 @@ export function OperationDatePicker({
|
||||
})}
|
||||
</Box>
|
||||
{value && (
|
||||
<Text fz="12px" c="#0A6F4D" fw={600} mt="sm">
|
||||
Selected:{" "}
|
||||
{new Date(value + "T00:00:00").toLocaleDateString(undefined, {
|
||||
weekday: "short",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
})}
|
||||
</Text>
|
||||
<Group
|
||||
justify="center"
|
||||
mt="sm"
|
||||
py={6}
|
||||
px={10}
|
||||
style={{
|
||||
borderRadius: 8,
|
||||
background: "#F4FBF7",
|
||||
border: "1px solid #CDEBDD",
|
||||
}}
|
||||
>
|
||||
<Text fz="12px" c="#0A6F4D" fw={600}>
|
||||
Selected:{" "}
|
||||
{new Date(value + "T00:00:00").toLocaleDateString(undefined, {
|
||||
weekday: "short",
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
})}
|
||||
</Text>
|
||||
</Group>
|
||||
)}
|
||||
{departureDays.size === 0 && (
|
||||
<Text fz="12px" c="orange.7" mt="sm">
|
||||
<Text fz="12px" c="orange.7" mt="sm" ta="center">
|
||||
No scheduled departures found for this route yet.
|
||||
</Text>
|
||||
)}
|
||||
@@ -245,4 +279,23 @@ export function OperationDatePicker({
|
||||
);
|
||||
}
|
||||
|
||||
function StackedMonthHeader({
|
||||
month,
|
||||
availableCount,
|
||||
}: {
|
||||
month: Date;
|
||||
availableCount: number;
|
||||
}) {
|
||||
return (
|
||||
<Box style={{ textAlign: "center" }}>
|
||||
<Text fz="14px" fw={800} c="#10202F" lh={1.2}>
|
||||
{MONTH_NAMES[month.getMonth()]} {month.getFullYear()}
|
||||
</Text>
|
||||
<Text fz="11px" c="#64748B" mt={2}>
|
||||
{availableCount} available day{availableCount === 1 ? "" : "s"}
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default OperationDatePicker;
|
||||
|
||||
Reference in New Issue
Block a user