@algenium/blocks 1.19.0 → 1.20.0
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 +671 -231
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +672 -232
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ import { Drawer as Drawer$1 } from 'vaul';
|
|
|
14
14
|
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
|
15
15
|
import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
|
|
16
16
|
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
17
|
-
import { startOfMonth, endOfMonth, eachDayOfInterval, endOfWeek, startOfWeek, format, isSameDay, subMonths, addMonths } from 'date-fns';
|
|
17
|
+
import { startOfMonth, endOfMonth, eachDayOfInterval, endOfWeek, startOfWeek, format, isSameDay, startOfDay, subMonths, addMonths, addDays, addHours, setMinutes, setHours } from 'date-fns';
|
|
18
18
|
import { DayPicker } from 'react-day-picker';
|
|
19
19
|
import { Command as Command$1 } from 'cmdk';
|
|
20
20
|
import valid from 'card-validator';
|
|
@@ -6522,6 +6522,258 @@ function CalendarView({
|
|
|
6522
6522
|
] })
|
|
6523
6523
|
] });
|
|
6524
6524
|
}
|
|
6525
|
+
var TIME_SLOTS = Array.from({ length: 24 * 4 }, (_, i) => {
|
|
6526
|
+
const hours = Math.floor(i / 4);
|
|
6527
|
+
const minutes = i % 4 * 15;
|
|
6528
|
+
return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}`;
|
|
6529
|
+
});
|
|
6530
|
+
function formatTimeDisplay(value) {
|
|
6531
|
+
const parsed = parseTimeInput(value);
|
|
6532
|
+
if (!parsed) return value;
|
|
6533
|
+
const [h, m] = parsed.split(":").map(Number);
|
|
6534
|
+
const period = h >= 12 ? "pm" : "am";
|
|
6535
|
+
const hour12 = h % 12 === 0 ? 12 : h % 12;
|
|
6536
|
+
return `${hour12}:${String(m).padStart(2, "0")}${period}`;
|
|
6537
|
+
}
|
|
6538
|
+
function parseTimeInput(raw) {
|
|
6539
|
+
const cleaned = raw.trim().toLowerCase().replace(/\s+/g, "");
|
|
6540
|
+
if (!cleaned) return null;
|
|
6541
|
+
const ampmMatch = cleaned.match(/^(\d{1,2})(?::(\d{2}))?(am|pm)$/);
|
|
6542
|
+
if (ampmMatch) {
|
|
6543
|
+
let hours = Number(ampmMatch[1]);
|
|
6544
|
+
const minutes = Number(ampmMatch[2] ?? "0");
|
|
6545
|
+
const period = ampmMatch[3];
|
|
6546
|
+
if (hours < 1 || hours > 12 || minutes > 59) return null;
|
|
6547
|
+
if (period === "am") {
|
|
6548
|
+
if (hours === 12) hours = 0;
|
|
6549
|
+
} else if (hours !== 12) {
|
|
6550
|
+
hours += 12;
|
|
6551
|
+
}
|
|
6552
|
+
return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}`;
|
|
6553
|
+
}
|
|
6554
|
+
const colonMatch = cleaned.match(/^(\d{1,2}):(\d{2})$/);
|
|
6555
|
+
if (colonMatch) {
|
|
6556
|
+
const hours = Number(colonMatch[1]);
|
|
6557
|
+
const minutes = Number(colonMatch[2]);
|
|
6558
|
+
if (hours > 23 || minutes > 59) return null;
|
|
6559
|
+
return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}`;
|
|
6560
|
+
}
|
|
6561
|
+
const compactMatch = cleaned.match(/^(\d{1,2})(\d{2})$/);
|
|
6562
|
+
if (compactMatch) {
|
|
6563
|
+
const hours = Number(compactMatch[1]);
|
|
6564
|
+
const minutes = Number(compactMatch[2]);
|
|
6565
|
+
if (hours > 23 || minutes > 59) return null;
|
|
6566
|
+
return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}`;
|
|
6567
|
+
}
|
|
6568
|
+
const hourOnly = cleaned.match(/^(\d{1,2})$/);
|
|
6569
|
+
if (hourOnly) {
|
|
6570
|
+
const hours = Number(hourOnly[1]);
|
|
6571
|
+
if (hours > 23) return null;
|
|
6572
|
+
return `${String(hours).padStart(2, "0")}:00`;
|
|
6573
|
+
}
|
|
6574
|
+
return null;
|
|
6575
|
+
}
|
|
6576
|
+
function minutesFromMidnight(value) {
|
|
6577
|
+
const [h, m] = value.split(":").map(Number);
|
|
6578
|
+
return h * 60 + m;
|
|
6579
|
+
}
|
|
6580
|
+
function formatDurationHintClean(start, end) {
|
|
6581
|
+
let mins = minutesFromMidnight(end) - minutesFromMidnight(start);
|
|
6582
|
+
if (mins <= 0) mins += 24 * 60;
|
|
6583
|
+
if (mins < 60) return `${mins} mins`;
|
|
6584
|
+
const hours = Math.floor(mins / 60);
|
|
6585
|
+
const rem = mins % 60;
|
|
6586
|
+
if (rem === 0) return hours === 1 ? "1 hr" : `${hours} hrs`;
|
|
6587
|
+
if (rem === 30) return `${hours}.5 hrs`;
|
|
6588
|
+
return `${hours} hr ${rem} mins`;
|
|
6589
|
+
}
|
|
6590
|
+
function TimeCombobox({
|
|
6591
|
+
value,
|
|
6592
|
+
onChange,
|
|
6593
|
+
disabled,
|
|
6594
|
+
durationFrom,
|
|
6595
|
+
className,
|
|
6596
|
+
placeholder = "Time",
|
|
6597
|
+
"aria-label": ariaLabel
|
|
6598
|
+
}) {
|
|
6599
|
+
const [open, setOpen] = useState(false);
|
|
6600
|
+
const [draft, setDraft] = useState(formatTimeDisplay(value));
|
|
6601
|
+
const listRef = useRef(null);
|
|
6602
|
+
const selectedRef = useRef(null);
|
|
6603
|
+
useEffect(() => {
|
|
6604
|
+
if (!open) {
|
|
6605
|
+
setDraft(formatTimeDisplay(value));
|
|
6606
|
+
}
|
|
6607
|
+
}, [value, open]);
|
|
6608
|
+
useEffect(() => {
|
|
6609
|
+
if (open) {
|
|
6610
|
+
requestAnimationFrame(() => {
|
|
6611
|
+
selectedRef.current?.scrollIntoView({ block: "center" });
|
|
6612
|
+
});
|
|
6613
|
+
}
|
|
6614
|
+
}, [open]);
|
|
6615
|
+
const filtered = useMemo(() => {
|
|
6616
|
+
const q = draft.trim().toLowerCase().replace(/\s+/g, "");
|
|
6617
|
+
if (!q || parseTimeInput(draft) === value) return TIME_SLOTS;
|
|
6618
|
+
return TIME_SLOTS.filter((slot) => {
|
|
6619
|
+
const display = formatTimeDisplay(slot).toLowerCase();
|
|
6620
|
+
return display.includes(q) || slot.includes(q);
|
|
6621
|
+
});
|
|
6622
|
+
}, [draft, value]);
|
|
6623
|
+
const commitDraft = () => {
|
|
6624
|
+
const parsed = parseTimeInput(draft);
|
|
6625
|
+
if (parsed) {
|
|
6626
|
+
onChange(parsed);
|
|
6627
|
+
setDraft(formatTimeDisplay(parsed));
|
|
6628
|
+
} else {
|
|
6629
|
+
setDraft(formatTimeDisplay(value));
|
|
6630
|
+
}
|
|
6631
|
+
};
|
|
6632
|
+
return /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
|
|
6633
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
6634
|
+
"button",
|
|
6635
|
+
{
|
|
6636
|
+
type: "button",
|
|
6637
|
+
disabled,
|
|
6638
|
+
"aria-label": ariaLabel,
|
|
6639
|
+
className: cn(
|
|
6640
|
+
"inline-flex h-9 min-w-[5.5rem] items-center justify-center rounded-md border border-input bg-background px-2 text-sm tabular-nums ring-offset-background transition-colors",
|
|
6641
|
+
"hover:bg-accent hover:text-accent-foreground",
|
|
6642
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
6643
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
6644
|
+
className
|
|
6645
|
+
),
|
|
6646
|
+
onClick: () => setOpen(true),
|
|
6647
|
+
children: formatTimeDisplay(value) || placeholder
|
|
6648
|
+
}
|
|
6649
|
+
) }),
|
|
6650
|
+
/* @__PURE__ */ jsxs(
|
|
6651
|
+
PopoverContent,
|
|
6652
|
+
{
|
|
6653
|
+
className: "z-[100] w-40 p-0",
|
|
6654
|
+
align: "start",
|
|
6655
|
+
onOpenAutoFocus: (e) => {
|
|
6656
|
+
e.preventDefault();
|
|
6657
|
+
const input = e.currentTarget?.querySelector(
|
|
6658
|
+
"input"
|
|
6659
|
+
);
|
|
6660
|
+
input?.focus();
|
|
6661
|
+
},
|
|
6662
|
+
children: [
|
|
6663
|
+
/* @__PURE__ */ jsx("div", { className: "border-b p-1.5", children: /* @__PURE__ */ jsx(
|
|
6664
|
+
"input",
|
|
6665
|
+
{
|
|
6666
|
+
value: draft,
|
|
6667
|
+
onChange: (e) => setDraft(e.target.value),
|
|
6668
|
+
onKeyDown: (e) => {
|
|
6669
|
+
if (e.key === "Enter") {
|
|
6670
|
+
e.preventDefault();
|
|
6671
|
+
commitDraft();
|
|
6672
|
+
setOpen(false);
|
|
6673
|
+
} else if (e.key === "Escape") {
|
|
6674
|
+
setDraft(formatTimeDisplay(value));
|
|
6675
|
+
setOpen(false);
|
|
6676
|
+
}
|
|
6677
|
+
},
|
|
6678
|
+
onBlur: commitDraft,
|
|
6679
|
+
placeholder,
|
|
6680
|
+
className: "w-full rounded-md border border-input bg-background px-2 py-1.5 text-sm tabular-nums focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
6681
|
+
"aria-label": ariaLabel
|
|
6682
|
+
}
|
|
6683
|
+
) }),
|
|
6684
|
+
/* @__PURE__ */ jsxs("div", { ref: listRef, className: "max-h-56 overflow-y-auto py-1", children: [
|
|
6685
|
+
filtered.map((slot) => {
|
|
6686
|
+
const selected = slot === value;
|
|
6687
|
+
const label = formatTimeDisplay(slot);
|
|
6688
|
+
const hint = durationFrom != null ? formatDurationHintClean(durationFrom, slot) : null;
|
|
6689
|
+
return /* @__PURE__ */ jsxs(
|
|
6690
|
+
"button",
|
|
6691
|
+
{
|
|
6692
|
+
ref: selected ? selectedRef : void 0,
|
|
6693
|
+
type: "button",
|
|
6694
|
+
className: cn(
|
|
6695
|
+
"flex w-full items-center justify-between px-3 py-1.5 text-left text-sm tabular-nums hover:bg-accent",
|
|
6696
|
+
selected && "bg-accent font-medium"
|
|
6697
|
+
),
|
|
6698
|
+
onMouseDown: (e) => {
|
|
6699
|
+
e.preventDefault();
|
|
6700
|
+
},
|
|
6701
|
+
onClick: () => {
|
|
6702
|
+
onChange(slot);
|
|
6703
|
+
setDraft(formatTimeDisplay(slot));
|
|
6704
|
+
setOpen(false);
|
|
6705
|
+
},
|
|
6706
|
+
children: [
|
|
6707
|
+
/* @__PURE__ */ jsx("span", { children: label }),
|
|
6708
|
+
hint && /* @__PURE__ */ jsx("span", { className: "ml-2 text-xs text-muted-foreground", children: hint })
|
|
6709
|
+
]
|
|
6710
|
+
},
|
|
6711
|
+
slot
|
|
6712
|
+
);
|
|
6713
|
+
}),
|
|
6714
|
+
filtered.length === 0 && /* @__PURE__ */ jsx("p", { className: "px-3 py-2 text-xs text-muted-foreground", children: "No matching times" })
|
|
6715
|
+
] })
|
|
6716
|
+
]
|
|
6717
|
+
}
|
|
6718
|
+
)
|
|
6719
|
+
] });
|
|
6720
|
+
}
|
|
6721
|
+
function toTimeValue(date) {
|
|
6722
|
+
return `${String(date.getHours()).padStart(2, "0")}:${String(date.getMinutes()).padStart(2, "0")}`;
|
|
6723
|
+
}
|
|
6724
|
+
function dateKey(date) {
|
|
6725
|
+
return format(date, "yyyy-MM-dd");
|
|
6726
|
+
}
|
|
6727
|
+
function combineDateAndTime(date, time) {
|
|
6728
|
+
const [h, m] = time.split(":").map(Number);
|
|
6729
|
+
return setMinutes(setHours(startOfDay(date), h), m);
|
|
6730
|
+
}
|
|
6731
|
+
function defaultTimes(from) {
|
|
6732
|
+
const base = /* @__PURE__ */ new Date();
|
|
6733
|
+
const nextHour = addHours(setMinutes(setHours(base, base.getHours()), 0), 1);
|
|
6734
|
+
const end = addHours(nextHour, 1);
|
|
6735
|
+
return {
|
|
6736
|
+
date: startOfDay(nextHour),
|
|
6737
|
+
startTime: toTimeValue(nextHour),
|
|
6738
|
+
endTime: toTimeValue(end)
|
|
6739
|
+
};
|
|
6740
|
+
}
|
|
6741
|
+
function splitEventTimes(event) {
|
|
6742
|
+
if (event?.dtstart) {
|
|
6743
|
+
const start = new Date(event.dtstart);
|
|
6744
|
+
const end = event.dtend ? new Date(event.dtend) : addHours(start, 1);
|
|
6745
|
+
return {
|
|
6746
|
+
date: startOfDay(start),
|
|
6747
|
+
startTime: toTimeValue(start),
|
|
6748
|
+
endTime: toTimeValue(end),
|
|
6749
|
+
allDay: event.allDay ?? false
|
|
6750
|
+
};
|
|
6751
|
+
}
|
|
6752
|
+
const defaults = defaultTimes();
|
|
6753
|
+
return { ...defaults, allDay: event?.allDay ?? false };
|
|
6754
|
+
}
|
|
6755
|
+
var dayPickerClassNames = {
|
|
6756
|
+
months: "flex flex-col",
|
|
6757
|
+
month: "space-y-2",
|
|
6758
|
+
month_caption: "flex justify-center relative items-center pt-1",
|
|
6759
|
+
caption_label: "text-sm font-medium",
|
|
6760
|
+
nav: "space-x-1 flex items-center",
|
|
6761
|
+
button_previous: "h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100 absolute left-1 top-1 inline-flex items-center justify-center rounded-md hover:bg-accent",
|
|
6762
|
+
button_next: "h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100 absolute right-1 top-1 inline-flex items-center justify-center rounded-md hover:bg-accent",
|
|
6763
|
+
month_grid: "w-full border-collapse space-y-1",
|
|
6764
|
+
weekdays: "flex",
|
|
6765
|
+
weekday: "text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]",
|
|
6766
|
+
week: "flex w-full mt-1",
|
|
6767
|
+
day: "relative p-0 text-center text-sm focus-within:relative focus-within:z-20",
|
|
6768
|
+
day_button: cn(
|
|
6769
|
+
"h-8 w-8 p-0 font-normal",
|
|
6770
|
+
"hover:bg-accent hover:text-accent-foreground rounded-md"
|
|
6771
|
+
),
|
|
6772
|
+
selected: "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground rounded-md",
|
|
6773
|
+
today: "bg-accent text-accent-foreground rounded-md",
|
|
6774
|
+
outside: "text-muted-foreground opacity-50",
|
|
6775
|
+
disabled: "text-muted-foreground opacity-50"
|
|
6776
|
+
};
|
|
6525
6777
|
function EventDialog({
|
|
6526
6778
|
open,
|
|
6527
6779
|
onOpenChange,
|
|
@@ -6541,13 +6793,11 @@ function EventDialog({
|
|
|
6541
6793
|
const [summary, setSummary] = useState(event?.summary ?? "");
|
|
6542
6794
|
const [description, setDescription] = useState(event?.description ?? "");
|
|
6543
6795
|
const [location, setLocation] = useState(event?.location ?? "");
|
|
6544
|
-
const
|
|
6545
|
-
|
|
6546
|
-
);
|
|
6547
|
-
const [
|
|
6548
|
-
|
|
6549
|
-
);
|
|
6550
|
-
const [allDay, setAllDay] = useState(event?.allDay ?? false);
|
|
6796
|
+
const initialTimes = splitEventTimes(event);
|
|
6797
|
+
const [date, setDate] = useState(initialTimes.date);
|
|
6798
|
+
const [startTime, setStartTime] = useState(initialTimes.startTime);
|
|
6799
|
+
const [endTime, setEndTime] = useState(initialTimes.endTime);
|
|
6800
|
+
const [allDay, setAllDay] = useState(initialTimes.allDay);
|
|
6551
6801
|
const [categoryId, setCategoryId] = useState(event?.categoryId ?? "");
|
|
6552
6802
|
const [referenceType, setReferenceType] = useState(
|
|
6553
6803
|
event?.referenceType ?? ""
|
|
@@ -6558,20 +6808,47 @@ function EventDialog({
|
|
|
6558
6808
|
const [linkOptions, setLinkOptions] = useState([]);
|
|
6559
6809
|
const [saving, setSaving] = useState(false);
|
|
6560
6810
|
const [completing, setCompleting] = useState(false);
|
|
6811
|
+
const [datePickerOpen, setDatePickerOpen] = useState(false);
|
|
6812
|
+
const [confirmDiscard, setConfirmDiscard] = useState(false);
|
|
6813
|
+
const [discardIntent, setDiscardIntent] = useState(
|
|
6814
|
+
"close"
|
|
6815
|
+
);
|
|
6816
|
+
const snapshotRef = useRef(null);
|
|
6817
|
+
const allowCloseRef = useRef(false);
|
|
6561
6818
|
const linkTimer = useRef(null);
|
|
6819
|
+
const requestDiscard = (intent) => {
|
|
6820
|
+
setDiscardIntent(intent);
|
|
6821
|
+
setConfirmDiscard(true);
|
|
6822
|
+
};
|
|
6823
|
+
const revertToSnapshot = () => {
|
|
6824
|
+
const snap = snapshotRef.current;
|
|
6825
|
+
if (!snap) return;
|
|
6826
|
+
setSummary(snap.summary);
|
|
6827
|
+
setDescription(snap.description);
|
|
6828
|
+
setLocation(snap.location);
|
|
6829
|
+
setDate(startOfDay(/* @__PURE__ */ new Date(`${snap.dateKey}T00:00:00`)));
|
|
6830
|
+
setStartTime(snap.startTime);
|
|
6831
|
+
setEndTime(snap.endTime);
|
|
6832
|
+
setAllDay(snap.allDay);
|
|
6833
|
+
setCategoryId(snap.categoryId);
|
|
6834
|
+
setReferenceType(snap.referenceType);
|
|
6835
|
+
setReferenceId(snap.referenceId);
|
|
6836
|
+
};
|
|
6562
6837
|
useEffect(() => {
|
|
6563
|
-
if (!open)
|
|
6838
|
+
if (!open) {
|
|
6839
|
+
setConfirmDiscard(false);
|
|
6840
|
+
allowCloseRef.current = false;
|
|
6841
|
+
return;
|
|
6842
|
+
}
|
|
6564
6843
|
setMode(event?.id ? "preview" : "edit");
|
|
6565
6844
|
setSummary(event?.summary ?? "");
|
|
6566
6845
|
setDescription(event?.description ?? "");
|
|
6567
6846
|
setLocation(event?.location ?? "");
|
|
6568
|
-
|
|
6569
|
-
|
|
6570
|
-
);
|
|
6571
|
-
|
|
6572
|
-
|
|
6573
|
-
);
|
|
6574
|
-
setAllDay(event?.allDay ?? false);
|
|
6847
|
+
const times = splitEventTimes(event);
|
|
6848
|
+
setDate(times.date);
|
|
6849
|
+
setStartTime(times.startTime);
|
|
6850
|
+
setEndTime(times.endTime);
|
|
6851
|
+
setAllDay(times.allDay);
|
|
6575
6852
|
setCategoryId(event?.categoryId ?? "");
|
|
6576
6853
|
setReferenceType(event?.referenceType ?? "");
|
|
6577
6854
|
setReferenceId(event?.referenceId ?? "");
|
|
@@ -6580,6 +6857,21 @@ function EventDialog({
|
|
|
6580
6857
|
);
|
|
6581
6858
|
setLinkQuery("");
|
|
6582
6859
|
setLinkOptions([]);
|
|
6860
|
+
setConfirmDiscard(false);
|
|
6861
|
+
allowCloseRef.current = false;
|
|
6862
|
+
const snap = {
|
|
6863
|
+
summary: (event?.summary ?? "").trim(),
|
|
6864
|
+
description: (event?.description ?? "").trim(),
|
|
6865
|
+
location: (event?.location ?? "").trim(),
|
|
6866
|
+
dateKey: dateKey(times.date),
|
|
6867
|
+
startTime: times.startTime,
|
|
6868
|
+
endTime: times.endTime,
|
|
6869
|
+
allDay: times.allDay,
|
|
6870
|
+
categoryId: event?.categoryId ?? "",
|
|
6871
|
+
referenceType: event?.referenceType ?? "",
|
|
6872
|
+
referenceId: event?.referenceId ?? ""
|
|
6873
|
+
};
|
|
6874
|
+
snapshotRef.current = snap;
|
|
6583
6875
|
}, [open, event]);
|
|
6584
6876
|
useEffect(() => {
|
|
6585
6877
|
if (!linkSearch || !linkQuery.trim()) {
|
|
@@ -6599,25 +6891,69 @@ function EventDialog({
|
|
|
6599
6891
|
if (linkTimer.current) clearTimeout(linkTimer.current);
|
|
6600
6892
|
};
|
|
6601
6893
|
}, [linkQuery, linkSearch]);
|
|
6894
|
+
const isDirty = useMemo(() => {
|
|
6895
|
+
const snap = snapshotRef.current;
|
|
6896
|
+
if (!snap) return false;
|
|
6897
|
+
return summary.trim() !== snap.summary || description.trim() !== snap.description || location.trim() !== snap.location || dateKey(date) !== snap.dateKey || startTime !== snap.startTime || endTime !== snap.endTime || allDay !== snap.allDay || categoryId !== snap.categoryId || referenceType !== snap.referenceType || referenceId !== snap.referenceId;
|
|
6898
|
+
}, [
|
|
6899
|
+
summary,
|
|
6900
|
+
description,
|
|
6901
|
+
location,
|
|
6902
|
+
date,
|
|
6903
|
+
startTime,
|
|
6904
|
+
endTime,
|
|
6905
|
+
allDay,
|
|
6906
|
+
categoryId,
|
|
6907
|
+
referenceType,
|
|
6908
|
+
referenceId
|
|
6909
|
+
]);
|
|
6602
6910
|
const selectedCategory = categories.find((c) => c.id === categoryId) ?? event?.category ?? null;
|
|
6911
|
+
const handleOpenChange = (nextOpen) => {
|
|
6912
|
+
if (nextOpen) {
|
|
6913
|
+
onOpenChange(true);
|
|
6914
|
+
return;
|
|
6915
|
+
}
|
|
6916
|
+
if (allowCloseRef.current || saving) {
|
|
6917
|
+
allowCloseRef.current = false;
|
|
6918
|
+
onOpenChange(false);
|
|
6919
|
+
return;
|
|
6920
|
+
}
|
|
6921
|
+
if (mode === "edit" && isDirty) {
|
|
6922
|
+
requestDiscard("close");
|
|
6923
|
+
return;
|
|
6924
|
+
}
|
|
6925
|
+
onOpenChange(false);
|
|
6926
|
+
};
|
|
6927
|
+
const forceClose = () => {
|
|
6928
|
+
allowCloseRef.current = true;
|
|
6929
|
+
setConfirmDiscard(false);
|
|
6930
|
+
onOpenChange(false);
|
|
6931
|
+
};
|
|
6603
6932
|
const handleSave = async () => {
|
|
6604
|
-
if (!summary.trim() || !
|
|
6933
|
+
if (!summary.trim() || !date || !startTime || !endTime) return;
|
|
6605
6934
|
setSaving(true);
|
|
6606
6935
|
try {
|
|
6936
|
+
const start = allDay ? startOfDay(date) : combineDateAndTime(date, startTime);
|
|
6937
|
+
let end = allDay ? startOfDay(addDays(date, 1)) : combineDateAndTime(date, endTime);
|
|
6938
|
+
if (!allDay && end.getTime() <= start.getTime()) {
|
|
6939
|
+
end = addDays(end, 1);
|
|
6940
|
+
}
|
|
6607
6941
|
await onSave({
|
|
6608
6942
|
...event?.id ? { id: event.id } : {},
|
|
6609
6943
|
summary: summary.trim(),
|
|
6610
6944
|
description: description.trim() || null,
|
|
6611
6945
|
location: location.trim() || null,
|
|
6612
|
-
dtstart:
|
|
6613
|
-
dtend:
|
|
6946
|
+
dtstart: start.toISOString(),
|
|
6947
|
+
dtend: end.toISOString(),
|
|
6614
6948
|
allDay,
|
|
6615
6949
|
categoryId: categoryId || null,
|
|
6616
6950
|
category: selectedCategory,
|
|
6617
6951
|
referenceType: referenceType || null,
|
|
6618
6952
|
referenceId: referenceId || null
|
|
6619
6953
|
});
|
|
6620
|
-
|
|
6954
|
+
forceClose();
|
|
6955
|
+
} catch (err) {
|
|
6956
|
+
console.error("[EventDialog] Failed to save event:", err);
|
|
6621
6957
|
} finally {
|
|
6622
6958
|
setSaving(false);
|
|
6623
6959
|
}
|
|
@@ -6627,275 +6963,379 @@ function EventDialog({
|
|
|
6627
6963
|
setCompleting(true);
|
|
6628
6964
|
try {
|
|
6629
6965
|
await onComplete();
|
|
6630
|
-
|
|
6966
|
+
forceClose();
|
|
6631
6967
|
} finally {
|
|
6632
6968
|
setCompleting(false);
|
|
6633
6969
|
}
|
|
6634
6970
|
};
|
|
6971
|
+
const handleStartTimeChange = (value) => {
|
|
6972
|
+
setStartTime(value);
|
|
6973
|
+
const [sh, sm] = value.split(":").map(Number);
|
|
6974
|
+
const [eh, em] = endTime.split(":").map(Number);
|
|
6975
|
+
if (eh * 60 + em <= sh * 60 + sm) {
|
|
6976
|
+
const next = addHours(combineDateAndTime(date, value), 1);
|
|
6977
|
+
setEndTime(toTimeValue(next));
|
|
6978
|
+
}
|
|
6979
|
+
};
|
|
6635
6980
|
const CategoryIcon = getCategoryIcon(selectedCategory?.alias);
|
|
6636
|
-
|
|
6637
|
-
|
|
6638
|
-
|
|
6639
|
-
/* @__PURE__ */
|
|
6640
|
-
|
|
6641
|
-
|
|
6642
|
-
/* @__PURE__ */ jsx(
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6647
|
-
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2 text-sm text-muted-foreground", children: [
|
|
6648
|
-
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
|
|
6649
|
-
/* @__PURE__ */ jsx(Clock, { className: "h-3.5 w-3.5" }),
|
|
6650
|
-
event?.dtstart ? new Date(event.dtstart).toLocaleString() : "\u2014",
|
|
6651
|
-
event?.dtend ? ` \u2013 ${new Date(event.dtend).toLocaleString()}` : ""
|
|
6981
|
+
const dateLabel = format(date, "EEEE, d MMMM");
|
|
6982
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6983
|
+
/* @__PURE__ */ jsx(Dialog, { open, onOpenChange: handleOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-[520px]", children: [
|
|
6984
|
+
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: mode === "preview" ? labels.previewTitle ?? "Event details" : isExisting ? labels.editTitle ?? "Edit event" : labels.createTitle ?? "New event" }) }),
|
|
6985
|
+
mode === "preview" ? /* @__PURE__ */ jsxs("div", { className: "space-y-4 py-2", children: [
|
|
6986
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
6987
|
+
/* @__PURE__ */ jsx("h3", { className: "text-lg font-semibold", children: event?.summary }),
|
|
6988
|
+
isCompleted && /* @__PURE__ */ jsxs("p", { className: "mt-1 inline-flex items-center gap-1 text-sm text-emerald-600", children: [
|
|
6989
|
+
/* @__PURE__ */ jsx(CheckCircle2, { className: "h-3.5 w-3.5" }),
|
|
6990
|
+
labels.completed ?? "Completed"
|
|
6991
|
+
] })
|
|
6652
6992
|
] }),
|
|
6653
|
-
event?.
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
|
|
6658
|
-
|
|
6659
|
-
|
|
6660
|
-
|
|
6661
|
-
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
color: selectedCategory.iconColor
|
|
6665
|
-
},
|
|
6666
|
-
children: [
|
|
6667
|
-
/* @__PURE__ */ jsx(CategoryIcon, { className: "h-3.5 w-3.5" }),
|
|
6668
|
-
selectedCategory.name
|
|
6669
|
-
]
|
|
6670
|
-
}
|
|
6671
|
-
),
|
|
6672
|
-
(event?.referenceId || linkLabel) && /* @__PURE__ */ jsxs("p", { className: "inline-flex items-center gap-1.5 text-sm", children: [
|
|
6673
|
-
/* @__PURE__ */ jsx(Link2, { className: "h-3.5 w-3.5 text-muted-foreground" }),
|
|
6674
|
-
/* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
|
|
6675
|
-
linkSearch?.label ?? labels.link ?? "Linked case",
|
|
6676
|
-
":"
|
|
6993
|
+
event?.description && /* @__PURE__ */ jsx("p", { className: "text-sm text-muted-foreground whitespace-pre-wrap", children: event.description }),
|
|
6994
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2 text-sm text-muted-foreground", children: [
|
|
6995
|
+
/* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
|
|
6996
|
+
/* @__PURE__ */ jsx(Clock, { className: "h-3.5 w-3.5" }),
|
|
6997
|
+
event?.dtstart ? new Date(event.dtstart).toLocaleString() : "\u2014",
|
|
6998
|
+
event?.dtend ? ` \u2013 ${new Date(event.dtend).toLocaleString()}` : ""
|
|
6999
|
+
] }),
|
|
7000
|
+
event?.location && /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-1", children: [
|
|
7001
|
+
/* @__PURE__ */ jsx(MapPin, { className: "h-3.5 w-3.5" }),
|
|
7002
|
+
event.location
|
|
7003
|
+
] })
|
|
6677
7004
|
] }),
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
/* @__PURE__ */ jsxs(DialogFooter, { className: "gap-2", children: [
|
|
6681
|
-
!isCompleted && onComplete && /* @__PURE__ */ jsxs(
|
|
6682
|
-
Button,
|
|
7005
|
+
selectedCategory && /* @__PURE__ */ jsxs(
|
|
7006
|
+
"span",
|
|
6683
7007
|
{
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
|
|
6687
|
-
|
|
7008
|
+
className: "inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 text-xs font-medium",
|
|
7009
|
+
style: {
|
|
7010
|
+
backgroundColor: selectedCategory.bgColor,
|
|
7011
|
+
color: selectedCategory.iconColor
|
|
7012
|
+
},
|
|
6688
7013
|
children: [
|
|
6689
|
-
|
|
6690
|
-
|
|
7014
|
+
/* @__PURE__ */ jsx(CategoryIcon, { className: "h-3.5 w-3.5" }),
|
|
7015
|
+
selectedCategory.name
|
|
6691
7016
|
]
|
|
6692
7017
|
}
|
|
6693
7018
|
),
|
|
6694
|
-
/* @__PURE__ */
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
/* @__PURE__ */ jsx("label", { className: "mb-1 block text-sm font-medium", children: labels.summary ?? "Summary" }),
|
|
6706
|
-
/* @__PURE__ */ jsx(
|
|
6707
|
-
"input",
|
|
7019
|
+
(event?.referenceId || linkLabel) && /* @__PURE__ */ jsxs("p", { className: "inline-flex items-center gap-1.5 text-sm", children: [
|
|
7020
|
+
/* @__PURE__ */ jsx(Link2, { className: "h-3.5 w-3.5 text-muted-foreground" }),
|
|
7021
|
+
/* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
|
|
7022
|
+
linkSearch?.label ?? labels.link ?? "Linked case",
|
|
7023
|
+
":"
|
|
7024
|
+
] }),
|
|
7025
|
+
linkLabel || event?.referenceId
|
|
7026
|
+
] }),
|
|
7027
|
+
/* @__PURE__ */ jsxs(DialogFooter, { className: "gap-2", children: [
|
|
7028
|
+
!isCompleted && onComplete && /* @__PURE__ */ jsxs(
|
|
7029
|
+
Button,
|
|
6708
7030
|
{
|
|
6709
|
-
|
|
6710
|
-
|
|
6711
|
-
|
|
6712
|
-
|
|
6713
|
-
|
|
7031
|
+
variant: "secondary",
|
|
7032
|
+
size: "sm",
|
|
7033
|
+
onClick: handleComplete,
|
|
7034
|
+
disabled: completing,
|
|
7035
|
+
children: [
|
|
7036
|
+
completing && /* @__PURE__ */ jsx(Loader2, { className: "mr-1 h-3.5 w-3.5 animate-spin" }),
|
|
7037
|
+
labels.markComplete ?? "Mark as completed"
|
|
7038
|
+
]
|
|
6714
7039
|
}
|
|
6715
|
-
)
|
|
6716
|
-
|
|
6717
|
-
|
|
6718
|
-
/* @__PURE__ */ jsx(
|
|
6719
|
-
/* @__PURE__ */
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
7040
|
+
),
|
|
7041
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1" }),
|
|
7042
|
+
isExisting && onDelete && !isCompleted && /* @__PURE__ */ jsx(Button, { variant: "destructive", size: "sm", onClick: onDelete, children: labels.delete ?? "Delete" }),
|
|
7043
|
+
/* @__PURE__ */ jsx(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx(Button, { variant: "outline", size: "sm", children: labels.cancel ?? "Close" }) }),
|
|
7044
|
+
!isCompleted && /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: () => setMode("edit"), children: [
|
|
7045
|
+
/* @__PURE__ */ jsx(Pencil, { className: "mr-1 h-3.5 w-3.5" }),
|
|
7046
|
+
labels.edit ?? "Edit"
|
|
7047
|
+
] })
|
|
7048
|
+
] })
|
|
7049
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7050
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-4 py-2", children: [
|
|
7051
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
7052
|
+
/* @__PURE__ */ jsx("label", { className: "mb-1 block text-sm font-medium", children: labels.summary ?? "Summary" }),
|
|
7053
|
+
/* @__PURE__ */ jsx(
|
|
7054
|
+
"input",
|
|
6724
7055
|
{
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6731
|
-
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
|
|
6735
|
-
|
|
7056
|
+
value: summary,
|
|
7057
|
+
onChange: (e) => setSummary(e.target.value),
|
|
7058
|
+
className: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
7059
|
+
placeholder: "Event name",
|
|
7060
|
+
disabled: isCompleted
|
|
7061
|
+
}
|
|
7062
|
+
)
|
|
7063
|
+
] }),
|
|
7064
|
+
categories.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
7065
|
+
/* @__PURE__ */ jsx("label", { className: "mb-1.5 block text-sm font-medium", children: labels.category ?? "Category" }),
|
|
7066
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-wrap gap-2", children: categories.map((cat) => {
|
|
7067
|
+
const Icon = getCategoryIcon(cat.alias);
|
|
7068
|
+
const selected = categoryId === cat.id;
|
|
7069
|
+
return /* @__PURE__ */ jsxs(
|
|
7070
|
+
"button",
|
|
7071
|
+
{
|
|
7072
|
+
type: "button",
|
|
7073
|
+
disabled: isCompleted,
|
|
7074
|
+
onClick: () => setCategoryId(selected ? "" : cat.id),
|
|
7075
|
+
className: cn(
|
|
7076
|
+
"inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs font-medium transition-all",
|
|
7077
|
+
selected ? "ring-2 ring-offset-1 ring-primary" : "opacity-80 hover:opacity-100"
|
|
7078
|
+
),
|
|
7079
|
+
style: {
|
|
7080
|
+
backgroundColor: cat.bgColor,
|
|
7081
|
+
color: cat.iconColor,
|
|
7082
|
+
borderColor: cat.iconColor
|
|
7083
|
+
},
|
|
7084
|
+
children: [
|
|
7085
|
+
/* @__PURE__ */ jsx(Icon, { className: "h-3.5 w-3.5" }),
|
|
7086
|
+
cat.name
|
|
7087
|
+
]
|
|
6736
7088
|
},
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
},
|
|
6742
|
-
cat.id
|
|
6743
|
-
);
|
|
6744
|
-
}) })
|
|
6745
|
-
] }),
|
|
6746
|
-
/* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
|
|
7089
|
+
cat.id
|
|
7090
|
+
);
|
|
7091
|
+
}) })
|
|
7092
|
+
] }),
|
|
6747
7093
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
6748
|
-
/* @__PURE__ */ jsxs("label", { className: "mb-1 block text-sm font-medium", children: [
|
|
7094
|
+
/* @__PURE__ */ jsxs("label", { className: "mb-1.5 block text-sm font-medium", children: [
|
|
6749
7095
|
/* @__PURE__ */ jsx(Clock, { className: "mr-1 inline h-3.5 w-3.5" }),
|
|
6750
|
-
labels.startDate ?? "
|
|
7096
|
+
labels.date ?? labels.startDate ?? "Date & time"
|
|
6751
7097
|
] }),
|
|
7098
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
7099
|
+
/* @__PURE__ */ jsxs(
|
|
7100
|
+
Popover,
|
|
7101
|
+
{
|
|
7102
|
+
open: datePickerOpen,
|
|
7103
|
+
onOpenChange: setDatePickerOpen,
|
|
7104
|
+
children: [
|
|
7105
|
+
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsx(
|
|
7106
|
+
"button",
|
|
7107
|
+
{
|
|
7108
|
+
type: "button",
|
|
7109
|
+
disabled: isCompleted,
|
|
7110
|
+
className: cn(
|
|
7111
|
+
"inline-flex h-9 items-center rounded-md border border-input bg-background px-3 text-sm",
|
|
7112
|
+
"hover:bg-accent hover:text-accent-foreground",
|
|
7113
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
7114
|
+
"disabled:cursor-not-allowed disabled:opacity-50"
|
|
7115
|
+
),
|
|
7116
|
+
children: dateLabel
|
|
7117
|
+
}
|
|
7118
|
+
) }),
|
|
7119
|
+
/* @__PURE__ */ jsx(
|
|
7120
|
+
PopoverContent,
|
|
7121
|
+
{
|
|
7122
|
+
className: "z-[100] w-auto p-2",
|
|
7123
|
+
align: "start",
|
|
7124
|
+
children: /* @__PURE__ */ jsx(
|
|
7125
|
+
DayPicker,
|
|
7126
|
+
{
|
|
7127
|
+
mode: "single",
|
|
7128
|
+
selected: date,
|
|
7129
|
+
onSelect: (d) => {
|
|
7130
|
+
if (d) {
|
|
7131
|
+
setDate(startOfDay(d));
|
|
7132
|
+
setDatePickerOpen(false);
|
|
7133
|
+
}
|
|
7134
|
+
},
|
|
7135
|
+
showOutsideDays: true,
|
|
7136
|
+
classNames: dayPickerClassNames
|
|
7137
|
+
}
|
|
7138
|
+
)
|
|
7139
|
+
}
|
|
7140
|
+
)
|
|
7141
|
+
]
|
|
7142
|
+
}
|
|
7143
|
+
),
|
|
7144
|
+
!allDay && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7145
|
+
/* @__PURE__ */ jsx(
|
|
7146
|
+
TimeCombobox,
|
|
7147
|
+
{
|
|
7148
|
+
value: startTime,
|
|
7149
|
+
onChange: handleStartTimeChange,
|
|
7150
|
+
disabled: isCompleted,
|
|
7151
|
+
"aria-label": labels.startTime ?? "Start time"
|
|
7152
|
+
}
|
|
7153
|
+
),
|
|
7154
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: "\u2013" }),
|
|
7155
|
+
/* @__PURE__ */ jsx(
|
|
7156
|
+
TimeCombobox,
|
|
7157
|
+
{
|
|
7158
|
+
value: endTime,
|
|
7159
|
+
onChange: setEndTime,
|
|
7160
|
+
disabled: isCompleted,
|
|
7161
|
+
durationFrom: startTime,
|
|
7162
|
+
"aria-label": labels.endTime ?? "End time"
|
|
7163
|
+
}
|
|
7164
|
+
)
|
|
7165
|
+
] })
|
|
7166
|
+
] })
|
|
7167
|
+
] }),
|
|
7168
|
+
/* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
|
|
6752
7169
|
/* @__PURE__ */ jsx(
|
|
6753
7170
|
"input",
|
|
6754
7171
|
{
|
|
6755
|
-
type: "
|
|
6756
|
-
|
|
6757
|
-
onChange: (e) =>
|
|
7172
|
+
type: "checkbox",
|
|
7173
|
+
checked: allDay,
|
|
7174
|
+
onChange: (e) => setAllDay(e.target.checked),
|
|
6758
7175
|
disabled: isCompleted,
|
|
6759
|
-
className: "
|
|
7176
|
+
className: "rounded border-input"
|
|
6760
7177
|
}
|
|
6761
|
-
)
|
|
7178
|
+
),
|
|
7179
|
+
labels.allDay ?? "All day"
|
|
7180
|
+
] }),
|
|
7181
|
+
(linkSearch || referenceId) && !isExisting && /* @__PURE__ */ jsxs("div", { children: [
|
|
7182
|
+
/* @__PURE__ */ jsxs("label", { className: "mb-1 block text-sm font-medium", children: [
|
|
7183
|
+
/* @__PURE__ */ jsx(Link2, { className: "mr-1 inline h-3.5 w-3.5" }),
|
|
7184
|
+
linkSearch?.label ?? labels.link ?? "Link to case"
|
|
7185
|
+
] }),
|
|
7186
|
+
referenceId ? /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between rounded-md border px-3 py-2 text-sm", children: [
|
|
7187
|
+
/* @__PURE__ */ jsx("span", { children: linkLabel || referenceId }),
|
|
7188
|
+
linkSearch && /* @__PURE__ */ jsx(
|
|
7189
|
+
"button",
|
|
7190
|
+
{
|
|
7191
|
+
type: "button",
|
|
7192
|
+
className: "text-xs text-muted-foreground hover:text-foreground",
|
|
7193
|
+
onClick: () => {
|
|
7194
|
+
setReferenceId("");
|
|
7195
|
+
setReferenceType("");
|
|
7196
|
+
setLinkLabel("");
|
|
7197
|
+
},
|
|
7198
|
+
children: "Clear"
|
|
7199
|
+
}
|
|
7200
|
+
)
|
|
7201
|
+
] }) : linkSearch ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7202
|
+
/* @__PURE__ */ jsx(
|
|
7203
|
+
"input",
|
|
7204
|
+
{
|
|
7205
|
+
value: linkQuery,
|
|
7206
|
+
onChange: (e) => setLinkQuery(e.target.value),
|
|
7207
|
+
placeholder: labels.linkPlaceholder ?? "Search cases\u2026",
|
|
7208
|
+
className: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
7209
|
+
}
|
|
7210
|
+
),
|
|
7211
|
+
linkOptions.length > 0 && /* @__PURE__ */ jsx("ul", { className: "mt-1 max-h-40 overflow-auto rounded-md border bg-popover text-sm shadow-md", children: linkOptions.map((opt) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
|
|
7212
|
+
"button",
|
|
7213
|
+
{
|
|
7214
|
+
type: "button",
|
|
7215
|
+
className: "flex w-full flex-col px-3 py-2 text-left hover:bg-accent",
|
|
7216
|
+
onClick: () => {
|
|
7217
|
+
setReferenceId(opt.id);
|
|
7218
|
+
setReferenceType("cases-svc");
|
|
7219
|
+
setLinkLabel(opt.label);
|
|
7220
|
+
setLinkQuery("");
|
|
7221
|
+
setLinkOptions([]);
|
|
7222
|
+
},
|
|
7223
|
+
children: [
|
|
7224
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: opt.label }),
|
|
7225
|
+
opt.description && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: opt.description })
|
|
7226
|
+
]
|
|
7227
|
+
}
|
|
7228
|
+
) }, opt.id)) })
|
|
7229
|
+
] }) : null
|
|
6762
7230
|
] }),
|
|
6763
7231
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
6764
|
-
/* @__PURE__ */
|
|
7232
|
+
/* @__PURE__ */ jsxs("label", { className: "mb-1 block text-sm font-medium", children: [
|
|
7233
|
+
/* @__PURE__ */ jsx(MapPin, { className: "mr-1 inline h-3.5 w-3.5" }),
|
|
7234
|
+
labels.location ?? "Location"
|
|
7235
|
+
] }),
|
|
6765
7236
|
/* @__PURE__ */ jsx(
|
|
6766
7237
|
"input",
|
|
6767
7238
|
{
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
onChange: (e) => setDtend(e.target.value),
|
|
7239
|
+
value: location,
|
|
7240
|
+
onChange: (e) => setLocation(e.target.value),
|
|
6771
7241
|
disabled: isCompleted,
|
|
6772
|
-
className: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
7242
|
+
className: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
7243
|
+
placeholder: "Add location"
|
|
6773
7244
|
}
|
|
6774
7245
|
)
|
|
6775
|
-
] })
|
|
6776
|
-
] }),
|
|
6777
|
-
/* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
|
|
6778
|
-
/* @__PURE__ */ jsx(
|
|
6779
|
-
"input",
|
|
6780
|
-
{
|
|
6781
|
-
type: "checkbox",
|
|
6782
|
-
checked: allDay,
|
|
6783
|
-
onChange: (e) => setAllDay(e.target.checked),
|
|
6784
|
-
disabled: isCompleted,
|
|
6785
|
-
className: "rounded border-input"
|
|
6786
|
-
}
|
|
6787
|
-
),
|
|
6788
|
-
labels.allDay ?? "All day"
|
|
6789
|
-
] }),
|
|
6790
|
-
(linkSearch || referenceId) && !isExisting && /* @__PURE__ */ jsxs("div", { children: [
|
|
6791
|
-
/* @__PURE__ */ jsxs("label", { className: "mb-1 block text-sm font-medium", children: [
|
|
6792
|
-
/* @__PURE__ */ jsx(Link2, { className: "mr-1 inline h-3.5 w-3.5" }),
|
|
6793
|
-
linkSearch?.label ?? labels.link ?? "Link to case"
|
|
6794
7246
|
] }),
|
|
6795
|
-
|
|
6796
|
-
/* @__PURE__ */ jsx("
|
|
6797
|
-
linkSearch && /* @__PURE__ */ jsx(
|
|
6798
|
-
"button",
|
|
6799
|
-
{
|
|
6800
|
-
type: "button",
|
|
6801
|
-
className: "text-xs text-muted-foreground hover:text-foreground",
|
|
6802
|
-
onClick: () => {
|
|
6803
|
-
setReferenceId("");
|
|
6804
|
-
setReferenceType("");
|
|
6805
|
-
setLinkLabel("");
|
|
6806
|
-
},
|
|
6807
|
-
children: "Clear"
|
|
6808
|
-
}
|
|
6809
|
-
)
|
|
6810
|
-
] }) : linkSearch ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7247
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
7248
|
+
/* @__PURE__ */ jsx("label", { className: "mb-1 block text-sm font-medium", children: labels.description ?? "Description" }),
|
|
6811
7249
|
/* @__PURE__ */ jsx(
|
|
6812
|
-
"
|
|
6813
|
-
{
|
|
6814
|
-
value: linkQuery,
|
|
6815
|
-
onChange: (e) => setLinkQuery(e.target.value),
|
|
6816
|
-
placeholder: labels.linkPlaceholder ?? "Search cases\u2026",
|
|
6817
|
-
className: "w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
6818
|
-
}
|
|
6819
|
-
),
|
|
6820
|
-
linkOptions.length > 0 && /* @__PURE__ */ jsx("ul", { className: "mt-1 max-h-40 overflow-auto rounded-md border bg-popover text-sm shadow-md", children: linkOptions.map((opt) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
|
|
6821
|
-
"button",
|
|
7250
|
+
"textarea",
|
|
6822
7251
|
{
|
|
6823
|
-
|
|
6824
|
-
|
|
6825
|
-
|
|
6826
|
-
|
|
6827
|
-
|
|
6828
|
-
|
|
6829
|
-
setLinkQuery("");
|
|
6830
|
-
setLinkOptions([]);
|
|
6831
|
-
},
|
|
6832
|
-
children: [
|
|
6833
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium", children: opt.label }),
|
|
6834
|
-
opt.description && /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: opt.description })
|
|
6835
|
-
]
|
|
7252
|
+
value: description,
|
|
7253
|
+
onChange: (e) => setDescription(e.target.value),
|
|
7254
|
+
disabled: isCompleted,
|
|
7255
|
+
rows: 3,
|
|
7256
|
+
className: "w-full resize-none rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
7257
|
+
placeholder: "Add description"
|
|
6836
7258
|
}
|
|
6837
|
-
)
|
|
6838
|
-
] })
|
|
7259
|
+
)
|
|
7260
|
+
] })
|
|
6839
7261
|
] }),
|
|
6840
|
-
/* @__PURE__ */ jsxs("
|
|
6841
|
-
/* @__PURE__ */
|
|
6842
|
-
|
|
6843
|
-
|
|
6844
|
-
|
|
6845
|
-
/* @__PURE__ */ jsx(
|
|
6846
|
-
"input",
|
|
7262
|
+
/* @__PURE__ */ jsxs(DialogFooter, { className: "gap-2", children: [
|
|
7263
|
+
isExisting && onDelete && !isCompleted && /* @__PURE__ */ jsx(Button, { variant: "destructive", size: "sm", onClick: onDelete, children: labels.delete ?? "Delete" }),
|
|
7264
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1" }),
|
|
7265
|
+
isExisting && /* @__PURE__ */ jsx(
|
|
7266
|
+
Button,
|
|
6847
7267
|
{
|
|
6848
|
-
|
|
6849
|
-
|
|
6850
|
-
|
|
6851
|
-
|
|
6852
|
-
|
|
7268
|
+
variant: "outline",
|
|
7269
|
+
size: "sm",
|
|
7270
|
+
onClick: () => {
|
|
7271
|
+
if (isDirty) {
|
|
7272
|
+
requestDiscard("preview");
|
|
7273
|
+
} else {
|
|
7274
|
+
setMode("preview");
|
|
7275
|
+
}
|
|
7276
|
+
},
|
|
7277
|
+
children: labels.cancel ?? "Cancel"
|
|
6853
7278
|
}
|
|
6854
|
-
)
|
|
6855
|
-
|
|
6856
|
-
|
|
6857
|
-
/* @__PURE__ */ jsx("label", { className: "mb-1 block text-sm font-medium", children: labels.description ?? "Description" }),
|
|
6858
|
-
/* @__PURE__ */ jsx(
|
|
6859
|
-
"textarea",
|
|
7279
|
+
),
|
|
7280
|
+
!isExisting && /* @__PURE__ */ jsx(
|
|
7281
|
+
Button,
|
|
6860
7282
|
{
|
|
6861
|
-
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
|
|
6865
|
-
|
|
6866
|
-
|
|
7283
|
+
variant: "outline",
|
|
7284
|
+
size: "sm",
|
|
7285
|
+
onClick: () => handleOpenChange(false),
|
|
7286
|
+
children: labels.cancel ?? "Cancel"
|
|
7287
|
+
}
|
|
7288
|
+
),
|
|
7289
|
+
!isCompleted && /* @__PURE__ */ jsxs(
|
|
7290
|
+
Button,
|
|
7291
|
+
{
|
|
7292
|
+
size: "sm",
|
|
7293
|
+
onClick: handleSave,
|
|
7294
|
+
disabled: saving || !summary.trim() || !date || !startTime || !endTime,
|
|
7295
|
+
children: [
|
|
7296
|
+
saving && /* @__PURE__ */ jsx(Loader2, { className: "mr-1 h-3.5 w-3.5 animate-spin" }),
|
|
7297
|
+
labels.save ?? "Save"
|
|
7298
|
+
]
|
|
6867
7299
|
}
|
|
6868
7300
|
)
|
|
6869
7301
|
] })
|
|
7302
|
+
] })
|
|
7303
|
+
] }) }),
|
|
7304
|
+
/* @__PURE__ */ jsx(Dialog, { open: confirmDiscard, onOpenChange: setConfirmDiscard, children: /* @__PURE__ */ jsxs(DialogContent, { className: "sm:max-w-[400px]", showCloseButton: false, children: [
|
|
7305
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
7306
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: labels.discardTitle ?? "Discard changes?" }),
|
|
7307
|
+
/* @__PURE__ */ jsx(DialogDescription, { children: labels.discardMessage ?? "You have unsaved changes. Are you sure you want to discard them?" })
|
|
6870
7308
|
] }),
|
|
6871
7309
|
/* @__PURE__ */ jsxs(DialogFooter, { className: "gap-2", children: [
|
|
6872
|
-
|
|
6873
|
-
/* @__PURE__ */ jsx("div", { className: "flex-1" }),
|
|
6874
|
-
isExisting && /* @__PURE__ */ jsx(
|
|
7310
|
+
/* @__PURE__ */ jsx(
|
|
6875
7311
|
Button,
|
|
6876
7312
|
{
|
|
6877
7313
|
variant: "outline",
|
|
6878
7314
|
size: "sm",
|
|
6879
|
-
onClick: () =>
|
|
6880
|
-
children: labels.
|
|
7315
|
+
onClick: () => setConfirmDiscard(false),
|
|
7316
|
+
children: labels.discardCancel ?? "Keep editing"
|
|
6881
7317
|
}
|
|
6882
7318
|
),
|
|
6883
|
-
|
|
6884
|
-
!isCompleted && /* @__PURE__ */ jsxs(
|
|
7319
|
+
/* @__PURE__ */ jsx(
|
|
6885
7320
|
Button,
|
|
6886
7321
|
{
|
|
7322
|
+
variant: "destructive",
|
|
6887
7323
|
size: "sm",
|
|
6888
|
-
onClick:
|
|
6889
|
-
|
|
6890
|
-
|
|
6891
|
-
|
|
6892
|
-
|
|
6893
|
-
|
|
7324
|
+
onClick: () => {
|
|
7325
|
+
if (discardIntent === "preview") {
|
|
7326
|
+
revertToSnapshot();
|
|
7327
|
+
setConfirmDiscard(false);
|
|
7328
|
+
setMode("preview");
|
|
7329
|
+
} else {
|
|
7330
|
+
forceClose();
|
|
7331
|
+
}
|
|
7332
|
+
},
|
|
7333
|
+
children: labels.discardConfirm ?? "Discard"
|
|
6894
7334
|
}
|
|
6895
7335
|
)
|
|
6896
7336
|
] })
|
|
6897
|
-
] })
|
|
6898
|
-
] })
|
|
7337
|
+
] }) })
|
|
7338
|
+
] });
|
|
6899
7339
|
}
|
|
6900
7340
|
function MiniCalendar({
|
|
6901
7341
|
selected,
|