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