@adatechnology/scheduling-ui 0.1.0-rc.1 → 0.1.0-rc.2
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/README.md +8 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.js +433 -220
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -360,6 +360,7 @@ var pt_BR_default = {
|
|
|
360
360
|
"agenda.viewDay": "Dia",
|
|
361
361
|
"agenda.viewWeek": "Semana",
|
|
362
362
|
"agenda.empty": "Sem reservas neste per\xEDodo",
|
|
363
|
+
"agenda.moreResults": "Este per\xEDodo tem mais reservas do que as exibidas. Filtre por recurso ou reduza a janela para ver o restante.",
|
|
363
364
|
"availability.weeklyRulesTitle": "Regras semanais",
|
|
364
365
|
"availability.exceptionsTitle": "Exce\xE7\xF5es",
|
|
365
366
|
"availability.resourceTimezone": "Fuso do recurso",
|
|
@@ -387,6 +388,8 @@ var pt_BR_default = {
|
|
|
387
388
|
"booking.complete": "Concluir",
|
|
388
389
|
"booking.markNoShow": "Marcar n\xE3o compareceu",
|
|
389
390
|
"booking.reschedule": "Reagendar",
|
|
391
|
+
"booking.rescheduleStart": "Novo in\xEDcio",
|
|
392
|
+
"booking.rescheduleEnd": "Novo fim",
|
|
390
393
|
"booking.detailTitle": "Detalhes da reserva",
|
|
391
394
|
"booking.cancelReason": "Motivo do cancelamento",
|
|
392
395
|
"booking.cancelledBy": "Cancelado por",
|
|
@@ -403,7 +406,11 @@ var pt_BR_default = {
|
|
|
403
406
|
"availability.startsAtLocal": "In\xEDcio",
|
|
404
407
|
"availability.endsAtLocal": "Fim",
|
|
405
408
|
"availability.exceptionFrom": "De",
|
|
406
|
-
"availability.exceptionUntil": "At\xE9"
|
|
409
|
+
"availability.exceptionUntil": "At\xE9",
|
|
410
|
+
"datetime.year": "Ano",
|
|
411
|
+
"datetime.month": "M\xEAs",
|
|
412
|
+
"datetime.day": "Dia",
|
|
413
|
+
"datetime.time": "Hora"
|
|
407
414
|
};
|
|
408
415
|
|
|
409
416
|
// src/locales/en.json
|
|
@@ -447,6 +454,7 @@ var en_default = {
|
|
|
447
454
|
"agenda.viewDay": "Day",
|
|
448
455
|
"agenda.viewWeek": "Week",
|
|
449
456
|
"agenda.empty": "No bookings in this period",
|
|
457
|
+
"agenda.moreResults": "This period has more bookings than shown. Filter by resource or narrow the window to see the rest.",
|
|
450
458
|
"availability.weeklyRulesTitle": "Weekly rules",
|
|
451
459
|
"availability.exceptionsTitle": "Exceptions",
|
|
452
460
|
"availability.resourceTimezone": "Resource timezone",
|
|
@@ -474,6 +482,8 @@ var en_default = {
|
|
|
474
482
|
"booking.complete": "Complete",
|
|
475
483
|
"booking.markNoShow": "Mark no-show",
|
|
476
484
|
"booking.reschedule": "Reschedule",
|
|
485
|
+
"booking.rescheduleStart": "New start",
|
|
486
|
+
"booking.rescheduleEnd": "New end",
|
|
477
487
|
"booking.detailTitle": "Booking details",
|
|
478
488
|
"booking.cancelReason": "Cancellation reason",
|
|
479
489
|
"booking.cancelledBy": "Cancelled by",
|
|
@@ -490,7 +500,11 @@ var en_default = {
|
|
|
490
500
|
"availability.startsAtLocal": "Starts",
|
|
491
501
|
"availability.endsAtLocal": "Ends",
|
|
492
502
|
"availability.exceptionFrom": "From",
|
|
493
|
-
"availability.exceptionUntil": "Until"
|
|
503
|
+
"availability.exceptionUntil": "Until",
|
|
504
|
+
"datetime.year": "Year",
|
|
505
|
+
"datetime.month": "Month",
|
|
506
|
+
"datetime.day": "Day",
|
|
507
|
+
"datetime.time": "Time"
|
|
494
508
|
};
|
|
495
509
|
|
|
496
510
|
// src/locales/index.ts
|
|
@@ -577,7 +591,7 @@ function AgendaGrid({ bookings, days }) {
|
|
|
577
591
|
const dayBookings = bookingsOnDay(bookings, day, agendaStartHour, agendaEndHour);
|
|
578
592
|
const positioned = layoutDayBookings(dayBookings);
|
|
579
593
|
const dayStart = startOfDay(day);
|
|
580
|
-
return /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-
|
|
594
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-40 border-r border-gray-200 dark:border-gray-700 last:border-r-0", children: [
|
|
581
595
|
/* @__PURE__ */ jsx2("div", { className: "h-8 px-2 flex items-center text-xs font-medium text-gray-700 dark:text-gray-300 border-b border-gray-200 dark:border-gray-700", children: day.toLocaleDateString(locale, { weekday: "short", day: "2-digit", month: "2-digit" }) }),
|
|
582
596
|
/* @__PURE__ */ jsxs("div", { className: "relative", style: { height: `${hours.length * 4}rem` }, children: [
|
|
583
597
|
positioned.length === 0 && /* @__PURE__ */ jsx2("p", { className: "absolute inset-x-2 top-2 text-xs text-gray-400", children: messages["agenda.empty"] }),
|
|
@@ -616,7 +630,7 @@ function AgendaGrid({ bookings, days }) {
|
|
|
616
630
|
}
|
|
617
631
|
|
|
618
632
|
// src/workspace/AgendaArea.tsx
|
|
619
|
-
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
633
|
+
import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
620
634
|
var DAY_IN_MS = 24 * 60 * 6e4;
|
|
621
635
|
function startOfWeek(date, weekStartsOn) {
|
|
622
636
|
const start = startOfDay(date);
|
|
@@ -692,7 +706,10 @@ function AgendaArea() {
|
|
|
692
706
|
] })
|
|
693
707
|
] }),
|
|
694
708
|
isError && /* @__PURE__ */ jsx3("p", { role: "alert", className: "text-sm text-red-700 bg-red-50 rounded-lg px-3 py-2", children: messages["common.loadFailure"] }),
|
|
695
|
-
isLoading ? /* @__PURE__ */ jsx3("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.loading"] }) : /* @__PURE__ */
|
|
709
|
+
isLoading ? /* @__PURE__ */ jsx3("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.loading"] }) : /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
710
|
+
bookingsPage && bookingsPage.total > bookingsPage.data.length && /* @__PURE__ */ jsx3("p", { className: "text-sm text-amber-700 bg-amber-50 rounded-lg px-3 py-2", children: messages["agenda.moreResults"] }),
|
|
711
|
+
/* @__PURE__ */ jsx3(AgendaGrid, { bookings: bookingsPage?.data ?? [], days })
|
|
712
|
+
] })
|
|
696
713
|
] });
|
|
697
714
|
}
|
|
698
715
|
|
|
@@ -825,16 +842,174 @@ function WeeklyRulesEditor({ resourceId }) {
|
|
|
825
842
|
import { Plus as Plus2, Trash2 as Trash22 } from "lucide-react";
|
|
826
843
|
import { useState as useState3 } from "react";
|
|
827
844
|
import { AVAILABILITY_EXCEPTION_KIND } from "@adatechnology/scheduling-contracts";
|
|
845
|
+
|
|
846
|
+
// src/components/DateTimeField.tsx
|
|
847
|
+
import { useId } from "react";
|
|
848
|
+
|
|
849
|
+
// src/components/dateTimeParts.util.ts
|
|
850
|
+
var DATE_TIME_LOCAL_PATTERN = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})$/;
|
|
851
|
+
var MONTHS_IN_YEAR = 12;
|
|
852
|
+
function parseDateTimeParts(value) {
|
|
853
|
+
const match = DATE_TIME_LOCAL_PATTERN.exec(value);
|
|
854
|
+
if (!match) return void 0;
|
|
855
|
+
const [, year, month, day, hour, minute] = match;
|
|
856
|
+
return { year: Number(year), month: Number(month), day: Number(day), time: `${hour}:${minute}` };
|
|
857
|
+
}
|
|
858
|
+
function daysInMonth(params) {
|
|
859
|
+
return new Date(Date.UTC(params.year, params.month, 0)).getUTCDate();
|
|
860
|
+
}
|
|
861
|
+
function pad(value) {
|
|
862
|
+
return String(value).padStart(2, "0");
|
|
863
|
+
}
|
|
864
|
+
function formatDateTimeParts(parts) {
|
|
865
|
+
const lastDay = daysInMonth({ year: parts.year, month: parts.month });
|
|
866
|
+
const day = Math.min(Math.max(parts.day, 1), lastDay);
|
|
867
|
+
return `${String(parts.year).padStart(4, "0")}-${pad(parts.month)}-${pad(day)}T${parts.time}`;
|
|
868
|
+
}
|
|
869
|
+
function buildYearOptions(params) {
|
|
870
|
+
const current = params.today.getFullYear();
|
|
871
|
+
const first = Math.min(current - params.past, params.year);
|
|
872
|
+
const last = Math.max(current + params.future, params.year);
|
|
873
|
+
return Array.from({ length: last - first + 1 }, (_, index) => first + index);
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
// src/components/DateTimeField.tsx
|
|
828
877
|
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
878
|
+
var FIELD_CLASS = "min-h-11 rounded-lg border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 text-sm";
|
|
879
|
+
var YEAR_WINDOW = { PAST: 1, FUTURE: 2 };
|
|
880
|
+
function partsOf(value, fallback) {
|
|
881
|
+
return parseDateTimeParts(value) ?? {
|
|
882
|
+
year: fallback.getFullYear(),
|
|
883
|
+
month: fallback.getMonth() + 1,
|
|
884
|
+
day: fallback.getDate(),
|
|
885
|
+
time: "09:00"
|
|
886
|
+
};
|
|
887
|
+
}
|
|
888
|
+
function monthLabels(locale) {
|
|
889
|
+
const format = new Intl.DateTimeFormat(locale, { month: "long", timeZone: "UTC" });
|
|
890
|
+
return Array.from(
|
|
891
|
+
{ length: MONTHS_IN_YEAR },
|
|
892
|
+
(_, index) => format.format(new Date(Date.UTC(2026, index, 1)))
|
|
893
|
+
);
|
|
894
|
+
}
|
|
895
|
+
function DateTimeField({ label, value, onChange, emptyDefault }) {
|
|
896
|
+
const { locale } = useSchedulingConfig();
|
|
897
|
+
const messages = resolveSchedulingMessages(locale);
|
|
898
|
+
const groupId = useId();
|
|
899
|
+
const today = emptyDefault ?? /* @__PURE__ */ new Date();
|
|
900
|
+
const parts = partsOf(value, today);
|
|
901
|
+
const years = buildYearOptions({
|
|
902
|
+
year: parts.year,
|
|
903
|
+
today,
|
|
904
|
+
past: YEAR_WINDOW.PAST,
|
|
905
|
+
future: YEAR_WINDOW.FUTURE
|
|
906
|
+
});
|
|
907
|
+
const days = daysInMonth({ year: parts.year, month: parts.month });
|
|
908
|
+
const months = monthLabels(locale);
|
|
909
|
+
function change(patch) {
|
|
910
|
+
onChange(formatDateTimeParts({ ...parts, ...patch }));
|
|
911
|
+
}
|
|
912
|
+
return /* @__PURE__ */ jsxs4("div", { role: "group", "aria-labelledby": groupId, className: "flex flex-wrap items-center gap-2", children: [
|
|
913
|
+
/* @__PURE__ */ jsx5("span", { id: groupId, className: "sr-only", children: label }),
|
|
914
|
+
/* @__PURE__ */ jsx5(
|
|
915
|
+
"select",
|
|
916
|
+
{
|
|
917
|
+
"aria-label": `${label} \u2014 ${messages["datetime.year"]}`,
|
|
918
|
+
value: parts.year,
|
|
919
|
+
onChange: (event) => change({ year: Number(event.target.value) }),
|
|
920
|
+
className: FIELD_CLASS,
|
|
921
|
+
children: years.map((year) => /* @__PURE__ */ jsx5("option", { value: year, children: year }, year))
|
|
922
|
+
}
|
|
923
|
+
),
|
|
924
|
+
/* @__PURE__ */ jsx5(
|
|
925
|
+
"select",
|
|
926
|
+
{
|
|
927
|
+
"aria-label": `${label} \u2014 ${messages["datetime.month"]}`,
|
|
928
|
+
value: parts.month,
|
|
929
|
+
onChange: (event) => change({ month: Number(event.target.value) }),
|
|
930
|
+
className: FIELD_CLASS,
|
|
931
|
+
children: months.map((name, index) => /* @__PURE__ */ jsx5("option", { value: index + 1, children: name }, name))
|
|
932
|
+
}
|
|
933
|
+
),
|
|
934
|
+
/* @__PURE__ */ jsx5(
|
|
935
|
+
"select",
|
|
936
|
+
{
|
|
937
|
+
"aria-label": `${label} \u2014 ${messages["datetime.day"]}`,
|
|
938
|
+
value: Math.min(parts.day, days),
|
|
939
|
+
onChange: (event) => change({ day: Number(event.target.value) }),
|
|
940
|
+
className: FIELD_CLASS,
|
|
941
|
+
children: Array.from({ length: days }, (_, index) => index + 1).map((day) => /* @__PURE__ */ jsx5("option", { value: day, children: day }, day))
|
|
942
|
+
}
|
|
943
|
+
),
|
|
944
|
+
/* @__PURE__ */ jsx5(
|
|
945
|
+
"input",
|
|
946
|
+
{
|
|
947
|
+
type: "time",
|
|
948
|
+
"aria-label": `${label} \u2014 ${messages["datetime.time"]}`,
|
|
949
|
+
value: parts.time,
|
|
950
|
+
onChange: (event) => change({ time: event.target.value }),
|
|
951
|
+
className: FIELD_CLASS
|
|
952
|
+
}
|
|
953
|
+
)
|
|
954
|
+
] });
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
// src/components/datetimeLocal.util.ts
|
|
958
|
+
function getTimeZoneOffsetMs(instant, timeZone) {
|
|
959
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
960
|
+
timeZone,
|
|
961
|
+
year: "numeric",
|
|
962
|
+
month: "2-digit",
|
|
963
|
+
day: "2-digit",
|
|
964
|
+
hour: "2-digit",
|
|
965
|
+
minute: "2-digit",
|
|
966
|
+
second: "2-digit",
|
|
967
|
+
hourCycle: "h23"
|
|
968
|
+
}).formatToParts(instant);
|
|
969
|
+
const get = (type) => Number(parts.find((part) => part.type === type)?.value ?? 0);
|
|
970
|
+
const asUtcOfWallClock = Date.UTC(
|
|
971
|
+
get("year"),
|
|
972
|
+
get("month") - 1,
|
|
973
|
+
get("day"),
|
|
974
|
+
get("hour") % 24,
|
|
975
|
+
get("minute"),
|
|
976
|
+
get("second")
|
|
977
|
+
);
|
|
978
|
+
return asUtcOfWallClock - instant.getTime();
|
|
979
|
+
}
|
|
980
|
+
function parseDateTimeLocalInTimeZone(value, timeZone) {
|
|
981
|
+
const naiveUtc = /* @__PURE__ */ new Date(`${value}:00.000Z`);
|
|
982
|
+
const firstOffset = getTimeZoneOffsetMs(naiveUtc, timeZone);
|
|
983
|
+
const firstPass = new Date(naiveUtc.getTime() - firstOffset);
|
|
984
|
+
const secondOffset = getTimeZoneOffsetMs(firstPass, timeZone);
|
|
985
|
+
return new Date(naiveUtc.getTime() - secondOffset);
|
|
986
|
+
}
|
|
987
|
+
function formatDateTimeLocalInTimeZone(instant, timeZone) {
|
|
988
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
989
|
+
timeZone,
|
|
990
|
+
year: "numeric",
|
|
991
|
+
month: "2-digit",
|
|
992
|
+
day: "2-digit",
|
|
993
|
+
hour: "2-digit",
|
|
994
|
+
minute: "2-digit",
|
|
995
|
+
hourCycle: "h23"
|
|
996
|
+
}).formatToParts(instant);
|
|
997
|
+
const get = (type) => parts.find((part) => part.type === type)?.value ?? "00";
|
|
998
|
+
const hour = get("hour") === "24" ? "00" : get("hour");
|
|
999
|
+
return `${get("year")}-${get("month")}-${get("day")}T${hour}:${get("minute")}`;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
// src/components/AvailabilityExceptionsEditor.tsx
|
|
1003
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
829
1004
|
var SELECT_CLASS = "min-h-11 rounded-lg border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 text-sm";
|
|
830
|
-
function AvailabilityExceptionsEditor({ resourceId }) {
|
|
1005
|
+
function AvailabilityExceptionsEditor({ resourceId, timezone }) {
|
|
831
1006
|
const { locale } = useSchedulingConfig();
|
|
832
1007
|
const messages = resolveSchedulingMessages(locale);
|
|
833
1008
|
const { data, isLoading, isError: isLoadError } = useAvailabilityExceptions(resourceId);
|
|
834
1009
|
const addException = useAddAvailabilityException();
|
|
835
1010
|
const removeException = useRemoveAvailabilityException();
|
|
836
|
-
const [from, setFrom] = useState3(
|
|
837
|
-
const [until, setUntil] = useState3(
|
|
1011
|
+
const [from, setFrom] = useState3(() => formatDateTimeLocalInTimeZone(/* @__PURE__ */ new Date(), timezone));
|
|
1012
|
+
const [until, setUntil] = useState3(() => formatDateTimeLocalInTimeZone(/* @__PURE__ */ new Date(), timezone));
|
|
838
1013
|
const [kind, setKind] = useState3(AVAILABILITY_EXCEPTION_KIND.BLOCK);
|
|
839
1014
|
const [reason, setReason] = useState3("");
|
|
840
1015
|
async function handleAdd() {
|
|
@@ -842,7 +1017,10 @@ function AvailabilityExceptionsEditor({ resourceId }) {
|
|
|
842
1017
|
try {
|
|
843
1018
|
await addException.mutateAsync({
|
|
844
1019
|
resourceId,
|
|
845
|
-
during: {
|
|
1020
|
+
during: {
|
|
1021
|
+
start: parseDateTimeLocalInTimeZone(from, timezone),
|
|
1022
|
+
end: parseDateTimeLocalInTimeZone(until, timezone)
|
|
1023
|
+
},
|
|
846
1024
|
kind,
|
|
847
1025
|
...reason ? { reason } : {}
|
|
848
1026
|
});
|
|
@@ -852,13 +1030,13 @@ function AvailabilityExceptionsEditor({ resourceId }) {
|
|
|
852
1030
|
} catch {
|
|
853
1031
|
}
|
|
854
1032
|
}
|
|
855
|
-
return /* @__PURE__ */
|
|
856
|
-
/* @__PURE__ */
|
|
857
|
-
(addException.isError || removeException.isError) && /* @__PURE__ */
|
|
858
|
-
isLoadError && /* @__PURE__ */
|
|
859
|
-
isLoading && /* @__PURE__ */
|
|
860
|
-
/* @__PURE__ */
|
|
861
|
-
/* @__PURE__ */
|
|
1033
|
+
return /* @__PURE__ */ jsxs5("section", { className: "space-y-3", children: [
|
|
1034
|
+
/* @__PURE__ */ jsx6("h3", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: messages["availability.exceptionsTitle"] }),
|
|
1035
|
+
(addException.isError || removeException.isError) && /* @__PURE__ */ jsx6("p", { role: "alert", className: "text-sm text-red-700 bg-red-50 rounded-lg px-3 py-2", children: messages["common.actionFailure"] }),
|
|
1036
|
+
isLoadError && /* @__PURE__ */ jsx6("p", { role: "alert", className: "text-sm text-red-700 bg-red-50 rounded-lg px-3 py-2", children: messages["common.loadFailure"] }),
|
|
1037
|
+
isLoading && /* @__PURE__ */ jsx6("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.loading"] }),
|
|
1038
|
+
/* @__PURE__ */ jsx6("ul", { className: "space-y-2", children: (data ?? []).map((exception) => /* @__PURE__ */ jsxs5("li", { className: "flex items-center gap-2 text-sm", children: [
|
|
1039
|
+
/* @__PURE__ */ jsxs5("span", { className: "flex-1", children: [
|
|
862
1040
|
messages[`availability.exceptionKind.${exception.kind === "block" ? "blocked" : "extra"}`],
|
|
863
1041
|
" \u2014",
|
|
864
1042
|
" ",
|
|
@@ -867,39 +1045,35 @@ function AvailabilityExceptionsEditor({ resourceId }) {
|
|
|
867
1045
|
exception.during.end.toLocaleString(locale),
|
|
868
1046
|
exception.reason ? ` (${exception.reason})` : ""
|
|
869
1047
|
] }),
|
|
870
|
-
/* @__PURE__ */
|
|
1048
|
+
/* @__PURE__ */ jsx6(
|
|
871
1049
|
"button",
|
|
872
1050
|
{
|
|
873
1051
|
type: "button",
|
|
874
1052
|
onClick: () => removeException.mutate({ id: exception.id, resourceId }),
|
|
875
1053
|
"aria-label": messages["availability.removeException"],
|
|
876
1054
|
className: "min-h-11 min-w-11 inline-flex items-center justify-center rounded-lg text-red-700 hover:bg-red-50",
|
|
877
|
-
children: /* @__PURE__ */
|
|
1055
|
+
children: /* @__PURE__ */ jsx6(Trash22, { "aria-hidden": "true", className: "w-4 h-4" })
|
|
878
1056
|
}
|
|
879
1057
|
)
|
|
880
1058
|
] }, exception.id)) }),
|
|
881
|
-
/* @__PURE__ */
|
|
882
|
-
/* @__PURE__ */
|
|
883
|
-
|
|
1059
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
1060
|
+
/* @__PURE__ */ jsx6(
|
|
1061
|
+
DateTimeField,
|
|
884
1062
|
{
|
|
885
|
-
|
|
886
|
-
type: "datetime-local",
|
|
1063
|
+
label: messages["availability.exceptionFrom"],
|
|
887
1064
|
value: from,
|
|
888
|
-
onChange:
|
|
889
|
-
className: SELECT_CLASS
|
|
1065
|
+
onChange: setFrom
|
|
890
1066
|
}
|
|
891
1067
|
),
|
|
892
|
-
/* @__PURE__ */
|
|
893
|
-
|
|
1068
|
+
/* @__PURE__ */ jsx6(
|
|
1069
|
+
DateTimeField,
|
|
894
1070
|
{
|
|
895
|
-
|
|
896
|
-
type: "datetime-local",
|
|
1071
|
+
label: messages["availability.exceptionUntil"],
|
|
897
1072
|
value: until,
|
|
898
|
-
onChange:
|
|
899
|
-
className: SELECT_CLASS
|
|
1073
|
+
onChange: setUntil
|
|
900
1074
|
}
|
|
901
1075
|
),
|
|
902
|
-
/* @__PURE__ */
|
|
1076
|
+
/* @__PURE__ */ jsxs5(
|
|
903
1077
|
"select",
|
|
904
1078
|
{
|
|
905
1079
|
"aria-label": messages["availability.exceptionKind.blocked"],
|
|
@@ -907,12 +1081,12 @@ function AvailabilityExceptionsEditor({ resourceId }) {
|
|
|
907
1081
|
onChange: (event) => setKind(event.target.value),
|
|
908
1082
|
className: SELECT_CLASS,
|
|
909
1083
|
children: [
|
|
910
|
-
/* @__PURE__ */
|
|
911
|
-
/* @__PURE__ */
|
|
1084
|
+
/* @__PURE__ */ jsx6("option", { value: AVAILABILITY_EXCEPTION_KIND.BLOCK, children: messages["availability.exceptionKind.blocked"] }),
|
|
1085
|
+
/* @__PURE__ */ jsx6("option", { value: AVAILABILITY_EXCEPTION_KIND.EXTRA, children: messages["availability.exceptionKind.extra"] })
|
|
912
1086
|
]
|
|
913
1087
|
}
|
|
914
1088
|
),
|
|
915
|
-
/* @__PURE__ */
|
|
1089
|
+
/* @__PURE__ */ jsx6(
|
|
916
1090
|
"input",
|
|
917
1091
|
{
|
|
918
1092
|
"aria-label": messages["availability.exceptionReason"],
|
|
@@ -923,7 +1097,7 @@ function AvailabilityExceptionsEditor({ resourceId }) {
|
|
|
923
1097
|
className: SELECT_CLASS
|
|
924
1098
|
}
|
|
925
1099
|
),
|
|
926
|
-
/* @__PURE__ */
|
|
1100
|
+
/* @__PURE__ */ jsxs5(
|
|
927
1101
|
"button",
|
|
928
1102
|
{
|
|
929
1103
|
type: "button",
|
|
@@ -931,7 +1105,7 @@ function AvailabilityExceptionsEditor({ resourceId }) {
|
|
|
931
1105
|
disabled: addException.isPending,
|
|
932
1106
|
className: "inline-flex items-center gap-2 min-h-11 px-3 py-2 rounded-lg text-sm font-medium bg-brand-600 text-white hover:bg-brand-700 disabled:opacity-50",
|
|
933
1107
|
children: [
|
|
934
|
-
/* @__PURE__ */
|
|
1108
|
+
/* @__PURE__ */ jsx6(Plus2, { "aria-hidden": "true", className: "w-4 h-4" }),
|
|
935
1109
|
messages["availability.addException"]
|
|
936
1110
|
]
|
|
937
1111
|
}
|
|
@@ -941,25 +1115,25 @@ function AvailabilityExceptionsEditor({ resourceId }) {
|
|
|
941
1115
|
}
|
|
942
1116
|
|
|
943
1117
|
// src/components/AvailabilityEditor.tsx
|
|
944
|
-
import { jsx as
|
|
1118
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
945
1119
|
function AvailabilityEditor({ resourceId, timezone }) {
|
|
946
1120
|
const { locale } = useSchedulingConfig();
|
|
947
1121
|
const messages = resolveSchedulingMessages(locale);
|
|
948
|
-
return /* @__PURE__ */
|
|
949
|
-
/* @__PURE__ */
|
|
950
|
-
/* @__PURE__ */
|
|
1122
|
+
return /* @__PURE__ */ jsxs6("div", { className: "space-y-6", children: [
|
|
1123
|
+
/* @__PURE__ */ jsxs6("p", { className: "inline-flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400", children: [
|
|
1124
|
+
/* @__PURE__ */ jsxs6("span", { className: "font-medium", children: [
|
|
951
1125
|
messages["availability.resourceTimezone"],
|
|
952
1126
|
":"
|
|
953
1127
|
] }),
|
|
954
1128
|
timezone
|
|
955
1129
|
] }),
|
|
956
|
-
/* @__PURE__ */
|
|
957
|
-
/* @__PURE__ */
|
|
1130
|
+
/* @__PURE__ */ jsx7(WeeklyRulesEditor, { resourceId }),
|
|
1131
|
+
/* @__PURE__ */ jsx7(AvailabilityExceptionsEditor, { resourceId, timezone })
|
|
958
1132
|
] });
|
|
959
1133
|
}
|
|
960
1134
|
|
|
961
1135
|
// src/workspace/AvailabilityArea.tsx
|
|
962
|
-
import { jsx as
|
|
1136
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
963
1137
|
function AvailabilityArea() {
|
|
964
1138
|
const { locale } = useSchedulingConfig();
|
|
965
1139
|
const messages = resolveSchedulingMessages(locale);
|
|
@@ -967,25 +1141,25 @@ function AvailabilityArea() {
|
|
|
967
1141
|
const [resourceId, setResourceId] = useState4("");
|
|
968
1142
|
const resources = data?.data ?? [];
|
|
969
1143
|
const selectedResource = resources.find((resource) => resource.id === resourceId);
|
|
970
|
-
return /* @__PURE__ */
|
|
971
|
-
/* @__PURE__ */
|
|
972
|
-
/* @__PURE__ */
|
|
973
|
-
/* @__PURE__ */
|
|
1144
|
+
return /* @__PURE__ */ jsxs7("div", { className: "flex flex-1 min-h-0 min-w-0 flex-col p-4 space-y-4", children: [
|
|
1145
|
+
/* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-2 text-sm", children: [
|
|
1146
|
+
/* @__PURE__ */ jsx8("span", { className: "font-medium text-gray-700 dark:text-gray-300", children: messages["agenda.resourceLabel"] }),
|
|
1147
|
+
/* @__PURE__ */ jsxs7(
|
|
974
1148
|
"select",
|
|
975
1149
|
{
|
|
976
1150
|
value: resourceId,
|
|
977
1151
|
onChange: (event) => setResourceId(event.target.value),
|
|
978
1152
|
className: "min-h-11 rounded-lg border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 text-sm",
|
|
979
1153
|
children: [
|
|
980
|
-
/* @__PURE__ */
|
|
981
|
-
resources.map((resource) => /* @__PURE__ */
|
|
1154
|
+
/* @__PURE__ */ jsx8("option", { value: "", children: "\u2014" }),
|
|
1155
|
+
resources.map((resource) => /* @__PURE__ */ jsx8("option", { value: resource.id, children: resource.name }, resource.id))
|
|
982
1156
|
]
|
|
983
1157
|
}
|
|
984
1158
|
)
|
|
985
1159
|
] }),
|
|
986
|
-
isError && /* @__PURE__ */
|
|
987
|
-
isLoading && /* @__PURE__ */
|
|
988
|
-
selectedResource && /* @__PURE__ */
|
|
1160
|
+
isError && /* @__PURE__ */ jsx8("p", { role: "alert", className: "text-sm text-red-700 bg-red-50 rounded-lg px-3 py-2", children: messages["common.loadFailure"] }),
|
|
1161
|
+
isLoading && /* @__PURE__ */ jsx8("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.loading"] }),
|
|
1162
|
+
selectedResource && /* @__PURE__ */ jsx8(
|
|
989
1163
|
AvailabilityEditor,
|
|
990
1164
|
{
|
|
991
1165
|
resourceId: selectedResource.id,
|
|
@@ -998,6 +1172,7 @@ function AvailabilityArea() {
|
|
|
998
1172
|
|
|
999
1173
|
// src/workspace/BookingsArea.tsx
|
|
1000
1174
|
import { useState as useState8 } from "react";
|
|
1175
|
+
import { MAX_PAGE_SIZE as MAX_PAGE_SIZE3 } from "@adatechnology/scheduling-contracts";
|
|
1001
1176
|
|
|
1002
1177
|
// src/components/BookingDrawer.tsx
|
|
1003
1178
|
import { XCircle } from "lucide-react";
|
|
@@ -1007,7 +1182,7 @@ import { BOOKING_STATUS } from "@adatechnology/scheduling-contracts";
|
|
|
1007
1182
|
// src/components/SidePanel.tsx
|
|
1008
1183
|
import { X } from "lucide-react";
|
|
1009
1184
|
import { useEffect } from "react";
|
|
1010
|
-
import { Fragment, jsx as
|
|
1185
|
+
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1011
1186
|
var BUTTON_CLASS = "inline-flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-colors min-h-11";
|
|
1012
1187
|
function SidePanel({ title, closeLabel, onClose, headerActions, children }) {
|
|
1013
1188
|
useEffect(() => {
|
|
@@ -1017,8 +1192,8 @@ function SidePanel({ title, closeLabel, onClose, headerActions, children }) {
|
|
|
1017
1192
|
window.addEventListener("keydown", handleKeyDown);
|
|
1018
1193
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1019
1194
|
}, [onClose]);
|
|
1020
|
-
return /* @__PURE__ */
|
|
1021
|
-
/* @__PURE__ */
|
|
1195
|
+
return /* @__PURE__ */ jsxs8(Fragment2, { children: [
|
|
1196
|
+
/* @__PURE__ */ jsx9(
|
|
1022
1197
|
"button",
|
|
1023
1198
|
{
|
|
1024
1199
|
type: "button",
|
|
@@ -1028,29 +1203,29 @@ function SidePanel({ title, closeLabel, onClose, headerActions, children }) {
|
|
|
1028
1203
|
className: "absolute inset-0 z-10 bg-gray-900/20 wide:hidden"
|
|
1029
1204
|
}
|
|
1030
1205
|
),
|
|
1031
|
-
/* @__PURE__ */
|
|
1206
|
+
/* @__PURE__ */ jsxs8(
|
|
1032
1207
|
"section",
|
|
1033
1208
|
{
|
|
1034
1209
|
"aria-label": title,
|
|
1035
1210
|
className: "absolute inset-y-0 right-0 z-20 flex w-full max-w-full flex-col bg-white shadow-2xl desktop:w-[28rem] dark:bg-gray-900 wide:static wide:z-auto wide:shrink-0 wide:border-l wide:border-gray-200 wide:shadow-none wide:dark:border-gray-700",
|
|
1036
1211
|
children: [
|
|
1037
|
-
/* @__PURE__ */
|
|
1038
|
-
/* @__PURE__ */
|
|
1212
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2 border-b border-gray-200 px-4 py-3 dark:border-gray-700", children: [
|
|
1213
|
+
/* @__PURE__ */ jsx9("h2", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100 mr-auto", children: title }),
|
|
1039
1214
|
headerActions,
|
|
1040
|
-
/* @__PURE__ */
|
|
1215
|
+
/* @__PURE__ */ jsxs8(
|
|
1041
1216
|
"button",
|
|
1042
1217
|
{
|
|
1043
1218
|
type: "button",
|
|
1044
1219
|
onClick: onClose,
|
|
1045
1220
|
className: `${BUTTON_CLASS} text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800`,
|
|
1046
1221
|
children: [
|
|
1047
|
-
/* @__PURE__ */
|
|
1222
|
+
/* @__PURE__ */ jsx9(X, { "aria-hidden": "true", className: "w-4 h-4" }),
|
|
1048
1223
|
closeLabel
|
|
1049
1224
|
]
|
|
1050
1225
|
}
|
|
1051
1226
|
)
|
|
1052
1227
|
] }),
|
|
1053
|
-
/* @__PURE__ */
|
|
1228
|
+
/* @__PURE__ */ jsx9("div", { className: "min-h-0 flex-1 overflow-y-auto p-4", children })
|
|
1054
1229
|
]
|
|
1055
1230
|
}
|
|
1056
1231
|
)
|
|
@@ -1058,16 +1233,13 @@ function SidePanel({ title, closeLabel, onClose, headerActions, children }) {
|
|
|
1058
1233
|
}
|
|
1059
1234
|
|
|
1060
1235
|
// src/components/BookingDrawer.tsx
|
|
1061
|
-
import { Fragment as
|
|
1236
|
+
import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1237
|
+
var BROWSER_TIME_ZONE = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
1062
1238
|
var ACTION_BUTTON_CLASS = "min-h-11 px-3 rounded-lg text-sm font-medium border border-gray-300 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800";
|
|
1063
1239
|
var PRIMARY_BUTTON_CLASS = "min-h-11 px-3 rounded-lg text-sm font-medium bg-brand-600 text-white hover:bg-brand-700";
|
|
1064
1240
|
var DANGER_BUTTON_CLASS = "inline-flex items-center gap-2 min-h-11 px-3 rounded-lg text-sm font-medium text-red-700 hover:bg-red-50";
|
|
1065
1241
|
var INPUT_CLASS = "min-h-11 w-full px-3 rounded-lg border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-900 text-sm";
|
|
1066
|
-
function
|
|
1067
|
-
const pad = (value) => String(value).padStart(2, "0");
|
|
1068
|
-
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
|
|
1069
|
-
}
|
|
1070
|
-
function BookingDrawer({ booking, onClose }) {
|
|
1242
|
+
function BookingDrawer({ booking, resourceTimezone, onClose }) {
|
|
1071
1243
|
const { locale } = useSchedulingConfig();
|
|
1072
1244
|
const messages = resolveSchedulingMessages(locale);
|
|
1073
1245
|
const confirmBooking = useConfirmBooking();
|
|
@@ -1075,12 +1247,13 @@ function BookingDrawer({ booking, onClose }) {
|
|
|
1075
1247
|
const markNoShow = useMarkNoShow();
|
|
1076
1248
|
const cancelBooking = useCancelBooking();
|
|
1077
1249
|
const rescheduleBooking = useRescheduleBooking();
|
|
1250
|
+
const timezone = resourceTimezone ?? BROWSER_TIME_ZONE;
|
|
1078
1251
|
const [isCancelling, setIsCancelling] = useState5(false);
|
|
1079
1252
|
const [cancelledBy, setCancelledBy] = useState5("");
|
|
1080
1253
|
const [cancellationReason, setCancellationReason] = useState5("");
|
|
1081
1254
|
const [isRescheduling, setIsRescheduling] = useState5(false);
|
|
1082
|
-
const [start, setStart] = useState5(() =>
|
|
1083
|
-
const [end, setEnd] = useState5(() =>
|
|
1255
|
+
const [start, setStart] = useState5(() => formatDateTimeLocalInTimeZone(booking.startsAt, timezone));
|
|
1256
|
+
const [end, setEnd] = useState5(() => formatDateTimeLocalInTimeZone(booking.endsAt, timezone));
|
|
1084
1257
|
async function handleCancel() {
|
|
1085
1258
|
if (!cancelledBy) return;
|
|
1086
1259
|
try {
|
|
@@ -1094,42 +1267,57 @@ function BookingDrawer({ booking, onClose }) {
|
|
|
1094
1267
|
}
|
|
1095
1268
|
async function handleReschedule() {
|
|
1096
1269
|
try {
|
|
1097
|
-
await rescheduleBooking.mutateAsync({
|
|
1270
|
+
await rescheduleBooking.mutateAsync({
|
|
1271
|
+
id: booking.id,
|
|
1272
|
+
input: {
|
|
1273
|
+
during: {
|
|
1274
|
+
start: parseDateTimeLocalInTimeZone(start, timezone),
|
|
1275
|
+
end: parseDateTimeLocalInTimeZone(end, timezone)
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
});
|
|
1098
1279
|
setIsRescheduling(false);
|
|
1099
1280
|
} catch {
|
|
1100
1281
|
}
|
|
1101
1282
|
}
|
|
1102
1283
|
const isTerminal = booking.status === BOOKING_STATUS.CANCELLED || booking.status === BOOKING_STATUS.COMPLETED || booking.status === BOOKING_STATUS.NO_SHOW;
|
|
1103
|
-
return /* @__PURE__ */
|
|
1104
|
-
/* @__PURE__ */
|
|
1105
|
-
/* @__PURE__ */
|
|
1106
|
-
/* @__PURE__ */
|
|
1107
|
-
/* @__PURE__ */
|
|
1284
|
+
return /* @__PURE__ */ jsx10(SidePanel, { title: messages["booking.detailTitle"], closeLabel: messages["common.close"], onClose, children: /* @__PURE__ */ jsxs9("div", { className: "space-y-4", children: [
|
|
1285
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
1286
|
+
/* @__PURE__ */ jsx10("p", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: booking.title }),
|
|
1287
|
+
/* @__PURE__ */ jsx10("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages[`booking.status.${booking.status === "no_show" ? "noShow" : booking.status}`] }),
|
|
1288
|
+
/* @__PURE__ */ jsxs9("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: [
|
|
1108
1289
|
booking.startsAt.toLocaleString(locale),
|
|
1109
1290
|
" \u2192 ",
|
|
1110
1291
|
booking.endsAt.toLocaleString(locale)
|
|
1111
1292
|
] })
|
|
1112
1293
|
] }),
|
|
1113
|
-
(confirmBooking.isError || completeBooking.isError || markNoShow.isError || cancelBooking.isError || rescheduleBooking.isError) && /* @__PURE__ */
|
|
1114
|
-
!isTerminal && /* @__PURE__ */
|
|
1115
|
-
booking.status === BOOKING_STATUS.REQUESTED && /* @__PURE__ */
|
|
1116
|
-
booking.status === BOOKING_STATUS.CONFIRMED && /* @__PURE__ */
|
|
1117
|
-
/* @__PURE__ */
|
|
1118
|
-
/* @__PURE__ */
|
|
1119
|
-
/* @__PURE__ */
|
|
1294
|
+
(confirmBooking.isError || completeBooking.isError || markNoShow.isError || cancelBooking.isError || rescheduleBooking.isError) && /* @__PURE__ */ jsx10("p", { role: "alert", className: "text-sm text-red-700 bg-red-50 rounded-lg px-3 py-2", children: messages["common.actionFailure"] }),
|
|
1295
|
+
!isTerminal && /* @__PURE__ */ jsxs9("div", { className: "flex flex-wrap gap-2", children: [
|
|
1296
|
+
booking.status === BOOKING_STATUS.REQUESTED && /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => confirmBooking.mutate(booking.id), className: PRIMARY_BUTTON_CLASS, children: messages["booking.confirm"] }),
|
|
1297
|
+
booking.status === BOOKING_STATUS.CONFIRMED && /* @__PURE__ */ jsxs9(Fragment3, { children: [
|
|
1298
|
+
/* @__PURE__ */ jsx10("button", { type: "button", onClick: () => completeBooking.mutate(booking.id), className: ACTION_BUTTON_CLASS, children: messages["booking.complete"] }),
|
|
1299
|
+
/* @__PURE__ */ jsx10("button", { type: "button", onClick: () => markNoShow.mutate(booking.id), className: ACTION_BUTTON_CLASS, children: messages["booking.markNoShow"] }),
|
|
1300
|
+
/* @__PURE__ */ jsx10("button", { type: "button", onClick: () => setIsRescheduling(true), className: ACTION_BUTTON_CLASS, children: messages["booking.reschedule"] })
|
|
1120
1301
|
] }),
|
|
1121
|
-
/* @__PURE__ */
|
|
1122
|
-
/* @__PURE__ */
|
|
1302
|
+
/* @__PURE__ */ jsxs9("button", { type: "button", onClick: () => setIsCancelling(true), className: DANGER_BUTTON_CLASS, children: [
|
|
1303
|
+
/* @__PURE__ */ jsx10(XCircle, { "aria-hidden": "true", className: "w-4 h-4" }),
|
|
1123
1304
|
messages["booking.cancel"]
|
|
1124
1305
|
] })
|
|
1125
1306
|
] }),
|
|
1126
|
-
isRescheduling && /* @__PURE__ */
|
|
1127
|
-
/* @__PURE__ */
|
|
1128
|
-
|
|
1129
|
-
|
|
1307
|
+
isRescheduling && /* @__PURE__ */ jsxs9("div", { className: "space-y-2 rounded-lg border border-gray-200 dark:border-gray-700 p-3", children: [
|
|
1308
|
+
/* @__PURE__ */ jsx10(
|
|
1309
|
+
DateTimeField,
|
|
1310
|
+
{
|
|
1311
|
+
label: messages["booking.rescheduleStart"],
|
|
1312
|
+
value: start,
|
|
1313
|
+
onChange: setStart
|
|
1314
|
+
}
|
|
1315
|
+
),
|
|
1316
|
+
/* @__PURE__ */ jsx10(DateTimeField, { label: messages["booking.rescheduleEnd"], value: end, onChange: setEnd }),
|
|
1317
|
+
/* @__PURE__ */ jsx10("button", { type: "button", onClick: handleReschedule, disabled: rescheduleBooking.isPending, className: PRIMARY_BUTTON_CLASS, children: messages["common.save"] })
|
|
1130
1318
|
] }),
|
|
1131
|
-
isCancelling && /* @__PURE__ */
|
|
1132
|
-
/* @__PURE__ */
|
|
1319
|
+
isCancelling && /* @__PURE__ */ jsxs9("div", { className: "space-y-2 rounded-lg border border-gray-200 dark:border-gray-700 p-3", children: [
|
|
1320
|
+
/* @__PURE__ */ jsx10(
|
|
1133
1321
|
"input",
|
|
1134
1322
|
{
|
|
1135
1323
|
type: "text",
|
|
@@ -1139,7 +1327,7 @@ function BookingDrawer({ booking, onClose }) {
|
|
|
1139
1327
|
className: INPUT_CLASS
|
|
1140
1328
|
}
|
|
1141
1329
|
),
|
|
1142
|
-
/* @__PURE__ */
|
|
1330
|
+
/* @__PURE__ */ jsx10(
|
|
1143
1331
|
"input",
|
|
1144
1332
|
{
|
|
1145
1333
|
type: "text",
|
|
@@ -1149,8 +1337,8 @@ function BookingDrawer({ booking, onClose }) {
|
|
|
1149
1337
|
className: INPUT_CLASS
|
|
1150
1338
|
}
|
|
1151
1339
|
),
|
|
1152
|
-
/* @__PURE__ */
|
|
1153
|
-
/* @__PURE__ */
|
|
1340
|
+
/* @__PURE__ */ jsxs9("button", { type: "button", onClick: handleCancel, disabled: cancelBooking.isPending, className: DANGER_BUTTON_CLASS, children: [
|
|
1341
|
+
/* @__PURE__ */ jsx10(XCircle, { "aria-hidden": "true", className: "w-4 h-4" }),
|
|
1154
1342
|
messages["booking.cancel"]
|
|
1155
1343
|
] })
|
|
1156
1344
|
] })
|
|
@@ -1160,18 +1348,23 @@ function BookingDrawer({ booking, onClose }) {
|
|
|
1160
1348
|
// src/components/BookingsTable.tsx
|
|
1161
1349
|
import { ArrowDown, ArrowLeft, ArrowRight, ArrowUp, ArrowUpDown } from "lucide-react";
|
|
1162
1350
|
import { useState as useState6 } from "react";
|
|
1163
|
-
import { BOOKING_STATUS as
|
|
1351
|
+
import { BOOKING_STATUS as BOOKING_STATUS3 } from "@adatechnology/scheduling-contracts";
|
|
1164
1352
|
|
|
1165
1353
|
// src/components/bookingsTableState.util.ts
|
|
1354
|
+
import { BOOKING_STATUS as BOOKING_STATUS2 } from "@adatechnology/scheduling-contracts";
|
|
1166
1355
|
var DEFAULT_BOOKINGS_TABLE_STATE = {
|
|
1167
1356
|
sortDirection: "asc",
|
|
1168
1357
|
statusFilters: [],
|
|
1169
1358
|
page: 1
|
|
1170
1359
|
};
|
|
1171
1360
|
var SORT_COLUMNS = ["title", "status", "startsAt", "endsAt"];
|
|
1361
|
+
var BOOKING_STATUSES = Object.values(BOOKING_STATUS2);
|
|
1172
1362
|
function isBookingSortColumn(value) {
|
|
1173
1363
|
return SORT_COLUMNS.includes(value);
|
|
1174
1364
|
}
|
|
1365
|
+
function isBookingStatus(value) {
|
|
1366
|
+
return BOOKING_STATUSES.includes(value);
|
|
1367
|
+
}
|
|
1175
1368
|
function parsePage(value) {
|
|
1176
1369
|
const parsed = Number(value);
|
|
1177
1370
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : 1;
|
|
@@ -1181,7 +1374,7 @@ function parseBookingsTableState(search) {
|
|
|
1181
1374
|
const sortColumnParam = params.get("sortBy");
|
|
1182
1375
|
const sortColumn = isBookingSortColumn(sortColumnParam) ? sortColumnParam : void 0;
|
|
1183
1376
|
const sortDirection = params.get("sortDirection") === "desc" ? "desc" : "asc";
|
|
1184
|
-
const statusFilters = params.getAll("status");
|
|
1377
|
+
const statusFilters = params.getAll("status").filter(isBookingStatus);
|
|
1185
1378
|
const page = parsePage(params.get("page"));
|
|
1186
1379
|
return { ...sortColumn ? { sortColumn } : {}, sortDirection, statusFilters, page };
|
|
1187
1380
|
}
|
|
@@ -1204,13 +1397,14 @@ function filterBookingsByStatus(bookings, statusFilters) {
|
|
|
1204
1397
|
}
|
|
1205
1398
|
|
|
1206
1399
|
// src/components/BookingsTable.tsx
|
|
1207
|
-
import { jsx as
|
|
1208
|
-
var ALL_STATUSES = Object.values(
|
|
1400
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1401
|
+
var ALL_STATUSES = Object.values(BOOKING_STATUS3);
|
|
1209
1402
|
var HEADER_BUTTON_CLASS = "inline-flex items-center gap-1 text-left text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400";
|
|
1210
1403
|
var CHECKBOX_CELL_CLASS = "px-3 py-2";
|
|
1211
|
-
function
|
|
1212
|
-
if (currentColumn !== column) return "asc";
|
|
1213
|
-
|
|
1404
|
+
function nextSortState(column, currentColumn, currentDirection) {
|
|
1405
|
+
if (currentColumn !== column) return { sortColumn: column, sortDirection: "asc" };
|
|
1406
|
+
if (currentDirection === "asc") return { sortColumn: column, sortDirection: "desc" };
|
|
1407
|
+
return { sortColumn: void 0, sortDirection: "asc" };
|
|
1214
1408
|
}
|
|
1215
1409
|
function BookingsTable({
|
|
1216
1410
|
bookings,
|
|
@@ -1228,8 +1422,7 @@ function BookingsTable({
|
|
|
1228
1422
|
function toggleSort(column) {
|
|
1229
1423
|
onStateChange?.({
|
|
1230
1424
|
...state,
|
|
1231
|
-
sortColumn
|
|
1232
|
-
sortDirection: nextSortDirection(column, state.sortColumn, state.sortDirection)
|
|
1425
|
+
...nextSortState(column, state.sortColumn, state.sortDirection)
|
|
1233
1426
|
});
|
|
1234
1427
|
}
|
|
1235
1428
|
function toggleStatusFilter(status) {
|
|
@@ -1253,19 +1446,20 @@ function BookingsTable({
|
|
|
1253
1446
|
setSelected(next);
|
|
1254
1447
|
}
|
|
1255
1448
|
function renderSortIcon(column) {
|
|
1256
|
-
if (state.sortColumn !== column) return /* @__PURE__ */
|
|
1257
|
-
return state.sortDirection === "asc" ? /* @__PURE__ */
|
|
1449
|
+
if (state.sortColumn !== column) return /* @__PURE__ */ jsx11(ArrowUpDown, { "aria-hidden": "true", className: "w-3 h-3" });
|
|
1450
|
+
return state.sortDirection === "asc" ? /* @__PURE__ */ jsx11(ArrowUp, { "aria-hidden": "true", className: "w-3 h-3" }) : /* @__PURE__ */ jsx11(ArrowDown, { "aria-hidden": "true", className: "w-3 h-3" });
|
|
1258
1451
|
}
|
|
1259
1452
|
function renderHeader(column, labelKey) {
|
|
1260
|
-
|
|
1453
|
+
const ariaSort = state.sortColumn !== column ? "none" : state.sortDirection === "asc" ? "ascending" : "descending";
|
|
1454
|
+
return /* @__PURE__ */ jsx11("th", { scope: "col", className: "px-3 py-2", "aria-sort": ariaSort, children: /* @__PURE__ */ jsxs10("button", { type: "button", onClick: () => toggleSort(column), className: HEADER_BUTTON_CLASS, children: [
|
|
1261
1455
|
messages[labelKey],
|
|
1262
1456
|
renderSortIcon(column)
|
|
1263
1457
|
] }) });
|
|
1264
1458
|
}
|
|
1265
|
-
return /* @__PURE__ */
|
|
1266
|
-
/* @__PURE__ */
|
|
1267
|
-
ALL_STATUSES.map((status) => /* @__PURE__ */
|
|
1268
|
-
/* @__PURE__ */
|
|
1459
|
+
return /* @__PURE__ */ jsxs10("div", { className: "space-y-3", children: [
|
|
1460
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
1461
|
+
ALL_STATUSES.map((status) => /* @__PURE__ */ jsxs10("label", { className: "flex items-center gap-1.5 text-sm min-h-11", children: [
|
|
1462
|
+
/* @__PURE__ */ jsx11(
|
|
1269
1463
|
"input",
|
|
1270
1464
|
{
|
|
1271
1465
|
type: "checkbox",
|
|
@@ -1275,7 +1469,7 @@ function BookingsTable({
|
|
|
1275
1469
|
),
|
|
1276
1470
|
messages[`booking.status.${status === "no_show" ? "noShow" : status}`]
|
|
1277
1471
|
] }, status)),
|
|
1278
|
-
!isBookingsTableStateDefault(state) && /* @__PURE__ */
|
|
1472
|
+
!isBookingsTableStateDefault(state) && /* @__PURE__ */ jsx11(
|
|
1279
1473
|
"button",
|
|
1280
1474
|
{
|
|
1281
1475
|
type: "button",
|
|
@@ -1285,7 +1479,7 @@ function BookingsTable({
|
|
|
1285
1479
|
}
|
|
1286
1480
|
)
|
|
1287
1481
|
] }),
|
|
1288
|
-
selected.size > 0 && bulkActions.length > 0 && /* @__PURE__ */
|
|
1482
|
+
selected.size > 0 && bulkActions.length > 0 && /* @__PURE__ */ jsx11("div", { className: "flex items-center gap-2 rounded-lg bg-brand-50 dark:bg-brand-900/30 px-3 py-2", children: bulkActions.map((action) => /* @__PURE__ */ jsx11(
|
|
1289
1483
|
"button",
|
|
1290
1484
|
{
|
|
1291
1485
|
type: "button",
|
|
@@ -1295,10 +1489,10 @@ function BookingsTable({
|
|
|
1295
1489
|
},
|
|
1296
1490
|
action.key
|
|
1297
1491
|
)) }),
|
|
1298
|
-
/* @__PURE__ */
|
|
1299
|
-
/* @__PURE__ */
|
|
1300
|
-
/* @__PURE__ */
|
|
1301
|
-
/* @__PURE__ */
|
|
1492
|
+
/* @__PURE__ */ jsxs10("div", { className: "overflow-x-auto rounded-lg border border-gray-200 dark:border-gray-700", children: [
|
|
1493
|
+
/* @__PURE__ */ jsxs10("table", { className: "min-w-full text-sm", children: [
|
|
1494
|
+
/* @__PURE__ */ jsx11("thead", { className: "border-b border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ jsxs10("tr", { children: [
|
|
1495
|
+
/* @__PURE__ */ jsx11("th", { scope: "col", className: CHECKBOX_CELL_CLASS, children: /* @__PURE__ */ jsx11(
|
|
1302
1496
|
"input",
|
|
1303
1497
|
{
|
|
1304
1498
|
type: "checkbox",
|
|
@@ -1312,12 +1506,12 @@ function BookingsTable({
|
|
|
1312
1506
|
renderHeader("startsAt", "booking.column.startsAt"),
|
|
1313
1507
|
renderHeader("endsAt", "booking.column.endsAt")
|
|
1314
1508
|
] }) }),
|
|
1315
|
-
/* @__PURE__ */
|
|
1509
|
+
/* @__PURE__ */ jsx11("tbody", { children: visibleBookings.map((booking, index) => /* @__PURE__ */ jsxs10(
|
|
1316
1510
|
"tr",
|
|
1317
1511
|
{
|
|
1318
1512
|
className: index % 2 === 1 ? "bg-gray-50 dark:bg-gray-800/50" : void 0,
|
|
1319
1513
|
children: [
|
|
1320
|
-
/* @__PURE__ */
|
|
1514
|
+
/* @__PURE__ */ jsx11("td", { className: CHECKBOX_CELL_CLASS, children: /* @__PURE__ */ jsx11(
|
|
1321
1515
|
"input",
|
|
1322
1516
|
{
|
|
1323
1517
|
type: "checkbox",
|
|
@@ -1326,19 +1520,19 @@ function BookingsTable({
|
|
|
1326
1520
|
onChange: () => toggleRowSelected(booking.id)
|
|
1327
1521
|
}
|
|
1328
1522
|
) }),
|
|
1329
|
-
/* @__PURE__ */
|
|
1330
|
-
/* @__PURE__ */
|
|
1331
|
-
/* @__PURE__ */
|
|
1332
|
-
/* @__PURE__ */
|
|
1523
|
+
/* @__PURE__ */ jsx11("td", { className: "px-3 py-2", children: /* @__PURE__ */ jsx11("button", { type: "button", onClick: () => onRowClick?.(booking), className: "min-h-11 text-left hover:underline", children: booking.title }) }),
|
|
1524
|
+
/* @__PURE__ */ jsx11("td", { className: "px-3 py-2", children: messages[`booking.status.${booking.status === "no_show" ? "noShow" : booking.status}`] }),
|
|
1525
|
+
/* @__PURE__ */ jsx11("td", { className: "px-3 py-2", children: booking.startsAt.toLocaleString(locale) }),
|
|
1526
|
+
/* @__PURE__ */ jsx11("td", { className: "px-3 py-2", children: booking.endsAt.toLocaleString(locale) })
|
|
1333
1527
|
]
|
|
1334
1528
|
},
|
|
1335
1529
|
booking.id
|
|
1336
1530
|
)) })
|
|
1337
1531
|
] }),
|
|
1338
|
-
visibleBookings.length === 0 && /* @__PURE__ */
|
|
1532
|
+
visibleBookings.length === 0 && /* @__PURE__ */ jsx11("p", { className: "px-3 py-4 text-sm text-gray-500 dark:text-gray-400", children: messages["common.empty"] })
|
|
1339
1533
|
] }),
|
|
1340
|
-
pagination && pagination.totalPages > 1 && /* @__PURE__ */
|
|
1341
|
-
/* @__PURE__ */
|
|
1534
|
+
pagination && pagination.totalPages > 1 && /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-end gap-3", children: [
|
|
1535
|
+
/* @__PURE__ */ jsx11(
|
|
1342
1536
|
"button",
|
|
1343
1537
|
{
|
|
1344
1538
|
type: "button",
|
|
@@ -1346,15 +1540,15 @@ function BookingsTable({
|
|
|
1346
1540
|
disabled: state.page <= 1,
|
|
1347
1541
|
onClick: () => goToPage(state.page - 1),
|
|
1348
1542
|
className: "min-h-11 min-w-11 inline-flex items-center justify-center rounded-lg border border-gray-300 dark:border-gray-700 disabled:opacity-50",
|
|
1349
|
-
children: /* @__PURE__ */
|
|
1543
|
+
children: /* @__PURE__ */ jsx11(ArrowLeft, { "aria-hidden": "true", className: "w-4 h-4" })
|
|
1350
1544
|
}
|
|
1351
1545
|
),
|
|
1352
|
-
/* @__PURE__ */
|
|
1546
|
+
/* @__PURE__ */ jsxs10("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: [
|
|
1353
1547
|
state.page,
|
|
1354
1548
|
" / ",
|
|
1355
1549
|
pagination.totalPages
|
|
1356
1550
|
] }),
|
|
1357
|
-
/* @__PURE__ */
|
|
1551
|
+
/* @__PURE__ */ jsx11(
|
|
1358
1552
|
"button",
|
|
1359
1553
|
{
|
|
1360
1554
|
type: "button",
|
|
@@ -1362,7 +1556,7 @@ function BookingsTable({
|
|
|
1362
1556
|
disabled: state.page >= pagination.totalPages,
|
|
1363
1557
|
onClick: () => goToPage(state.page + 1),
|
|
1364
1558
|
className: "min-h-11 min-w-11 inline-flex items-center justify-center rounded-lg border border-gray-300 dark:border-gray-700 disabled:opacity-50",
|
|
1365
|
-
children: /* @__PURE__ */
|
|
1559
|
+
children: /* @__PURE__ */ jsx11(ArrowRight, { "aria-hidden": "true", className: "w-4 h-4" })
|
|
1366
1560
|
}
|
|
1367
1561
|
)
|
|
1368
1562
|
] })
|
|
@@ -1391,7 +1585,7 @@ function useBookingsTableState() {
|
|
|
1391
1585
|
}
|
|
1392
1586
|
|
|
1393
1587
|
// src/workspace/BookingsArea.tsx
|
|
1394
|
-
import { jsx as
|
|
1588
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1395
1589
|
var PAGE_SIZE = 20;
|
|
1396
1590
|
function BookingsArea() {
|
|
1397
1591
|
const { locale } = useSchedulingConfig();
|
|
@@ -1406,14 +1600,19 @@ function BookingsArea() {
|
|
|
1406
1600
|
sortDirection: tableState.sortColumn ? tableState.sortDirection : void 0
|
|
1407
1601
|
});
|
|
1408
1602
|
const confirmBooking = useConfirmBooking();
|
|
1603
|
+
const { data: resourcesData } = useResources({ pageSize: MAX_PAGE_SIZE3 });
|
|
1409
1604
|
const [selectedBookingId, setSelectedBookingId] = useState8(void 0);
|
|
1410
1605
|
const selectedBooking = data?.data.find((booking) => booking.id === selectedBookingId);
|
|
1606
|
+
const selectedBookingResourceTimezone = resourcesData?.data.find(
|
|
1607
|
+
(resource) => resource.id === selectedBooking?.resourceIds[0]
|
|
1608
|
+
)?.timezone;
|
|
1411
1609
|
function bulkConfirm(ids) {
|
|
1412
1610
|
for (const id of ids) confirmBooking.mutate(id);
|
|
1413
1611
|
}
|
|
1414
|
-
return /* @__PURE__ */
|
|
1415
|
-
isError && /* @__PURE__ */
|
|
1416
|
-
|
|
1612
|
+
return /* @__PURE__ */ jsxs11("div", { className: "flex flex-1 min-h-0 min-w-0 flex-col p-4 space-y-4", children: [
|
|
1613
|
+
isError && /* @__PURE__ */ jsx12("p", { role: "alert", className: "text-sm text-red-700 bg-red-50 rounded-lg px-3 py-2", children: messages["common.loadFailure"] }),
|
|
1614
|
+
confirmBooking.isError && /* @__PURE__ */ jsx12("p", { role: "alert", className: "text-sm text-red-700 bg-red-50 rounded-lg px-3 py-2", children: messages["common.actionFailure"] }),
|
|
1615
|
+
isLoading ? /* @__PURE__ */ jsx12("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.loading"] }) : /* @__PURE__ */ jsx12(
|
|
1417
1616
|
BookingsTable,
|
|
1418
1617
|
{
|
|
1419
1618
|
bookings: data?.data ?? [],
|
|
@@ -1424,24 +1623,37 @@ function BookingsArea() {
|
|
|
1424
1623
|
bulkActions: [{ key: "confirm", label: messages["booking.confirm"], onRun: bulkConfirm }]
|
|
1425
1624
|
}
|
|
1426
1625
|
),
|
|
1427
|
-
selectedBooking && /* @__PURE__ */
|
|
1626
|
+
selectedBooking && /* @__PURE__ */ jsx12(
|
|
1627
|
+
BookingDrawer,
|
|
1628
|
+
{
|
|
1629
|
+
booking: selectedBooking,
|
|
1630
|
+
resourceTimezone: selectedBookingResourceTimezone,
|
|
1631
|
+
onClose: () => setSelectedBookingId(void 0)
|
|
1632
|
+
},
|
|
1633
|
+
selectedBooking.id
|
|
1634
|
+
)
|
|
1428
1635
|
] });
|
|
1429
1636
|
}
|
|
1430
1637
|
|
|
1431
1638
|
// src/workspace/ResourcesArea.tsx
|
|
1432
1639
|
import { Plus as Plus3, Trash2 as Trash23 } from "lucide-react";
|
|
1433
1640
|
import { useState as useState10 } from "react";
|
|
1641
|
+
import { MAX_PAGE_SIZE as MAX_PAGE_SIZE4 } from "@adatechnology/scheduling-contracts";
|
|
1434
1642
|
|
|
1435
1643
|
// src/components/ResourceForm.tsx
|
|
1436
|
-
import { useState as useState9 } from "react";
|
|
1644
|
+
import { useId as useId2, useState as useState9 } from "react";
|
|
1437
1645
|
import { RESOURCE_KIND } from "@adatechnology/scheduling-contracts";
|
|
1438
|
-
import { jsx as
|
|
1646
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1439
1647
|
var INPUT_CLASS2 = "w-full min-h-11 px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500 bg-white dark:bg-gray-900";
|
|
1440
1648
|
var LABEL_CLASS = "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1";
|
|
1441
1649
|
var BUTTON_PRIMARY = "inline-flex items-center justify-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-colors min-h-11 bg-brand-600 text-white hover:bg-brand-700 disabled:opacity-50";
|
|
1442
1650
|
function ResourceForm({ initialValues, onSubmit }) {
|
|
1443
1651
|
const { locale } = useSchedulingConfig();
|
|
1444
1652
|
const messages = resolveSchedulingMessages(locale);
|
|
1653
|
+
const formId = useId2();
|
|
1654
|
+
const nameId = `${formId}-name`;
|
|
1655
|
+
const kindId = `${formId}-kind`;
|
|
1656
|
+
const timezoneId = `${formId}-timezone`;
|
|
1445
1657
|
const [name, setName] = useState9(initialValues?.name ?? "");
|
|
1446
1658
|
const [kind, setKind] = useState9(initialValues?.kind ?? RESOURCE_KIND.PERSON);
|
|
1447
1659
|
const [timezone, setTimezone] = useState9(initialValues?.timezone ?? "America/Sao_Paulo");
|
|
@@ -1456,13 +1668,13 @@ function ResourceForm({ initialValues, onSubmit }) {
|
|
|
1456
1668
|
setSubmitting(false);
|
|
1457
1669
|
}
|
|
1458
1670
|
}
|
|
1459
|
-
return /* @__PURE__ */
|
|
1460
|
-
/* @__PURE__ */
|
|
1461
|
-
/* @__PURE__ */
|
|
1462
|
-
/* @__PURE__ */
|
|
1671
|
+
return /* @__PURE__ */ jsxs12("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
|
|
1672
|
+
/* @__PURE__ */ jsxs12("div", { children: [
|
|
1673
|
+
/* @__PURE__ */ jsx13("label", { htmlFor: nameId, className: LABEL_CLASS, children: messages["resource.name"] }),
|
|
1674
|
+
/* @__PURE__ */ jsx13(
|
|
1463
1675
|
"input",
|
|
1464
1676
|
{
|
|
1465
|
-
id:
|
|
1677
|
+
id: nameId,
|
|
1466
1678
|
type: "text",
|
|
1467
1679
|
required: true,
|
|
1468
1680
|
value: name,
|
|
@@ -1471,29 +1683,29 @@ function ResourceForm({ initialValues, onSubmit }) {
|
|
|
1471
1683
|
}
|
|
1472
1684
|
)
|
|
1473
1685
|
] }),
|
|
1474
|
-
/* @__PURE__ */
|
|
1475
|
-
/* @__PURE__ */
|
|
1476
|
-
/* @__PURE__ */
|
|
1686
|
+
/* @__PURE__ */ jsxs12("div", { children: [
|
|
1687
|
+
/* @__PURE__ */ jsx13("label", { htmlFor: kindId, className: LABEL_CLASS, children: messages["resource.kind"] }),
|
|
1688
|
+
/* @__PURE__ */ jsxs12(
|
|
1477
1689
|
"select",
|
|
1478
1690
|
{
|
|
1479
|
-
id:
|
|
1691
|
+
id: kindId,
|
|
1480
1692
|
value: kind,
|
|
1481
1693
|
onChange: (event) => setKind(event.target.value),
|
|
1482
1694
|
className: INPUT_CLASS2,
|
|
1483
1695
|
children: [
|
|
1484
|
-
/* @__PURE__ */
|
|
1485
|
-
/* @__PURE__ */
|
|
1486
|
-
/* @__PURE__ */
|
|
1696
|
+
/* @__PURE__ */ jsx13("option", { value: RESOURCE_KIND.PERSON, children: messages["resource.kind.person"] }),
|
|
1697
|
+
/* @__PURE__ */ jsx13("option", { value: RESOURCE_KIND.ROOM, children: messages["resource.kind.room"] }),
|
|
1698
|
+
/* @__PURE__ */ jsx13("option", { value: RESOURCE_KIND.EQUIPMENT, children: messages["resource.kind.equipment"] })
|
|
1487
1699
|
]
|
|
1488
1700
|
}
|
|
1489
1701
|
)
|
|
1490
1702
|
] }),
|
|
1491
|
-
/* @__PURE__ */
|
|
1492
|
-
/* @__PURE__ */
|
|
1493
|
-
/* @__PURE__ */
|
|
1703
|
+
/* @__PURE__ */ jsxs12("div", { children: [
|
|
1704
|
+
/* @__PURE__ */ jsx13("label", { htmlFor: timezoneId, className: LABEL_CLASS, children: messages["resource.timezone"] }),
|
|
1705
|
+
/* @__PURE__ */ jsx13(
|
|
1494
1706
|
"input",
|
|
1495
1707
|
{
|
|
1496
|
-
id:
|
|
1708
|
+
id: timezoneId,
|
|
1497
1709
|
type: "text",
|
|
1498
1710
|
required: true,
|
|
1499
1711
|
value: timezone,
|
|
@@ -1503,47 +1715,47 @@ function ResourceForm({ initialValues, onSubmit }) {
|
|
|
1503
1715
|
}
|
|
1504
1716
|
)
|
|
1505
1717
|
] }),
|
|
1506
|
-
initialValues && /* @__PURE__ */
|
|
1507
|
-
/* @__PURE__ */
|
|
1718
|
+
initialValues && /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-2 text-sm text-gray-700 dark:text-gray-300 min-h-11", children: [
|
|
1719
|
+
/* @__PURE__ */ jsx13("input", { type: "checkbox", checked: active, onChange: (event) => setActive(event.target.checked) }),
|
|
1508
1720
|
messages["resource.active"]
|
|
1509
1721
|
] }),
|
|
1510
|
-
/* @__PURE__ */
|
|
1722
|
+
/* @__PURE__ */ jsx13("button", { type: "submit", disabled: submitting, className: BUTTON_PRIMARY, children: messages["common.save"] })
|
|
1511
1723
|
] });
|
|
1512
1724
|
}
|
|
1513
1725
|
|
|
1514
1726
|
// src/components/ResourceList.tsx
|
|
1515
|
-
import { jsx as
|
|
1727
|
+
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1516
1728
|
function ResourceList({ resources, onSelect }) {
|
|
1517
1729
|
const { locale } = useSchedulingConfig();
|
|
1518
1730
|
const messages = resolveSchedulingMessages(locale);
|
|
1519
1731
|
if (resources.length === 0) {
|
|
1520
|
-
return /* @__PURE__ */
|
|
1732
|
+
return /* @__PURE__ */ jsx14("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.empty"] });
|
|
1521
1733
|
}
|
|
1522
|
-
return /* @__PURE__ */
|
|
1734
|
+
return /* @__PURE__ */ jsx14("ul", { className: "divide-y divide-gray-200 dark:divide-gray-700 rounded-lg border border-gray-200 dark:border-gray-700", children: resources.map((resource, index) => /* @__PURE__ */ jsx14("li", { className: index % 2 === 1 ? "bg-gray-50 dark:bg-gray-800/50" : void 0, children: /* @__PURE__ */ jsxs13(
|
|
1523
1735
|
"button",
|
|
1524
1736
|
{
|
|
1525
1737
|
type: "button",
|
|
1526
1738
|
onClick: () => onSelect(resource),
|
|
1527
1739
|
className: "flex w-full items-center gap-3 px-4 py-3 min-h-11 text-left text-sm hover:bg-gray-100 dark:hover:bg-gray-800",
|
|
1528
1740
|
children: [
|
|
1529
|
-
/* @__PURE__ */
|
|
1530
|
-
/* @__PURE__ */
|
|
1531
|
-
/* @__PURE__ */
|
|
1532
|
-
!resource.active && /* @__PURE__ */
|
|
1741
|
+
/* @__PURE__ */ jsx14("span", { className: "flex-1 font-medium text-gray-900 dark:text-gray-100", children: resource.name }),
|
|
1742
|
+
/* @__PURE__ */ jsx14("span", { className: "text-gray-500 dark:text-gray-400", children: messages[`resource.kind.${resource.kind}`] }),
|
|
1743
|
+
/* @__PURE__ */ jsx14("span", { className: "text-gray-500 dark:text-gray-400", children: resource.timezone }),
|
|
1744
|
+
!resource.active && /* @__PURE__ */ jsx14("span", { className: "rounded-full bg-gray-200 px-2 py-0.5 text-xs text-gray-700 dark:bg-gray-700 dark:text-gray-300", children: messages["resource.inactive"] })
|
|
1533
1745
|
]
|
|
1534
1746
|
}
|
|
1535
1747
|
) }, resource.id)) });
|
|
1536
1748
|
}
|
|
1537
1749
|
|
|
1538
1750
|
// src/workspace/ResourcesArea.tsx
|
|
1539
|
-
import { jsx as
|
|
1751
|
+
import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1540
1752
|
var BUTTON_CLASS2 = "inline-flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-colors min-h-11";
|
|
1541
1753
|
var BUTTON_PRIMARY2 = `${BUTTON_CLASS2} bg-brand-600 text-white hover:bg-brand-700`;
|
|
1542
1754
|
var BUTTON_DANGER = `${BUTTON_CLASS2} text-red-700 hover:bg-red-50`;
|
|
1543
1755
|
function ResourcesArea() {
|
|
1544
1756
|
const { locale } = useSchedulingConfig();
|
|
1545
1757
|
const messages = resolveSchedulingMessages(locale);
|
|
1546
|
-
const { data, isLoading, isError } = useResources();
|
|
1758
|
+
const { data, isLoading, isError } = useResources({ pageSize: MAX_PAGE_SIZE4 });
|
|
1547
1759
|
const createResource = useCreateResource();
|
|
1548
1760
|
const updateResource = useUpdateResource();
|
|
1549
1761
|
const deleteResource = useDeleteResource();
|
|
@@ -1561,21 +1773,21 @@ function ResourcesArea() {
|
|
|
1561
1773
|
} catch {
|
|
1562
1774
|
}
|
|
1563
1775
|
}
|
|
1564
|
-
return /* @__PURE__ */
|
|
1565
|
-
/* @__PURE__ */
|
|
1566
|
-
/* @__PURE__ */
|
|
1776
|
+
return /* @__PURE__ */ jsxs14("div", { className: "flex flex-1 min-h-0 min-w-0 flex-col p-4 space-y-4", children: [
|
|
1777
|
+
/* @__PURE__ */ jsx15("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxs14("button", { type: "button", onClick: () => setDraft(null), className: `${BUTTON_PRIMARY2} ml-auto`, children: [
|
|
1778
|
+
/* @__PURE__ */ jsx15(Plus3, { "aria-hidden": "true", className: "w-4 h-4" }),
|
|
1567
1779
|
messages["resource.newResource"]
|
|
1568
1780
|
] }) }),
|
|
1569
|
-
isError && /* @__PURE__ */
|
|
1570
|
-
(createResource.isError || updateResource.isError || deleteResource.isError) && /* @__PURE__ */
|
|
1571
|
-
isLoading ? /* @__PURE__ */
|
|
1572
|
-
isDraftOpen && /* @__PURE__ */
|
|
1781
|
+
isError && /* @__PURE__ */ jsx15("p", { role: "alert", className: "text-sm text-red-700 bg-red-50 rounded-lg px-3 py-2", children: messages["common.loadFailure"] }),
|
|
1782
|
+
(createResource.isError || updateResource.isError || deleteResource.isError) && /* @__PURE__ */ jsx15("p", { role: "alert", className: "text-sm text-red-700 bg-red-50 rounded-lg px-3 py-2", children: messages["common.actionFailure"] }),
|
|
1783
|
+
isLoading ? /* @__PURE__ */ jsx15("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.loading"] }) : /* @__PURE__ */ jsx15(ResourceList, { resources: data?.data ?? [], onSelect: setDraft }),
|
|
1784
|
+
isDraftOpen && /* @__PURE__ */ jsx15(
|
|
1573
1785
|
SidePanel,
|
|
1574
1786
|
{
|
|
1575
1787
|
title: isEditing ? messages["resource.editTitle"] : messages["resource.createTitle"],
|
|
1576
1788
|
closeLabel: messages["common.close"],
|
|
1577
1789
|
onClose: () => setDraft(void 0),
|
|
1578
|
-
headerActions: isEditing ? /* @__PURE__ */
|
|
1790
|
+
headerActions: isEditing ? /* @__PURE__ */ jsxs14(
|
|
1579
1791
|
"button",
|
|
1580
1792
|
{
|
|
1581
1793
|
type: "button",
|
|
@@ -1585,12 +1797,12 @@ function ResourcesArea() {
|
|
|
1585
1797
|
},
|
|
1586
1798
|
className: BUTTON_DANGER,
|
|
1587
1799
|
children: [
|
|
1588
|
-
/* @__PURE__ */
|
|
1800
|
+
/* @__PURE__ */ jsx15(Trash23, { "aria-hidden": "true", className: "w-4 h-4" }),
|
|
1589
1801
|
messages["common.remove"]
|
|
1590
1802
|
]
|
|
1591
1803
|
}
|
|
1592
1804
|
) : void 0,
|
|
1593
|
-
children: /* @__PURE__ */
|
|
1805
|
+
children: /* @__PURE__ */ jsx15(
|
|
1594
1806
|
ResourceForm,
|
|
1595
1807
|
{
|
|
1596
1808
|
...draft ? { initialValues: draft } : {},
|
|
@@ -1606,10 +1818,11 @@ function ResourcesArea() {
|
|
|
1606
1818
|
// src/workspace/ServicesArea.tsx
|
|
1607
1819
|
import { Plus as Plus4, Trash2 as Trash24 } from "lucide-react";
|
|
1608
1820
|
import { useState as useState12 } from "react";
|
|
1821
|
+
import { MAX_PAGE_SIZE as MAX_PAGE_SIZE5 } from "@adatechnology/scheduling-contracts";
|
|
1609
1822
|
|
|
1610
1823
|
// src/components/ServiceForm.tsx
|
|
1611
1824
|
import { useState as useState11 } from "react";
|
|
1612
|
-
import { jsx as
|
|
1825
|
+
import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1613
1826
|
var INPUT_CLASS3 = "w-full min-h-11 px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-brand-500 bg-white dark:bg-gray-900";
|
|
1614
1827
|
var LABEL_CLASS2 = "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1";
|
|
1615
1828
|
var BUTTON_PRIMARY3 = "inline-flex items-center justify-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-colors min-h-11 bg-brand-600 text-white hover:bg-brand-700 disabled:opacity-50";
|
|
@@ -1631,10 +1844,10 @@ function ServiceForm({ initialValues, onSubmit }) {
|
|
|
1631
1844
|
setSubmitting(false);
|
|
1632
1845
|
}
|
|
1633
1846
|
}
|
|
1634
|
-
return /* @__PURE__ */
|
|
1635
|
-
/* @__PURE__ */
|
|
1636
|
-
/* @__PURE__ */
|
|
1637
|
-
/* @__PURE__ */
|
|
1847
|
+
return /* @__PURE__ */ jsxs15("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
|
|
1848
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
1849
|
+
/* @__PURE__ */ jsx16("label", { htmlFor: "scheduling-service-name", className: LABEL_CLASS2, children: messages["service.name"] }),
|
|
1850
|
+
/* @__PURE__ */ jsx16(
|
|
1638
1851
|
"input",
|
|
1639
1852
|
{
|
|
1640
1853
|
id: "scheduling-service-name",
|
|
@@ -1646,9 +1859,9 @@ function ServiceForm({ initialValues, onSubmit }) {
|
|
|
1646
1859
|
}
|
|
1647
1860
|
)
|
|
1648
1861
|
] }),
|
|
1649
|
-
/* @__PURE__ */
|
|
1650
|
-
/* @__PURE__ */
|
|
1651
|
-
/* @__PURE__ */
|
|
1862
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
1863
|
+
/* @__PURE__ */ jsx16("label", { htmlFor: "scheduling-service-duration", className: LABEL_CLASS2, children: messages["service.durationMinutes"] }),
|
|
1864
|
+
/* @__PURE__ */ jsx16(
|
|
1652
1865
|
"input",
|
|
1653
1866
|
{
|
|
1654
1867
|
id: "scheduling-service-duration",
|
|
@@ -1661,10 +1874,10 @@ function ServiceForm({ initialValues, onSubmit }) {
|
|
|
1661
1874
|
}
|
|
1662
1875
|
)
|
|
1663
1876
|
] }),
|
|
1664
|
-
/* @__PURE__ */
|
|
1665
|
-
/* @__PURE__ */
|
|
1666
|
-
/* @__PURE__ */
|
|
1667
|
-
/* @__PURE__ */
|
|
1877
|
+
/* @__PURE__ */ jsxs15("div", { className: "grid grid-cols-2 gap-3", children: [
|
|
1878
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
1879
|
+
/* @__PURE__ */ jsx16("label", { htmlFor: "scheduling-service-buffer-before", className: LABEL_CLASS2, children: messages["service.bufferBeforeMinutes"] }),
|
|
1880
|
+
/* @__PURE__ */ jsx16(
|
|
1668
1881
|
"input",
|
|
1669
1882
|
{
|
|
1670
1883
|
id: "scheduling-service-buffer-before",
|
|
@@ -1676,9 +1889,9 @@ function ServiceForm({ initialValues, onSubmit }) {
|
|
|
1676
1889
|
}
|
|
1677
1890
|
)
|
|
1678
1891
|
] }),
|
|
1679
|
-
/* @__PURE__ */
|
|
1680
|
-
/* @__PURE__ */
|
|
1681
|
-
/* @__PURE__ */
|
|
1892
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
1893
|
+
/* @__PURE__ */ jsx16("label", { htmlFor: "scheduling-service-buffer-after", className: LABEL_CLASS2, children: messages["service.bufferAfterMinutes"] }),
|
|
1894
|
+
/* @__PURE__ */ jsx16(
|
|
1682
1895
|
"input",
|
|
1683
1896
|
{
|
|
1684
1897
|
id: "scheduling-service-buffer-after",
|
|
@@ -1691,49 +1904,49 @@ function ServiceForm({ initialValues, onSubmit }) {
|
|
|
1691
1904
|
)
|
|
1692
1905
|
] })
|
|
1693
1906
|
] }),
|
|
1694
|
-
initialValues && /* @__PURE__ */
|
|
1695
|
-
/* @__PURE__ */
|
|
1907
|
+
initialValues && /* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-2 text-sm text-gray-700 dark:text-gray-300 min-h-11", children: [
|
|
1908
|
+
/* @__PURE__ */ jsx16("input", { type: "checkbox", checked: active, onChange: (event) => setActive(event.target.checked) }),
|
|
1696
1909
|
messages["service.active"]
|
|
1697
1910
|
] }),
|
|
1698
|
-
/* @__PURE__ */
|
|
1911
|
+
/* @__PURE__ */ jsx16("button", { type: "submit", disabled: submitting, className: BUTTON_PRIMARY3, children: messages["common.save"] })
|
|
1699
1912
|
] });
|
|
1700
1913
|
}
|
|
1701
1914
|
|
|
1702
1915
|
// src/components/ServiceList.tsx
|
|
1703
|
-
import { jsx as
|
|
1916
|
+
import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1704
1917
|
function ServiceList({ services, onSelect }) {
|
|
1705
1918
|
const { locale } = useSchedulingConfig();
|
|
1706
1919
|
const messages = resolveSchedulingMessages(locale);
|
|
1707
1920
|
if (services.length === 0) {
|
|
1708
|
-
return /* @__PURE__ */
|
|
1921
|
+
return /* @__PURE__ */ jsx17("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.empty"] });
|
|
1709
1922
|
}
|
|
1710
|
-
return /* @__PURE__ */
|
|
1923
|
+
return /* @__PURE__ */ jsx17("ul", { className: "divide-y divide-gray-200 dark:divide-gray-700 rounded-lg border border-gray-200 dark:border-gray-700", children: services.map((service, index) => /* @__PURE__ */ jsx17("li", { className: index % 2 === 1 ? "bg-gray-50 dark:bg-gray-800/50" : void 0, children: /* @__PURE__ */ jsxs16(
|
|
1711
1924
|
"button",
|
|
1712
1925
|
{
|
|
1713
1926
|
type: "button",
|
|
1714
1927
|
onClick: () => onSelect(service),
|
|
1715
1928
|
className: "flex w-full items-center gap-3 px-4 py-3 min-h-11 text-left text-sm hover:bg-gray-100 dark:hover:bg-gray-800",
|
|
1716
1929
|
children: [
|
|
1717
|
-
/* @__PURE__ */
|
|
1718
|
-
/* @__PURE__ */
|
|
1930
|
+
/* @__PURE__ */ jsx17("span", { className: "flex-1 font-medium text-gray-900 dark:text-gray-100", children: service.name }),
|
|
1931
|
+
/* @__PURE__ */ jsxs16("span", { className: "text-gray-500 dark:text-gray-400", children: [
|
|
1719
1932
|
service.durationMinutes,
|
|
1720
1933
|
" min"
|
|
1721
1934
|
] }),
|
|
1722
|
-
!service.active && /* @__PURE__ */
|
|
1935
|
+
!service.active && /* @__PURE__ */ jsx17("span", { className: "rounded-full bg-gray-200 px-2 py-0.5 text-xs text-gray-700 dark:bg-gray-700 dark:text-gray-300", children: messages["service.inactive"] })
|
|
1723
1936
|
]
|
|
1724
1937
|
}
|
|
1725
1938
|
) }, service.id)) });
|
|
1726
1939
|
}
|
|
1727
1940
|
|
|
1728
1941
|
// src/workspace/ServicesArea.tsx
|
|
1729
|
-
import { jsx as
|
|
1942
|
+
import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1730
1943
|
var BUTTON_CLASS3 = "inline-flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-colors min-h-11";
|
|
1731
1944
|
var BUTTON_PRIMARY4 = `${BUTTON_CLASS3} bg-brand-600 text-white hover:bg-brand-700`;
|
|
1732
1945
|
var BUTTON_DANGER2 = `${BUTTON_CLASS3} text-red-700 hover:bg-red-50`;
|
|
1733
1946
|
function ServicesArea() {
|
|
1734
1947
|
const { locale } = useSchedulingConfig();
|
|
1735
1948
|
const messages = resolveSchedulingMessages(locale);
|
|
1736
|
-
const { data, isLoading, isError } = useServices();
|
|
1949
|
+
const { data, isLoading, isError } = useServices({ pageSize: MAX_PAGE_SIZE5 });
|
|
1737
1950
|
const createService = useCreateService();
|
|
1738
1951
|
const updateService = useUpdateService();
|
|
1739
1952
|
const deleteService = useDeleteService();
|
|
@@ -1751,21 +1964,21 @@ function ServicesArea() {
|
|
|
1751
1964
|
} catch {
|
|
1752
1965
|
}
|
|
1753
1966
|
}
|
|
1754
|
-
return /* @__PURE__ */
|
|
1755
|
-
/* @__PURE__ */
|
|
1756
|
-
/* @__PURE__ */
|
|
1967
|
+
return /* @__PURE__ */ jsxs17("div", { className: "flex flex-1 min-h-0 min-w-0 flex-col p-4 space-y-4", children: [
|
|
1968
|
+
/* @__PURE__ */ jsx18("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxs17("button", { type: "button", onClick: () => setDraft(null), className: `${BUTTON_PRIMARY4} ml-auto`, children: [
|
|
1969
|
+
/* @__PURE__ */ jsx18(Plus4, { "aria-hidden": "true", className: "w-4 h-4" }),
|
|
1757
1970
|
messages["service.newService"]
|
|
1758
1971
|
] }) }),
|
|
1759
|
-
isError && /* @__PURE__ */
|
|
1760
|
-
(createService.isError || updateService.isError || deleteService.isError) && /* @__PURE__ */
|
|
1761
|
-
isLoading ? /* @__PURE__ */
|
|
1762
|
-
isDraftOpen && /* @__PURE__ */
|
|
1972
|
+
isError && /* @__PURE__ */ jsx18("p", { role: "alert", className: "text-sm text-red-700 bg-red-50 rounded-lg px-3 py-2", children: messages["common.loadFailure"] }),
|
|
1973
|
+
(createService.isError || updateService.isError || deleteService.isError) && /* @__PURE__ */ jsx18("p", { role: "alert", className: "text-sm text-red-700 bg-red-50 rounded-lg px-3 py-2", children: messages["common.actionFailure"] }),
|
|
1974
|
+
isLoading ? /* @__PURE__ */ jsx18("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.loading"] }) : /* @__PURE__ */ jsx18(ServiceList, { services: data?.data ?? [], onSelect: setDraft }),
|
|
1975
|
+
isDraftOpen && /* @__PURE__ */ jsx18(
|
|
1763
1976
|
SidePanel,
|
|
1764
1977
|
{
|
|
1765
1978
|
title: isEditing ? messages["service.editTitle"] : messages["service.createTitle"],
|
|
1766
1979
|
closeLabel: messages["common.close"],
|
|
1767
1980
|
onClose: () => setDraft(void 0),
|
|
1768
|
-
headerActions: isEditing ? /* @__PURE__ */
|
|
1981
|
+
headerActions: isEditing ? /* @__PURE__ */ jsxs17(
|
|
1769
1982
|
"button",
|
|
1770
1983
|
{
|
|
1771
1984
|
type: "button",
|
|
@@ -1775,12 +1988,12 @@ function ServicesArea() {
|
|
|
1775
1988
|
},
|
|
1776
1989
|
className: BUTTON_DANGER2,
|
|
1777
1990
|
children: [
|
|
1778
|
-
/* @__PURE__ */
|
|
1991
|
+
/* @__PURE__ */ jsx18(Trash24, { "aria-hidden": "true", className: "w-4 h-4" }),
|
|
1779
1992
|
messages["common.remove"]
|
|
1780
1993
|
]
|
|
1781
1994
|
}
|
|
1782
1995
|
) : void 0,
|
|
1783
|
-
children: /* @__PURE__ */
|
|
1996
|
+
children: /* @__PURE__ */ jsx18(
|
|
1784
1997
|
ServiceForm,
|
|
1785
1998
|
{
|
|
1786
1999
|
...draft ? { initialValues: draft } : {},
|
|
@@ -1810,7 +2023,7 @@ function isSchedulingWorkspaceArea(value) {
|
|
|
1810
2023
|
}
|
|
1811
2024
|
|
|
1812
2025
|
// src/workspace/WorkspaceAreaNav.tsx
|
|
1813
|
-
import { jsx as
|
|
2026
|
+
import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1814
2027
|
var ITEM_BASE = "flex items-center gap-2 px-3 py-2 -mb-px border-b-2 text-sm font-medium transition-colors min-h-11";
|
|
1815
2028
|
var ITEM_ACTIVE = "border-brand-600 text-brand-700 dark:text-brand-400";
|
|
1816
2029
|
var ITEM_IDLE = "border-transparent text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100";
|
|
@@ -1829,9 +2042,9 @@ function WorkspaceAreaNav({ area, labels, onSelect }) {
|
|
|
1829
2042
|
[SCHEDULING_WORKSPACE_AREA.SERVICES, labels.servicesTab],
|
|
1830
2043
|
[SCHEDULING_WORKSPACE_AREA.AVAILABILITY, labels.availabilityTab]
|
|
1831
2044
|
];
|
|
1832
|
-
return /* @__PURE__ */
|
|
2045
|
+
return /* @__PURE__ */ jsx19("nav", { "aria-label": labels.areaNav, className: "flex gap-1 px-4 border-b border-gray-200 dark:border-gray-700 overflow-x-auto", children: items.map(([value, label]) => {
|
|
1833
2046
|
const Icon = AREA_ICON[value];
|
|
1834
|
-
return /* @__PURE__ */
|
|
2047
|
+
return /* @__PURE__ */ jsxs18(
|
|
1835
2048
|
"button",
|
|
1836
2049
|
{
|
|
1837
2050
|
type: "button",
|
|
@@ -1839,7 +2052,7 @@ function WorkspaceAreaNav({ area, labels, onSelect }) {
|
|
|
1839
2052
|
"aria-current": value === area ? "page" : void 0,
|
|
1840
2053
|
className: `${ITEM_BASE} ${value === area ? ITEM_ACTIVE : ITEM_IDLE} whitespace-nowrap`,
|
|
1841
2054
|
children: [
|
|
1842
|
-
/* @__PURE__ */
|
|
2055
|
+
/* @__PURE__ */ jsx19(Icon, { "aria-hidden": "true", className: "w-4 h-4 shrink-0" }),
|
|
1843
2056
|
label
|
|
1844
2057
|
]
|
|
1845
2058
|
},
|
|
@@ -1849,7 +2062,7 @@ function WorkspaceAreaNav({ area, labels, onSelect }) {
|
|
|
1849
2062
|
}
|
|
1850
2063
|
|
|
1851
2064
|
// src/workspace/SchedulingWorkspace.tsx
|
|
1852
|
-
import { jsx as
|
|
2065
|
+
import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1853
2066
|
var AREA_COMPONENT = {
|
|
1854
2067
|
[SCHEDULING_WORKSPACE_AREA.AGENDA]: AgendaArea,
|
|
1855
2068
|
[SCHEDULING_WORKSPACE_AREA.BOOKINGS]: BookingsArea,
|
|
@@ -1871,13 +2084,13 @@ function SchedulingWorkspace({
|
|
|
1871
2084
|
setInternalArea(next);
|
|
1872
2085
|
onAreaChange?.(next);
|
|
1873
2086
|
}
|
|
1874
|
-
return /* @__PURE__ */
|
|
1875
|
-
/* @__PURE__ */
|
|
1876
|
-
/* @__PURE__ */
|
|
2087
|
+
return /* @__PURE__ */ jsxs19("div", { className: "flex flex-col h-full", children: [
|
|
2088
|
+
/* @__PURE__ */ jsxs19("header", { className: "flex flex-wrap items-center gap-3 px-4 py-3", children: [
|
|
2089
|
+
/* @__PURE__ */ jsx20("h1", { className: "text-lg font-semibold text-gray-900 dark:text-gray-100 mr-auto", children: labels.title }),
|
|
1877
2090
|
renderHeaderActions?.()
|
|
1878
2091
|
] }),
|
|
1879
|
-
/* @__PURE__ */
|
|
1880
|
-
/* @__PURE__ */
|
|
2092
|
+
/* @__PURE__ */ jsx20(WorkspaceAreaNav, { area, labels, onSelect: handleSelectArea }),
|
|
2093
|
+
/* @__PURE__ */ jsx20("div", { className: "relative flex flex-1 min-h-0 overflow-hidden", children: /* @__PURE__ */ jsx20(AreaComponent, {}) })
|
|
1881
2094
|
] });
|
|
1882
2095
|
}
|
|
1883
2096
|
export {
|