@j3m-quantum/ui 1.9.1 → 1.11.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/index.cjs +1916 -192
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +261 -14
- package/dist/index.d.ts +261 -14
- package/dist/index.js +1887 -196
- package/dist/index.js.map +1 -1
- package/package.json +19 -10
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React27 from 'react';
|
|
2
|
-
import { useMemo } from 'react';
|
|
2
|
+
import { createContext, memo, useContext, useMemo, useId, useCallback, useState, useEffect, useRef } from 'react';
|
|
3
3
|
import { Slot } from '@radix-ui/react-slot';
|
|
4
4
|
import { cva } from 'class-variance-authority';
|
|
5
5
|
import { clsx } from 'clsx';
|
|
@@ -7,7 +7,7 @@ import { twMerge } from 'tailwind-merge';
|
|
|
7
7
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
8
|
import * as SeparatorPrimitive from '@radix-ui/react-separator';
|
|
9
9
|
import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
|
|
10
|
-
import { SearchIcon, CheckIcon, CircleIcon, ChevronDownIcon, ChevronUpIcon, ChevronRightIcon, ChevronLeftIcon, ArrowLeft, ArrowRight, Check, Loader2Icon, OctagonXIcon, TriangleAlertIcon, InfoIcon, CircleCheckIcon, ChevronRight, MoreHorizontal, MoreHorizontalIcon, XIcon, GripVerticalIcon, PanelLeftIcon, ArrowDown, ArrowUp, ChevronsUpDown, EyeOff, ChevronsLeft, ChevronLeft, ChevronsRight, Settings2, FolderIcon, ShareIcon,
|
|
10
|
+
import { SearchIcon, TrashIcon, CheckIcon, CircleIcon, ChevronDownIcon, ChevronUpIcon, ChevronRightIcon, ChevronLeftIcon, ArrowLeft, ArrowRight, Check, Loader2Icon, OctagonXIcon, TriangleAlertIcon, InfoIcon, CircleCheckIcon, ChevronRight, MoreHorizontal, MoreHorizontalIcon, XIcon, GripVerticalIcon, PanelLeftIcon, ArrowDown, ArrowUp, ChevronsUpDown, EyeOff, ChevronsLeft, ChevronLeft, ChevronsRight, Settings2, FolderIcon, ShareIcon, ChevronsUpDownIcon, SparklesIcon, BadgeCheckIcon, CreditCardIcon, BellIcon, LogOutIcon, X, Flag, Factory, Truck, MessageSquare, ChevronDown, Plus, Send, MessageSquarePlus, AlertTriangle, CheckCircle, Calendar as Calendar$1, MapPin, Package, User, Clock, CalendarX2, List, Columns, Grid2x2, Grid3x3, CalendarRange, Settings, Info, Moon, PlusIcon, PencilIcon, CopyIcon, ArrowUpDown, CheckCircle2, XCircle } from 'lucide-react';
|
|
11
11
|
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group';
|
|
12
12
|
import * as SwitchPrimitive from '@radix-ui/react-switch';
|
|
13
13
|
import * as SliderPrimitive from '@radix-ui/react-slider';
|
|
@@ -42,8 +42,17 @@ import * as ResizablePrimitive from 'react-resizable-panels';
|
|
|
42
42
|
import { MapContainer, TileLayer, Marker, Popup, Tooltip, ZoomControl } from 'react-leaflet';
|
|
43
43
|
import { useReactTable, getPaginationRowModel, getFilteredRowModel, getSortedRowModel, getCoreRowModel, flexRender } from '@tanstack/react-table';
|
|
44
44
|
export { flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from '@tanstack/react-table';
|
|
45
|
-
import {
|
|
45
|
+
import { formatDate as formatDate$1, differenceInDays, getDaysInMonth, isSameDay, getDate, getISOWeek as getISOWeek$1, startOfWeek, addWeeks, differenceInWeeks, differenceInMonths, startOfMonth, endOfWeek, endOfMonth, addDays, isToday, subMonths, subYears, subWeeks, subDays, addMonths, addYears, format, startOfYear, endOfYear, isSameMonth, isSameWeek, isSameYear, isWithinInterval, parseISO, differenceInMinutes, eachDayOfInterval, startOfDay, setMinutes, setHours, eachHourOfInterval, endOfDay, getHours, getMinutes, addMinutes, areIntervalsOverlapping, formatDistance } from 'date-fns';
|
|
46
46
|
export { areIntervalsOverlapping, format, getDay, isSameDay, isSameMonth, isToday, parseISO } from 'date-fns';
|
|
47
|
+
import { useDraggable as useDraggable$1, useSensor, MouseSensor, DndContext, useDroppable as useDroppable$1, useSensors, TouchSensor, KeyboardSensor, closestCenter, DragOverlay } from '@dnd-kit/core';
|
|
48
|
+
import { restrictToHorizontalAxis } from '@dnd-kit/modifiers';
|
|
49
|
+
import { useMouse, useWindowScroll, useThrottle } from '@uidotdev/usehooks';
|
|
50
|
+
import { atom, useAtom } from 'jotai';
|
|
51
|
+
import throttle from 'lodash.throttle';
|
|
52
|
+
import { useSortable, SortableContext, arrayMove } from '@dnd-kit/sortable';
|
|
53
|
+
import { CSS } from '@dnd-kit/utilities';
|
|
54
|
+
import { createPortal } from 'react-dom';
|
|
55
|
+
import tunnel from 'tunnel-rat';
|
|
47
56
|
|
|
48
57
|
// src/hooks/use-mobile.ts
|
|
49
58
|
var MOBILE_BREAKPOINT = 768;
|
|
@@ -6779,7 +6788,7 @@ function PlanningWeekCommentPopover({
|
|
|
6779
6788
|
onCommentClick(comment);
|
|
6780
6789
|
}
|
|
6781
6790
|
};
|
|
6782
|
-
const
|
|
6791
|
+
const formatDate3 = (date) => {
|
|
6783
6792
|
return new Intl.DateTimeFormat("en-US", {
|
|
6784
6793
|
month: "short",
|
|
6785
6794
|
day: "numeric",
|
|
@@ -6859,7 +6868,7 @@ function PlanningWeekCommentPopover({
|
|
|
6859
6868
|
] }),
|
|
6860
6869
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
6861
6870
|
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: comment.author }),
|
|
6862
|
-
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children:
|
|
6871
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate3(comment.createdAt) })
|
|
6863
6872
|
] }),
|
|
6864
6873
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-foreground", children: comment.text })
|
|
6865
6874
|
]
|
|
@@ -7386,7 +7395,7 @@ function DeliveryCommentPopover({
|
|
|
7386
7395
|
setNewCommentText("");
|
|
7387
7396
|
}
|
|
7388
7397
|
};
|
|
7389
|
-
const
|
|
7398
|
+
const formatDate3 = (date) => {
|
|
7390
7399
|
return new Intl.DateTimeFormat("en-US", {
|
|
7391
7400
|
month: "short",
|
|
7392
7401
|
day: "numeric",
|
|
@@ -7432,7 +7441,7 @@ function DeliveryCommentPopover({
|
|
|
7432
7441
|
/* @__PURE__ */ jsx(CollapsibleContent2, { className: "space-y-2 pt-2", children: comments.length > 0 ? comments.map((comment) => /* @__PURE__ */ jsxs("div", { className: "rounded-lg bg-muted/50 p-3 space-y-2", children: [
|
|
7433
7442
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
7434
7443
|
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: comment.author }),
|
|
7435
|
-
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children:
|
|
7444
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate3(comment.createdAt) })
|
|
7436
7445
|
] }),
|
|
7437
7446
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-foreground", children: comment.text })
|
|
7438
7447
|
] }, comment.id)) : /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground text-center py-2", children: "No comments yet" }) })
|
|
@@ -7526,7 +7535,7 @@ function ProductionCommentSection({
|
|
|
7526
7535
|
setNewComment("");
|
|
7527
7536
|
}
|
|
7528
7537
|
};
|
|
7529
|
-
const
|
|
7538
|
+
const formatDate3 = (date) => {
|
|
7530
7539
|
return new Intl.DateTimeFormat("en-US", {
|
|
7531
7540
|
month: "short",
|
|
7532
7541
|
day: "numeric",
|
|
@@ -7538,7 +7547,7 @@ function ProductionCommentSection({
|
|
|
7538
7547
|
comments.length > 0 && /* @__PURE__ */ jsx("div", { className: "space-y-2", children: comments.map((comment) => /* @__PURE__ */ jsxs("div", { className: "rounded-lg bg-muted/50 p-2.5 space-y-1", children: [
|
|
7539
7548
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
7540
7549
|
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: comment.author }),
|
|
7541
|
-
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children:
|
|
7550
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate3(comment.createdAt) })
|
|
7542
7551
|
] }),
|
|
7543
7552
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-foreground", children: comment.text })
|
|
7544
7553
|
] }, comment.id)) }),
|
|
@@ -8482,7 +8491,7 @@ function CommentPopover({
|
|
|
8482
8491
|
setNewCommentText("");
|
|
8483
8492
|
}
|
|
8484
8493
|
};
|
|
8485
|
-
const
|
|
8494
|
+
const formatDate3 = (date) => {
|
|
8486
8495
|
return new Intl.DateTimeFormat("en-US", {
|
|
8487
8496
|
month: "short",
|
|
8488
8497
|
day: "numeric",
|
|
@@ -8550,7 +8559,7 @@ function CommentPopover({
|
|
|
8550
8559
|
),
|
|
8551
8560
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
8552
8561
|
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: comment.author }),
|
|
8553
|
-
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children:
|
|
8562
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate3(comment.createdAt) })
|
|
8554
8563
|
] }),
|
|
8555
8564
|
/* @__PURE__ */ jsx("p", { className: "text-sm text-foreground", children: comment.text })
|
|
8556
8565
|
]
|
|
@@ -9269,7 +9278,7 @@ function generateLoadingWeek(date) {
|
|
|
9269
9278
|
const today = /* @__PURE__ */ new Date();
|
|
9270
9279
|
today.setHours(0, 0, 0, 0);
|
|
9271
9280
|
const isCurrentWeek = monday <= today && today <= friday;
|
|
9272
|
-
const
|
|
9281
|
+
const formatDate3 = (d) => {
|
|
9273
9282
|
return d.toLocaleDateString("en-US", { month: "short", day: "numeric" });
|
|
9274
9283
|
};
|
|
9275
9284
|
return {
|
|
@@ -9277,7 +9286,7 @@ function generateLoadingWeek(date) {
|
|
|
9277
9286
|
label: `W${getLoadingISOWeek(monday).toString().padStart(2, "0")}`,
|
|
9278
9287
|
startDate: monday,
|
|
9279
9288
|
endDate: friday,
|
|
9280
|
-
dateRange: `${
|
|
9289
|
+
dateRange: `${formatDate3(monday)} - ${formatDate3(friday)}`,
|
|
9281
9290
|
isCurrentWeek
|
|
9282
9291
|
};
|
|
9283
9292
|
}
|
|
@@ -9369,36 +9378,41 @@ function getLeftStrokeStyles(state, hasRisk, isHovered) {
|
|
|
9369
9378
|
stroke: "border-l-[3px] border-l-red-500",
|
|
9370
9379
|
content: "text-foreground",
|
|
9371
9380
|
progressBg: "bg-red-500",
|
|
9372
|
-
iconColor: "text-red-600 dark:text-red-400"
|
|
9381
|
+
iconColor: "text-red-600 dark:text-red-400",
|
|
9382
|
+
cardBg: "bg-background"
|
|
9373
9383
|
};
|
|
9374
9384
|
}
|
|
9375
9385
|
switch (state) {
|
|
9376
9386
|
case "sent":
|
|
9377
9387
|
return {
|
|
9378
|
-
stroke: "border-l-[3px] border-l-green-500/
|
|
9379
|
-
content: "text-muted-foreground/
|
|
9380
|
-
progressBg: "bg-green-500",
|
|
9381
|
-
iconColor: "text-green-600 dark:text-green-400"
|
|
9388
|
+
stroke: "border-l-[3px] border-l-green-500/40",
|
|
9389
|
+
content: "text-muted-foreground/50",
|
|
9390
|
+
progressBg: "bg-green-500/50",
|
|
9391
|
+
iconColor: "text-green-600/50 dark:text-green-400/50",
|
|
9392
|
+
cardBg: "bg-muted/30"
|
|
9382
9393
|
};
|
|
9383
9394
|
case "ready":
|
|
9384
9395
|
return {
|
|
9385
9396
|
stroke: "border-l-[3px] border-l-green-500",
|
|
9386
9397
|
content: "text-foreground",
|
|
9387
9398
|
progressBg: "bg-green-500",
|
|
9388
|
-
iconColor: "text-green-600 dark:text-green-400"
|
|
9399
|
+
iconColor: "text-green-600 dark:text-green-400",
|
|
9400
|
+
cardBg: "bg-background"
|
|
9389
9401
|
};
|
|
9390
9402
|
default:
|
|
9391
9403
|
return {
|
|
9392
9404
|
stroke: isHovered ? "border-l-[3px] border-l-primary/50" : "border-l-[3px] border-l-border",
|
|
9393
9405
|
content: "text-foreground",
|
|
9394
9406
|
progressBg: "bg-primary",
|
|
9395
|
-
iconColor: "text-muted-foreground"
|
|
9407
|
+
iconColor: "text-muted-foreground",
|
|
9408
|
+
cardBg: "bg-background"
|
|
9396
9409
|
};
|
|
9397
9410
|
}
|
|
9398
9411
|
}
|
|
9399
9412
|
function DeliveryBadge({
|
|
9400
9413
|
delivery,
|
|
9401
9414
|
onClick,
|
|
9415
|
+
onCommentClick,
|
|
9402
9416
|
className
|
|
9403
9417
|
}) {
|
|
9404
9418
|
const [isHovered, setIsHovered] = React27.useState(false);
|
|
@@ -9461,70 +9475,125 @@ function DeliveryBadge({
|
|
|
9461
9475
|
onClick?.();
|
|
9462
9476
|
}
|
|
9463
9477
|
};
|
|
9478
|
+
const handleCommentClick = (e) => {
|
|
9479
|
+
e.stopPropagation();
|
|
9480
|
+
onCommentClick?.();
|
|
9481
|
+
};
|
|
9482
|
+
const amountColorClass = React27.useMemo(() => {
|
|
9483
|
+
if (visualState === "sent") {
|
|
9484
|
+
return "text-muted-foreground/40";
|
|
9485
|
+
}
|
|
9486
|
+
if (delivery.isReadyToUnload) {
|
|
9487
|
+
return "text-green-600 dark:text-green-400";
|
|
9488
|
+
}
|
|
9489
|
+
if (delivery.hasProductionRisk) {
|
|
9490
|
+
return "text-red-600 dark:text-red-400";
|
|
9491
|
+
}
|
|
9492
|
+
return "text-muted-foreground";
|
|
9493
|
+
}, [visualState, delivery.isReadyToUnload, delivery.hasProductionRisk]);
|
|
9464
9494
|
return /* @__PURE__ */ jsxs(
|
|
9465
|
-
"
|
|
9495
|
+
"div",
|
|
9466
9496
|
{
|
|
9467
|
-
type: "button",
|
|
9468
|
-
onClick: handleClick,
|
|
9469
|
-
onKeyDown: handleKeyDown,
|
|
9470
|
-
onMouseEnter: () => setIsHovered(true),
|
|
9471
|
-
onMouseLeave: () => setIsHovered(false),
|
|
9472
9497
|
className: cn(
|
|
9473
|
-
// Position relative for comment
|
|
9498
|
+
// Position relative for comment button
|
|
9474
9499
|
"relative",
|
|
9475
9500
|
// Full-width in cell, 90° corners
|
|
9476
9501
|
"w-full rounded-none",
|
|
9477
9502
|
// Sizing using Quantum tokens:
|
|
9478
|
-
// - h-[
|
|
9479
|
-
// -
|
|
9480
|
-
// -
|
|
9481
|
-
|
|
9482
|
-
|
|
9483
|
-
|
|
9484
|
-
|
|
9485
|
-
"
|
|
9503
|
+
// - min-h-[100px] card min-height
|
|
9504
|
+
// - pt-4 pb-3 = vertical padding (j3m.spacing.m / j3m.spacing.s)
|
|
9505
|
+
// - pl-4 = left padding (j3m.spacing.m)
|
|
9506
|
+
// - pr-2 = minimal right padding (progress bar extends further)
|
|
9507
|
+
"min-h-[100px] pt-4 pb-3 pl-4 pr-2",
|
|
9508
|
+
// Card base: dynamic background based on state, complete border
|
|
9509
|
+
styles.cardBg,
|
|
9510
|
+
"border border-border",
|
|
9486
9511
|
// Left stroke for status
|
|
9487
9512
|
styles.stroke,
|
|
9488
|
-
// Interactive states
|
|
9489
|
-
"
|
|
9490
|
-
"hover:-translate-y-0.5 hover:shadow-[var(--j3m-shadow-md)]",
|
|
9491
|
-
"active:translate-y-0 active:shadow-sm",
|
|
9492
|
-
// Focus state
|
|
9493
|
-
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1",
|
|
9494
|
-
// Greyed out for sent state
|
|
9495
|
-
visualState === "sent" && "opacity-60",
|
|
9513
|
+
// Interactive states (reduced for sent state)
|
|
9514
|
+
"transition-all duration-200 ease-out",
|
|
9515
|
+
visualState !== "sent" && "hover:-translate-y-0.5 hover:shadow-[var(--j3m-shadow-md)]",
|
|
9496
9516
|
className
|
|
9497
9517
|
),
|
|
9498
9518
|
children: [
|
|
9499
|
-
|
|
9500
|
-
|
|
9519
|
+
/* @__PURE__ */ jsx(
|
|
9520
|
+
Button,
|
|
9501
9521
|
{
|
|
9502
|
-
|
|
9503
|
-
|
|
9522
|
+
type: "button",
|
|
9523
|
+
variant: "ghost",
|
|
9524
|
+
size: "icon",
|
|
9525
|
+
className: cn(
|
|
9526
|
+
"absolute top-2 right-2",
|
|
9527
|
+
// 44px touch target for accessibility
|
|
9528
|
+
"h-11 w-11",
|
|
9529
|
+
"rounded-full",
|
|
9530
|
+
hasComments && "text-primary"
|
|
9531
|
+
),
|
|
9532
|
+
onClick: handleCommentClick,
|
|
9533
|
+
"aria-label": hasComments ? `${delivery.comments.length} comments` : "Add comment",
|
|
9534
|
+
children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
9535
|
+
/* @__PURE__ */ jsx(MessageSquare, { className: "h-5 w-5" }),
|
|
9536
|
+
hasComments && /* @__PURE__ */ jsx(
|
|
9537
|
+
"span",
|
|
9538
|
+
{
|
|
9539
|
+
className: "absolute -top-1 -right-1 h-2.5 w-2.5 rounded-full bg-primary border-2 border-background",
|
|
9540
|
+
"aria-hidden": "true"
|
|
9541
|
+
}
|
|
9542
|
+
)
|
|
9543
|
+
] })
|
|
9504
9544
|
}
|
|
9505
9545
|
),
|
|
9506
|
-
/* @__PURE__ */ jsxs(
|
|
9507
|
-
|
|
9508
|
-
|
|
9509
|
-
|
|
9510
|
-
|
|
9511
|
-
|
|
9512
|
-
|
|
9513
|
-
|
|
9514
|
-
|
|
9515
|
-
|
|
9516
|
-
"
|
|
9517
|
-
|
|
9518
|
-
|
|
9519
|
-
|
|
9520
|
-
|
|
9521
|
-
|
|
9522
|
-
|
|
9523
|
-
"
|
|
9524
|
-
|
|
9525
|
-
|
|
9526
|
-
|
|
9527
|
-
|
|
9546
|
+
/* @__PURE__ */ jsxs(
|
|
9547
|
+
"button",
|
|
9548
|
+
{
|
|
9549
|
+
type: "button",
|
|
9550
|
+
onClick: handleClick,
|
|
9551
|
+
onKeyDown: handleKeyDown,
|
|
9552
|
+
onMouseEnter: () => setIsHovered(true),
|
|
9553
|
+
onMouseLeave: () => setIsHovered(false),
|
|
9554
|
+
className: cn(
|
|
9555
|
+
// Full width, no background (inherits from parent)
|
|
9556
|
+
"w-full bg-transparent text-left",
|
|
9557
|
+
// Layout - vertical stack
|
|
9558
|
+
"flex flex-col gap-2",
|
|
9559
|
+
// Interactive states
|
|
9560
|
+
"cursor-pointer",
|
|
9561
|
+
"active:translate-y-0 active:shadow-sm",
|
|
9562
|
+
// Focus state
|
|
9563
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-1"
|
|
9564
|
+
),
|
|
9565
|
+
children: [
|
|
9566
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 overflow-hidden pr-12", children: [
|
|
9567
|
+
/* @__PURE__ */ jsx("span", { className: cn("text-sm font-semibold truncate", styles.content), children: prefixTitle }),
|
|
9568
|
+
delivery.hasProductionRisk && /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4 text-red-500 shrink-0" }),
|
|
9569
|
+
delivery.supplierName && /* @__PURE__ */ jsx("span", { className: cn(
|
|
9570
|
+
"text-xs truncate ml-auto",
|
|
9571
|
+
visualState === "sent" ? "text-muted-foreground/40" : "text-muted-foreground"
|
|
9572
|
+
), children: delivery.supplierName })
|
|
9573
|
+
] }),
|
|
9574
|
+
/* @__PURE__ */ jsx("div", { className: "pr-14", children: /* @__PURE__ */ jsx("div", { className: "h-2 bg-black/10 dark:bg-white/10 rounded-full overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
9575
|
+
"div",
|
|
9576
|
+
{
|
|
9577
|
+
className: cn("h-full rounded-full transition-all", styles.progressBg),
|
|
9578
|
+
style: { width: `${productionProgress}%` }
|
|
9579
|
+
}
|
|
9580
|
+
) }) }),
|
|
9581
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-2", children: [
|
|
9582
|
+
productionDisplay && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
9583
|
+
/* @__PURE__ */ jsx(Factory, { className: cn("h-3 w-3 shrink-0", styles.iconColor) }),
|
|
9584
|
+
/* @__PURE__ */ jsx("span", { className: cn(
|
|
9585
|
+
"text-[11px] tabular-nums font-medium",
|
|
9586
|
+
amountColorClass
|
|
9587
|
+
), children: productionDisplay })
|
|
9588
|
+
] }),
|
|
9589
|
+
visualState === "sent" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 ml-auto", children: [
|
|
9590
|
+
/* @__PURE__ */ jsx(Check, { className: "h-3.5 w-3.5 text-green-600/60 dark:text-green-400/60 shrink-0" }),
|
|
9591
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-medium text-muted-foreground/50 uppercase tracking-wide", children: "Sent" })
|
|
9592
|
+
] })
|
|
9593
|
+
] })
|
|
9594
|
+
]
|
|
9595
|
+
}
|
|
9596
|
+
)
|
|
9528
9597
|
]
|
|
9529
9598
|
}
|
|
9530
9599
|
);
|
|
@@ -9534,7 +9603,7 @@ function WeeklyLoadingView({
|
|
|
9534
9603
|
deliveries,
|
|
9535
9604
|
onDeliveryClick,
|
|
9536
9605
|
onWeekChange,
|
|
9537
|
-
|
|
9606
|
+
onDeliveryCommentClick,
|
|
9538
9607
|
showNavigation = true,
|
|
9539
9608
|
className
|
|
9540
9609
|
}) {
|
|
@@ -9565,20 +9634,6 @@ function WeeklyLoadingView({
|
|
|
9565
9634
|
}
|
|
9566
9635
|
return grouped;
|
|
9567
9636
|
}, [deliveries]);
|
|
9568
|
-
const commentCountByDay = React27.useMemo(() => {
|
|
9569
|
-
const counts = /* @__PURE__ */ new Map();
|
|
9570
|
-
for (let i = 1; i <= 5; i++) {
|
|
9571
|
-
counts.set(i, 0);
|
|
9572
|
-
}
|
|
9573
|
-
for (const delivery of deliveries) {
|
|
9574
|
-
const dayOfWeek = delivery.date.getDay();
|
|
9575
|
-
if (dayOfWeek >= 1 && dayOfWeek <= 5) {
|
|
9576
|
-
const current = counts.get(dayOfWeek) ?? 0;
|
|
9577
|
-
counts.set(dayOfWeek, current + delivery.comments.length);
|
|
9578
|
-
}
|
|
9579
|
-
}
|
|
9580
|
-
return counts;
|
|
9581
|
-
}, [deliveries]);
|
|
9582
9637
|
const totalDeliveries = deliveries.length;
|
|
9583
9638
|
return /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col", className), children: [
|
|
9584
9639
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 border-b border-border p-4 lg:flex-row lg:items-center lg:justify-between", children: [
|
|
@@ -9643,54 +9698,27 @@ function WeeklyLoadingView({
|
|
|
9643
9698
|
] }),
|
|
9644
9699
|
/* @__PURE__ */ jsxs(ScrollArea, { className: "flex-1", children: [
|
|
9645
9700
|
/* @__PURE__ */ jsxs("div", { className: "hidden sm:block", children: [
|
|
9646
|
-
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-5 border-b border-border bg-muted/30", children: weekDays.map(({ date, dayOfWeek, isToday: dayIsToday }) =>
|
|
9647
|
-
|
|
9648
|
-
|
|
9649
|
-
|
|
9650
|
-
|
|
9651
|
-
|
|
9652
|
-
|
|
9653
|
-
|
|
9654
|
-
|
|
9655
|
-
|
|
9656
|
-
|
|
9657
|
-
|
|
9658
|
-
children:
|
|
9659
|
-
|
|
9660
|
-
|
|
9661
|
-
|
|
9662
|
-
|
|
9663
|
-
|
|
9664
|
-
|
|
9665
|
-
|
|
9666
|
-
|
|
9667
|
-
/* @__PURE__ */ jsxs(
|
|
9668
|
-
Button,
|
|
9669
|
-
{
|
|
9670
|
-
variant: "ghost",
|
|
9671
|
-
size: "icon",
|
|
9672
|
-
className: cn(
|
|
9673
|
-
"absolute top-1 right-1 h-7 w-7",
|
|
9674
|
-
dayCommentCount > 0 && "text-primary"
|
|
9675
|
-
),
|
|
9676
|
-
onClick: (e) => {
|
|
9677
|
-
e.stopPropagation();
|
|
9678
|
-
onDayCommentClick?.(dayOfWeek, date);
|
|
9679
|
-
},
|
|
9680
|
-
children: [
|
|
9681
|
-
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
9682
|
-
/* @__PURE__ */ jsx(MessageSquare, { className: "h-4 w-4" }),
|
|
9683
|
-
dayCommentCount > 0 && /* @__PURE__ */ jsx("span", { className: "absolute -top-1 -right-1 h-2 w-2 rounded-full bg-primary" })
|
|
9684
|
-
] }),
|
|
9685
|
-
/* @__PURE__ */ jsx("span", { className: "sr-only", children: dayCommentCount > 0 ? `${dayCommentCount} comments on ${getShortDayLabel(dayOfWeek)}` : `Add comment for ${getShortDayLabel(dayOfWeek)}` })
|
|
9686
|
-
]
|
|
9687
|
-
}
|
|
9688
|
-
)
|
|
9689
|
-
]
|
|
9690
|
-
},
|
|
9691
|
-
dayOfWeek
|
|
9692
|
-
);
|
|
9693
|
-
}) }),
|
|
9701
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-5 border-b border-border bg-muted/30", children: weekDays.map(({ date, dayOfWeek, isToday: dayIsToday }) => /* @__PURE__ */ jsxs(
|
|
9702
|
+
"div",
|
|
9703
|
+
{
|
|
9704
|
+
className: cn(
|
|
9705
|
+
// Compact padding
|
|
9706
|
+
"flex flex-col items-center justify-center py-2 px-2",
|
|
9707
|
+
dayIsToday && "bg-primary/5"
|
|
9708
|
+
),
|
|
9709
|
+
children: [
|
|
9710
|
+
/* @__PURE__ */ jsx("span", { className: cn(
|
|
9711
|
+
"text-[11px] font-semibold uppercase tracking-wide leading-none",
|
|
9712
|
+
dayIsToday ? "text-primary" : "text-muted-foreground"
|
|
9713
|
+
), children: getShortDayLabel(dayOfWeek) }),
|
|
9714
|
+
/* @__PURE__ */ jsx("span", { className: cn(
|
|
9715
|
+
"text-lg font-medium tabular-nums leading-tight mt-0.5",
|
|
9716
|
+
dayIsToday ? "text-primary" : "text-foreground"
|
|
9717
|
+
), children: date.getDate() })
|
|
9718
|
+
]
|
|
9719
|
+
},
|
|
9720
|
+
dayOfWeek
|
|
9721
|
+
)) }),
|
|
9694
9722
|
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-5", children: weekDays.map(({ dayOfWeek, isToday: dayIsToday }) => {
|
|
9695
9723
|
const dayDeliveries = deliveriesByDay.get(dayOfWeek) ?? [];
|
|
9696
9724
|
return /* @__PURE__ */ jsx(
|
|
@@ -9705,7 +9733,8 @@ function WeeklyLoadingView({
|
|
|
9705
9733
|
DeliveryBadge,
|
|
9706
9734
|
{
|
|
9707
9735
|
delivery,
|
|
9708
|
-
onClick: () => onDeliveryClick?.(delivery)
|
|
9736
|
+
onClick: () => onDeliveryClick?.(delivery),
|
|
9737
|
+
onCommentClick: () => onDeliveryCommentClick?.(delivery)
|
|
9709
9738
|
},
|
|
9710
9739
|
delivery.id
|
|
9711
9740
|
)) : /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-6 text-sm text-muted-foreground/40", children: "\u2014" }) })
|
|
@@ -9716,7 +9745,6 @@ function WeeklyLoadingView({
|
|
|
9716
9745
|
] }),
|
|
9717
9746
|
/* @__PURE__ */ jsx("div", { className: "sm:hidden divide-y divide-border", children: weekDays.map(({ date, dayOfWeek, isToday: dayIsToday }) => {
|
|
9718
9747
|
const dayDeliveries = deliveriesByDay.get(dayOfWeek) ?? [];
|
|
9719
|
-
const dayCommentCount = commentCountByDay.get(dayOfWeek) ?? 0;
|
|
9720
9748
|
return /* @__PURE__ */ jsxs(
|
|
9721
9749
|
"div",
|
|
9722
9750
|
{
|
|
@@ -9725,52 +9753,31 @@ function WeeklyLoadingView({
|
|
|
9725
9753
|
),
|
|
9726
9754
|
children: [
|
|
9727
9755
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-4 py-2", children: [
|
|
9728
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-
|
|
9729
|
-
/* @__PURE__ */
|
|
9730
|
-
|
|
9731
|
-
|
|
9732
|
-
|
|
9733
|
-
|
|
9734
|
-
|
|
9735
|
-
|
|
9736
|
-
|
|
9737
|
-
|
|
9738
|
-
] }),
|
|
9739
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
9740
|
-
/* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
9741
|
-
dayDeliveries.length,
|
|
9742
|
-
" ",
|
|
9743
|
-
dayDeliveries.length === 1 ? "delivery" : "deliveries"
|
|
9756
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
9757
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center min-w-[40px]", children: [
|
|
9758
|
+
/* @__PURE__ */ jsx("span", { className: cn(
|
|
9759
|
+
"text-[11px] font-semibold uppercase tracking-wide leading-none",
|
|
9760
|
+
dayIsToday ? "text-primary" : "text-muted-foreground"
|
|
9761
|
+
), children: getShortDayLabel(dayOfWeek) }),
|
|
9762
|
+
/* @__PURE__ */ jsx("span", { className: cn(
|
|
9763
|
+
"text-lg font-medium tabular-nums leading-tight mt-0.5",
|
|
9764
|
+
dayIsToday ? "text-primary" : "text-foreground"
|
|
9765
|
+
), children: date.getDate() })
|
|
9744
9766
|
] }),
|
|
9745
|
-
/* @__PURE__ */
|
|
9746
|
-
|
|
9747
|
-
|
|
9748
|
-
|
|
9749
|
-
|
|
9750
|
-
|
|
9751
|
-
"h-7 w-7",
|
|
9752
|
-
dayCommentCount > 0 && "text-primary"
|
|
9753
|
-
),
|
|
9754
|
-
onClick: (e) => {
|
|
9755
|
-
e.stopPropagation();
|
|
9756
|
-
onDayCommentClick?.(dayOfWeek, date);
|
|
9757
|
-
},
|
|
9758
|
-
children: [
|
|
9759
|
-
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
9760
|
-
/* @__PURE__ */ jsx(MessageSquare, { className: "h-4 w-4" }),
|
|
9761
|
-
dayCommentCount > 0 && /* @__PURE__ */ jsx("span", { className: "absolute -top-1 -right-1 h-2 w-2 rounded-full bg-primary" })
|
|
9762
|
-
] }),
|
|
9763
|
-
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "Comments" })
|
|
9764
|
-
]
|
|
9765
|
-
}
|
|
9766
|
-
)
|
|
9767
|
+
dayIsToday && /* @__PURE__ */ jsx("span", { className: "text-xs text-primary font-medium bg-primary/10 px-2 py-0.5 rounded", children: "Today" })
|
|
9768
|
+
] }),
|
|
9769
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
9770
|
+
dayDeliveries.length,
|
|
9771
|
+
" ",
|
|
9772
|
+
dayDeliveries.length === 1 ? "delivery" : "deliveries"
|
|
9767
9773
|
] })
|
|
9768
9774
|
] }),
|
|
9769
9775
|
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3 p-3 pt-0", children: dayDeliveries.length > 0 ? dayDeliveries.map((delivery) => /* @__PURE__ */ jsx(
|
|
9770
9776
|
DeliveryBadge,
|
|
9771
9777
|
{
|
|
9772
9778
|
delivery,
|
|
9773
|
-
onClick: () => onDeliveryClick?.(delivery)
|
|
9779
|
+
onClick: () => onDeliveryClick?.(delivery),
|
|
9780
|
+
onCommentClick: () => onDeliveryCommentClick?.(delivery)
|
|
9774
9781
|
},
|
|
9775
9782
|
delivery.id
|
|
9776
9783
|
)) : /* @__PURE__ */ jsx("div", { className: "text-sm text-muted-foreground/40 py-4 text-center", children: "\u2014" }) })
|
|
@@ -9880,7 +9887,7 @@ function AddCommentDialog({
|
|
|
9880
9887
|
}, [open]);
|
|
9881
9888
|
return /* @__PURE__ */ jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-md", children: [
|
|
9882
9889
|
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
9883
|
-
/* @__PURE__ */ jsx(DialogTitle, { children: "Add pre-
|
|
9890
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: "Add pre-loading note" }),
|
|
9884
9891
|
/* @__PURE__ */ jsxs(DialogDescription, { children: [
|
|
9885
9892
|
"Add a note for ",
|
|
9886
9893
|
/* @__PURE__ */ jsx("strong", { children: delivery.label }),
|
|
@@ -9896,7 +9903,7 @@ function AddCommentDialog({
|
|
|
9896
9903
|
Textarea,
|
|
9897
9904
|
{
|
|
9898
9905
|
id: "comment-text",
|
|
9899
|
-
placeholder: "Add a note before
|
|
9906
|
+
placeholder: "Add a note before loading...",
|
|
9900
9907
|
value: commentText,
|
|
9901
9908
|
onChange: (e) => setCommentText(e.target.value),
|
|
9902
9909
|
onKeyDown: handleKeyDown,
|
|
@@ -9938,7 +9945,7 @@ function CommentsSection({
|
|
|
9938
9945
|
}) {
|
|
9939
9946
|
const [viewCommentsOpen, setViewCommentsOpen] = React27.useState(true);
|
|
9940
9947
|
const [addDialogOpen, setAddDialogOpen] = React27.useState(false);
|
|
9941
|
-
const
|
|
9948
|
+
const formatDate3 = (date) => {
|
|
9942
9949
|
return new Intl.DateTimeFormat("en-US", {
|
|
9943
9950
|
month: "short",
|
|
9944
9951
|
day: "numeric",
|
|
@@ -9951,7 +9958,7 @@ function CommentsSection({
|
|
|
9951
9958
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
9952
9959
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
9953
9960
|
/* @__PURE__ */ jsx(MessageSquare, { className: "h-4 w-4 text-muted-foreground" }),
|
|
9954
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: "Notes before
|
|
9961
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: "Notes before loading" }),
|
|
9955
9962
|
comments.length > 0 && /* @__PURE__ */ jsx(Badge, { variant: "secondary", className: "text-[10px] h-5", children: comments.length })
|
|
9956
9963
|
] }),
|
|
9957
9964
|
/* @__PURE__ */ jsxs(
|
|
@@ -9982,11 +9989,11 @@ function CommentsSection({
|
|
|
9982
9989
|
/* @__PURE__ */ jsx("span", { className: "text-xs font-medium", children: comment.author }),
|
|
9983
9990
|
comment.supplierName && /* @__PURE__ */ jsx(Badge, { variant: "outline", className: "text-[9px] px-1.5 py-0 h-4", children: comment.prefixName ? `${comment.supplierName} - ${comment.prefixName}` : comment.supplierName })
|
|
9984
9991
|
] }),
|
|
9985
|
-
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children:
|
|
9992
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground", children: formatDate3(comment.createdAt) })
|
|
9986
9993
|
] }),
|
|
9987
9994
|
/* @__PURE__ */ jsx("p", { className: "text-sm", children: comment.text })
|
|
9988
9995
|
] }, comment.id)) })
|
|
9989
|
-
] }) : /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-dashed p-4 text-center text-sm text-muted-foreground", children: "No pre-
|
|
9996
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "rounded-lg border border-dashed p-4 text-center text-sm text-muted-foreground", children: "No pre-loading notes yet. Add notes before confirming the load." })
|
|
9990
9997
|
] }),
|
|
9991
9998
|
/* @__PURE__ */ jsx(
|
|
9992
9999
|
AddCommentDialog,
|
|
@@ -10049,7 +10056,7 @@ function DeliveryDetailPage({
|
|
|
10049
10056
|
const addons = delivery.elements.filter((e) => e.status === "addon");
|
|
10050
10057
|
return { loaded, missing, moved, addons };
|
|
10051
10058
|
}, [delivery.elements]);
|
|
10052
|
-
const
|
|
10059
|
+
const preLoadingComments = delivery.comments.filter((c) => c.context === "pre_unloading");
|
|
10053
10060
|
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col h-full", children: [
|
|
10054
10061
|
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-2 px-4 py-3 border-b bg-background sticky top-0 z-10", children: /* @__PURE__ */ jsxs(
|
|
10055
10062
|
Button,
|
|
@@ -10098,7 +10105,7 @@ function DeliveryDetailPage({
|
|
|
10098
10105
|
{
|
|
10099
10106
|
variant: "outline",
|
|
10100
10107
|
className: "bg-green-100 dark:bg-green-900/50 border-green-300 dark:border-green-700 text-green-700 dark:text-green-300",
|
|
10101
|
-
children: "Ready to
|
|
10108
|
+
children: "Ready to load"
|
|
10102
10109
|
}
|
|
10103
10110
|
)
|
|
10104
10111
|
] })
|
|
@@ -10189,13 +10196,13 @@ function DeliveryDetailPage({
|
|
|
10189
10196
|
] })
|
|
10190
10197
|
] })
|
|
10191
10198
|
] }),
|
|
10192
|
-
|
|
10199
|
+
(elementsByStatus.loaded.length > 0 || elementsByStatus.missing.length > 0 || elementsByStatus.moved.length > 0) && /* @__PURE__ */ jsxs("section", { className: "space-y-3", children: [
|
|
10193
10200
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
10194
10201
|
/* @__PURE__ */ jsx(Package, { className: "h-4 w-4 text-muted-foreground" }),
|
|
10195
|
-
/* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: "
|
|
10202
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: "What should be packed" }),
|
|
10196
10203
|
/* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground ml-auto", children: [
|
|
10197
|
-
|
|
10198
|
-
"
|
|
10204
|
+
elementsByStatus.loaded.length + elementsByStatus.missing.length + elementsByStatus.moved.length,
|
|
10205
|
+
" items"
|
|
10199
10206
|
] })
|
|
10200
10207
|
] }),
|
|
10201
10208
|
/* @__PURE__ */ jsx("div", { className: "rounded-lg border overflow-hidden", children: /* @__PURE__ */ jsxs(Table, { children: [
|
|
@@ -10206,7 +10213,7 @@ function DeliveryDetailPage({
|
|
|
10206
10213
|
/* @__PURE__ */ jsx(TableHead, { className: "font-semibold text-right", children: "Size (m\xB2)" }),
|
|
10207
10214
|
/* @__PURE__ */ jsx(TableHead, { className: "font-semibold text-center", children: "Status" })
|
|
10208
10215
|
] }) }),
|
|
10209
|
-
/* @__PURE__ */ jsx(TableBody, { children:
|
|
10216
|
+
/* @__PURE__ */ jsx(TableBody, { children: [...elementsByStatus.loaded, ...elementsByStatus.missing, ...elementsByStatus.moved].map((element) => /* @__PURE__ */ jsxs(
|
|
10210
10217
|
TableRow,
|
|
10211
10218
|
{
|
|
10212
10219
|
className: getElementRowBg(element.status),
|
|
@@ -10234,10 +10241,6 @@ function DeliveryDetailPage({
|
|
|
10234
10241
|
element.status === "moved" && element.actualDeliveryLabel && /* @__PURE__ */ jsxs("span", { className: "text-[9px] text-blue-600 dark:text-blue-400", children: [
|
|
10235
10242
|
"\u2192 ",
|
|
10236
10243
|
element.actualDeliveryLabel
|
|
10237
|
-
] }),
|
|
10238
|
-
element.status === "addon" && element.originalDeliveryLabel && /* @__PURE__ */ jsxs("span", { className: "text-[9px] text-purple-600 dark:text-purple-400", children: [
|
|
10239
|
-
"from ",
|
|
10240
|
-
element.originalDeliveryLabel
|
|
10241
10244
|
] })
|
|
10242
10245
|
] }) })
|
|
10243
10246
|
]
|
|
@@ -10246,10 +10249,48 @@ function DeliveryDetailPage({
|
|
|
10246
10249
|
)) })
|
|
10247
10250
|
] }) })
|
|
10248
10251
|
] }),
|
|
10252
|
+
elementsByStatus.addons.length > 0 && /* @__PURE__ */ jsxs("section", { className: "space-y-3", children: [
|
|
10253
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
10254
|
+
/* @__PURE__ */ jsx(Plus, { className: "h-4 w-4 text-purple-600 dark:text-purple-400" }),
|
|
10255
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: "Extra items (moved to this delivery)" }),
|
|
10256
|
+
/* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground ml-auto", children: [
|
|
10257
|
+
elementsByStatus.addons.length,
|
|
10258
|
+
" items"
|
|
10259
|
+
] })
|
|
10260
|
+
] }),
|
|
10261
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "These items were originally planned for other deliveries but have been moved to this one." }),
|
|
10262
|
+
/* @__PURE__ */ jsx("div", { className: "rounded-lg border border-purple-200 dark:border-purple-800 overflow-hidden", children: /* @__PURE__ */ jsxs(Table, { children: [
|
|
10263
|
+
/* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { className: "bg-purple-50/50 dark:bg-purple-950/30 hover:bg-purple-50/50 dark:hover:bg-purple-950/30", children: [
|
|
10264
|
+
/* @__PURE__ */ jsx(TableHead, { className: "font-semibold", children: "Prefix" }),
|
|
10265
|
+
/* @__PURE__ */ jsx(TableHead, { className: "font-semibold", children: "Type" }),
|
|
10266
|
+
/* @__PURE__ */ jsx(TableHead, { className: "font-semibold text-right", children: "Weight" }),
|
|
10267
|
+
/* @__PURE__ */ jsx(TableHead, { className: "font-semibold text-right", children: "Size (m\xB2)" }),
|
|
10268
|
+
/* @__PURE__ */ jsx(TableHead, { className: "font-semibold", children: "Moved from" })
|
|
10269
|
+
] }) }),
|
|
10270
|
+
/* @__PURE__ */ jsx(TableBody, { children: elementsByStatus.addons.map((element) => /* @__PURE__ */ jsxs(
|
|
10271
|
+
TableRow,
|
|
10272
|
+
{
|
|
10273
|
+
className: "bg-purple-50/30 dark:bg-purple-950/10",
|
|
10274
|
+
children: [
|
|
10275
|
+
/* @__PURE__ */ jsx(TableCell, { className: "font-medium", children: element.prefix }),
|
|
10276
|
+
/* @__PURE__ */ jsx(TableCell, { children: element.type }),
|
|
10277
|
+
/* @__PURE__ */ jsx(TableCell, { className: "text-right tabular-nums", children: element.weight ? /* @__PURE__ */ jsxs("span", { children: [
|
|
10278
|
+
element.weight,
|
|
10279
|
+
" ",
|
|
10280
|
+
element.weightUnit || "kg"
|
|
10281
|
+
] }) : "\u2014" }),
|
|
10282
|
+
/* @__PURE__ */ jsx(TableCell, { className: "text-right tabular-nums", children: element.sizeSqm ?? "\u2014" }),
|
|
10283
|
+
/* @__PURE__ */ jsx(TableCell, { children: element.originalDeliveryLabel ? /* @__PURE__ */ jsx("span", { className: "text-sm text-purple-600 dark:text-purple-400", children: element.originalDeliveryLabel }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2014" }) })
|
|
10284
|
+
]
|
|
10285
|
+
},
|
|
10286
|
+
element.id
|
|
10287
|
+
)) })
|
|
10288
|
+
] }) })
|
|
10289
|
+
] }),
|
|
10249
10290
|
/* @__PURE__ */ jsx(
|
|
10250
10291
|
CommentsSection,
|
|
10251
10292
|
{
|
|
10252
|
-
comments:
|
|
10293
|
+
comments: preLoadingComments,
|
|
10253
10294
|
delivery,
|
|
10254
10295
|
weekId: week.weekKey,
|
|
10255
10296
|
onAddComment
|
|
@@ -10286,6 +10327,9 @@ function SupplierWeeklyLoading({
|
|
|
10286
10327
|
}) {
|
|
10287
10328
|
const [selectedDelivery, setSelectedDelivery] = React27.useState(null);
|
|
10288
10329
|
const [sheetOpen, setSheetOpen] = React27.useState(false);
|
|
10330
|
+
const [commentDelivery, setCommentDelivery] = React27.useState(null);
|
|
10331
|
+
const [commentDialogOpen, setCommentDialogOpen] = React27.useState(false);
|
|
10332
|
+
const [commentText, setCommentText] = React27.useState("");
|
|
10289
10333
|
const handleDeliveryClick = (delivery) => {
|
|
10290
10334
|
setSelectedDelivery(delivery);
|
|
10291
10335
|
setSheetOpen(true);
|
|
@@ -10296,6 +10340,38 @@ function SupplierWeeklyLoading({
|
|
|
10296
10340
|
setTimeout(() => setSelectedDelivery(null), 200);
|
|
10297
10341
|
onBack?.();
|
|
10298
10342
|
};
|
|
10343
|
+
const handleDeliveryCommentClick = (delivery) => {
|
|
10344
|
+
setCommentDelivery(delivery);
|
|
10345
|
+
setCommentDialogOpen(true);
|
|
10346
|
+
};
|
|
10347
|
+
const handleCommentDialogClose = () => {
|
|
10348
|
+
setCommentDialogOpen(false);
|
|
10349
|
+
setCommentText("");
|
|
10350
|
+
setTimeout(() => setCommentDelivery(null), 200);
|
|
10351
|
+
};
|
|
10352
|
+
const handleCommentSubmit = () => {
|
|
10353
|
+
if (commentText.trim() && commentDelivery && onAddComment) {
|
|
10354
|
+
onAddComment({
|
|
10355
|
+
author: "Current User",
|
|
10356
|
+
// Would come from auth context in real app
|
|
10357
|
+
text: commentText.trim(),
|
|
10358
|
+
context: "pre_unloading",
|
|
10359
|
+
weekId: week.weekKey,
|
|
10360
|
+
deliveryId: commentDelivery.id,
|
|
10361
|
+
supplierId: commentDelivery.supplierId,
|
|
10362
|
+
supplierName: commentDelivery.supplierName,
|
|
10363
|
+
prefixId: commentDelivery.prefixScope,
|
|
10364
|
+
prefixName: commentDelivery.prefixScope
|
|
10365
|
+
});
|
|
10366
|
+
handleCommentDialogClose();
|
|
10367
|
+
}
|
|
10368
|
+
};
|
|
10369
|
+
const handleCommentKeyDown = (e) => {
|
|
10370
|
+
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
10371
|
+
e.preventDefault();
|
|
10372
|
+
handleCommentSubmit();
|
|
10373
|
+
}
|
|
10374
|
+
};
|
|
10299
10375
|
const Wrapper = bordered ? Card : "div";
|
|
10300
10376
|
const Content14 = bordered ? CardContent : "div";
|
|
10301
10377
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
@@ -10314,6 +10390,7 @@ function SupplierWeeklyLoading({
|
|
|
10314
10390
|
week,
|
|
10315
10391
|
deliveries,
|
|
10316
10392
|
onDeliveryClick: handleDeliveryClick,
|
|
10393
|
+
onDeliveryCommentClick: handleDeliveryCommentClick,
|
|
10317
10394
|
onWeekChange,
|
|
10318
10395
|
showNavigation
|
|
10319
10396
|
}
|
|
@@ -10342,7 +10419,58 @@ function SupplierWeeklyLoading({
|
|
|
10342
10419
|
)
|
|
10343
10420
|
]
|
|
10344
10421
|
}
|
|
10345
|
-
) })
|
|
10422
|
+
) }),
|
|
10423
|
+
/* @__PURE__ */ jsx(Dialog, { open: commentDialogOpen, onOpenChange: (open) => !open && handleCommentDialogClose(), children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-md", children: [
|
|
10424
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
10425
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: "Add pre-loading note" }),
|
|
10426
|
+
/* @__PURE__ */ jsxs(DialogDescription, { children: [
|
|
10427
|
+
"Add a note for ",
|
|
10428
|
+
/* @__PURE__ */ jsx("strong", { children: commentDelivery?.label }),
|
|
10429
|
+
" (",
|
|
10430
|
+
commentDelivery?.supplierName,
|
|
10431
|
+
commentDelivery?.prefixScope && ` \u2022 ${commentDelivery.prefixScope}`,
|
|
10432
|
+
")."
|
|
10433
|
+
] })
|
|
10434
|
+
] }),
|
|
10435
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-4 py-2", children: /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
10436
|
+
/* @__PURE__ */ jsx(Label2, { htmlFor: "card-comment-text", className: "text-sm font-medium", children: "Note" }),
|
|
10437
|
+
/* @__PURE__ */ jsx(
|
|
10438
|
+
Textarea,
|
|
10439
|
+
{
|
|
10440
|
+
id: "card-comment-text",
|
|
10441
|
+
placeholder: "Add a note before loading...",
|
|
10442
|
+
value: commentText,
|
|
10443
|
+
onChange: (e) => setCommentText(e.target.value),
|
|
10444
|
+
onKeyDown: handleCommentKeyDown,
|
|
10445
|
+
className: "min-h-[120px] text-base resize-none",
|
|
10446
|
+
autoFocus: true
|
|
10447
|
+
}
|
|
10448
|
+
),
|
|
10449
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: "\u2318+Enter to save" })
|
|
10450
|
+
] }) }),
|
|
10451
|
+
/* @__PURE__ */ jsxs(DialogFooter, { className: "gap-2 sm:gap-0", children: [
|
|
10452
|
+
/* @__PURE__ */ jsx(
|
|
10453
|
+
Button,
|
|
10454
|
+
{
|
|
10455
|
+
variant: "ghost",
|
|
10456
|
+
onClick: handleCommentDialogClose,
|
|
10457
|
+
children: "Cancel"
|
|
10458
|
+
}
|
|
10459
|
+
),
|
|
10460
|
+
/* @__PURE__ */ jsxs(
|
|
10461
|
+
Button,
|
|
10462
|
+
{
|
|
10463
|
+
onClick: handleCommentSubmit,
|
|
10464
|
+
disabled: !commentText.trim(),
|
|
10465
|
+
className: "gap-1.5",
|
|
10466
|
+
children: [
|
|
10467
|
+
/* @__PURE__ */ jsx(Send, { className: "h-4 w-4" }),
|
|
10468
|
+
"Save note"
|
|
10469
|
+
]
|
|
10470
|
+
}
|
|
10471
|
+
)
|
|
10472
|
+
] })
|
|
10473
|
+
] }) })
|
|
10346
10474
|
] });
|
|
10347
10475
|
}
|
|
10348
10476
|
function getStatusBadgeVariant3(status) {
|
|
@@ -10853,11 +10981,11 @@ function getVisibleHours(visibleHours, singleDayEvents) {
|
|
|
10853
10981
|
function getCalendarCells(selectedDate) {
|
|
10854
10982
|
const currentYear = selectedDate.getFullYear();
|
|
10855
10983
|
const currentMonth = selectedDate.getMonth();
|
|
10856
|
-
const
|
|
10984
|
+
const getDaysInMonth2 = (year, month) => new Date(year, month + 1, 0).getDate();
|
|
10857
10985
|
const getFirstDayOfMonth = (year, month) => new Date(year, month, 1).getDay();
|
|
10858
|
-
const daysInMonth =
|
|
10986
|
+
const daysInMonth = getDaysInMonth2(currentYear, currentMonth);
|
|
10859
10987
|
const firstDayOfMonth = getFirstDayOfMonth(currentYear, currentMonth);
|
|
10860
|
-
const daysInPrevMonth =
|
|
10988
|
+
const daysInPrevMonth = getDaysInMonth2(currentYear, currentMonth - 1);
|
|
10861
10989
|
const totalDays = firstDayOfMonth + daysInMonth;
|
|
10862
10990
|
const prevMonthCells = Array.from({ length: firstDayOfMonth }, (_, i) => ({
|
|
10863
10991
|
day: daysInPrevMonth - firstDayOfMonth + i + 1,
|
|
@@ -13578,7 +13706,1570 @@ function CalendarView({
|
|
|
13578
13706
|
return null;
|
|
13579
13707
|
}
|
|
13580
13708
|
}
|
|
13709
|
+
var draggingAtom = atom(false);
|
|
13710
|
+
var scrollXAtom = atom(0);
|
|
13711
|
+
var useGanttDragging = () => useAtom(draggingAtom);
|
|
13712
|
+
var useGanttScrollX = () => useAtom(scrollXAtom);
|
|
13713
|
+
var getDifferenceIn = (range) => {
|
|
13714
|
+
if (range === "weekly") {
|
|
13715
|
+
return differenceInWeeks;
|
|
13716
|
+
}
|
|
13717
|
+
return differenceInMonths;
|
|
13718
|
+
};
|
|
13719
|
+
var getInnerDifferenceIn = (range) => {
|
|
13720
|
+
if (range === "weekly") {
|
|
13721
|
+
return differenceInDays;
|
|
13722
|
+
}
|
|
13723
|
+
return differenceInDays;
|
|
13724
|
+
};
|
|
13725
|
+
var getStartOf = (range) => {
|
|
13726
|
+
if (range === "weekly") {
|
|
13727
|
+
return (date) => startOfWeek(date, { weekStartsOn: 1 });
|
|
13728
|
+
}
|
|
13729
|
+
return startOfMonth;
|
|
13730
|
+
};
|
|
13731
|
+
var getEndOf = (range) => {
|
|
13732
|
+
if (range === "weekly") {
|
|
13733
|
+
return (date) => endOfWeek(date, { weekStartsOn: 1 });
|
|
13734
|
+
}
|
|
13735
|
+
return endOfMonth;
|
|
13736
|
+
};
|
|
13737
|
+
var getAddRange = (range) => {
|
|
13738
|
+
if (range === "weekly") {
|
|
13739
|
+
return addWeeks;
|
|
13740
|
+
}
|
|
13741
|
+
return addMonths;
|
|
13742
|
+
};
|
|
13743
|
+
var getDateByMousePosition = (context, mouseX) => {
|
|
13744
|
+
const columnWidth = context.columnWidth * context.zoom / 100;
|
|
13745
|
+
const offset = Math.floor(mouseX / columnWidth);
|
|
13746
|
+
const addRange = getAddRange(context.range);
|
|
13747
|
+
if (context.range === "weekly") {
|
|
13748
|
+
const firstYear = context.timelineData[0].year;
|
|
13749
|
+
const weekStart = getWeekStartDate(firstYear, 1);
|
|
13750
|
+
const targetWeekStart = addRange(weekStart, offset);
|
|
13751
|
+
const pixelsPerDay2 = columnWidth / 7;
|
|
13752
|
+
const dayOffset2 = Math.floor(mouseX % columnWidth / pixelsPerDay2);
|
|
13753
|
+
return addDays(targetWeekStart, dayOffset2);
|
|
13754
|
+
}
|
|
13755
|
+
const timelineStartDate = new Date(context.timelineData[0].year, 0, 1);
|
|
13756
|
+
const month = addRange(timelineStartDate, offset);
|
|
13757
|
+
const daysInMonth = getDaysInMonth(month);
|
|
13758
|
+
const pixelsPerDay = Math.round(columnWidth / daysInMonth);
|
|
13759
|
+
const dayOffset = Math.floor(mouseX % columnWidth / pixelsPerDay);
|
|
13760
|
+
return addDays(month, dayOffset);
|
|
13761
|
+
};
|
|
13762
|
+
var createInitialTimelineData = (today) => {
|
|
13763
|
+
const data = [];
|
|
13764
|
+
data.push(
|
|
13765
|
+
{ year: today.getFullYear() - 1, quarters: new Array(4).fill(null) },
|
|
13766
|
+
{ year: today.getFullYear(), quarters: new Array(4).fill(null) },
|
|
13767
|
+
{ year: today.getFullYear() + 1, quarters: new Array(4).fill(null) }
|
|
13768
|
+
);
|
|
13769
|
+
for (const yearObj of data) {
|
|
13770
|
+
yearObj.quarters = new Array(4).fill(null).map((_, quarterIndex) => ({
|
|
13771
|
+
months: new Array(3).fill(null).map((_2, monthIndex) => {
|
|
13772
|
+
const month = quarterIndex * 3 + monthIndex;
|
|
13773
|
+
return {
|
|
13774
|
+
days: getDaysInMonth(new Date(yearObj.year, month, 1))
|
|
13775
|
+
};
|
|
13776
|
+
})
|
|
13777
|
+
}));
|
|
13778
|
+
}
|
|
13779
|
+
return data;
|
|
13780
|
+
};
|
|
13781
|
+
var getOffset = (date, timelineStartDate, context) => {
|
|
13782
|
+
const parsedColumnWidth = context.columnWidth * context.zoom / 100;
|
|
13783
|
+
const differenceIn = getDifferenceIn(context.range);
|
|
13784
|
+
const startOf = getStartOf(context.range);
|
|
13785
|
+
const fullColumns = differenceIn(startOf(date), startOf(timelineStartDate));
|
|
13786
|
+
if (context.range === "weekly") {
|
|
13787
|
+
const weekStart = startOf(date);
|
|
13788
|
+
const dayOfWeek = differenceInDays(date, weekStart);
|
|
13789
|
+
const pixelsPerDay2 = parsedColumnWidth / 7;
|
|
13790
|
+
return fullColumns * parsedColumnWidth + dayOfWeek * pixelsPerDay2;
|
|
13791
|
+
}
|
|
13792
|
+
const partialColumns = date.getDate();
|
|
13793
|
+
const daysInMonth = getDaysInMonth(date);
|
|
13794
|
+
const pixelsPerDay = parsedColumnWidth / daysInMonth;
|
|
13795
|
+
return fullColumns * parsedColumnWidth + partialColumns * pixelsPerDay;
|
|
13796
|
+
};
|
|
13797
|
+
var getWidth = (startAt, endAt, context) => {
|
|
13798
|
+
const parsedColumnWidth = context.columnWidth * context.zoom / 100;
|
|
13799
|
+
if (!endAt) {
|
|
13800
|
+
return parsedColumnWidth * 2;
|
|
13801
|
+
}
|
|
13802
|
+
const startOf = getStartOf(context.range);
|
|
13803
|
+
if (context.range === "weekly") {
|
|
13804
|
+
const pixelsPerDay = parsedColumnWidth / 7;
|
|
13805
|
+
const daysDiff = differenceInDays(endAt, startAt);
|
|
13806
|
+
return Math.max(pixelsPerDay, daysDiff * pixelsPerDay);
|
|
13807
|
+
}
|
|
13808
|
+
const differenceIn = getDifferenceIn(context.range);
|
|
13809
|
+
const daysInStartMonth = getDaysInMonth(startAt);
|
|
13810
|
+
const pixelsPerDayInStartMonth = parsedColumnWidth / daysInStartMonth;
|
|
13811
|
+
if (isSameDay(startAt, endAt)) {
|
|
13812
|
+
return pixelsPerDayInStartMonth;
|
|
13813
|
+
}
|
|
13814
|
+
const innerDifferenceIn = getInnerDifferenceIn(context.range);
|
|
13815
|
+
if (isSameDay(startOf(startAt), startOf(endAt))) {
|
|
13816
|
+
return innerDifferenceIn(endAt, startAt) * pixelsPerDayInStartMonth;
|
|
13817
|
+
}
|
|
13818
|
+
const startRangeOffset = daysInStartMonth - getDate(startAt);
|
|
13819
|
+
const endRangeOffset = getDate(endAt);
|
|
13820
|
+
const fullRangeOffset = differenceIn(startOf(endAt), startOf(startAt));
|
|
13821
|
+
const daysInEndMonth = getDaysInMonth(endAt);
|
|
13822
|
+
const pixelsPerDayInEndMonth = parsedColumnWidth / daysInEndMonth;
|
|
13823
|
+
return (fullRangeOffset - 1) * parsedColumnWidth + startRangeOffset * pixelsPerDayInStartMonth + endRangeOffset * pixelsPerDayInEndMonth;
|
|
13824
|
+
};
|
|
13825
|
+
var calculateInnerOffset = (date, range, columnWidth) => {
|
|
13826
|
+
const startOf = getStartOf(range);
|
|
13827
|
+
const endOf = getEndOf(range);
|
|
13828
|
+
const startOfRange = startOf(date);
|
|
13829
|
+
const endOfRange = endOf(date);
|
|
13830
|
+
if (range === "weekly") {
|
|
13831
|
+
const dayOfWeek = differenceInDays(date, startOfRange);
|
|
13832
|
+
return dayOfWeek / 7 * columnWidth;
|
|
13833
|
+
}
|
|
13834
|
+
const totalRangeDays = differenceInDays(endOfRange, startOfRange);
|
|
13835
|
+
const dayOfMonth = date.getDate();
|
|
13836
|
+
return dayOfMonth / totalRangeDays * columnWidth;
|
|
13837
|
+
};
|
|
13838
|
+
var GanttContext = createContext({
|
|
13839
|
+
zoom: 100,
|
|
13840
|
+
range: "monthly",
|
|
13841
|
+
columnWidth: 50,
|
|
13842
|
+
headerHeight: 60,
|
|
13843
|
+
sidebarWidth: 300,
|
|
13844
|
+
rowHeight: 36,
|
|
13845
|
+
onAddItem: void 0,
|
|
13846
|
+
placeholderLength: 2,
|
|
13847
|
+
timelineData: [],
|
|
13848
|
+
ref: null,
|
|
13849
|
+
scrollToFeature: void 0,
|
|
13850
|
+
expandedGroups: {},
|
|
13851
|
+
setGroupExpanded: () => {
|
|
13852
|
+
}
|
|
13853
|
+
});
|
|
13854
|
+
var GanttContentHeader = ({
|
|
13855
|
+
title,
|
|
13856
|
+
columns,
|
|
13857
|
+
renderHeaderItem
|
|
13858
|
+
}) => {
|
|
13859
|
+
const id = useId();
|
|
13860
|
+
return /* @__PURE__ */ jsxs(
|
|
13861
|
+
"div",
|
|
13862
|
+
{
|
|
13863
|
+
className: "sticky top-0 z-20 grid w-full shrink-0 bg-background/95 backdrop-blur-sm",
|
|
13864
|
+
style: { height: "var(--gantt-header-height)" },
|
|
13865
|
+
children: [
|
|
13866
|
+
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
|
|
13867
|
+
"div",
|
|
13868
|
+
{
|
|
13869
|
+
className: "sticky inline-flex whitespace-nowrap px-3 py-2 text-muted-foreground text-xs",
|
|
13870
|
+
style: {
|
|
13871
|
+
left: "var(--gantt-sidebar-width)"
|
|
13872
|
+
},
|
|
13873
|
+
children: /* @__PURE__ */ jsx("p", { children: title })
|
|
13874
|
+
}
|
|
13875
|
+
) }),
|
|
13876
|
+
/* @__PURE__ */ jsx(
|
|
13877
|
+
"div",
|
|
13878
|
+
{
|
|
13879
|
+
className: "grid w-full",
|
|
13880
|
+
style: {
|
|
13881
|
+
gridTemplateColumns: `repeat(${columns}, var(--gantt-column-width))`
|
|
13882
|
+
},
|
|
13883
|
+
children: Array.from({ length: columns }).map((_, index) => /* @__PURE__ */ jsx(
|
|
13884
|
+
"div",
|
|
13885
|
+
{
|
|
13886
|
+
className: "shrink-0 border-border/50 border-b py-1 text-center text-xs",
|
|
13887
|
+
children: renderHeaderItem(index)
|
|
13888
|
+
},
|
|
13889
|
+
`${id}-${index}`
|
|
13890
|
+
))
|
|
13891
|
+
}
|
|
13892
|
+
)
|
|
13893
|
+
]
|
|
13894
|
+
}
|
|
13895
|
+
);
|
|
13896
|
+
};
|
|
13897
|
+
var getWeeksInYear = (year) => {
|
|
13898
|
+
const dec28 = new Date(year, 11, 28);
|
|
13899
|
+
return getISOWeek$1(dec28);
|
|
13900
|
+
};
|
|
13901
|
+
var getWeekStartDate = (year, weekNumber) => {
|
|
13902
|
+
const jan4 = new Date(year, 0, 4);
|
|
13903
|
+
const week1Start = startOfWeek(jan4, { weekStartsOn: 1 });
|
|
13904
|
+
return addWeeks(week1Start, weekNumber - 1);
|
|
13905
|
+
};
|
|
13906
|
+
var WeeklyHeader = () => {
|
|
13907
|
+
const gantt = useContext(GanttContext);
|
|
13908
|
+
const weeklyData = useMemo(() => {
|
|
13909
|
+
const result = [];
|
|
13910
|
+
for (const yearData of gantt.timelineData) {
|
|
13911
|
+
const year = yearData.year;
|
|
13912
|
+
const weeksInYear = getWeeksInYear(year);
|
|
13913
|
+
const weeks = [];
|
|
13914
|
+
for (let w = 1; w <= weeksInYear; w++) {
|
|
13915
|
+
weeks.push({
|
|
13916
|
+
weekNumber: w,
|
|
13917
|
+
startDate: getWeekStartDate(year, w)
|
|
13918
|
+
});
|
|
13919
|
+
}
|
|
13920
|
+
result.push({ year, weeks });
|
|
13921
|
+
}
|
|
13922
|
+
return result;
|
|
13923
|
+
}, [gantt.timelineData]);
|
|
13924
|
+
return weeklyData.map((yearData) => /* @__PURE__ */ jsxs("div", { className: "relative flex flex-col", children: [
|
|
13925
|
+
/* @__PURE__ */ jsx(
|
|
13926
|
+
GanttContentHeader,
|
|
13927
|
+
{
|
|
13928
|
+
columns: yearData.weeks.length,
|
|
13929
|
+
renderHeaderItem: (weekIndex) => {
|
|
13930
|
+
const week = yearData.weeks[weekIndex];
|
|
13931
|
+
return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center", children: /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
|
|
13932
|
+
"W",
|
|
13933
|
+
week.weekNumber.toString().padStart(2, "0")
|
|
13934
|
+
] }) });
|
|
13935
|
+
},
|
|
13936
|
+
title: `${yearData.year}`
|
|
13937
|
+
}
|
|
13938
|
+
),
|
|
13939
|
+
/* @__PURE__ */ jsx(GanttColumns, { columns: yearData.weeks.length })
|
|
13940
|
+
] }, yearData.year));
|
|
13941
|
+
};
|
|
13942
|
+
var MonthlyHeader = () => {
|
|
13943
|
+
const gantt = useContext(GanttContext);
|
|
13944
|
+
return gantt.timelineData.map((year) => /* @__PURE__ */ jsxs("div", { className: "relative flex flex-col", children: [
|
|
13945
|
+
/* @__PURE__ */ jsx(
|
|
13946
|
+
GanttContentHeader,
|
|
13947
|
+
{
|
|
13948
|
+
columns: year.quarters.flatMap((quarter) => quarter.months).length,
|
|
13949
|
+
renderHeaderItem: (item) => /* @__PURE__ */ jsx("p", { children: format(new Date(year.year, item, 1), "MMM") }),
|
|
13950
|
+
title: `${year.year}`
|
|
13951
|
+
}
|
|
13952
|
+
),
|
|
13953
|
+
/* @__PURE__ */ jsx(
|
|
13954
|
+
GanttColumns,
|
|
13955
|
+
{
|
|
13956
|
+
columns: year.quarters.flatMap((quarter) => quarter.months).length
|
|
13957
|
+
}
|
|
13958
|
+
)
|
|
13959
|
+
] }, year.year));
|
|
13960
|
+
};
|
|
13961
|
+
var QuarterlyHeader = () => {
|
|
13962
|
+
const gantt = useContext(GanttContext);
|
|
13963
|
+
return gantt.timelineData.map(
|
|
13964
|
+
(year) => year.quarters.map((quarter, quarterIndex) => /* @__PURE__ */ jsxs(
|
|
13965
|
+
"div",
|
|
13966
|
+
{
|
|
13967
|
+
className: "relative flex flex-col",
|
|
13968
|
+
children: [
|
|
13969
|
+
/* @__PURE__ */ jsx(
|
|
13970
|
+
GanttContentHeader,
|
|
13971
|
+
{
|
|
13972
|
+
columns: quarter.months.length,
|
|
13973
|
+
renderHeaderItem: (item) => /* @__PURE__ */ jsx("p", { children: format(new Date(year.year, quarterIndex * 3 + item, 1), "MMM") }),
|
|
13974
|
+
title: `Q${quarterIndex + 1} ${year.year}`
|
|
13975
|
+
}
|
|
13976
|
+
),
|
|
13977
|
+
/* @__PURE__ */ jsx(GanttColumns, { columns: quarter.months.length })
|
|
13978
|
+
]
|
|
13979
|
+
},
|
|
13980
|
+
`${year.year}-${quarterIndex}`
|
|
13981
|
+
))
|
|
13982
|
+
);
|
|
13983
|
+
};
|
|
13984
|
+
var headers = {
|
|
13985
|
+
weekly: WeeklyHeader,
|
|
13986
|
+
monthly: MonthlyHeader,
|
|
13987
|
+
quarterly: QuarterlyHeader
|
|
13988
|
+
};
|
|
13989
|
+
var GanttHeader = ({ className }) => {
|
|
13990
|
+
const gantt = useContext(GanttContext);
|
|
13991
|
+
const Header2 = headers[gantt.range];
|
|
13992
|
+
return /* @__PURE__ */ jsx(
|
|
13993
|
+
"div",
|
|
13994
|
+
{
|
|
13995
|
+
className: cn(
|
|
13996
|
+
"-space-x-px flex h-full w-max divide-x-2 divide-border",
|
|
13997
|
+
className
|
|
13998
|
+
),
|
|
13999
|
+
children: /* @__PURE__ */ jsx(Header2, {})
|
|
14000
|
+
}
|
|
14001
|
+
);
|
|
14002
|
+
};
|
|
14003
|
+
var GanttSidebarItem = ({
|
|
14004
|
+
feature,
|
|
14005
|
+
onSelectItem,
|
|
14006
|
+
className
|
|
14007
|
+
}) => {
|
|
14008
|
+
const gantt = useContext(GanttContext);
|
|
14009
|
+
const tempEndAt = feature.endAt && isSameDay(feature.startAt, feature.endAt) ? addDays(feature.endAt, 1) : feature.endAt;
|
|
14010
|
+
const duration = tempEndAt ? formatDistance(feature.startAt, tempEndAt) : `${formatDistance(feature.startAt, /* @__PURE__ */ new Date())} so far`;
|
|
14011
|
+
const handleClick = (event) => {
|
|
14012
|
+
if (event.target === event.currentTarget) {
|
|
14013
|
+
gantt.scrollToFeature?.(feature);
|
|
14014
|
+
onSelectItem?.(feature.id);
|
|
14015
|
+
}
|
|
14016
|
+
};
|
|
14017
|
+
const handleKeyDown = (event) => {
|
|
14018
|
+
if (event.key === "Enter") {
|
|
14019
|
+
gantt.scrollToFeature?.(feature);
|
|
14020
|
+
onSelectItem?.(feature.id);
|
|
14021
|
+
}
|
|
14022
|
+
};
|
|
14023
|
+
return /* @__PURE__ */ jsxs(
|
|
14024
|
+
"div",
|
|
14025
|
+
{
|
|
14026
|
+
className: cn(
|
|
14027
|
+
"relative flex items-center gap-2.5 px-2.5 py-1.5 text-xs hover:bg-muted/50 border-b border-border/30",
|
|
14028
|
+
className
|
|
14029
|
+
),
|
|
14030
|
+
onClick: handleClick,
|
|
14031
|
+
onKeyDown: handleKeyDown,
|
|
14032
|
+
role: "button",
|
|
14033
|
+
style: {
|
|
14034
|
+
height: "var(--gantt-row-height)"
|
|
14035
|
+
},
|
|
14036
|
+
tabIndex: 0,
|
|
14037
|
+
children: [
|
|
14038
|
+
/* @__PURE__ */ jsx(
|
|
14039
|
+
"div",
|
|
14040
|
+
{
|
|
14041
|
+
className: "pointer-events-none h-2 w-2 shrink-0 rounded-full",
|
|
14042
|
+
style: {
|
|
14043
|
+
backgroundColor: feature.status.color
|
|
14044
|
+
}
|
|
14045
|
+
}
|
|
14046
|
+
),
|
|
14047
|
+
/* @__PURE__ */ jsx("p", { className: "pointer-events-none flex-1 truncate text-left font-medium", children: feature.name }),
|
|
14048
|
+
/* @__PURE__ */ jsx("p", { className: "pointer-events-none text-muted-foreground text-[11px]", children: duration })
|
|
14049
|
+
]
|
|
14050
|
+
},
|
|
14051
|
+
feature.id
|
|
14052
|
+
);
|
|
14053
|
+
};
|
|
14054
|
+
var GanttSidebarHeader = ({
|
|
14055
|
+
title = "Tasks",
|
|
14056
|
+
durationLabel = "Duration"
|
|
14057
|
+
}) => /* @__PURE__ */ jsxs(
|
|
14058
|
+
"div",
|
|
14059
|
+
{
|
|
14060
|
+
className: "sticky top-0 z-10 flex shrink-0 items-end justify-between gap-2.5 border-border/50 border-b bg-background/95 px-2.5 py-2 font-medium text-muted-foreground text-xs backdrop-blur-sm",
|
|
14061
|
+
style: { height: "var(--gantt-header-height)" },
|
|
14062
|
+
children: [
|
|
14063
|
+
/* @__PURE__ */ jsx("p", { className: "flex-1 truncate text-left", children: title }),
|
|
14064
|
+
/* @__PURE__ */ jsx("p", { className: "shrink-0", children: durationLabel })
|
|
14065
|
+
]
|
|
14066
|
+
}
|
|
14067
|
+
);
|
|
14068
|
+
function computeGroupRange(features) {
|
|
14069
|
+
if (features.length === 0) {
|
|
14070
|
+
return { start: null, end: null };
|
|
14071
|
+
}
|
|
14072
|
+
let minStart = features[0].startAt;
|
|
14073
|
+
let maxEnd = features[0].endAt;
|
|
14074
|
+
for (const feature of features) {
|
|
14075
|
+
if (feature.startAt < minStart) {
|
|
14076
|
+
minStart = feature.startAt;
|
|
14077
|
+
}
|
|
14078
|
+
if (feature.endAt > maxEnd) {
|
|
14079
|
+
maxEnd = feature.endAt;
|
|
14080
|
+
}
|
|
14081
|
+
}
|
|
14082
|
+
return { start: minStart, end: maxEnd };
|
|
14083
|
+
}
|
|
14084
|
+
var GanttGroupSummaryBar = memo(({
|
|
14085
|
+
group,
|
|
14086
|
+
className
|
|
14087
|
+
}) => {
|
|
14088
|
+
const gantt = useContext(GanttContext);
|
|
14089
|
+
const timelineStartDate = useMemo(
|
|
14090
|
+
() => new Date(gantt.timelineData.at(0)?.year ?? 0, 0, 1),
|
|
14091
|
+
[gantt.timelineData]
|
|
14092
|
+
);
|
|
14093
|
+
const { start: groupStart, end: groupEnd } = useMemo(
|
|
14094
|
+
() => computeGroupRange(group.features),
|
|
14095
|
+
[group.features]
|
|
14096
|
+
);
|
|
14097
|
+
const offset = useMemo(() => {
|
|
14098
|
+
if (!groupStart) return 0;
|
|
14099
|
+
return Math.round(getOffset(groupStart, timelineStartDate, gantt));
|
|
14100
|
+
}, [groupStart, timelineStartDate, gantt]);
|
|
14101
|
+
const width = useMemo(() => {
|
|
14102
|
+
if (!groupStart || !groupEnd) return 0;
|
|
14103
|
+
return Math.round(getWidth(groupStart, groupEnd, gantt));
|
|
14104
|
+
}, [groupStart, groupEnd, gantt]);
|
|
14105
|
+
if (!groupStart || !groupEnd || width === 0) {
|
|
14106
|
+
return null;
|
|
14107
|
+
}
|
|
14108
|
+
return /* @__PURE__ */ jsx(
|
|
14109
|
+
"div",
|
|
14110
|
+
{
|
|
14111
|
+
className: cn(
|
|
14112
|
+
"absolute pointer-events-none",
|
|
14113
|
+
className
|
|
14114
|
+
),
|
|
14115
|
+
style: {
|
|
14116
|
+
height: "calc(var(--gantt-row-height) - 12px)",
|
|
14117
|
+
top: "6px",
|
|
14118
|
+
width,
|
|
14119
|
+
left: offset
|
|
14120
|
+
},
|
|
14121
|
+
children: /* @__PURE__ */ jsx(
|
|
14122
|
+
"div",
|
|
14123
|
+
{
|
|
14124
|
+
className: "h-full w-full rounded-sm border border-border/60 bg-muted/40 shadow-sm",
|
|
14125
|
+
style: {
|
|
14126
|
+
// Subtle gradient for depth
|
|
14127
|
+
background: "linear-gradient(180deg, hsl(var(--muted) / 0.5) 0%, hsl(var(--muted) / 0.3) 100%)"
|
|
14128
|
+
}
|
|
14129
|
+
}
|
|
14130
|
+
)
|
|
14131
|
+
}
|
|
14132
|
+
);
|
|
14133
|
+
});
|
|
14134
|
+
GanttGroupSummaryBar.displayName = "GanttGroupSummaryBar";
|
|
14135
|
+
var GanttCollapsibleSidebarGroup = ({
|
|
14136
|
+
group,
|
|
14137
|
+
children,
|
|
14138
|
+
className
|
|
14139
|
+
}) => {
|
|
14140
|
+
const gantt = useContext(GanttContext);
|
|
14141
|
+
const isExpanded = gantt.expandedGroups[group.id] ?? true;
|
|
14142
|
+
const { start: groupStart, end: groupEnd } = useMemo(
|
|
14143
|
+
() => computeGroupRange(group.features),
|
|
14144
|
+
[group.features]
|
|
14145
|
+
);
|
|
14146
|
+
const duration = useMemo(() => {
|
|
14147
|
+
if (!groupStart || !groupEnd) return null;
|
|
14148
|
+
return formatDistance(groupStart, groupEnd);
|
|
14149
|
+
}, [groupStart, groupEnd]);
|
|
14150
|
+
return /* @__PURE__ */ jsxs(
|
|
14151
|
+
Collapsible,
|
|
14152
|
+
{
|
|
14153
|
+
open: isExpanded,
|
|
14154
|
+
onOpenChange: (open) => gantt.setGroupExpanded(group.id, open),
|
|
14155
|
+
className,
|
|
14156
|
+
children: [
|
|
14157
|
+
/* @__PURE__ */ jsx(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
14158
|
+
"button",
|
|
14159
|
+
{
|
|
14160
|
+
className: "flex w-full items-center gap-2 px-2.5 py-2 text-left font-medium text-xs hover:bg-muted/30 border-b border-border/50 bg-background",
|
|
14161
|
+
style: { height: "var(--gantt-row-height)" },
|
|
14162
|
+
type: "button",
|
|
14163
|
+
children: [
|
|
14164
|
+
/* @__PURE__ */ jsx(
|
|
14165
|
+
ChevronRightIcon,
|
|
14166
|
+
{
|
|
14167
|
+
className: cn(
|
|
14168
|
+
"h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200",
|
|
14169
|
+
isExpanded && "rotate-90"
|
|
14170
|
+
)
|
|
14171
|
+
}
|
|
14172
|
+
),
|
|
14173
|
+
group.icon && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-muted-foreground", children: group.icon }),
|
|
14174
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 truncate", children: group.title }),
|
|
14175
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 rounded-full bg-muted px-2 py-0.5 text-[10px] text-muted-foreground", children: group.features.length }),
|
|
14176
|
+
duration && /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[10px] text-muted-foreground", children: duration })
|
|
14177
|
+
]
|
|
14178
|
+
}
|
|
14179
|
+
) }),
|
|
14180
|
+
/* @__PURE__ */ jsx(CollapsibleContent2, { className: "[&[data-state]]:!opacity-100", children })
|
|
14181
|
+
]
|
|
14182
|
+
}
|
|
14183
|
+
);
|
|
14184
|
+
};
|
|
14185
|
+
var GanttCollapsibleTimelineGroup = ({
|
|
14186
|
+
group,
|
|
14187
|
+
children,
|
|
14188
|
+
className
|
|
14189
|
+
}) => {
|
|
14190
|
+
const gantt = useContext(GanttContext);
|
|
14191
|
+
const isExpanded = gantt.expandedGroups[group.id] ?? true;
|
|
14192
|
+
return /* @__PURE__ */ jsxs(
|
|
14193
|
+
Collapsible,
|
|
14194
|
+
{
|
|
14195
|
+
open: isExpanded,
|
|
14196
|
+
onOpenChange: (open) => gantt.setGroupExpanded(group.id, open),
|
|
14197
|
+
className,
|
|
14198
|
+
children: [
|
|
14199
|
+
/* @__PURE__ */ jsx(
|
|
14200
|
+
"div",
|
|
14201
|
+
{
|
|
14202
|
+
className: "relative w-full border-b border-border/50",
|
|
14203
|
+
style: { height: "var(--gantt-row-height)" },
|
|
14204
|
+
children: /* @__PURE__ */ jsx(GanttGroupSummaryBar, { group })
|
|
14205
|
+
}
|
|
14206
|
+
),
|
|
14207
|
+
/* @__PURE__ */ jsx(CollapsibleContent2, { className: "[&[data-state]]:!opacity-100", children })
|
|
14208
|
+
]
|
|
14209
|
+
}
|
|
14210
|
+
);
|
|
14211
|
+
};
|
|
14212
|
+
var GanttSidebarGroup = ({
|
|
14213
|
+
children,
|
|
14214
|
+
name,
|
|
14215
|
+
className
|
|
14216
|
+
}) => /* @__PURE__ */ jsxs("div", { className, children: [
|
|
14217
|
+
/* @__PURE__ */ jsx(
|
|
14218
|
+
"p",
|
|
14219
|
+
{
|
|
14220
|
+
className: "w-full truncate px-2.5 py-2 text-left font-medium text-muted-foreground text-xs border-b border-border/50 bg-background",
|
|
14221
|
+
style: { height: "var(--gantt-row-height)" },
|
|
14222
|
+
children: name
|
|
14223
|
+
}
|
|
14224
|
+
),
|
|
14225
|
+
/* @__PURE__ */ jsx("div", { children })
|
|
14226
|
+
] });
|
|
14227
|
+
var GanttSidebar = ({
|
|
14228
|
+
children,
|
|
14229
|
+
className
|
|
14230
|
+
}) => /* @__PURE__ */ jsxs(
|
|
14231
|
+
"div",
|
|
14232
|
+
{
|
|
14233
|
+
className: cn(
|
|
14234
|
+
"sticky left-0 z-30 h-max min-h-full border-border/50 border-r bg-background",
|
|
14235
|
+
className
|
|
14236
|
+
),
|
|
14237
|
+
style: { width: "var(--gantt-sidebar-width)" },
|
|
14238
|
+
"data-roadmap-ui": "gantt-sidebar",
|
|
14239
|
+
children: [
|
|
14240
|
+
/* @__PURE__ */ jsx(GanttSidebarHeader, {}),
|
|
14241
|
+
/* @__PURE__ */ jsx("div", { children })
|
|
14242
|
+
]
|
|
14243
|
+
}
|
|
14244
|
+
);
|
|
14245
|
+
var GanttAddFeatureHelper = ({
|
|
14246
|
+
top,
|
|
14247
|
+
className
|
|
14248
|
+
}) => {
|
|
14249
|
+
const [scrollX] = useGanttScrollX();
|
|
14250
|
+
const gantt = useContext(GanttContext);
|
|
14251
|
+
const [mousePosition, mouseRef] = useMouse();
|
|
14252
|
+
const handleClick = () => {
|
|
14253
|
+
const ganttRect = gantt.ref?.current?.getBoundingClientRect();
|
|
14254
|
+
const x = mousePosition.x - (ganttRect?.left ?? 0) + scrollX - gantt.sidebarWidth;
|
|
14255
|
+
const currentDate = getDateByMousePosition(gantt, x);
|
|
14256
|
+
gantt.onAddItem?.(currentDate);
|
|
14257
|
+
};
|
|
14258
|
+
return /* @__PURE__ */ jsx(
|
|
14259
|
+
"div",
|
|
14260
|
+
{
|
|
14261
|
+
className: cn("absolute top-0 w-full px-0.5", className),
|
|
14262
|
+
ref: mouseRef,
|
|
14263
|
+
style: {
|
|
14264
|
+
marginTop: -gantt.rowHeight / 2,
|
|
14265
|
+
transform: `translateY(${top}px)`
|
|
14266
|
+
},
|
|
14267
|
+
children: /* @__PURE__ */ jsx(
|
|
14268
|
+
"button",
|
|
14269
|
+
{
|
|
14270
|
+
className: "flex h-full w-full items-center justify-center rounded-sm border border-dashed p-2",
|
|
14271
|
+
onClick: handleClick,
|
|
14272
|
+
type: "button",
|
|
14273
|
+
children: /* @__PURE__ */ jsx(
|
|
14274
|
+
PlusIcon,
|
|
14275
|
+
{
|
|
14276
|
+
className: "pointer-events-none select-none text-muted-foreground",
|
|
14277
|
+
size: 16
|
|
14278
|
+
}
|
|
14279
|
+
)
|
|
14280
|
+
}
|
|
14281
|
+
)
|
|
14282
|
+
}
|
|
14283
|
+
);
|
|
14284
|
+
};
|
|
14285
|
+
var GanttColumn = ({
|
|
14286
|
+
index,
|
|
14287
|
+
isColumnSecondary
|
|
14288
|
+
}) => {
|
|
14289
|
+
const gantt = useContext(GanttContext);
|
|
14290
|
+
const [dragging] = useGanttDragging();
|
|
14291
|
+
const [mousePosition, mouseRef] = useMouse();
|
|
14292
|
+
const [hovering, setHovering] = useState(false);
|
|
14293
|
+
const [windowScroll] = useWindowScroll();
|
|
14294
|
+
const handleMouseEnter = () => setHovering(true);
|
|
14295
|
+
const handleMouseLeave = () => setHovering(false);
|
|
14296
|
+
const top = useThrottle(
|
|
14297
|
+
mousePosition.y - (mouseRef.current?.getBoundingClientRect().y ?? 0) - (windowScroll.y ?? 0),
|
|
14298
|
+
10
|
|
14299
|
+
);
|
|
14300
|
+
return (
|
|
14301
|
+
// biome-ignore lint/a11y/noStaticElementInteractions: "This is a clickable column"
|
|
14302
|
+
// biome-ignore lint/nursery/noNoninteractiveElementInteractions: "This is a clickable column"
|
|
14303
|
+
/* @__PURE__ */ jsx(
|
|
14304
|
+
"div",
|
|
14305
|
+
{
|
|
14306
|
+
className: cn(
|
|
14307
|
+
"group relative h-full overflow-hidden",
|
|
14308
|
+
isColumnSecondary?.(index) ? "bg-muted/30" : ""
|
|
14309
|
+
),
|
|
14310
|
+
onMouseEnter: handleMouseEnter,
|
|
14311
|
+
onMouseLeave: handleMouseLeave,
|
|
14312
|
+
ref: mouseRef,
|
|
14313
|
+
children: !dragging && hovering && gantt.onAddItem ? /* @__PURE__ */ jsx(GanttAddFeatureHelper, { top }) : null
|
|
14314
|
+
}
|
|
14315
|
+
)
|
|
14316
|
+
);
|
|
14317
|
+
};
|
|
14318
|
+
var GanttColumns = ({
|
|
14319
|
+
columns,
|
|
14320
|
+
isColumnSecondary
|
|
14321
|
+
}) => {
|
|
14322
|
+
const id = useId();
|
|
14323
|
+
return /* @__PURE__ */ jsx(
|
|
14324
|
+
"div",
|
|
14325
|
+
{
|
|
14326
|
+
className: "divide grid h-full w-full divide-x divide-border",
|
|
14327
|
+
style: {
|
|
14328
|
+
gridTemplateColumns: `repeat(${columns}, var(--gantt-column-width))`
|
|
14329
|
+
},
|
|
14330
|
+
children: Array.from({ length: columns }).map((_, index) => /* @__PURE__ */ jsx(
|
|
14331
|
+
GanttColumn,
|
|
14332
|
+
{
|
|
14333
|
+
index,
|
|
14334
|
+
isColumnSecondary
|
|
14335
|
+
},
|
|
14336
|
+
`${id}-${index}`
|
|
14337
|
+
))
|
|
14338
|
+
}
|
|
14339
|
+
);
|
|
14340
|
+
};
|
|
14341
|
+
var GanttGridLines = memo(({
|
|
14342
|
+
className
|
|
14343
|
+
}) => {
|
|
14344
|
+
const gantt = useContext(GanttContext);
|
|
14345
|
+
const id = useId();
|
|
14346
|
+
const { columns, monthBoundaryIndices } = useMemo(() => {
|
|
14347
|
+
let totalColumns = 0;
|
|
14348
|
+
const monthIndices = [];
|
|
14349
|
+
if (gantt.range === "weekly") {
|
|
14350
|
+
let weekIndex = 0;
|
|
14351
|
+
for (const yearData of gantt.timelineData) {
|
|
14352
|
+
const weeksInYear = getWeeksInYear(yearData.year);
|
|
14353
|
+
let currentMonth = -1;
|
|
14354
|
+
for (let w = 1; w <= weeksInYear; w++) {
|
|
14355
|
+
const weekStart = getWeekStartDate(yearData.year, w);
|
|
14356
|
+
const monthOfWeek = weekStart.getMonth();
|
|
14357
|
+
if (monthOfWeek !== currentMonth) {
|
|
14358
|
+
monthIndices.push(weekIndex);
|
|
14359
|
+
currentMonth = monthOfWeek;
|
|
14360
|
+
}
|
|
14361
|
+
weekIndex++;
|
|
14362
|
+
}
|
|
14363
|
+
totalColumns += weeksInYear;
|
|
14364
|
+
}
|
|
14365
|
+
} else {
|
|
14366
|
+
for (const yearData of gantt.timelineData) {
|
|
14367
|
+
const monthsInYear = yearData.quarters.flatMap((q) => q.months).length;
|
|
14368
|
+
totalColumns += monthsInYear;
|
|
14369
|
+
}
|
|
14370
|
+
}
|
|
14371
|
+
return { columns: totalColumns, monthBoundaryIndices: monthIndices };
|
|
14372
|
+
}, [gantt.timelineData, gantt.range]);
|
|
14373
|
+
const columnWidth = gantt.columnWidth * gantt.zoom / 100;
|
|
14374
|
+
const totalWidth = columns * columnWidth;
|
|
14375
|
+
return /* @__PURE__ */ jsx(
|
|
14376
|
+
"div",
|
|
14377
|
+
{
|
|
14378
|
+
className: cn(
|
|
14379
|
+
"pointer-events-none absolute top-0 left-0 h-full",
|
|
14380
|
+
className
|
|
14381
|
+
),
|
|
14382
|
+
style: {
|
|
14383
|
+
marginTop: "var(--gantt-header-height)",
|
|
14384
|
+
width: totalWidth
|
|
14385
|
+
},
|
|
14386
|
+
children: Array.from({ length: columns + 1 }).map((_, index) => {
|
|
14387
|
+
const isMonthBoundary = gantt.range === "weekly" && monthBoundaryIndices.includes(index);
|
|
14388
|
+
const x = Math.round(index * columnWidth);
|
|
14389
|
+
return /* @__PURE__ */ jsx(
|
|
14390
|
+
"div",
|
|
14391
|
+
{
|
|
14392
|
+
className: "absolute top-0 bottom-0",
|
|
14393
|
+
style: {
|
|
14394
|
+
left: x,
|
|
14395
|
+
width: isMonthBoundary ? "2px" : "1px",
|
|
14396
|
+
backgroundColor: isMonthBoundary ? "hsl(var(--foreground) / 0.25)" : "hsl(var(--border) / 0.8)"
|
|
14397
|
+
}
|
|
14398
|
+
},
|
|
14399
|
+
`${id}-grid-${index}`
|
|
14400
|
+
);
|
|
14401
|
+
})
|
|
14402
|
+
}
|
|
14403
|
+
);
|
|
14404
|
+
});
|
|
14405
|
+
GanttGridLines.displayName = "GanttGridLines";
|
|
14406
|
+
var GanttCreateMarkerTrigger = ({
|
|
14407
|
+
onCreateMarker,
|
|
14408
|
+
className
|
|
14409
|
+
}) => {
|
|
14410
|
+
const gantt = useContext(GanttContext);
|
|
14411
|
+
const [mousePosition, mouseRef] = useMouse();
|
|
14412
|
+
const [windowScroll] = useWindowScroll();
|
|
14413
|
+
const x = useThrottle(
|
|
14414
|
+
mousePosition.x - (mouseRef.current?.getBoundingClientRect().x ?? 0) - (windowScroll.x ?? 0),
|
|
14415
|
+
10
|
|
14416
|
+
);
|
|
14417
|
+
const date = getDateByMousePosition(gantt, x);
|
|
14418
|
+
const handleClick = () => onCreateMarker(date);
|
|
14419
|
+
return /* @__PURE__ */ jsx(
|
|
14420
|
+
"div",
|
|
14421
|
+
{
|
|
14422
|
+
className: cn(
|
|
14423
|
+
"group pointer-events-none absolute top-0 left-0 h-full w-full select-none overflow-visible",
|
|
14424
|
+
className
|
|
14425
|
+
),
|
|
14426
|
+
ref: mouseRef,
|
|
14427
|
+
children: /* @__PURE__ */ jsxs(
|
|
14428
|
+
"div",
|
|
14429
|
+
{
|
|
14430
|
+
className: "-ml-2 pointer-events-auto sticky top-6 z-20 flex w-4 flex-col items-center justify-center gap-1 overflow-visible opacity-0 group-hover:opacity-100",
|
|
14431
|
+
style: { transform: `translateX(${x}px)` },
|
|
14432
|
+
children: [
|
|
14433
|
+
/* @__PURE__ */ jsx(
|
|
14434
|
+
"button",
|
|
14435
|
+
{
|
|
14436
|
+
className: "z-50 inline-flex h-4 w-4 items-center justify-center rounded-full bg-card",
|
|
14437
|
+
onClick: handleClick,
|
|
14438
|
+
type: "button",
|
|
14439
|
+
children: /* @__PURE__ */ jsx(PlusIcon, { className: "text-muted-foreground", size: 12 })
|
|
14440
|
+
}
|
|
14441
|
+
),
|
|
14442
|
+
/* @__PURE__ */ jsx("div", { className: "whitespace-nowrap rounded-sm border border-border/50 bg-background/95 px-2 py-1 text-foreground text-xs backdrop-blur-sm", children: formatDate$1(date, "MMM dd, yyyy") })
|
|
14443
|
+
]
|
|
14444
|
+
}
|
|
14445
|
+
)
|
|
14446
|
+
}
|
|
14447
|
+
);
|
|
14448
|
+
};
|
|
14449
|
+
var GanttFeatureDragHelper = ({
|
|
14450
|
+
direction,
|
|
14451
|
+
featureId,
|
|
14452
|
+
date
|
|
14453
|
+
}) => {
|
|
14454
|
+
const [, setDragging] = useGanttDragging();
|
|
14455
|
+
const { attributes, listeners, setNodeRef } = useDraggable$1({
|
|
14456
|
+
id: `feature-drag-helper-${featureId}`
|
|
14457
|
+
});
|
|
14458
|
+
const isPressed = Boolean(attributes["aria-pressed"]);
|
|
14459
|
+
useEffect(() => setDragging(isPressed), [isPressed, setDragging]);
|
|
14460
|
+
return /* @__PURE__ */ jsxs(
|
|
14461
|
+
"div",
|
|
14462
|
+
{
|
|
14463
|
+
className: cn(
|
|
14464
|
+
"group -translate-y-1/2 !cursor-col-resize absolute top-1/2 z-[3] h-full w-6 rounded-sm outline-none",
|
|
14465
|
+
direction === "left" ? "-left-2.5" : "-right-2.5"
|
|
14466
|
+
),
|
|
14467
|
+
ref: setNodeRef,
|
|
14468
|
+
...attributes,
|
|
14469
|
+
...listeners,
|
|
14470
|
+
children: [
|
|
14471
|
+
/* @__PURE__ */ jsx(
|
|
14472
|
+
"div",
|
|
14473
|
+
{
|
|
14474
|
+
className: cn(
|
|
14475
|
+
"-translate-y-1/2 absolute top-1/2 h-[80%] w-1 rounded-sm bg-muted-foreground opacity-0 transition-all",
|
|
14476
|
+
direction === "left" ? "left-2.5" : "right-2.5",
|
|
14477
|
+
direction === "left" ? "group-hover:left-0" : "group-hover:right-0",
|
|
14478
|
+
isPressed && (direction === "left" ? "left-0" : "right-0"),
|
|
14479
|
+
"group-hover:opacity-100",
|
|
14480
|
+
isPressed && "opacity-100"
|
|
14481
|
+
)
|
|
14482
|
+
}
|
|
14483
|
+
),
|
|
14484
|
+
date && /* @__PURE__ */ jsx(
|
|
14485
|
+
"div",
|
|
14486
|
+
{
|
|
14487
|
+
className: cn(
|
|
14488
|
+
"-translate-x-1/2 absolute top-10 hidden whitespace-nowrap rounded-sm border border-border/50 bg-background/95 px-2 py-1 text-foreground text-xs backdrop-blur-sm group-hover:block",
|
|
14489
|
+
isPressed && "block"
|
|
14490
|
+
),
|
|
14491
|
+
children: format(date, "MMM dd, yyyy")
|
|
14492
|
+
}
|
|
14493
|
+
)
|
|
14494
|
+
]
|
|
14495
|
+
}
|
|
14496
|
+
);
|
|
14497
|
+
};
|
|
14498
|
+
var GanttFeatureItemCard = ({
|
|
14499
|
+
id,
|
|
14500
|
+
children
|
|
14501
|
+
}) => {
|
|
14502
|
+
const [, setDragging] = useGanttDragging();
|
|
14503
|
+
const { attributes, listeners, setNodeRef } = useDraggable$1({ id });
|
|
14504
|
+
const isPressed = Boolean(attributes["aria-pressed"]);
|
|
14505
|
+
useEffect(() => setDragging(isPressed), [isPressed, setDragging]);
|
|
14506
|
+
return /* @__PURE__ */ jsx(Card, { className: "h-full w-full rounded-sm border bg-background px-2 py-1.5 text-xs shadow-sm overflow-hidden", children: /* @__PURE__ */ jsx(
|
|
14507
|
+
"div",
|
|
14508
|
+
{
|
|
14509
|
+
className: cn(
|
|
14510
|
+
"flex h-full w-full items-center justify-between gap-2 text-left",
|
|
14511
|
+
isPressed && "cursor-grabbing"
|
|
14512
|
+
),
|
|
14513
|
+
...attributes,
|
|
14514
|
+
...listeners,
|
|
14515
|
+
ref: setNodeRef,
|
|
14516
|
+
children
|
|
14517
|
+
}
|
|
14518
|
+
) });
|
|
14519
|
+
};
|
|
14520
|
+
var GanttFeatureItem = ({
|
|
14521
|
+
onMove,
|
|
14522
|
+
contextMenuActions,
|
|
14523
|
+
onEdit,
|
|
14524
|
+
onDelete,
|
|
14525
|
+
onDuplicate,
|
|
14526
|
+
children,
|
|
14527
|
+
className,
|
|
14528
|
+
...feature
|
|
14529
|
+
}) => {
|
|
14530
|
+
const [scrollX] = useGanttScrollX();
|
|
14531
|
+
const gantt = useContext(GanttContext);
|
|
14532
|
+
const timelineStartDate = useMemo(
|
|
14533
|
+
() => new Date(gantt.timelineData.at(0)?.year ?? 0, 0, 1),
|
|
14534
|
+
[gantt.timelineData]
|
|
14535
|
+
);
|
|
14536
|
+
const [startAt, setStartAt] = useState(feature.startAt);
|
|
14537
|
+
const [endAt, setEndAt] = useState(feature.endAt);
|
|
14538
|
+
const width = useMemo(
|
|
14539
|
+
() => Math.round(getWidth(startAt, endAt, gantt)),
|
|
14540
|
+
[startAt, endAt, gantt]
|
|
14541
|
+
);
|
|
14542
|
+
const offset = useMemo(
|
|
14543
|
+
() => Math.round(getOffset(startAt, timelineStartDate, gantt)),
|
|
14544
|
+
[startAt, timelineStartDate, gantt]
|
|
14545
|
+
);
|
|
14546
|
+
const addRange = useMemo(() => getAddRange(gantt.range), [gantt.range]);
|
|
14547
|
+
const [mousePosition] = useMouse();
|
|
14548
|
+
const [previousMouseX, setPreviousMouseX] = useState(0);
|
|
14549
|
+
const [previousStartAt, setPreviousStartAt] = useState(startAt);
|
|
14550
|
+
const [previousEndAt, setPreviousEndAt] = useState(endAt);
|
|
14551
|
+
const mouseSensor = useSensor(MouseSensor, {
|
|
14552
|
+
activationConstraint: {
|
|
14553
|
+
distance: 10
|
|
14554
|
+
}
|
|
14555
|
+
});
|
|
14556
|
+
const handleItemDragStart = useCallback(() => {
|
|
14557
|
+
setPreviousMouseX(mousePosition.x);
|
|
14558
|
+
setPreviousStartAt(startAt);
|
|
14559
|
+
setPreviousEndAt(endAt);
|
|
14560
|
+
}, [mousePosition.x, startAt, endAt]);
|
|
14561
|
+
const handleItemDragMove = useCallback(() => {
|
|
14562
|
+
const currentDate = getDateByMousePosition(gantt, mousePosition.x);
|
|
14563
|
+
const originalDate = getDateByMousePosition(gantt, previousMouseX);
|
|
14564
|
+
const delta = gantt.range === "weekly" ? differenceInDays(currentDate, originalDate) : getInnerDifferenceIn(gantt.range)(currentDate, originalDate);
|
|
14565
|
+
const newStartDate = addDays(previousStartAt, delta);
|
|
14566
|
+
const newEndDate = previousEndAt ? addDays(previousEndAt, delta) : null;
|
|
14567
|
+
setStartAt(newStartDate);
|
|
14568
|
+
setEndAt(newEndDate);
|
|
14569
|
+
}, [gantt, mousePosition.x, previousMouseX, previousStartAt, previousEndAt]);
|
|
14570
|
+
const onDragEnd = useCallback(
|
|
14571
|
+
() => onMove?.(feature.id, startAt, endAt),
|
|
14572
|
+
[onMove, feature.id, startAt, endAt]
|
|
14573
|
+
);
|
|
14574
|
+
const handleLeftDragMove = useCallback(() => {
|
|
14575
|
+
const ganttRect = gantt.ref?.current?.getBoundingClientRect();
|
|
14576
|
+
const x = mousePosition.x - (ganttRect?.left ?? 0) + scrollX - gantt.sidebarWidth;
|
|
14577
|
+
const newStartAt = getDateByMousePosition(gantt, x);
|
|
14578
|
+
setStartAt(newStartAt);
|
|
14579
|
+
}, [gantt, mousePosition.x, scrollX]);
|
|
14580
|
+
const handleRightDragMove = useCallback(() => {
|
|
14581
|
+
const ganttRect = gantt.ref?.current?.getBoundingClientRect();
|
|
14582
|
+
const x = mousePosition.x - (ganttRect?.left ?? 0) + scrollX - gantt.sidebarWidth;
|
|
14583
|
+
const newEndAt = getDateByMousePosition(gantt, x);
|
|
14584
|
+
setEndAt(newEndAt);
|
|
14585
|
+
}, [gantt, mousePosition.x, scrollX]);
|
|
14586
|
+
return /* @__PURE__ */ jsx(
|
|
14587
|
+
"div",
|
|
14588
|
+
{
|
|
14589
|
+
className: cn("relative flex w-max min-w-full", className),
|
|
14590
|
+
style: { height: "var(--gantt-row-height)" },
|
|
14591
|
+
children: /* @__PURE__ */ jsxs(
|
|
14592
|
+
"div",
|
|
14593
|
+
{
|
|
14594
|
+
className: "pointer-events-auto absolute",
|
|
14595
|
+
style: {
|
|
14596
|
+
height: "calc(var(--gantt-row-height) - 8px)",
|
|
14597
|
+
top: "4px",
|
|
14598
|
+
width,
|
|
14599
|
+
left: offset
|
|
14600
|
+
},
|
|
14601
|
+
children: [
|
|
14602
|
+
onMove && /* @__PURE__ */ jsx(
|
|
14603
|
+
DndContext,
|
|
14604
|
+
{
|
|
14605
|
+
modifiers: [restrictToHorizontalAxis],
|
|
14606
|
+
onDragEnd,
|
|
14607
|
+
onDragMove: handleLeftDragMove,
|
|
14608
|
+
sensors: [mouseSensor],
|
|
14609
|
+
children: /* @__PURE__ */ jsx(
|
|
14610
|
+
GanttFeatureDragHelper,
|
|
14611
|
+
{
|
|
14612
|
+
date: startAt,
|
|
14613
|
+
direction: "left",
|
|
14614
|
+
featureId: feature.id
|
|
14615
|
+
}
|
|
14616
|
+
)
|
|
14617
|
+
}
|
|
14618
|
+
),
|
|
14619
|
+
/* @__PURE__ */ jsxs(ContextMenu, { children: [
|
|
14620
|
+
/* @__PURE__ */ jsx(ContextMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsx("div", { className: "h-full w-full", children: /* @__PURE__ */ jsx(
|
|
14621
|
+
DndContext,
|
|
14622
|
+
{
|
|
14623
|
+
modifiers: [restrictToHorizontalAxis],
|
|
14624
|
+
onDragEnd,
|
|
14625
|
+
onDragMove: handleItemDragMove,
|
|
14626
|
+
onDragStart: handleItemDragStart,
|
|
14627
|
+
sensors: [mouseSensor],
|
|
14628
|
+
children: /* @__PURE__ */ jsx(GanttFeatureItemCard, { id: feature.id, children: children ?? /* @__PURE__ */ jsx("p", { className: "flex-1 truncate text-xs", children: feature.name }) })
|
|
14629
|
+
}
|
|
14630
|
+
) }) }),
|
|
14631
|
+
/* @__PURE__ */ jsxs(ContextMenuContent, { children: [
|
|
14632
|
+
onEdit && /* @__PURE__ */ jsxs(
|
|
14633
|
+
ContextMenuItem,
|
|
14634
|
+
{
|
|
14635
|
+
className: "flex items-center gap-2",
|
|
14636
|
+
onClick: () => onEdit(feature),
|
|
14637
|
+
children: [
|
|
14638
|
+
/* @__PURE__ */ jsx(PencilIcon, { size: 14 }),
|
|
14639
|
+
"Edit"
|
|
14640
|
+
]
|
|
14641
|
+
}
|
|
14642
|
+
),
|
|
14643
|
+
onDuplicate && /* @__PURE__ */ jsxs(
|
|
14644
|
+
ContextMenuItem,
|
|
14645
|
+
{
|
|
14646
|
+
className: "flex items-center gap-2",
|
|
14647
|
+
onClick: () => onDuplicate(feature),
|
|
14648
|
+
children: [
|
|
14649
|
+
/* @__PURE__ */ jsx(CopyIcon, { size: 14 }),
|
|
14650
|
+
"Duplicate"
|
|
14651
|
+
]
|
|
14652
|
+
}
|
|
14653
|
+
),
|
|
14654
|
+
contextMenuActions?.map((action, index) => /* @__PURE__ */ jsxs(
|
|
14655
|
+
ContextMenuItem,
|
|
14656
|
+
{
|
|
14657
|
+
className: cn(
|
|
14658
|
+
"flex items-center gap-2",
|
|
14659
|
+
action.destructive && "text-destructive"
|
|
14660
|
+
),
|
|
14661
|
+
onClick: () => action.onClick(feature),
|
|
14662
|
+
disabled: action.disabled,
|
|
14663
|
+
children: [
|
|
14664
|
+
action.icon,
|
|
14665
|
+
action.label
|
|
14666
|
+
]
|
|
14667
|
+
},
|
|
14668
|
+
index
|
|
14669
|
+
)),
|
|
14670
|
+
onDelete && /* @__PURE__ */ jsxs(
|
|
14671
|
+
ContextMenuItem,
|
|
14672
|
+
{
|
|
14673
|
+
className: "flex items-center gap-2 text-destructive",
|
|
14674
|
+
onClick: () => onDelete(feature),
|
|
14675
|
+
children: [
|
|
14676
|
+
/* @__PURE__ */ jsx(TrashIcon, { size: 14 }),
|
|
14677
|
+
"Delete"
|
|
14678
|
+
]
|
|
14679
|
+
}
|
|
14680
|
+
)
|
|
14681
|
+
] })
|
|
14682
|
+
] }),
|
|
14683
|
+
onMove && /* @__PURE__ */ jsx(
|
|
14684
|
+
DndContext,
|
|
14685
|
+
{
|
|
14686
|
+
modifiers: [restrictToHorizontalAxis],
|
|
14687
|
+
onDragEnd,
|
|
14688
|
+
onDragMove: handleRightDragMove,
|
|
14689
|
+
sensors: [mouseSensor],
|
|
14690
|
+
children: /* @__PURE__ */ jsx(
|
|
14691
|
+
GanttFeatureDragHelper,
|
|
14692
|
+
{
|
|
14693
|
+
date: endAt ?? addRange(startAt, 2),
|
|
14694
|
+
direction: "right",
|
|
14695
|
+
featureId: feature.id
|
|
14696
|
+
}
|
|
14697
|
+
)
|
|
14698
|
+
}
|
|
14699
|
+
)
|
|
14700
|
+
]
|
|
14701
|
+
}
|
|
14702
|
+
)
|
|
14703
|
+
}
|
|
14704
|
+
);
|
|
14705
|
+
};
|
|
14706
|
+
var GanttFeatureListGroup = ({
|
|
14707
|
+
children,
|
|
14708
|
+
className
|
|
14709
|
+
}) => /* @__PURE__ */ jsx(
|
|
14710
|
+
"div",
|
|
14711
|
+
{
|
|
14712
|
+
className,
|
|
14713
|
+
style: { paddingTop: "var(--gantt-row-height)" },
|
|
14714
|
+
children
|
|
14715
|
+
}
|
|
14716
|
+
);
|
|
14717
|
+
var GanttFeatureRow = ({
|
|
14718
|
+
features,
|
|
14719
|
+
onMove,
|
|
14720
|
+
children,
|
|
14721
|
+
className
|
|
14722
|
+
}) => {
|
|
14723
|
+
const sortedFeatures = [...features].sort(
|
|
14724
|
+
(a, b) => a.startAt.getTime() - b.startAt.getTime()
|
|
14725
|
+
);
|
|
14726
|
+
const featureWithPositions = [];
|
|
14727
|
+
const subRowEndTimes = [];
|
|
14728
|
+
for (const feature of sortedFeatures) {
|
|
14729
|
+
let subRow = 0;
|
|
14730
|
+
while (subRow < subRowEndTimes.length && subRowEndTimes[subRow] > feature.startAt) {
|
|
14731
|
+
subRow++;
|
|
14732
|
+
}
|
|
14733
|
+
if (subRow === subRowEndTimes.length) {
|
|
14734
|
+
subRowEndTimes.push(feature.endAt);
|
|
14735
|
+
} else {
|
|
14736
|
+
subRowEndTimes[subRow] = feature.endAt;
|
|
14737
|
+
}
|
|
14738
|
+
featureWithPositions.push({ ...feature, subRow });
|
|
14739
|
+
}
|
|
14740
|
+
const maxSubRows = Math.max(1, subRowEndTimes.length);
|
|
14741
|
+
const subRowHeight = 36;
|
|
14742
|
+
return /* @__PURE__ */ jsx(
|
|
14743
|
+
"div",
|
|
14744
|
+
{
|
|
14745
|
+
className: cn("relative", className),
|
|
14746
|
+
style: {
|
|
14747
|
+
height: `${maxSubRows * subRowHeight}px`,
|
|
14748
|
+
minHeight: "var(--gantt-row-height)"
|
|
14749
|
+
},
|
|
14750
|
+
children: featureWithPositions.map((feature) => /* @__PURE__ */ jsx(
|
|
14751
|
+
"div",
|
|
14752
|
+
{
|
|
14753
|
+
className: "absolute w-full",
|
|
14754
|
+
style: {
|
|
14755
|
+
top: `${feature.subRow * subRowHeight}px`,
|
|
14756
|
+
height: `${subRowHeight}px`
|
|
14757
|
+
},
|
|
14758
|
+
children: /* @__PURE__ */ jsx(GanttFeatureItem, { ...feature, onMove, children: children ? children(feature) : /* @__PURE__ */ jsx("p", { className: "flex-1 truncate text-xs", children: feature.name }) })
|
|
14759
|
+
},
|
|
14760
|
+
feature.id
|
|
14761
|
+
))
|
|
14762
|
+
}
|
|
14763
|
+
);
|
|
14764
|
+
};
|
|
14765
|
+
var GanttFeatureList = ({
|
|
14766
|
+
className,
|
|
14767
|
+
children
|
|
14768
|
+
}) => /* @__PURE__ */ jsx(
|
|
14769
|
+
"div",
|
|
14770
|
+
{
|
|
14771
|
+
className: cn("absolute top-0 left-0 h-max w-max min-w-full", className),
|
|
14772
|
+
style: { marginTop: "var(--gantt-header-height)" },
|
|
14773
|
+
children
|
|
14774
|
+
}
|
|
14775
|
+
);
|
|
14776
|
+
var GanttMarker = memo(({ label, date, id, onRemove, className }) => {
|
|
14777
|
+
const gantt = useContext(GanttContext);
|
|
14778
|
+
const differenceIn = useMemo(
|
|
14779
|
+
() => getDifferenceIn(gantt.range),
|
|
14780
|
+
[gantt.range]
|
|
14781
|
+
);
|
|
14782
|
+
const timelineStartDate = useMemo(
|
|
14783
|
+
() => new Date(gantt.timelineData.at(0)?.year ?? 0, 0, 1),
|
|
14784
|
+
[gantt.timelineData]
|
|
14785
|
+
);
|
|
14786
|
+
const offset = useMemo(
|
|
14787
|
+
() => differenceIn(date, timelineStartDate),
|
|
14788
|
+
[differenceIn, date, timelineStartDate]
|
|
14789
|
+
);
|
|
14790
|
+
const innerOffset = useMemo(
|
|
14791
|
+
() => calculateInnerOffset(
|
|
14792
|
+
date,
|
|
14793
|
+
gantt.range,
|
|
14794
|
+
gantt.columnWidth * gantt.zoom / 100
|
|
14795
|
+
),
|
|
14796
|
+
[date, gantt.range, gantt.columnWidth, gantt.zoom]
|
|
14797
|
+
);
|
|
14798
|
+
const handleRemove = useCallback(() => onRemove?.(id), [onRemove, id]);
|
|
14799
|
+
return /* @__PURE__ */ jsxs(
|
|
14800
|
+
"div",
|
|
14801
|
+
{
|
|
14802
|
+
className: "pointer-events-none absolute top-0 left-0 z-20 flex h-full select-none flex-col items-center justify-center overflow-visible",
|
|
14803
|
+
style: {
|
|
14804
|
+
width: 0,
|
|
14805
|
+
transform: `translateX(calc(var(--gantt-column-width) * ${offset} + ${Math.round(innerOffset)}px))`
|
|
14806
|
+
},
|
|
14807
|
+
children: [
|
|
14808
|
+
/* @__PURE__ */ jsxs(ContextMenu, { children: [
|
|
14809
|
+
/* @__PURE__ */ jsx(ContextMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
14810
|
+
"div",
|
|
14811
|
+
{
|
|
14812
|
+
className: cn(
|
|
14813
|
+
"group pointer-events-auto sticky top-0 flex select-auto flex-col flex-nowrap items-center justify-center whitespace-nowrap rounded-sm bg-card px-2 py-1 text-foreground text-xs shadow-sm",
|
|
14814
|
+
className
|
|
14815
|
+
),
|
|
14816
|
+
children: [
|
|
14817
|
+
label,
|
|
14818
|
+
/* @__PURE__ */ jsx("span", { className: "max-h-[0] overflow-hidden opacity-80 transition-all group-hover:max-h-[2rem]", children: formatDate$1(date, "MMM dd, yyyy") })
|
|
14819
|
+
]
|
|
14820
|
+
}
|
|
14821
|
+
) }),
|
|
14822
|
+
/* @__PURE__ */ jsx(ContextMenuContent, { children: onRemove ? /* @__PURE__ */ jsxs(
|
|
14823
|
+
ContextMenuItem,
|
|
14824
|
+
{
|
|
14825
|
+
className: "flex items-center gap-2 text-destructive",
|
|
14826
|
+
onClick: handleRemove,
|
|
14827
|
+
children: [
|
|
14828
|
+
/* @__PURE__ */ jsx(TrashIcon, { size: 16 }),
|
|
14829
|
+
"Remove marker"
|
|
14830
|
+
]
|
|
14831
|
+
}
|
|
14832
|
+
) : null })
|
|
14833
|
+
] }),
|
|
14834
|
+
/* @__PURE__ */ jsx("div", { className: cn("h-full w-px bg-card", className) })
|
|
14835
|
+
]
|
|
14836
|
+
}
|
|
14837
|
+
);
|
|
14838
|
+
});
|
|
14839
|
+
GanttMarker.displayName = "GanttMarker";
|
|
14840
|
+
var GanttProvider = ({
|
|
14841
|
+
zoom = 100,
|
|
14842
|
+
range = "monthly",
|
|
14843
|
+
onAddItem,
|
|
14844
|
+
children,
|
|
14845
|
+
className,
|
|
14846
|
+
defaultExpandedGroups = {}
|
|
14847
|
+
}) => {
|
|
14848
|
+
const scrollRef = useRef(null);
|
|
14849
|
+
const [timelineData, setTimelineData] = useState(
|
|
14850
|
+
createInitialTimelineData(/* @__PURE__ */ new Date())
|
|
14851
|
+
);
|
|
14852
|
+
const [, setScrollX] = useGanttScrollX();
|
|
14853
|
+
const sidebarWidth = 280;
|
|
14854
|
+
const [expandedGroups, setExpandedGroups] = useState(defaultExpandedGroups);
|
|
14855
|
+
const setGroupExpanded = useCallback((groupId, expanded) => {
|
|
14856
|
+
setExpandedGroups((prev) => ({ ...prev, [groupId]: expanded }));
|
|
14857
|
+
}, []);
|
|
14858
|
+
const headerHeight = 60;
|
|
14859
|
+
const rowHeight = 36;
|
|
14860
|
+
let columnWidth = 50;
|
|
14861
|
+
if (range === "monthly") {
|
|
14862
|
+
columnWidth = 150;
|
|
14863
|
+
} else if (range === "quarterly") {
|
|
14864
|
+
columnWidth = 100;
|
|
14865
|
+
}
|
|
14866
|
+
const cssVariables = useMemo(
|
|
14867
|
+
() => ({
|
|
14868
|
+
"--gantt-zoom": `${zoom}`,
|
|
14869
|
+
"--gantt-column-width": `${zoom / 100 * columnWidth}px`,
|
|
14870
|
+
"--gantt-header-height": `${headerHeight}px`,
|
|
14871
|
+
"--gantt-row-height": `${rowHeight}px`,
|
|
14872
|
+
"--gantt-sidebar-width": `${sidebarWidth}px`
|
|
14873
|
+
}),
|
|
14874
|
+
[zoom, columnWidth, sidebarWidth]
|
|
14875
|
+
);
|
|
14876
|
+
useEffect(() => {
|
|
14877
|
+
if (scrollRef.current) {
|
|
14878
|
+
scrollRef.current.scrollLeft = scrollRef.current.scrollWidth / 2 - scrollRef.current.clientWidth / 2;
|
|
14879
|
+
setScrollX(scrollRef.current.scrollLeft);
|
|
14880
|
+
}
|
|
14881
|
+
}, [setScrollX]);
|
|
14882
|
+
const handleScroll = useCallback(
|
|
14883
|
+
throttle(() => {
|
|
14884
|
+
const scrollElement = scrollRef.current;
|
|
14885
|
+
if (!scrollElement) {
|
|
14886
|
+
return;
|
|
14887
|
+
}
|
|
14888
|
+
const { scrollLeft, scrollWidth, clientWidth } = scrollElement;
|
|
14889
|
+
setScrollX(scrollLeft);
|
|
14890
|
+
if (scrollLeft === 0) {
|
|
14891
|
+
const firstYear = timelineData[0]?.year;
|
|
14892
|
+
if (!firstYear) {
|
|
14893
|
+
return;
|
|
14894
|
+
}
|
|
14895
|
+
const newTimelineData = [...timelineData];
|
|
14896
|
+
newTimelineData.unshift({
|
|
14897
|
+
year: firstYear - 1,
|
|
14898
|
+
quarters: new Array(4).fill(null).map((_, quarterIndex) => ({
|
|
14899
|
+
months: new Array(3).fill(null).map((_2, monthIndex) => {
|
|
14900
|
+
const month = quarterIndex * 3 + monthIndex;
|
|
14901
|
+
return {
|
|
14902
|
+
days: getDaysInMonth(new Date(firstYear, month, 1))
|
|
14903
|
+
};
|
|
14904
|
+
})
|
|
14905
|
+
}))
|
|
14906
|
+
});
|
|
14907
|
+
setTimelineData(newTimelineData);
|
|
14908
|
+
scrollElement.scrollLeft = scrollElement.clientWidth;
|
|
14909
|
+
setScrollX(scrollElement.scrollLeft);
|
|
14910
|
+
} else if (scrollLeft + clientWidth >= scrollWidth) {
|
|
14911
|
+
const lastYear = timelineData.at(-1)?.year;
|
|
14912
|
+
if (!lastYear) {
|
|
14913
|
+
return;
|
|
14914
|
+
}
|
|
14915
|
+
const newTimelineData = [...timelineData];
|
|
14916
|
+
newTimelineData.push({
|
|
14917
|
+
year: lastYear + 1,
|
|
14918
|
+
quarters: new Array(4).fill(null).map((_, quarterIndex) => ({
|
|
14919
|
+
months: new Array(3).fill(null).map((_2, monthIndex) => {
|
|
14920
|
+
const month = quarterIndex * 3 + monthIndex;
|
|
14921
|
+
return {
|
|
14922
|
+
days: getDaysInMonth(new Date(lastYear, month, 1))
|
|
14923
|
+
};
|
|
14924
|
+
})
|
|
14925
|
+
}))
|
|
14926
|
+
});
|
|
14927
|
+
setTimelineData(newTimelineData);
|
|
14928
|
+
scrollElement.scrollLeft = scrollElement.scrollWidth - scrollElement.clientWidth;
|
|
14929
|
+
setScrollX(scrollElement.scrollLeft);
|
|
14930
|
+
}
|
|
14931
|
+
}, 100),
|
|
14932
|
+
[]
|
|
14933
|
+
);
|
|
14934
|
+
useEffect(() => {
|
|
14935
|
+
const scrollElement = scrollRef.current;
|
|
14936
|
+
if (scrollElement) {
|
|
14937
|
+
scrollElement.addEventListener("scroll", handleScroll);
|
|
14938
|
+
}
|
|
14939
|
+
return () => {
|
|
14940
|
+
if (scrollElement) {
|
|
14941
|
+
scrollElement.removeEventListener("scroll", handleScroll);
|
|
14942
|
+
}
|
|
14943
|
+
};
|
|
14944
|
+
}, [handleScroll]);
|
|
14945
|
+
const scrollToFeature = useCallback(
|
|
14946
|
+
(feature) => {
|
|
14947
|
+
const scrollElement = scrollRef.current;
|
|
14948
|
+
if (!scrollElement) {
|
|
14949
|
+
return;
|
|
14950
|
+
}
|
|
14951
|
+
const timelineStartDate = new Date(timelineData[0].year, 0, 1);
|
|
14952
|
+
const offset = getOffset(feature.startAt, timelineStartDate, {
|
|
14953
|
+
zoom,
|
|
14954
|
+
range,
|
|
14955
|
+
columnWidth});
|
|
14956
|
+
const targetScrollLeft = Math.max(0, offset);
|
|
14957
|
+
scrollElement.scrollTo({
|
|
14958
|
+
left: targetScrollLeft,
|
|
14959
|
+
behavior: "smooth"
|
|
14960
|
+
});
|
|
14961
|
+
},
|
|
14962
|
+
[timelineData, zoom, range, columnWidth, sidebarWidth, onAddItem, expandedGroups, setGroupExpanded]
|
|
14963
|
+
);
|
|
14964
|
+
return /* @__PURE__ */ jsx(
|
|
14965
|
+
GanttContext.Provider,
|
|
14966
|
+
{
|
|
14967
|
+
value: {
|
|
14968
|
+
zoom,
|
|
14969
|
+
range,
|
|
14970
|
+
headerHeight,
|
|
14971
|
+
columnWidth,
|
|
14972
|
+
sidebarWidth,
|
|
14973
|
+
rowHeight,
|
|
14974
|
+
onAddItem,
|
|
14975
|
+
timelineData,
|
|
14976
|
+
placeholderLength: 2,
|
|
14977
|
+
ref: scrollRef,
|
|
14978
|
+
scrollToFeature,
|
|
14979
|
+
expandedGroups,
|
|
14980
|
+
setGroupExpanded
|
|
14981
|
+
},
|
|
14982
|
+
children: /* @__PURE__ */ jsx(
|
|
14983
|
+
"div",
|
|
14984
|
+
{
|
|
14985
|
+
className: cn(
|
|
14986
|
+
"gantt relative isolate grid h-full w-full flex-none select-none rounded-sm border bg-background",
|
|
14987
|
+
range,
|
|
14988
|
+
className
|
|
14989
|
+
),
|
|
14990
|
+
style: {
|
|
14991
|
+
...cssVariables,
|
|
14992
|
+
gridTemplateColumns: "var(--gantt-sidebar-width) 1fr"
|
|
14993
|
+
},
|
|
14994
|
+
children: /* @__PURE__ */ jsx(
|
|
14995
|
+
"div",
|
|
14996
|
+
{
|
|
14997
|
+
className: "col-span-2 grid overflow-auto",
|
|
14998
|
+
ref: scrollRef,
|
|
14999
|
+
style: {
|
|
15000
|
+
gridTemplateColumns: "var(--gantt-sidebar-width) 1fr"
|
|
15001
|
+
},
|
|
15002
|
+
children
|
|
15003
|
+
}
|
|
15004
|
+
)
|
|
15005
|
+
}
|
|
15006
|
+
)
|
|
15007
|
+
}
|
|
15008
|
+
);
|
|
15009
|
+
};
|
|
15010
|
+
var GanttTimeline = ({
|
|
15011
|
+
children,
|
|
15012
|
+
className
|
|
15013
|
+
}) => /* @__PURE__ */ jsx(
|
|
15014
|
+
"div",
|
|
15015
|
+
{
|
|
15016
|
+
className: cn(
|
|
15017
|
+
"relative flex h-max min-h-full w-max flex-none",
|
|
15018
|
+
className
|
|
15019
|
+
),
|
|
15020
|
+
children
|
|
15021
|
+
}
|
|
15022
|
+
);
|
|
15023
|
+
var GanttToday = ({ className }) => {
|
|
15024
|
+
const label = "Today";
|
|
15025
|
+
const date = useMemo(() => /* @__PURE__ */ new Date(), []);
|
|
15026
|
+
const gantt = useContext(GanttContext);
|
|
15027
|
+
const differenceIn = useMemo(
|
|
15028
|
+
() => getDifferenceIn(gantt.range),
|
|
15029
|
+
[gantt.range]
|
|
15030
|
+
);
|
|
15031
|
+
const timelineStartDate = useMemo(
|
|
15032
|
+
() => new Date(gantt.timelineData.at(0)?.year ?? 0, 0, 1),
|
|
15033
|
+
[gantt.timelineData]
|
|
15034
|
+
);
|
|
15035
|
+
const offset = useMemo(
|
|
15036
|
+
() => differenceIn(date, timelineStartDate),
|
|
15037
|
+
[differenceIn, date, timelineStartDate]
|
|
15038
|
+
);
|
|
15039
|
+
const innerOffset = useMemo(
|
|
15040
|
+
() => Math.round(calculateInnerOffset(
|
|
15041
|
+
date,
|
|
15042
|
+
gantt.range,
|
|
15043
|
+
gantt.columnWidth * gantt.zoom / 100
|
|
15044
|
+
)),
|
|
15045
|
+
[date, gantt.range, gantt.columnWidth, gantt.zoom]
|
|
15046
|
+
);
|
|
15047
|
+
return /* @__PURE__ */ jsxs(
|
|
15048
|
+
"div",
|
|
15049
|
+
{
|
|
15050
|
+
className: "pointer-events-none absolute top-0 left-0 z-20 flex h-full select-none flex-col items-center justify-center overflow-visible",
|
|
15051
|
+
style: {
|
|
15052
|
+
width: 0,
|
|
15053
|
+
transform: `translateX(calc(var(--gantt-column-width) * ${offset} + ${innerOffset}px))`
|
|
15054
|
+
},
|
|
15055
|
+
children: [
|
|
15056
|
+
/* @__PURE__ */ jsxs(
|
|
15057
|
+
"div",
|
|
15058
|
+
{
|
|
15059
|
+
className: cn(
|
|
15060
|
+
"group pointer-events-auto sticky top-0 flex select-auto flex-col flex-nowrap items-center justify-center whitespace-nowrap rounded-sm bg-primary px-2 py-1 text-primary-foreground text-xs shadow-sm",
|
|
15061
|
+
className
|
|
15062
|
+
),
|
|
15063
|
+
children: [
|
|
15064
|
+
label,
|
|
15065
|
+
/* @__PURE__ */ jsx("span", { className: "max-h-[0] overflow-hidden opacity-80 transition-all group-hover:max-h-[2rem]", children: formatDate$1(date, "MMM dd, yyyy") })
|
|
15066
|
+
]
|
|
15067
|
+
}
|
|
15068
|
+
),
|
|
15069
|
+
/* @__PURE__ */ jsx("div", { className: cn("h-full w-px bg-primary", className) })
|
|
15070
|
+
]
|
|
15071
|
+
}
|
|
15072
|
+
);
|
|
15073
|
+
};
|
|
15074
|
+
var t = tunnel();
|
|
15075
|
+
var KanbanContext = createContext({
|
|
15076
|
+
columns: [],
|
|
15077
|
+
data: [],
|
|
15078
|
+
activeCardId: null
|
|
15079
|
+
});
|
|
15080
|
+
var KanbanBoard = ({ id, children, className }) => {
|
|
15081
|
+
const { isOver, setNodeRef } = useDroppable$1({
|
|
15082
|
+
id
|
|
15083
|
+
});
|
|
15084
|
+
return /* @__PURE__ */ jsx(
|
|
15085
|
+
"div",
|
|
15086
|
+
{
|
|
15087
|
+
className: cn(
|
|
15088
|
+
"flex size-full min-h-40 flex-col divide-y overflow-hidden rounded-md border bg-secondary text-xs shadow-sm ring-2 transition-all",
|
|
15089
|
+
isOver ? "ring-primary" : "ring-transparent",
|
|
15090
|
+
className
|
|
15091
|
+
),
|
|
15092
|
+
ref: setNodeRef,
|
|
15093
|
+
children
|
|
15094
|
+
}
|
|
15095
|
+
);
|
|
15096
|
+
};
|
|
15097
|
+
var KanbanCard = ({
|
|
15098
|
+
id,
|
|
15099
|
+
name,
|
|
15100
|
+
children,
|
|
15101
|
+
className
|
|
15102
|
+
}) => {
|
|
15103
|
+
const {
|
|
15104
|
+
attributes,
|
|
15105
|
+
listeners,
|
|
15106
|
+
setNodeRef,
|
|
15107
|
+
transition,
|
|
15108
|
+
transform,
|
|
15109
|
+
isDragging
|
|
15110
|
+
} = useSortable({
|
|
15111
|
+
id
|
|
15112
|
+
});
|
|
15113
|
+
const { activeCardId } = useContext(KanbanContext);
|
|
15114
|
+
const style = {
|
|
15115
|
+
transition,
|
|
15116
|
+
transform: CSS.Transform.toString(transform)
|
|
15117
|
+
};
|
|
15118
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
15119
|
+
/* @__PURE__ */ jsx("div", { style, ...listeners, ...attributes, ref: setNodeRef, className: "min-w-0", children: /* @__PURE__ */ jsx(
|
|
15120
|
+
Card,
|
|
15121
|
+
{
|
|
15122
|
+
className: cn(
|
|
15123
|
+
"cursor-grab gap-4 rounded-md p-2 shadow-sm overflow-hidden",
|
|
15124
|
+
isDragging && "pointer-events-none cursor-grabbing opacity-30",
|
|
15125
|
+
className
|
|
15126
|
+
),
|
|
15127
|
+
children: children ?? /* @__PURE__ */ jsx("p", { className: "m-0 font-medium text-sm", children: name })
|
|
15128
|
+
}
|
|
15129
|
+
) }),
|
|
15130
|
+
activeCardId === id && /* @__PURE__ */ jsx(t.In, { children: /* @__PURE__ */ jsx(
|
|
15131
|
+
Card,
|
|
15132
|
+
{
|
|
15133
|
+
className: cn(
|
|
15134
|
+
"cursor-grab gap-4 rounded-md p-2 shadow-sm ring-2 ring-primary overflow-hidden",
|
|
15135
|
+
isDragging && "cursor-grabbing",
|
|
15136
|
+
className
|
|
15137
|
+
),
|
|
15138
|
+
children: children ?? /* @__PURE__ */ jsx("p", { className: "m-0 font-medium text-sm", children: name })
|
|
15139
|
+
}
|
|
15140
|
+
) })
|
|
15141
|
+
] });
|
|
15142
|
+
};
|
|
15143
|
+
var KanbanCards = ({
|
|
15144
|
+
children,
|
|
15145
|
+
className,
|
|
15146
|
+
...props
|
|
15147
|
+
}) => {
|
|
15148
|
+
const { data } = useContext(KanbanContext);
|
|
15149
|
+
const filteredData = data.filter((item) => item.column === props.id);
|
|
15150
|
+
const items = filteredData.map((item) => item.id);
|
|
15151
|
+
return /* @__PURE__ */ jsxs(ScrollArea, { className: "overflow-hidden", children: [
|
|
15152
|
+
/* @__PURE__ */ jsx(SortableContext, { items, children: /* @__PURE__ */ jsx(
|
|
15153
|
+
"div",
|
|
15154
|
+
{
|
|
15155
|
+
className: cn("flex flex-grow flex-col gap-2 p-2", className),
|
|
15156
|
+
...props,
|
|
15157
|
+
children: filteredData.map(children)
|
|
15158
|
+
}
|
|
15159
|
+
) }),
|
|
15160
|
+
/* @__PURE__ */ jsx(ScrollBar, { orientation: "vertical" })
|
|
15161
|
+
] });
|
|
15162
|
+
};
|
|
15163
|
+
var KanbanHeader = ({ className, ...props }) => /* @__PURE__ */ jsx("div", { className: cn("m-0 p-2 font-semibold text-sm", className), ...props });
|
|
15164
|
+
var KanbanProvider = ({
|
|
15165
|
+
children,
|
|
15166
|
+
onDragStart,
|
|
15167
|
+
onDragEnd,
|
|
15168
|
+
onDragOver,
|
|
15169
|
+
className,
|
|
15170
|
+
columns,
|
|
15171
|
+
data,
|
|
15172
|
+
onDataChange,
|
|
15173
|
+
...props
|
|
15174
|
+
}) => {
|
|
15175
|
+
const [activeCardId, setActiveCardId] = useState(null);
|
|
15176
|
+
const sensors = useSensors(
|
|
15177
|
+
useSensor(MouseSensor),
|
|
15178
|
+
useSensor(TouchSensor),
|
|
15179
|
+
useSensor(KeyboardSensor)
|
|
15180
|
+
);
|
|
15181
|
+
const handleDragStart = (event) => {
|
|
15182
|
+
const card = data.find((item) => item.id === event.active.id);
|
|
15183
|
+
if (card) {
|
|
15184
|
+
setActiveCardId(event.active.id);
|
|
15185
|
+
}
|
|
15186
|
+
onDragStart?.(event);
|
|
15187
|
+
};
|
|
15188
|
+
const handleDragOver = (event) => {
|
|
15189
|
+
const { active, over } = event;
|
|
15190
|
+
if (!over) {
|
|
15191
|
+
return;
|
|
15192
|
+
}
|
|
15193
|
+
const activeItem = data.find((item) => item.id === active.id);
|
|
15194
|
+
const overItem = data.find((item) => item.id === over.id);
|
|
15195
|
+
if (!activeItem) {
|
|
15196
|
+
return;
|
|
15197
|
+
}
|
|
15198
|
+
const activeColumn = activeItem.column;
|
|
15199
|
+
const overColumn = overItem?.column || columns.find((col) => col.id === over.id)?.id || columns[0]?.id;
|
|
15200
|
+
if (activeColumn !== overColumn) {
|
|
15201
|
+
let newData = [...data];
|
|
15202
|
+
const activeIndex = newData.findIndex((item) => item.id === active.id);
|
|
15203
|
+
const overIndex = newData.findIndex((item) => item.id === over.id);
|
|
15204
|
+
newData[activeIndex].column = overColumn;
|
|
15205
|
+
newData = arrayMove(newData, activeIndex, overIndex);
|
|
15206
|
+
onDataChange?.(newData);
|
|
15207
|
+
}
|
|
15208
|
+
onDragOver?.(event);
|
|
15209
|
+
};
|
|
15210
|
+
const handleDragEnd = (event) => {
|
|
15211
|
+
setActiveCardId(null);
|
|
15212
|
+
onDragEnd?.(event);
|
|
15213
|
+
const { active, over } = event;
|
|
15214
|
+
if (!over || active.id === over.id) {
|
|
15215
|
+
return;
|
|
15216
|
+
}
|
|
15217
|
+
let newData = [...data];
|
|
15218
|
+
const oldIndex = newData.findIndex((item) => item.id === active.id);
|
|
15219
|
+
const newIndex = newData.findIndex((item) => item.id === over.id);
|
|
15220
|
+
newData = arrayMove(newData, oldIndex, newIndex);
|
|
15221
|
+
onDataChange?.(newData);
|
|
15222
|
+
};
|
|
15223
|
+
const announcements = {
|
|
15224
|
+
onDragStart({ active }) {
|
|
15225
|
+
const { name, column } = data.find((item) => item.id === active.id) ?? {};
|
|
15226
|
+
return `Picked up the card "${name}" from the "${column}" column`;
|
|
15227
|
+
},
|
|
15228
|
+
onDragOver({ active, over }) {
|
|
15229
|
+
const { name } = data.find((item) => item.id === active.id) ?? {};
|
|
15230
|
+
const newColumn = columns.find((column) => column.id === over?.id)?.name;
|
|
15231
|
+
return `Dragged the card "${name}" over the "${newColumn}" column`;
|
|
15232
|
+
},
|
|
15233
|
+
onDragEnd({ active, over }) {
|
|
15234
|
+
const { name } = data.find((item) => item.id === active.id) ?? {};
|
|
15235
|
+
const newColumn = columns.find((column) => column.id === over?.id)?.name;
|
|
15236
|
+
return `Dropped the card "${name}" into the "${newColumn}" column`;
|
|
15237
|
+
},
|
|
15238
|
+
onDragCancel({ active }) {
|
|
15239
|
+
const { name } = data.find((item) => item.id === active.id) ?? {};
|
|
15240
|
+
return `Cancelled dragging the card "${name}"`;
|
|
15241
|
+
}
|
|
15242
|
+
};
|
|
15243
|
+
return /* @__PURE__ */ jsx(KanbanContext.Provider, { value: { columns, data, activeCardId }, children: /* @__PURE__ */ jsxs(
|
|
15244
|
+
DndContext,
|
|
15245
|
+
{
|
|
15246
|
+
accessibility: { announcements },
|
|
15247
|
+
collisionDetection: closestCenter,
|
|
15248
|
+
onDragEnd: handleDragEnd,
|
|
15249
|
+
onDragOver: handleDragOver,
|
|
15250
|
+
onDragStart: handleDragStart,
|
|
15251
|
+
sensors,
|
|
15252
|
+
...props,
|
|
15253
|
+
children: [
|
|
15254
|
+
/* @__PURE__ */ jsx(
|
|
15255
|
+
"div",
|
|
15256
|
+
{
|
|
15257
|
+
className: cn(
|
|
15258
|
+
"grid size-full auto-cols-fr grid-flow-col gap-4",
|
|
15259
|
+
className
|
|
15260
|
+
),
|
|
15261
|
+
children: columns.map((column) => children(column))
|
|
15262
|
+
}
|
|
15263
|
+
),
|
|
15264
|
+
typeof window !== "undefined" && createPortal(
|
|
15265
|
+
/* @__PURE__ */ jsx(DragOverlay, { children: /* @__PURE__ */ jsx(t.Out, {}) }),
|
|
15266
|
+
document.body
|
|
15267
|
+
)
|
|
15268
|
+
]
|
|
15269
|
+
}
|
|
15270
|
+
) });
|
|
15271
|
+
};
|
|
13581
15272
|
|
|
13582
|
-
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, AgendaView, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AspectRatio, Avatar, AvatarFallback, AvatarImage, BADGE_VARIANT_LABELS, Badge, BigCalendar, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, Calendar, CalendarContext, CalendarDayButton, CalendarHeader, CalendarHeaderCompact, CalendarSettingsButton, CalendarSettingsContent, CalendarSettingsDialog, CalibrationTable, CalibrationWeekCell, CalibrationWeekHeader, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, ChangeBadgeVariantInput, ChangeVisibleHoursInput, ChangeWorkingHoursInput, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, Checkbox, CircularProgress, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, CommentButton, CommentDialog, CommentPopover, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DEFAULT_VISIBLE_HOURS, DEFAULT_WORKING_HOURS, DataTableColumnHeader, DataTablePagination, DataTableViewOptions, DateBadge, DayView, DeliveryBadge, DeliveryCard, DeliveryDetailPage, DeliveryIndicator, DeliveryIndicators, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DragContext, DragProvider, DraggableEvent, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, DroppableZone, EVENT_COLORS, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, EventBadge, EventCalendarProvider, EventDialog, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, HoverCard, HoverCardContent, HoverCardTrigger, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Item6 as Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, Label2 as Label, Map2 as Map, MapMarker, MapPopup, MapTileLayer, MapTooltip, MapZoomControl, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, MonthView, MoreEvents, NativeSelect, NativeSelectOptGroup, NativeSelectOption, NavMain, NavProjects, NavSecondary, NavUser, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NetBadge, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PlanningTable, PlanningTableToolbar, PlanningWeekCommentPopover, PlayerCanvas, PlayerCanvasActionButton, PlayerCanvasControls, PlayerCanvasDivider, PlayerCanvasInfo, PlayerCanvasLabel, PlayerCanvasPlayButton, PlayerCanvasProgress, PlayerCanvasSkipButton, PlayerCanvasTitle, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, QuickAddEvent, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, RowHeaderCell, ScrollArea, ScrollBar, SearchForm, SearchTrigger, Section, SectionContent, SectionDescription, SectionFooter, SectionHeader, SectionTitle, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetBody, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, SiteHeader, Skeleton, Slider, Spinner, SubmitCalibrationBar, SupplierCell, SupplierWeeklyLoading, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, ThemeSwitch, TimeIndicator, Toaster, Toggle, ToggleGroup, ToggleGroupItem, ToolBarCanvas, ToolBarCanvasButton, ToolBarCanvasDivider, ToolBarCanvasGroup, Tooltip2 as Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserAvatarsDropdown, VIEW_LABELS, WeekCell, WeekDetailDialog, WeekHeader, WeekView, WeeklyLoadingView, YearView, badgeVariants, buttonGroupVariants, buttonVariants, calculateCalibrationCells, calculateDropDates, calculateMonthEventPositions, canSubmitCalibration, cardVariants, createDefaultEvent, deliveryIndicatorVariants, extractPrefixes, formatCalibrationUnit, formatDateRange2 as formatDateRange, formatProductionUnit, formatTime, generateColumns, generateEventId, generateLoadingWeek, generateLocationOptions, generateWeekColumns, generateWeeks, getCalendarCells, getCommentLocationLabel, getCurrentEvents, getDayHours, getDayLabel, getDeliveryVisualState, getElementShipmentStatus, getEventBlockStyle, getEventDuration, getEventDurationMinutes, getEventsCount, getEventsForDate, getEventsInRange, getHeaderLabel, getISOWeek, getLoadingDeliveryStatusLabel, getLoadingElementStatusLabel, getLoadingISOWeek, getLoadingWeekKey, getMonthCellEvents, getMonthDays, getShipmentStatusLabel, getShortDayLabel, getSupplierColumn, getTimeHeight, getTimePosition, getViewDateRange, getVisibleHours, getWeekDayNames, getWeekDays, getWeekKey, getYearMonths, groupDeliveriesByDay, groupDeliveriesByPrefixAndDay, groupEvents, isMultiDayEvent, isWorkingHour, navigateDate, navigationMenuTriggerStyle, playerCanvasPlayButtonVariants, playerCanvasSkipButtonVariants, rangeText, sectionVariants, snapToInterval, sortEvents, splitEventsByDuration, toggleVariants, toolBarCanvasButtonVariants, useDrag, useDraggable, useDroppable, useEventCalendar, useEventsInRange, useFilteredEvents, useFormField, useIsMobile, useSearchShortcut, useSidebar };
|
|
15273
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, AgendaView, Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AspectRatio, Avatar, AvatarFallback, AvatarImage, BADGE_VARIANT_LABELS, Badge, BigCalendar, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, Calendar, CalendarContext, CalendarDayButton, CalendarHeader, CalendarHeaderCompact, CalendarSettingsButton, CalendarSettingsContent, CalendarSettingsDialog, CalibrationTable, CalibrationWeekCell, CalibrationWeekHeader, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, ChangeBadgeVariantInput, ChangeVisibleHoursInput, ChangeWorkingHoursInput, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, Checkbox, CircularProgress, Collapsible, CollapsibleContent2 as CollapsibleContent, CollapsibleTrigger2 as CollapsibleTrigger, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, CommentButton, CommentDialog, CommentPopover, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, DEFAULT_VISIBLE_HOURS, DEFAULT_WORKING_HOURS, DataTableColumnHeader, DataTablePagination, DataTableViewOptions, DateBadge, DayView, DeliveryBadge, DeliveryCard, DeliveryDetailPage, DeliveryIndicator, DeliveryIndicators, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DragContext, DragProvider, DraggableEvent, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, DroppableZone, EVENT_COLORS, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, EventBadge, EventCalendarProvider, EventDialog, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, GanttAddFeatureHelper, GanttCollapsibleSidebarGroup, GanttCollapsibleTimelineGroup, GanttColumn, GanttColumns, GanttContentHeader, GanttCreateMarkerTrigger, GanttFeatureDragHelper, GanttFeatureItem, GanttFeatureItemCard, GanttFeatureList, GanttFeatureListGroup, GanttFeatureRow, GanttGridLines, GanttGroupSummaryBar, GanttHeader, GanttMarker, GanttProvider, GanttSidebar, GanttSidebarGroup, GanttSidebarHeader, GanttSidebarItem, GanttTimeline, GanttToday, HoverCard, HoverCardContent, HoverCardTrigger, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, Item6 as Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, KanbanBoard, KanbanCard, KanbanCards, KanbanHeader, KanbanProvider, Kbd, KbdGroup, Label2 as Label, Map2 as Map, MapMarker, MapPopup, MapTileLayer, MapTooltip, MapZoomControl, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, MonthView, MoreEvents, NativeSelect, NativeSelectOptGroup, NativeSelectOption, NavMain, NavProjects, NavSecondary, NavUser, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NetBadge, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PlanningTable, PlanningTableToolbar, PlanningWeekCommentPopover, PlayerCanvas, PlayerCanvasActionButton, PlayerCanvasControls, PlayerCanvasDivider, PlayerCanvasInfo, PlayerCanvasLabel, PlayerCanvasPlayButton, PlayerCanvasProgress, PlayerCanvasSkipButton, PlayerCanvasTitle, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, Progress, QuickAddEvent, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, RowHeaderCell, ScrollArea, ScrollBar, SearchForm, SearchTrigger, Section, SectionContent, SectionDescription, SectionFooter, SectionHeader, SectionTitle, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetBody, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, SiteHeader, Skeleton, Slider, Spinner, SubmitCalibrationBar, SupplierCell, SupplierWeeklyLoading, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, ThemeSwitch, TimeIndicator, Toaster, Toggle, ToggleGroup, ToggleGroupItem, ToolBarCanvas, ToolBarCanvasButton, ToolBarCanvasDivider, ToolBarCanvasGroup, Tooltip2 as Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserAvatarsDropdown, VIEW_LABELS, WeekCell, WeekDetailDialog, WeekHeader, WeekView, WeeklyLoadingView, YearView, badgeVariants, buttonGroupVariants, buttonVariants, calculateCalibrationCells, calculateDropDates, calculateMonthEventPositions, canSubmitCalibration, cardVariants, createDefaultEvent, deliveryIndicatorVariants, extractPrefixes, formatCalibrationUnit, formatDateRange2 as formatDateRange, formatProductionUnit, formatTime, generateColumns, generateEventId, generateLoadingWeek, generateLocationOptions, generateWeekColumns, generateWeeks, getCalendarCells, getCommentLocationLabel, getCurrentEvents, getDayHours, getDayLabel, getDeliveryVisualState, getElementShipmentStatus, getEventBlockStyle, getEventDuration, getEventDurationMinutes, getEventsCount, getEventsForDate, getEventsInRange, getHeaderLabel, getISOWeek, getLoadingDeliveryStatusLabel, getLoadingElementStatusLabel, getLoadingISOWeek, getLoadingWeekKey, getMonthCellEvents, getMonthDays, getShipmentStatusLabel, getShortDayLabel, getSupplierColumn, getTimeHeight, getTimePosition, getViewDateRange, getVisibleHours, getWeekDayNames, getWeekDays, getWeekKey, getYearMonths, groupDeliveriesByDay, groupDeliveriesByPrefixAndDay, groupEvents, isMultiDayEvent, isWorkingHour, navigateDate, navigationMenuTriggerStyle, playerCanvasPlayButtonVariants, playerCanvasSkipButtonVariants, rangeText, sectionVariants, snapToInterval, sortEvents, splitEventsByDuration, toggleVariants, toolBarCanvasButtonVariants, useDrag, useDraggable, useDroppable, useEventCalendar, useEventsInRange, useFilteredEvents, useFormField, useGanttDragging, useGanttScrollX, useIsMobile, useSearchShortcut, useSidebar };
|
|
13583
15274
|
//# sourceMappingURL=index.js.map
|
|
13584
15275
|
//# sourceMappingURL=index.js.map
|