@voyantjs/availability-ui 0.50.8 → 0.51.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/availability-slot-detail-page.d.ts +25 -1
- package/dist/components/availability-slot-detail-page.d.ts.map +1 -1
- package/dist/components/availability-slot-detail-page.js +82 -19
- package/dist/i18n/provider.d.ts +72 -0
- package/dist/i18n/provider.d.ts.map +1 -1
- package/package.json +7 -7
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { QueryClient } from "@tanstack/react-query";
|
|
2
2
|
import { type VoyantAvailabilityContextValue } from "@voyantjs/availability-react";
|
|
3
|
+
import type { ReactNode } from "react";
|
|
3
4
|
export interface AvailabilitySlotDetailPageProps {
|
|
4
5
|
id: string;
|
|
5
6
|
className?: string;
|
|
@@ -8,6 +9,29 @@ export interface AvailabilitySlotDetailPageProps {
|
|
|
8
9
|
onOpenProduct?: (productId: string) => void;
|
|
9
10
|
onOpenStartTime?: (startTimeId: string) => void;
|
|
10
11
|
confirmAction?: (message: string) => boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Breadcrumb element rendered above the page header. Hosts that
|
|
14
|
+
* already render breadcrumbs in their sidebar inset top bar can
|
|
15
|
+
* leave this undefined.
|
|
16
|
+
*/
|
|
17
|
+
breadcrumb?: ReactNode;
|
|
18
|
+
/**
|
|
19
|
+
* Primary header actions (Open product, Delete, …). When supplied,
|
|
20
|
+
* the in-page action buttons are hidden so the host can render the
|
|
21
|
+
* same actions in the inset top bar instead.
|
|
22
|
+
*/
|
|
23
|
+
headerActions?: ReactNode;
|
|
24
|
+
/**
|
|
25
|
+
* Content for the Allocation tab. Hosts mount their allocation
|
|
26
|
+
* manager here (e.g. `@voyantjs/allocation-ui`'s
|
|
27
|
+
* `SlotAllocationPage` in `embed` mode) so this package keeps no
|
|
28
|
+
* runtime dependency on the allocation UI. When omitted, the tab
|
|
29
|
+
* shows a stub message instead.
|
|
30
|
+
*/
|
|
31
|
+
renderAllocation?: (context: {
|
|
32
|
+
slotId: string;
|
|
33
|
+
productId: string | null;
|
|
34
|
+
}) => ReactNode;
|
|
11
35
|
}
|
|
12
36
|
export declare function getAvailabilitySlotDetailQueryOptions(client: VoyantAvailabilityContextValue, id: string | null | undefined): import("@tanstack/react-query").OmitKeyof<import("@tanstack/react-query").UseQueryOptions<{
|
|
13
37
|
data: {
|
|
@@ -579,5 +603,5 @@ export declare function loadAvailabilitySlotDetailPage(queryClient: QueryClient,
|
|
|
579
603
|
limit: number;
|
|
580
604
|
offset: number;
|
|
581
605
|
}]>;
|
|
582
|
-
export declare function AvailabilitySlotDetailPage({ id, className, onBack, onDeleted, onOpenProduct, onOpenStartTime, confirmAction, }: AvailabilitySlotDetailPageProps): import("react/jsx-runtime").JSX.Element;
|
|
606
|
+
export declare function AvailabilitySlotDetailPage({ id, className, onBack: _onBack, onDeleted, onOpenProduct, onOpenStartTime, confirmAction, breadcrumb, headerActions, renderAllocation, }: AvailabilitySlotDetailPageProps): import("react/jsx-runtime").JSX.Element;
|
|
583
607
|
//# sourceMappingURL=availability-slot-detail-page.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"availability-slot-detail-page.d.ts","sourceRoot":"","sources":["../../src/components/availability-slot-detail-page.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAExD,OAAO,
|
|
1
|
+
{"version":3,"file":"availability-slot-detail-page.d.ts","sourceRoot":"","sources":["../../src/components/availability-slot-detail-page.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useQuery } from "@tanstack/react-query";
|
|
4
|
-
import { formatDateTime, getPickupPointsQueryOptions, getProductQueryOptions, getSlotAssignmentsQueryOptions, getSlotBookingsQueryOptions, getSlotCloseoutsQueryOptions, getSlotPickupsQueryOptions, getSlotQueryOptions, getSlotResourcesQueryOptions, slotStatusVariant, useAvailabilitySlotMutation, useVoyantAvailabilityContext, } from "@voyantjs/availability-react";
|
|
5
|
-
import { Badge, Button, Card, CardContent, CardHeader, CardTitle, cn, } from "@voyantjs/ui/components";
|
|
6
|
-
import {
|
|
4
|
+
import { formatDateTime, getPickupPointsQueryOptions, getProductQueryOptions, getSlotAssignmentsQueryOptions, getSlotBookingsQueryOptions, getSlotCloseoutsQueryOptions, getSlotPickupsQueryOptions, getSlotQueryOptions, getSlotResourcesQueryOptions, slotStatusVariant, useAvailabilitySlotMutation, useSlotAllocationAuditLog, useVoyantAvailabilityContext, } from "@voyantjs/availability-react";
|
|
5
|
+
import { Badge, Button, Card, CardContent, CardHeader, CardTitle, cn, Tabs, TabsContent, TabsList, TabsTrigger, } from "@voyantjs/ui/components";
|
|
6
|
+
import { CalendarDays, History, Package, Truck, Wrench } from "lucide-react";
|
|
7
7
|
import { useAvailabilityUiI18nOrDefault } from "../i18n/index.js";
|
|
8
8
|
import { getSlotStatusLabel } from "./availability-columns.js";
|
|
9
9
|
import { AvailabilitySlotDetailSkeleton } from "./availability-skeletons.js";
|
|
@@ -48,7 +48,7 @@ export async function loadAvailabilitySlotDetailPage(queryClient, client, id) {
|
|
|
48
48
|
queryClient.ensureQueryData(getAvailabilitySlotPickupPointsQueryOptions(client, slotData.data.productId)),
|
|
49
49
|
]);
|
|
50
50
|
}
|
|
51
|
-
export function AvailabilitySlotDetailPage({ id, className, onBack, onDeleted, onOpenProduct, onOpenStartTime, confirmAction = (message) => globalThis.confirm?.(message) ?? true, }) {
|
|
51
|
+
export function AvailabilitySlotDetailPage({ id, className, onBack: _onBack, onDeleted, onOpenProduct, onOpenStartTime, confirmAction = (message) => globalThis.confirm?.(message) ?? true, breadcrumb, headerActions, renderAllocation, }) {
|
|
52
52
|
const client = useVoyantAvailabilityContext();
|
|
53
53
|
const i18n = useAvailabilityUiI18nOrDefault();
|
|
54
54
|
const messages = i18n.messages;
|
|
@@ -70,36 +70,99 @@ export function AvailabilitySlotDetailPage({ id, className, onBack, onDeleted, o
|
|
|
70
70
|
const assignmentsQuery = useQuery(getAvailabilitySlotAssignmentsQueryOptions(client, id));
|
|
71
71
|
const resourcesQuery = useQuery(getAvailabilitySlotResourcesQueryOptions(client));
|
|
72
72
|
const bookingsQuery = useQuery(getAvailabilitySlotBookingsQueryOptions(client));
|
|
73
|
+
const auditLogQuery = useSlotAllocationAuditLog({ slotId: id });
|
|
73
74
|
if (isPending) {
|
|
74
75
|
return _jsx(AvailabilitySlotDetailSkeleton, {});
|
|
75
76
|
}
|
|
76
77
|
if (!slot) {
|
|
77
|
-
return (_jsx(
|
|
78
|
+
return (_jsx("div", { className: "flex flex-col items-center justify-center gap-4 py-12", children: _jsx("p", { className: "text-muted-foreground", children: detailMessages.slot.notFound }) }));
|
|
78
79
|
}
|
|
79
80
|
const pickupPointById = new Map((pickupPointsQuery.data?.data ?? []).map((item) => [item.id, item]));
|
|
80
81
|
const resourceById = new Map((resourcesQuery.data?.data ?? []).map((item) => [item.id, item]));
|
|
81
82
|
const bookingById = new Map((bookingsQuery.data?.data ?? []).map((item) => [item.id, item]));
|
|
83
|
+
const productName = productQuery.data?.data.name ?? null;
|
|
84
|
+
const dateRangeLabel = formatSlotDateRange(slot, i18n.formatDateTime);
|
|
85
|
+
const nightsLabel = computeSlotNightsLabel(slot, detailMessages.duration);
|
|
86
|
+
const titleText = productName ?? dateRangeLabel;
|
|
87
|
+
const pickupRows = slotPickupsQuery.data?.data ?? [];
|
|
88
|
+
const assignmentRows = assignmentsQuery.data?.data ?? [];
|
|
89
|
+
const closeoutRows = closeoutsQuery.data?.data ?? [];
|
|
90
|
+
const auditEntries = auditLogQuery.data?.data ?? [];
|
|
82
91
|
async function deleteSlot(currentSlot) {
|
|
83
92
|
if (!confirmAction(detailMessages.slot.deleteConfirm))
|
|
84
93
|
return;
|
|
85
94
|
await slotMutation.remove.mutateAsync(currentSlot.id);
|
|
86
|
-
|
|
87
|
-
onDeleted();
|
|
88
|
-
else
|
|
89
|
-
onBack?.();
|
|
95
|
+
onDeleted?.();
|
|
90
96
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
const fallbackActions = headerActions ?? (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [slot.productId && onOpenProduct ? (_jsxs(Button, { variant: "outline", onClick: () => onOpenProduct(slot.productId), children: [_jsx(Package, { "data-icon": "inline-start", "aria-hidden": "true" }), detailMessages.openProduct] })) : null, _jsx(Button, { variant: "destructive", onClick: () => void deleteSlot(slot), disabled: slotMutation.remove.isPending, children: detailMessages.delete })] }));
|
|
98
|
+
return (_jsxs("div", { className: cn("flex flex-col gap-6 p-6", className), children: [breadcrumb ? _jsx("div", { className: "text-sm", children: breadcrumb }) : null, _jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-start md:justify-between", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("h1", { className: "text-2xl font-bold tracking-tight", children: titleText }), _jsxs("p", { className: "mt-1 text-sm text-muted-foreground", children: [dateRangeLabel, nightsLabel ? ` · ${nightsLabel}` : null] }), _jsxs("div", { className: "mt-2 flex flex-wrap items-center gap-2", children: [_jsx(Badge, { variant: slotStatusVariant[slot.status], children: getSlotStatusLabel(slot.status, messages) }), _jsx(Badge, { variant: "outline", children: slot.timezone }), slot.unlimited ? (_jsx(Badge, { variant: "outline", children: detailMessages.slot.unlimitedLabel })) : null, slot.pastCutoff ? (_jsx(Badge, { variant: "secondary", children: detailMessages.slot.pastCutoffLabel })) : null, slot.tooEarly ? (_jsx(Badge, { variant: "secondary", children: detailMessages.slot.tooEarlyLabel })) : null] })] }), fallbackActions] }), _jsx(KpiStrip, { slot: slot, productName: productName, productId: slot.productId, onOpenProduct: onOpenProduct, i18nLabels: {
|
|
99
|
+
pax: detailMessages.slot.initialPaxLabel,
|
|
100
|
+
remainingPax: messages.remainingPaxLabel,
|
|
101
|
+
product: messages.productLabel,
|
|
102
|
+
date: messages.dateLabel,
|
|
103
|
+
notes: detailMessages.notesTitle,
|
|
104
|
+
} }), _jsxs(Tabs, { defaultValue: "allocation", children: [_jsxs(TabsList, { className: "flex h-auto w-fit flex-wrap justify-start", children: [_jsx(TabsTrigger, { value: "allocation", children: detailMessages.tabs.allocation }), _jsxs(TabsTrigger, { value: "pickup", children: [detailMessages.tabs.pickup, pickupRows.length > 0 ? (_jsx(Badge, { variant: "outline", className: "ml-1.5", children: pickupRows.length })) : null] }), _jsxs(TabsTrigger, { value: "closeouts", children: [detailMessages.tabs.closeouts, closeoutRows.length > 0 ? (_jsx(Badge, { variant: "outline", className: "ml-1.5", children: closeoutRows.length })) : null] }), _jsxs(TabsTrigger, { value: "activity", children: [detailMessages.tabs.activity, auditEntries.length > 0 ? (_jsx(Badge, { variant: "outline", className: "ml-1.5", children: auditEntries.length })) : null] }), _jsx(TabsTrigger, { value: "meta", children: detailMessages.tabs.meta })] }), _jsx(TabsContent, { value: "allocation", className: "mt-4", children: renderAllocation ? (renderAllocation({ slotId: id, productId: slot.productId })) : (_jsx("p", { className: "rounded-md border border-dashed p-6 text-sm text-muted-foreground", children: detailMessages.tabs.allocationUnwired })) }), _jsx(TabsContent, { value: "pickup", className: "mt-4", children: pickupRows.length === 0 ? (_jsx("p", { className: "rounded-md border border-dashed p-6 text-sm text-muted-foreground", children: detailMessages.slot.pickupCapacityEmpty })) : (_jsx("div", { className: "flex flex-col gap-3 text-sm", children: pickupRows.map((pickup) => {
|
|
105
|
+
const point = pickupPointById.get(pickup.pickupPointId);
|
|
106
|
+
return (_jsxs("div", { className: "rounded-md border p-3", children: [_jsxs("div", { className: "flex items-center gap-2 font-medium", children: [_jsx(Truck, { className: "size-4", "aria-hidden": "true" }), point?.name ?? pickup.pickupPointId] }), _jsx("div", { className: "mt-1 text-muted-foreground", children: point?.locationText ?? detailMessages.slot.noLocationText }), _jsxs("div", { className: "mt-2", children: [detailMessages.slot.initialLabel, ": ", pickup.initialCapacity ?? noValue, " \u00B7", " ", detailMessages.slot.remainingLabel, ": ", pickup.remainingCapacity ?? noValue] })] }, pickup.id));
|
|
107
|
+
}) })) }), _jsx(TabsContent, { value: "closeouts", className: "mt-4", children: closeoutRows.length === 0 ? (_jsx("p", { className: "rounded-md border border-dashed p-6 text-sm text-muted-foreground", children: detailMessages.slot.relatedCloseoutsEmpty })) : (_jsx("div", { className: "flex flex-col gap-3 text-sm", children: closeoutRows.map((closeout) => (_jsxs("div", { className: "rounded-md border p-3", children: [_jsxs("div", { className: "flex items-center gap-2 font-medium", children: [_jsx(CalendarDays, { className: "size-4", "aria-hidden": "true" }), closeout.dateLocal] }), _jsxs("div", { className: "mt-1 text-muted-foreground", children: [detailMessages.slot.createdByLabel, ": ", closeout.createdBy ?? noValue] }), closeout.reason ? (_jsx("div", { className: "mt-2 whitespace-pre-wrap", children: closeout.reason })) : null] }, closeout.id))) })) }), _jsx(TabsContent, { value: "activity", className: "mt-4", children: auditEntries.length === 0 && assignmentRows.length === 0 ? (_jsx("p", { className: "rounded-md border border-dashed p-6 text-sm text-muted-foreground", children: detailMessages.tabs.activityEmpty })) : (_jsxs("div", { className: "flex flex-col gap-4 text-sm", children: [assignmentRows.length > 0 ? (_jsxs("div", { className: "flex flex-col gap-3", children: [_jsxs("h3", { className: "text-sm font-semibold uppercase tracking-wide text-muted-foreground", children: [_jsx(Wrench, { className: "mr-1 inline-block size-4", "aria-hidden": "true" }), detailMessages.slot.resourceAssignmentsTitle] }), assignmentRows.map((assignment) => (_jsxs("div", { className: "rounded-md border p-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Badge, { variant: "outline", className: "capitalize", children: assignment.status }), _jsx("span", { children: resourceById.get(assignment.resourceId ?? "")?.name ??
|
|
108
|
+
assignment.resourceId ??
|
|
109
|
+
detailMessages.slot.unassignedResource })] }), _jsxs("div", { className: "mt-2 text-muted-foreground", children: [detailMessages.slot.bookingLabel, ":", " ", bookingById.get(assignment.bookingId ?? "")?.bookingNumber ??
|
|
110
|
+
assignment.bookingId ??
|
|
111
|
+
noValue] }), _jsxs("div", { className: "text-muted-foreground", children: [detailMessages.slot.poolLabel, ": ", assignment.poolId ?? noValue, " \u00B7", " ", detailMessages.slot.releasedLabel, ": ", formatDateTime(assignment.releasedAt)] }), assignment.notes ? (_jsx("div", { className: "mt-2 whitespace-pre-wrap", children: assignment.notes })) : null] }, assignment.id)))] })) : null, auditEntries.length > 0 ? (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsxs("h3", { className: "text-sm font-semibold uppercase tracking-wide text-muted-foreground", children: [_jsx(History, { className: "mr-1 inline-block size-4", "aria-hidden": "true" }), detailMessages.tabs.activityAuditTitle] }), _jsx("ul", { className: "flex flex-col gap-1.5", children: auditEntries.map((entry) => (_jsxs("li", { className: "flex items-baseline gap-2 rounded-md border bg-muted/20 px-2 py-1.5 text-xs", children: [_jsx("span", { className: "text-muted-foreground", children: i18n.formatDateTime(entry.createdAt) }), _jsx("span", { className: "font-medium", children: entry.action }), _jsx("span", { className: "text-muted-foreground", children: entry.actorId ?? detailMessages.slot.createdByLabel })] }, entry.id))) })] })) : null] })) }), _jsx(TabsContent, { value: "meta", className: "mt-4", children: _jsx(MetaTab, { slot: slot, productName: productName, onOpenProduct: onOpenProduct, onOpenStartTime: onOpenStartTime, i18n: {
|
|
112
|
+
identifiersTitle: detailMessages.tabs.metaIdentifiersTitle,
|
|
113
|
+
lifecycleTitle: detailMessages.tabs.metaLifecycleTitle,
|
|
114
|
+
notesTitle: detailMessages.notesTitle,
|
|
115
|
+
ruleLabel: detailMessages.slot.ruleLabel,
|
|
116
|
+
startTimeLabel: detailMessages.slot.startTimeIdLabel,
|
|
117
|
+
endsAtLabel: detailMessages.slot.endsAtLabel,
|
|
118
|
+
createdLabel: detailMessages.createdLabel,
|
|
119
|
+
updatedLabel: detailMessages.updatedLabel,
|
|
120
|
+
productLabel: messages.productLabel,
|
|
121
|
+
noValue,
|
|
122
|
+
format: i18n.formatDateTime,
|
|
123
|
+
} }) })] })] }));
|
|
124
|
+
}
|
|
125
|
+
function KpiStrip({ slot, productName, productId, onOpenProduct, i18nLabels, }) {
|
|
126
|
+
return (_jsxs("div", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-4", children: [_jsx(KpiCell, { label: `${i18nLabels.remainingPax} / ${i18nLabels.pax}`, value: slot.unlimited ? "∞" : `${slot.remainingPax ?? 0} / ${slot.initialPax ?? 0}` }), _jsx(KpiCell, { label: i18nLabels.product, value: productId && onOpenProduct ? (_jsx(Button, { variant: "link", className: "h-auto p-0", onClick: () => onOpenProduct(productId), children: productName ?? productId })) : ((productName ?? productId ?? "—")) }), _jsx(KpiCell, { label: i18nLabels.date, value: slot.dateLocal }), _jsx(KpiCell, { label: i18nLabels.notes, value: slot.notes ?? "—", muted: !slot.notes })] }));
|
|
127
|
+
}
|
|
128
|
+
function KpiCell({ label, value, muted }) {
|
|
129
|
+
return (_jsxs(Card, { children: [_jsx(CardHeader, { className: "pb-2", children: _jsx(CardTitle, { className: "text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: label }) }), _jsx(CardContent, { className: cn("truncate text-base font-medium", muted ? "text-muted-foreground" : null), children: value })] }));
|
|
130
|
+
}
|
|
131
|
+
function MetaTab({ slot, productName, onOpenProduct, onOpenStartTime, i18n: msg, }) {
|
|
132
|
+
return (_jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: msg.identifiersTitle }) }), _jsxs(CardContent, { className: "flex flex-col gap-3 text-sm", children: [_jsx(DetailLine, { label: msg.productLabel, children: slot.productId && onOpenProduct ? (_jsx(Button, { variant: "link", className: "h-auto p-0", onClick: () => onOpenProduct(slot.productId), children: productName ?? slot.productId })) : ((productName ?? slot.productId ?? msg.noValue)) }), slot.availabilityRuleId ? (_jsx(DetailLine, { label: msg.ruleLabel, children: slot.availabilityRuleId })) : null, slot.startTimeId ? (_jsx(DetailLine, { label: msg.startTimeLabel, children: onOpenStartTime ? (_jsx(Button, { variant: "link", className: "h-auto p-0", onClick: () => onOpenStartTime(slot.startTimeId ?? ""), children: slot.startTimeId })) : (slot.startTimeId) })) : null, _jsx(DetailLine, { label: msg.endsAtLabel, children: slot.endsAt ? formatDateTime(slot.endsAt) : msg.noValue })] })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: msg.lifecycleTitle }) }), _jsxs(CardContent, { className: "flex flex-col gap-3 text-sm", children: [_jsx(DetailLine, { label: msg.createdLabel, children: msg.format(slot.createdAt) }), _jsx(DetailLine, { label: msg.updatedLabel, children: msg.format(slot.updatedAt) })] })] }), slot.notes ? (_jsxs(Card, { className: "md:col-span-2", children: [_jsx(CardHeader, { children: _jsx(CardTitle, { children: msg.notesTitle }) }), _jsx(CardContent, { className: "text-sm whitespace-pre-wrap", children: slot.notes })] })) : null] }));
|
|
99
133
|
}
|
|
100
134
|
function DetailLine({ label, children }) {
|
|
101
135
|
return (_jsxs("div", { children: [_jsxs("span", { className: "text-muted-foreground", children: [label, ":"] }), " ", _jsx("span", { children: children })] }));
|
|
102
136
|
}
|
|
103
|
-
function
|
|
104
|
-
|
|
137
|
+
function formatSlotDateRange(slot, format) {
|
|
138
|
+
if (!slot.endsAt)
|
|
139
|
+
return `${slot.dateLocal} · ${format(slot.startsAt)}`;
|
|
140
|
+
const startLocal = slot.dateLocal;
|
|
141
|
+
const endLocal = isoDateOf(slot.endsAt);
|
|
142
|
+
if (!endLocal || startLocal === endLocal) {
|
|
143
|
+
return `${slot.dateLocal} · ${format(slot.startsAt)}`;
|
|
144
|
+
}
|
|
145
|
+
return `${startLocal} → ${endLocal}`;
|
|
146
|
+
}
|
|
147
|
+
function computeSlotNightsLabel(slot, labels) {
|
|
148
|
+
if (slot.nights && slot.nights > 0) {
|
|
149
|
+
return slot.nights === 1
|
|
150
|
+
? labels.nightSingular
|
|
151
|
+
: labels.nightsPlural.replace("{count}", String(slot.nights));
|
|
152
|
+
}
|
|
153
|
+
if (slot.days && slot.days > 0) {
|
|
154
|
+
return slot.days === 1
|
|
155
|
+
? labels.daySingular
|
|
156
|
+
: labels.daysPlural.replace("{count}", String(slot.days));
|
|
157
|
+
}
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
function isoDateOf(value) {
|
|
161
|
+
if (!value)
|
|
162
|
+
return null;
|
|
163
|
+
const date = new Date(value);
|
|
164
|
+
if (Number.isNaN(date.getTime())) {
|
|
165
|
+
return value.length >= 10 ? value.slice(0, 10) : null;
|
|
166
|
+
}
|
|
167
|
+
return date.toISOString().slice(0, 10);
|
|
105
168
|
}
|
package/dist/i18n/provider.d.ts
CHANGED
|
@@ -278,6 +278,24 @@ export declare const availabilityUiEn: {
|
|
|
278
278
|
generatedSlotsTitle: string;
|
|
279
279
|
generatedSlotsEmpty: string;
|
|
280
280
|
};
|
|
281
|
+
tabs: {
|
|
282
|
+
allocation: string;
|
|
283
|
+
pickup: string;
|
|
284
|
+
closeouts: string;
|
|
285
|
+
activity: string;
|
|
286
|
+
meta: string;
|
|
287
|
+
allocationUnwired: string;
|
|
288
|
+
activityEmpty: string;
|
|
289
|
+
activityAuditTitle: string;
|
|
290
|
+
metaIdentifiersTitle: string;
|
|
291
|
+
metaLifecycleTitle: string;
|
|
292
|
+
};
|
|
293
|
+
duration: {
|
|
294
|
+
nightSingular: string;
|
|
295
|
+
nightsPlural: string;
|
|
296
|
+
daySingular: string;
|
|
297
|
+
daysPlural: string;
|
|
298
|
+
};
|
|
281
299
|
};
|
|
282
300
|
dialogs: {
|
|
283
301
|
slot: {
|
|
@@ -650,6 +668,24 @@ export declare const availabilityUiRo: {
|
|
|
650
668
|
generatedSlotsTitle: string;
|
|
651
669
|
generatedSlotsEmpty: string;
|
|
652
670
|
};
|
|
671
|
+
tabs: {
|
|
672
|
+
allocation: string;
|
|
673
|
+
pickup: string;
|
|
674
|
+
closeouts: string;
|
|
675
|
+
activity: string;
|
|
676
|
+
meta: string;
|
|
677
|
+
allocationUnwired: string;
|
|
678
|
+
activityEmpty: string;
|
|
679
|
+
activityAuditTitle: string;
|
|
680
|
+
metaIdentifiersTitle: string;
|
|
681
|
+
metaLifecycleTitle: string;
|
|
682
|
+
};
|
|
683
|
+
duration: {
|
|
684
|
+
nightSingular: string;
|
|
685
|
+
nightsPlural: string;
|
|
686
|
+
daySingular: string;
|
|
687
|
+
daysPlural: string;
|
|
688
|
+
};
|
|
653
689
|
};
|
|
654
690
|
dialogs: {
|
|
655
691
|
slot: {
|
|
@@ -1023,6 +1059,24 @@ export declare const availabilityUiMessageDefinitions: {
|
|
|
1023
1059
|
generatedSlotsTitle: string;
|
|
1024
1060
|
generatedSlotsEmpty: string;
|
|
1025
1061
|
};
|
|
1062
|
+
tabs: {
|
|
1063
|
+
allocation: string;
|
|
1064
|
+
pickup: string;
|
|
1065
|
+
closeouts: string;
|
|
1066
|
+
activity: string;
|
|
1067
|
+
meta: string;
|
|
1068
|
+
allocationUnwired: string;
|
|
1069
|
+
activityEmpty: string;
|
|
1070
|
+
activityAuditTitle: string;
|
|
1071
|
+
metaIdentifiersTitle: string;
|
|
1072
|
+
metaLifecycleTitle: string;
|
|
1073
|
+
};
|
|
1074
|
+
duration: {
|
|
1075
|
+
nightSingular: string;
|
|
1076
|
+
nightsPlural: string;
|
|
1077
|
+
daySingular: string;
|
|
1078
|
+
daysPlural: string;
|
|
1079
|
+
};
|
|
1026
1080
|
};
|
|
1027
1081
|
dialogs: {
|
|
1028
1082
|
slot: {
|
|
@@ -1395,6 +1449,24 @@ export declare const availabilityUiMessageDefinitions: {
|
|
|
1395
1449
|
generatedSlotsTitle: string;
|
|
1396
1450
|
generatedSlotsEmpty: string;
|
|
1397
1451
|
};
|
|
1452
|
+
tabs: {
|
|
1453
|
+
allocation: string;
|
|
1454
|
+
pickup: string;
|
|
1455
|
+
closeouts: string;
|
|
1456
|
+
activity: string;
|
|
1457
|
+
meta: string;
|
|
1458
|
+
allocationUnwired: string;
|
|
1459
|
+
activityEmpty: string;
|
|
1460
|
+
activityAuditTitle: string;
|
|
1461
|
+
metaIdentifiersTitle: string;
|
|
1462
|
+
metaLifecycleTitle: string;
|
|
1463
|
+
};
|
|
1464
|
+
duration: {
|
|
1465
|
+
nightSingular: string;
|
|
1466
|
+
nightsPlural: string;
|
|
1467
|
+
daySingular: string;
|
|
1468
|
+
daysPlural: string;
|
|
1469
|
+
};
|
|
1398
1470
|
};
|
|
1399
1471
|
dialogs: {
|
|
1400
1472
|
slot: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/i18n/provider.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,yBAAyB,EAIzB,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EAEtB,MAAM,gBAAgB,CAAA;AACvB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,KAAK,wBAAwB,GAAG,CAAC,OAAO,yBAAyB,CAAC,EAAE,CAAC,CAAC,cAAc,CAAC,CAAA;AAErF,MAAM,MAAM,sBAAsB,GAAG,wBAAwB,GAAG;IAC9D,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAA;QACf,UAAU,EAAE,MAAM,CAAA;QAClB,WAAW,EAAE,MAAM,CAAA;QACnB,OAAO,EAAE;YACP,WAAW,EAAE,MAAM,CAAA;YACnB,UAAU,EAAE,MAAM,CAAA;YAClB,cAAc,EAAE,MAAM,CAAA;YACtB,OAAO,EAAE,MAAM,CAAA;YACf,WAAW,EAAE,MAAM,CAAA;YACnB,SAAS,EAAE,MAAM,CAAA;YACjB,MAAM,EAAE,MAAM,CAAA;YACd,QAAQ,EAAE,MAAM,CAAA;YAChB,KAAK,EAAE,MAAM,CAAA;YACb,kBAAkB,EAAE,MAAM,CAAA;SAC3B,CAAA;QACD,QAAQ,EAAE;YACR,IAAI,EAAE,MAAM,CAAA;YACZ,OAAO,EAAE,MAAM,CAAA;YACf,MAAM,EAAE,MAAM,CAAA;YACd,SAAS,EAAE,MAAM,CAAA;YACjB,QAAQ,EAAE,MAAM,CAAA;SACjB,CAAA;KACF,CAAA;CACF,CAAA;AAwDD,eAAO,MAAM,gBAAgB
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/i18n/provider.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,yBAAyB,EAIzB,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EAEtB,MAAM,gBAAgB,CAAA;AACvB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAEtC,KAAK,wBAAwB,GAAG,CAAC,OAAO,yBAAyB,CAAC,EAAE,CAAC,CAAC,cAAc,CAAC,CAAA;AAErF,MAAM,MAAM,sBAAsB,GAAG,wBAAwB,GAAG;IAC9D,IAAI,EAAE;QACJ,OAAO,EAAE,MAAM,CAAA;QACf,UAAU,EAAE,MAAM,CAAA;QAClB,WAAW,EAAE,MAAM,CAAA;QACnB,OAAO,EAAE;YACP,WAAW,EAAE,MAAM,CAAA;YACnB,UAAU,EAAE,MAAM,CAAA;YAClB,cAAc,EAAE,MAAM,CAAA;YACtB,OAAO,EAAE,MAAM,CAAA;YACf,WAAW,EAAE,MAAM,CAAA;YACnB,SAAS,EAAE,MAAM,CAAA;YACjB,MAAM,EAAE,MAAM,CAAA;YACd,QAAQ,EAAE,MAAM,CAAA;YAChB,KAAK,EAAE,MAAM,CAAA;YACb,kBAAkB,EAAE,MAAM,CAAA;SAC3B,CAAA;QACD,QAAQ,EAAE;YACR,IAAI,EAAE,MAAM,CAAA;YACZ,OAAO,EAAE,MAAM,CAAA;YACf,MAAM,EAAE,MAAM,CAAA;YACd,SAAS,EAAE,MAAM,CAAA;YACjB,QAAQ,EAAE,MAAM,CAAA;SACjB,CAAA;KACF,CAAA;CACF,CAAA;AAwDD,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAGK,CAAA;AAElC,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAGK,CAAA;AAIlC,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAGe,CAAA;AAE5D,MAAM,MAAM,8BAA8B,GAAG,sBAAsB,CAAC,sBAAsB,CAAC,CAAA;AAU3F,wBAAgB,6BAA6B,CAAC,EAC5C,MAAM,EACN,SAAS,GACV,EAAE;IACD,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IACjC,SAAS,CAAC,EAAE,8BAA8B,GAAG,IAAI,CAAA;CAClD,0BAOA;AAED,wBAAgB,qBAAqB,CAAC,EACpC,MAAM,EACN,SAAS,GACV,EAAE;IACD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IAClC,SAAS,CAAC,EAAE,8BAA8B,GAAG,IAAI,CAAA;CAClD,GAAG,gBAAgB,CAAC,sBAAsB,CAAC,CAU3C;AAED,wBAAgB,8BAA8B,CAAC,EAC7C,QAAQ,EACR,MAAM,EACN,SAAS,GACV,EAAE;IACD,QAAQ,EAAE,SAAS,CAAA;IACnB,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IACjC,SAAS,CAAC,EAAE,8BAA8B,GAAG,IAAI,CAAA;CAClD,2CAWA;AAED,eAAO,MAAM,qBAAqB,gDAAgC,CAAA;AAClE,eAAO,MAAM,yBAAyB,8BAAoC,CAAA;AAE1E,wBAAgB,8BAA8B,6CAE7C;AAED,wBAAgB,kCAAkC,2BAEjD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyantjs/availability-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.51.1",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"react-dom": "^19.0.0",
|
|
43
43
|
"react-hook-form": "^7.72.1",
|
|
44
44
|
"zod": "^4.3.6",
|
|
45
|
-
"@voyantjs/availability-react": "0.
|
|
46
|
-
"@voyantjs/ui": "0.
|
|
45
|
+
"@voyantjs/availability-react": "0.51.1",
|
|
46
|
+
"@voyantjs/ui": "0.51.1"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"@tanstack/react-table": "^8.21.3",
|
|
@@ -57,13 +57,13 @@
|
|
|
57
57
|
"typescript": "^6.0.2",
|
|
58
58
|
"vitest": "^4.1.2",
|
|
59
59
|
"zod": "^4.3.6",
|
|
60
|
-
"@voyantjs/availability-react": "0.
|
|
61
|
-
"@voyantjs/i18n": "0.
|
|
62
|
-
"@voyantjs/ui": "0.
|
|
60
|
+
"@voyantjs/availability-react": "0.51.1",
|
|
61
|
+
"@voyantjs/i18n": "0.51.1",
|
|
62
|
+
"@voyantjs/ui": "0.51.1",
|
|
63
63
|
"@voyantjs/voyant-typescript-config": "0.1.0"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@voyantjs/i18n": "0.
|
|
66
|
+
"@voyantjs/i18n": "0.51.1"
|
|
67
67
|
},
|
|
68
68
|
"files": [
|
|
69
69
|
"dist",
|