@adatechnology/scheduling-ui 0.1.0-rc.1 → 0.1.0-rc.3
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 +436 -222
- 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,175 @@ 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
|
|
837
|
-
const [
|
|
1011
|
+
const emptyValue = () => formatDateTimeLocalInTimeZone(/* @__PURE__ */ new Date(), timezone);
|
|
1012
|
+
const [from, setFrom] = useState3(emptyValue);
|
|
1013
|
+
const [until, setUntil] = useState3(emptyValue);
|
|
838
1014
|
const [kind, setKind] = useState3(AVAILABILITY_EXCEPTION_KIND.BLOCK);
|
|
839
1015
|
const [reason, setReason] = useState3("");
|
|
840
1016
|
async function handleAdd() {
|
|
@@ -842,23 +1018,26 @@ function AvailabilityExceptionsEditor({ resourceId }) {
|
|
|
842
1018
|
try {
|
|
843
1019
|
await addException.mutateAsync({
|
|
844
1020
|
resourceId,
|
|
845
|
-
during: {
|
|
1021
|
+
during: {
|
|
1022
|
+
start: parseDateTimeLocalInTimeZone(from, timezone),
|
|
1023
|
+
end: parseDateTimeLocalInTimeZone(until, timezone)
|
|
1024
|
+
},
|
|
846
1025
|
kind,
|
|
847
1026
|
...reason ? { reason } : {}
|
|
848
1027
|
});
|
|
849
|
-
setFrom(
|
|
850
|
-
setUntil(
|
|
1028
|
+
setFrom(emptyValue());
|
|
1029
|
+
setUntil(emptyValue());
|
|
851
1030
|
setReason("");
|
|
852
1031
|
} catch {
|
|
853
1032
|
}
|
|
854
1033
|
}
|
|
855
|
-
return /* @__PURE__ */
|
|
856
|
-
/* @__PURE__ */
|
|
857
|
-
(addException.isError || removeException.isError) && /* @__PURE__ */
|
|
858
|
-
isLoadError && /* @__PURE__ */
|
|
859
|
-
isLoading && /* @__PURE__ */
|
|
860
|
-
/* @__PURE__ */
|
|
861
|
-
/* @__PURE__ */
|
|
1034
|
+
return /* @__PURE__ */ jsxs5("section", { className: "space-y-3", children: [
|
|
1035
|
+
/* @__PURE__ */ jsx6("h3", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: messages["availability.exceptionsTitle"] }),
|
|
1036
|
+
(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"] }),
|
|
1037
|
+
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"] }),
|
|
1038
|
+
isLoading && /* @__PURE__ */ jsx6("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.loading"] }),
|
|
1039
|
+
/* @__PURE__ */ jsx6("ul", { className: "space-y-2", children: (data ?? []).map((exception) => /* @__PURE__ */ jsxs5("li", { className: "flex items-center gap-2 text-sm", children: [
|
|
1040
|
+
/* @__PURE__ */ jsxs5("span", { className: "flex-1", children: [
|
|
862
1041
|
messages[`availability.exceptionKind.${exception.kind === "block" ? "blocked" : "extra"}`],
|
|
863
1042
|
" \u2014",
|
|
864
1043
|
" ",
|
|
@@ -867,39 +1046,35 @@ function AvailabilityExceptionsEditor({ resourceId }) {
|
|
|
867
1046
|
exception.during.end.toLocaleString(locale),
|
|
868
1047
|
exception.reason ? ` (${exception.reason})` : ""
|
|
869
1048
|
] }),
|
|
870
|
-
/* @__PURE__ */
|
|
1049
|
+
/* @__PURE__ */ jsx6(
|
|
871
1050
|
"button",
|
|
872
1051
|
{
|
|
873
1052
|
type: "button",
|
|
874
1053
|
onClick: () => removeException.mutate({ id: exception.id, resourceId }),
|
|
875
1054
|
"aria-label": messages["availability.removeException"],
|
|
876
1055
|
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__ */
|
|
1056
|
+
children: /* @__PURE__ */ jsx6(Trash22, { "aria-hidden": "true", className: "w-4 h-4" })
|
|
878
1057
|
}
|
|
879
1058
|
)
|
|
880
1059
|
] }, exception.id)) }),
|
|
881
|
-
/* @__PURE__ */
|
|
882
|
-
/* @__PURE__ */
|
|
883
|
-
|
|
1060
|
+
/* @__PURE__ */ jsxs5("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
1061
|
+
/* @__PURE__ */ jsx6(
|
|
1062
|
+
DateTimeField,
|
|
884
1063
|
{
|
|
885
|
-
|
|
886
|
-
type: "datetime-local",
|
|
1064
|
+
label: messages["availability.exceptionFrom"],
|
|
887
1065
|
value: from,
|
|
888
|
-
onChange:
|
|
889
|
-
className: SELECT_CLASS
|
|
1066
|
+
onChange: setFrom
|
|
890
1067
|
}
|
|
891
1068
|
),
|
|
892
|
-
/* @__PURE__ */
|
|
893
|
-
|
|
1069
|
+
/* @__PURE__ */ jsx6(
|
|
1070
|
+
DateTimeField,
|
|
894
1071
|
{
|
|
895
|
-
|
|
896
|
-
type: "datetime-local",
|
|
1072
|
+
label: messages["availability.exceptionUntil"],
|
|
897
1073
|
value: until,
|
|
898
|
-
onChange:
|
|
899
|
-
className: SELECT_CLASS
|
|
1074
|
+
onChange: setUntil
|
|
900
1075
|
}
|
|
901
1076
|
),
|
|
902
|
-
/* @__PURE__ */
|
|
1077
|
+
/* @__PURE__ */ jsxs5(
|
|
903
1078
|
"select",
|
|
904
1079
|
{
|
|
905
1080
|
"aria-label": messages["availability.exceptionKind.blocked"],
|
|
@@ -907,12 +1082,12 @@ function AvailabilityExceptionsEditor({ resourceId }) {
|
|
|
907
1082
|
onChange: (event) => setKind(event.target.value),
|
|
908
1083
|
className: SELECT_CLASS,
|
|
909
1084
|
children: [
|
|
910
|
-
/* @__PURE__ */
|
|
911
|
-
/* @__PURE__ */
|
|
1085
|
+
/* @__PURE__ */ jsx6("option", { value: AVAILABILITY_EXCEPTION_KIND.BLOCK, children: messages["availability.exceptionKind.blocked"] }),
|
|
1086
|
+
/* @__PURE__ */ jsx6("option", { value: AVAILABILITY_EXCEPTION_KIND.EXTRA, children: messages["availability.exceptionKind.extra"] })
|
|
912
1087
|
]
|
|
913
1088
|
}
|
|
914
1089
|
),
|
|
915
|
-
/* @__PURE__ */
|
|
1090
|
+
/* @__PURE__ */ jsx6(
|
|
916
1091
|
"input",
|
|
917
1092
|
{
|
|
918
1093
|
"aria-label": messages["availability.exceptionReason"],
|
|
@@ -923,7 +1098,7 @@ function AvailabilityExceptionsEditor({ resourceId }) {
|
|
|
923
1098
|
className: SELECT_CLASS
|
|
924
1099
|
}
|
|
925
1100
|
),
|
|
926
|
-
/* @__PURE__ */
|
|
1101
|
+
/* @__PURE__ */ jsxs5(
|
|
927
1102
|
"button",
|
|
928
1103
|
{
|
|
929
1104
|
type: "button",
|
|
@@ -931,7 +1106,7 @@ function AvailabilityExceptionsEditor({ resourceId }) {
|
|
|
931
1106
|
disabled: addException.isPending,
|
|
932
1107
|
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
1108
|
children: [
|
|
934
|
-
/* @__PURE__ */
|
|
1109
|
+
/* @__PURE__ */ jsx6(Plus2, { "aria-hidden": "true", className: "w-4 h-4" }),
|
|
935
1110
|
messages["availability.addException"]
|
|
936
1111
|
]
|
|
937
1112
|
}
|
|
@@ -941,25 +1116,25 @@ function AvailabilityExceptionsEditor({ resourceId }) {
|
|
|
941
1116
|
}
|
|
942
1117
|
|
|
943
1118
|
// src/components/AvailabilityEditor.tsx
|
|
944
|
-
import { jsx as
|
|
1119
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
945
1120
|
function AvailabilityEditor({ resourceId, timezone }) {
|
|
946
1121
|
const { locale } = useSchedulingConfig();
|
|
947
1122
|
const messages = resolveSchedulingMessages(locale);
|
|
948
|
-
return /* @__PURE__ */
|
|
949
|
-
/* @__PURE__ */
|
|
950
|
-
/* @__PURE__ */
|
|
1123
|
+
return /* @__PURE__ */ jsxs6("div", { className: "space-y-6", children: [
|
|
1124
|
+
/* @__PURE__ */ jsxs6("p", { className: "inline-flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400", children: [
|
|
1125
|
+
/* @__PURE__ */ jsxs6("span", { className: "font-medium", children: [
|
|
951
1126
|
messages["availability.resourceTimezone"],
|
|
952
1127
|
":"
|
|
953
1128
|
] }),
|
|
954
1129
|
timezone
|
|
955
1130
|
] }),
|
|
956
|
-
/* @__PURE__ */
|
|
957
|
-
/* @__PURE__ */
|
|
1131
|
+
/* @__PURE__ */ jsx7(WeeklyRulesEditor, { resourceId }),
|
|
1132
|
+
/* @__PURE__ */ jsx7(AvailabilityExceptionsEditor, { resourceId, timezone })
|
|
958
1133
|
] });
|
|
959
1134
|
}
|
|
960
1135
|
|
|
961
1136
|
// src/workspace/AvailabilityArea.tsx
|
|
962
|
-
import { jsx as
|
|
1137
|
+
import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
963
1138
|
function AvailabilityArea() {
|
|
964
1139
|
const { locale } = useSchedulingConfig();
|
|
965
1140
|
const messages = resolveSchedulingMessages(locale);
|
|
@@ -967,25 +1142,25 @@ function AvailabilityArea() {
|
|
|
967
1142
|
const [resourceId, setResourceId] = useState4("");
|
|
968
1143
|
const resources = data?.data ?? [];
|
|
969
1144
|
const selectedResource = resources.find((resource) => resource.id === resourceId);
|
|
970
|
-
return /* @__PURE__ */
|
|
971
|
-
/* @__PURE__ */
|
|
972
|
-
/* @__PURE__ */
|
|
973
|
-
/* @__PURE__ */
|
|
1145
|
+
return /* @__PURE__ */ jsxs7("div", { className: "flex flex-1 min-h-0 min-w-0 flex-col p-4 space-y-4", children: [
|
|
1146
|
+
/* @__PURE__ */ jsxs7("label", { className: "flex items-center gap-2 text-sm", children: [
|
|
1147
|
+
/* @__PURE__ */ jsx8("span", { className: "font-medium text-gray-700 dark:text-gray-300", children: messages["agenda.resourceLabel"] }),
|
|
1148
|
+
/* @__PURE__ */ jsxs7(
|
|
974
1149
|
"select",
|
|
975
1150
|
{
|
|
976
1151
|
value: resourceId,
|
|
977
1152
|
onChange: (event) => setResourceId(event.target.value),
|
|
978
1153
|
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
1154
|
children: [
|
|
980
|
-
/* @__PURE__ */
|
|
981
|
-
resources.map((resource) => /* @__PURE__ */
|
|
1155
|
+
/* @__PURE__ */ jsx8("option", { value: "", children: "\u2014" }),
|
|
1156
|
+
resources.map((resource) => /* @__PURE__ */ jsx8("option", { value: resource.id, children: resource.name }, resource.id))
|
|
982
1157
|
]
|
|
983
1158
|
}
|
|
984
1159
|
)
|
|
985
1160
|
] }),
|
|
986
|
-
isError && /* @__PURE__ */
|
|
987
|
-
isLoading && /* @__PURE__ */
|
|
988
|
-
selectedResource && /* @__PURE__ */
|
|
1161
|
+
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"] }),
|
|
1162
|
+
isLoading && /* @__PURE__ */ jsx8("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.loading"] }),
|
|
1163
|
+
selectedResource && /* @__PURE__ */ jsx8(
|
|
989
1164
|
AvailabilityEditor,
|
|
990
1165
|
{
|
|
991
1166
|
resourceId: selectedResource.id,
|
|
@@ -998,6 +1173,7 @@ function AvailabilityArea() {
|
|
|
998
1173
|
|
|
999
1174
|
// src/workspace/BookingsArea.tsx
|
|
1000
1175
|
import { useState as useState8 } from "react";
|
|
1176
|
+
import { MAX_PAGE_SIZE as MAX_PAGE_SIZE3 } from "@adatechnology/scheduling-contracts";
|
|
1001
1177
|
|
|
1002
1178
|
// src/components/BookingDrawer.tsx
|
|
1003
1179
|
import { XCircle } from "lucide-react";
|
|
@@ -1007,7 +1183,7 @@ import { BOOKING_STATUS } from "@adatechnology/scheduling-contracts";
|
|
|
1007
1183
|
// src/components/SidePanel.tsx
|
|
1008
1184
|
import { X } from "lucide-react";
|
|
1009
1185
|
import { useEffect } from "react";
|
|
1010
|
-
import { Fragment, jsx as
|
|
1186
|
+
import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1011
1187
|
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
1188
|
function SidePanel({ title, closeLabel, onClose, headerActions, children }) {
|
|
1013
1189
|
useEffect(() => {
|
|
@@ -1017,8 +1193,8 @@ function SidePanel({ title, closeLabel, onClose, headerActions, children }) {
|
|
|
1017
1193
|
window.addEventListener("keydown", handleKeyDown);
|
|
1018
1194
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
1019
1195
|
}, [onClose]);
|
|
1020
|
-
return /* @__PURE__ */
|
|
1021
|
-
/* @__PURE__ */
|
|
1196
|
+
return /* @__PURE__ */ jsxs8(Fragment2, { children: [
|
|
1197
|
+
/* @__PURE__ */ jsx9(
|
|
1022
1198
|
"button",
|
|
1023
1199
|
{
|
|
1024
1200
|
type: "button",
|
|
@@ -1028,29 +1204,29 @@ function SidePanel({ title, closeLabel, onClose, headerActions, children }) {
|
|
|
1028
1204
|
className: "absolute inset-0 z-10 bg-gray-900/20 wide:hidden"
|
|
1029
1205
|
}
|
|
1030
1206
|
),
|
|
1031
|
-
/* @__PURE__ */
|
|
1207
|
+
/* @__PURE__ */ jsxs8(
|
|
1032
1208
|
"section",
|
|
1033
1209
|
{
|
|
1034
1210
|
"aria-label": title,
|
|
1035
1211
|
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
1212
|
children: [
|
|
1037
|
-
/* @__PURE__ */
|
|
1038
|
-
/* @__PURE__ */
|
|
1213
|
+
/* @__PURE__ */ jsxs8("div", { className: "flex items-center gap-2 border-b border-gray-200 px-4 py-3 dark:border-gray-700", children: [
|
|
1214
|
+
/* @__PURE__ */ jsx9("h2", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100 mr-auto", children: title }),
|
|
1039
1215
|
headerActions,
|
|
1040
|
-
/* @__PURE__ */
|
|
1216
|
+
/* @__PURE__ */ jsxs8(
|
|
1041
1217
|
"button",
|
|
1042
1218
|
{
|
|
1043
1219
|
type: "button",
|
|
1044
1220
|
onClick: onClose,
|
|
1045
1221
|
className: `${BUTTON_CLASS} text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800`,
|
|
1046
1222
|
children: [
|
|
1047
|
-
/* @__PURE__ */
|
|
1223
|
+
/* @__PURE__ */ jsx9(X, { "aria-hidden": "true", className: "w-4 h-4" }),
|
|
1048
1224
|
closeLabel
|
|
1049
1225
|
]
|
|
1050
1226
|
}
|
|
1051
1227
|
)
|
|
1052
1228
|
] }),
|
|
1053
|
-
/* @__PURE__ */
|
|
1229
|
+
/* @__PURE__ */ jsx9("div", { className: "min-h-0 flex-1 overflow-y-auto p-4", children })
|
|
1054
1230
|
]
|
|
1055
1231
|
}
|
|
1056
1232
|
)
|
|
@@ -1058,16 +1234,13 @@ function SidePanel({ title, closeLabel, onClose, headerActions, children }) {
|
|
|
1058
1234
|
}
|
|
1059
1235
|
|
|
1060
1236
|
// src/components/BookingDrawer.tsx
|
|
1061
|
-
import { Fragment as
|
|
1237
|
+
import { Fragment as Fragment3, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1238
|
+
var BROWSER_TIME_ZONE = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
1062
1239
|
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
1240
|
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
1241
|
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
1242
|
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 }) {
|
|
1243
|
+
function BookingDrawer({ booking, resourceTimezone, onClose }) {
|
|
1071
1244
|
const { locale } = useSchedulingConfig();
|
|
1072
1245
|
const messages = resolveSchedulingMessages(locale);
|
|
1073
1246
|
const confirmBooking = useConfirmBooking();
|
|
@@ -1075,12 +1248,13 @@ function BookingDrawer({ booking, onClose }) {
|
|
|
1075
1248
|
const markNoShow = useMarkNoShow();
|
|
1076
1249
|
const cancelBooking = useCancelBooking();
|
|
1077
1250
|
const rescheduleBooking = useRescheduleBooking();
|
|
1251
|
+
const timezone = resourceTimezone ?? BROWSER_TIME_ZONE;
|
|
1078
1252
|
const [isCancelling, setIsCancelling] = useState5(false);
|
|
1079
1253
|
const [cancelledBy, setCancelledBy] = useState5("");
|
|
1080
1254
|
const [cancellationReason, setCancellationReason] = useState5("");
|
|
1081
1255
|
const [isRescheduling, setIsRescheduling] = useState5(false);
|
|
1082
|
-
const [start, setStart] = useState5(() =>
|
|
1083
|
-
const [end, setEnd] = useState5(() =>
|
|
1256
|
+
const [start, setStart] = useState5(() => formatDateTimeLocalInTimeZone(booking.startsAt, timezone));
|
|
1257
|
+
const [end, setEnd] = useState5(() => formatDateTimeLocalInTimeZone(booking.endsAt, timezone));
|
|
1084
1258
|
async function handleCancel() {
|
|
1085
1259
|
if (!cancelledBy) return;
|
|
1086
1260
|
try {
|
|
@@ -1094,42 +1268,57 @@ function BookingDrawer({ booking, onClose }) {
|
|
|
1094
1268
|
}
|
|
1095
1269
|
async function handleReschedule() {
|
|
1096
1270
|
try {
|
|
1097
|
-
await rescheduleBooking.mutateAsync({
|
|
1271
|
+
await rescheduleBooking.mutateAsync({
|
|
1272
|
+
id: booking.id,
|
|
1273
|
+
input: {
|
|
1274
|
+
during: {
|
|
1275
|
+
start: parseDateTimeLocalInTimeZone(start, timezone),
|
|
1276
|
+
end: parseDateTimeLocalInTimeZone(end, timezone)
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
});
|
|
1098
1280
|
setIsRescheduling(false);
|
|
1099
1281
|
} catch {
|
|
1100
1282
|
}
|
|
1101
1283
|
}
|
|
1102
1284
|
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__ */
|
|
1285
|
+
return /* @__PURE__ */ jsx10(SidePanel, { title: messages["booking.detailTitle"], closeLabel: messages["common.close"], onClose, children: /* @__PURE__ */ jsxs9("div", { className: "space-y-4", children: [
|
|
1286
|
+
/* @__PURE__ */ jsxs9("div", { children: [
|
|
1287
|
+
/* @__PURE__ */ jsx10("p", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: booking.title }),
|
|
1288
|
+
/* @__PURE__ */ jsx10("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages[`booking.status.${booking.status === "no_show" ? "noShow" : booking.status}`] }),
|
|
1289
|
+
/* @__PURE__ */ jsxs9("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: [
|
|
1108
1290
|
booking.startsAt.toLocaleString(locale),
|
|
1109
1291
|
" \u2192 ",
|
|
1110
1292
|
booking.endsAt.toLocaleString(locale)
|
|
1111
1293
|
] })
|
|
1112
1294
|
] }),
|
|
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__ */
|
|
1295
|
+
(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"] }),
|
|
1296
|
+
!isTerminal && /* @__PURE__ */ jsxs9("div", { className: "flex flex-wrap gap-2", children: [
|
|
1297
|
+
booking.status === BOOKING_STATUS.REQUESTED && /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => confirmBooking.mutate(booking.id), className: PRIMARY_BUTTON_CLASS, children: messages["booking.confirm"] }),
|
|
1298
|
+
booking.status === BOOKING_STATUS.CONFIRMED && /* @__PURE__ */ jsxs9(Fragment3, { children: [
|
|
1299
|
+
/* @__PURE__ */ jsx10("button", { type: "button", onClick: () => completeBooking.mutate(booking.id), className: ACTION_BUTTON_CLASS, children: messages["booking.complete"] }),
|
|
1300
|
+
/* @__PURE__ */ jsx10("button", { type: "button", onClick: () => markNoShow.mutate(booking.id), className: ACTION_BUTTON_CLASS, children: messages["booking.markNoShow"] }),
|
|
1301
|
+
/* @__PURE__ */ jsx10("button", { type: "button", onClick: () => setIsRescheduling(true), className: ACTION_BUTTON_CLASS, children: messages["booking.reschedule"] })
|
|
1120
1302
|
] }),
|
|
1121
|
-
/* @__PURE__ */
|
|
1122
|
-
/* @__PURE__ */
|
|
1303
|
+
/* @__PURE__ */ jsxs9("button", { type: "button", onClick: () => setIsCancelling(true), className: DANGER_BUTTON_CLASS, children: [
|
|
1304
|
+
/* @__PURE__ */ jsx10(XCircle, { "aria-hidden": "true", className: "w-4 h-4" }),
|
|
1123
1305
|
messages["booking.cancel"]
|
|
1124
1306
|
] })
|
|
1125
1307
|
] }),
|
|
1126
|
-
isRescheduling && /* @__PURE__ */
|
|
1127
|
-
/* @__PURE__ */
|
|
1128
|
-
|
|
1129
|
-
|
|
1308
|
+
isRescheduling && /* @__PURE__ */ jsxs9("div", { className: "space-y-2 rounded-lg border border-gray-200 dark:border-gray-700 p-3", children: [
|
|
1309
|
+
/* @__PURE__ */ jsx10(
|
|
1310
|
+
DateTimeField,
|
|
1311
|
+
{
|
|
1312
|
+
label: messages["booking.rescheduleStart"],
|
|
1313
|
+
value: start,
|
|
1314
|
+
onChange: setStart
|
|
1315
|
+
}
|
|
1316
|
+
),
|
|
1317
|
+
/* @__PURE__ */ jsx10(DateTimeField, { label: messages["booking.rescheduleEnd"], value: end, onChange: setEnd }),
|
|
1318
|
+
/* @__PURE__ */ jsx10("button", { type: "button", onClick: handleReschedule, disabled: rescheduleBooking.isPending, className: PRIMARY_BUTTON_CLASS, children: messages["common.save"] })
|
|
1130
1319
|
] }),
|
|
1131
|
-
isCancelling && /* @__PURE__ */
|
|
1132
|
-
/* @__PURE__ */
|
|
1320
|
+
isCancelling && /* @__PURE__ */ jsxs9("div", { className: "space-y-2 rounded-lg border border-gray-200 dark:border-gray-700 p-3", children: [
|
|
1321
|
+
/* @__PURE__ */ jsx10(
|
|
1133
1322
|
"input",
|
|
1134
1323
|
{
|
|
1135
1324
|
type: "text",
|
|
@@ -1139,7 +1328,7 @@ function BookingDrawer({ booking, onClose }) {
|
|
|
1139
1328
|
className: INPUT_CLASS
|
|
1140
1329
|
}
|
|
1141
1330
|
),
|
|
1142
|
-
/* @__PURE__ */
|
|
1331
|
+
/* @__PURE__ */ jsx10(
|
|
1143
1332
|
"input",
|
|
1144
1333
|
{
|
|
1145
1334
|
type: "text",
|
|
@@ -1149,8 +1338,8 @@ function BookingDrawer({ booking, onClose }) {
|
|
|
1149
1338
|
className: INPUT_CLASS
|
|
1150
1339
|
}
|
|
1151
1340
|
),
|
|
1152
|
-
/* @__PURE__ */
|
|
1153
|
-
/* @__PURE__ */
|
|
1341
|
+
/* @__PURE__ */ jsxs9("button", { type: "button", onClick: handleCancel, disabled: cancelBooking.isPending, className: DANGER_BUTTON_CLASS, children: [
|
|
1342
|
+
/* @__PURE__ */ jsx10(XCircle, { "aria-hidden": "true", className: "w-4 h-4" }),
|
|
1154
1343
|
messages["booking.cancel"]
|
|
1155
1344
|
] })
|
|
1156
1345
|
] })
|
|
@@ -1160,18 +1349,23 @@ function BookingDrawer({ booking, onClose }) {
|
|
|
1160
1349
|
// src/components/BookingsTable.tsx
|
|
1161
1350
|
import { ArrowDown, ArrowLeft, ArrowRight, ArrowUp, ArrowUpDown } from "lucide-react";
|
|
1162
1351
|
import { useState as useState6 } from "react";
|
|
1163
|
-
import { BOOKING_STATUS as
|
|
1352
|
+
import { BOOKING_STATUS as BOOKING_STATUS3 } from "@adatechnology/scheduling-contracts";
|
|
1164
1353
|
|
|
1165
1354
|
// src/components/bookingsTableState.util.ts
|
|
1355
|
+
import { BOOKING_STATUS as BOOKING_STATUS2 } from "@adatechnology/scheduling-contracts";
|
|
1166
1356
|
var DEFAULT_BOOKINGS_TABLE_STATE = {
|
|
1167
1357
|
sortDirection: "asc",
|
|
1168
1358
|
statusFilters: [],
|
|
1169
1359
|
page: 1
|
|
1170
1360
|
};
|
|
1171
1361
|
var SORT_COLUMNS = ["title", "status", "startsAt", "endsAt"];
|
|
1362
|
+
var BOOKING_STATUSES = Object.values(BOOKING_STATUS2);
|
|
1172
1363
|
function isBookingSortColumn(value) {
|
|
1173
1364
|
return SORT_COLUMNS.includes(value);
|
|
1174
1365
|
}
|
|
1366
|
+
function isBookingStatus(value) {
|
|
1367
|
+
return BOOKING_STATUSES.includes(value);
|
|
1368
|
+
}
|
|
1175
1369
|
function parsePage(value) {
|
|
1176
1370
|
const parsed = Number(value);
|
|
1177
1371
|
return Number.isInteger(parsed) && parsed > 0 ? parsed : 1;
|
|
@@ -1181,7 +1375,7 @@ function parseBookingsTableState(search) {
|
|
|
1181
1375
|
const sortColumnParam = params.get("sortBy");
|
|
1182
1376
|
const sortColumn = isBookingSortColumn(sortColumnParam) ? sortColumnParam : void 0;
|
|
1183
1377
|
const sortDirection = params.get("sortDirection") === "desc" ? "desc" : "asc";
|
|
1184
|
-
const statusFilters = params.getAll("status");
|
|
1378
|
+
const statusFilters = params.getAll("status").filter(isBookingStatus);
|
|
1185
1379
|
const page = parsePage(params.get("page"));
|
|
1186
1380
|
return { ...sortColumn ? { sortColumn } : {}, sortDirection, statusFilters, page };
|
|
1187
1381
|
}
|
|
@@ -1204,13 +1398,14 @@ function filterBookingsByStatus(bookings, statusFilters) {
|
|
|
1204
1398
|
}
|
|
1205
1399
|
|
|
1206
1400
|
// src/components/BookingsTable.tsx
|
|
1207
|
-
import { jsx as
|
|
1208
|
-
var ALL_STATUSES = Object.values(
|
|
1401
|
+
import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1402
|
+
var ALL_STATUSES = Object.values(BOOKING_STATUS3);
|
|
1209
1403
|
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
1404
|
var CHECKBOX_CELL_CLASS = "px-3 py-2";
|
|
1211
|
-
function
|
|
1212
|
-
if (currentColumn !== column) return "asc";
|
|
1213
|
-
|
|
1405
|
+
function nextSortState(column, currentColumn, currentDirection) {
|
|
1406
|
+
if (currentColumn !== column) return { sortColumn: column, sortDirection: "asc" };
|
|
1407
|
+
if (currentDirection === "asc") return { sortColumn: column, sortDirection: "desc" };
|
|
1408
|
+
return { sortColumn: void 0, sortDirection: "asc" };
|
|
1214
1409
|
}
|
|
1215
1410
|
function BookingsTable({
|
|
1216
1411
|
bookings,
|
|
@@ -1228,8 +1423,7 @@ function BookingsTable({
|
|
|
1228
1423
|
function toggleSort(column) {
|
|
1229
1424
|
onStateChange?.({
|
|
1230
1425
|
...state,
|
|
1231
|
-
sortColumn
|
|
1232
|
-
sortDirection: nextSortDirection(column, state.sortColumn, state.sortDirection)
|
|
1426
|
+
...nextSortState(column, state.sortColumn, state.sortDirection)
|
|
1233
1427
|
});
|
|
1234
1428
|
}
|
|
1235
1429
|
function toggleStatusFilter(status) {
|
|
@@ -1253,19 +1447,20 @@ function BookingsTable({
|
|
|
1253
1447
|
setSelected(next);
|
|
1254
1448
|
}
|
|
1255
1449
|
function renderSortIcon(column) {
|
|
1256
|
-
if (state.sortColumn !== column) return /* @__PURE__ */
|
|
1257
|
-
return state.sortDirection === "asc" ? /* @__PURE__ */
|
|
1450
|
+
if (state.sortColumn !== column) return /* @__PURE__ */ jsx11(ArrowUpDown, { "aria-hidden": "true", className: "w-3 h-3" });
|
|
1451
|
+
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
1452
|
}
|
|
1259
1453
|
function renderHeader(column, labelKey) {
|
|
1260
|
-
|
|
1454
|
+
const ariaSort = state.sortColumn !== column ? "none" : state.sortDirection === "asc" ? "ascending" : "descending";
|
|
1455
|
+
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
1456
|
messages[labelKey],
|
|
1262
1457
|
renderSortIcon(column)
|
|
1263
1458
|
] }) });
|
|
1264
1459
|
}
|
|
1265
|
-
return /* @__PURE__ */
|
|
1266
|
-
/* @__PURE__ */
|
|
1267
|
-
ALL_STATUSES.map((status) => /* @__PURE__ */
|
|
1268
|
-
/* @__PURE__ */
|
|
1460
|
+
return /* @__PURE__ */ jsxs10("div", { className: "space-y-3", children: [
|
|
1461
|
+
/* @__PURE__ */ jsxs10("div", { className: "flex flex-wrap items-center gap-3", children: [
|
|
1462
|
+
ALL_STATUSES.map((status) => /* @__PURE__ */ jsxs10("label", { className: "flex items-center gap-1.5 text-sm min-h-11", children: [
|
|
1463
|
+
/* @__PURE__ */ jsx11(
|
|
1269
1464
|
"input",
|
|
1270
1465
|
{
|
|
1271
1466
|
type: "checkbox",
|
|
@@ -1275,7 +1470,7 @@ function BookingsTable({
|
|
|
1275
1470
|
),
|
|
1276
1471
|
messages[`booking.status.${status === "no_show" ? "noShow" : status}`]
|
|
1277
1472
|
] }, status)),
|
|
1278
|
-
!isBookingsTableStateDefault(state) && /* @__PURE__ */
|
|
1473
|
+
!isBookingsTableStateDefault(state) && /* @__PURE__ */ jsx11(
|
|
1279
1474
|
"button",
|
|
1280
1475
|
{
|
|
1281
1476
|
type: "button",
|
|
@@ -1285,7 +1480,7 @@ function BookingsTable({
|
|
|
1285
1480
|
}
|
|
1286
1481
|
)
|
|
1287
1482
|
] }),
|
|
1288
|
-
selected.size > 0 && bulkActions.length > 0 && /* @__PURE__ */
|
|
1483
|
+
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
1484
|
"button",
|
|
1290
1485
|
{
|
|
1291
1486
|
type: "button",
|
|
@@ -1295,10 +1490,10 @@ function BookingsTable({
|
|
|
1295
1490
|
},
|
|
1296
1491
|
action.key
|
|
1297
1492
|
)) }),
|
|
1298
|
-
/* @__PURE__ */
|
|
1299
|
-
/* @__PURE__ */
|
|
1300
|
-
/* @__PURE__ */
|
|
1301
|
-
/* @__PURE__ */
|
|
1493
|
+
/* @__PURE__ */ jsxs10("div", { className: "overflow-x-auto rounded-lg border border-gray-200 dark:border-gray-700", children: [
|
|
1494
|
+
/* @__PURE__ */ jsxs10("table", { className: "min-w-full text-sm", children: [
|
|
1495
|
+
/* @__PURE__ */ jsx11("thead", { className: "border-b border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ jsxs10("tr", { children: [
|
|
1496
|
+
/* @__PURE__ */ jsx11("th", { scope: "col", className: CHECKBOX_CELL_CLASS, children: /* @__PURE__ */ jsx11(
|
|
1302
1497
|
"input",
|
|
1303
1498
|
{
|
|
1304
1499
|
type: "checkbox",
|
|
@@ -1312,12 +1507,12 @@ function BookingsTable({
|
|
|
1312
1507
|
renderHeader("startsAt", "booking.column.startsAt"),
|
|
1313
1508
|
renderHeader("endsAt", "booking.column.endsAt")
|
|
1314
1509
|
] }) }),
|
|
1315
|
-
/* @__PURE__ */
|
|
1510
|
+
/* @__PURE__ */ jsx11("tbody", { children: visibleBookings.map((booking, index) => /* @__PURE__ */ jsxs10(
|
|
1316
1511
|
"tr",
|
|
1317
1512
|
{
|
|
1318
1513
|
className: index % 2 === 1 ? "bg-gray-50 dark:bg-gray-800/50" : void 0,
|
|
1319
1514
|
children: [
|
|
1320
|
-
/* @__PURE__ */
|
|
1515
|
+
/* @__PURE__ */ jsx11("td", { className: CHECKBOX_CELL_CLASS, children: /* @__PURE__ */ jsx11(
|
|
1321
1516
|
"input",
|
|
1322
1517
|
{
|
|
1323
1518
|
type: "checkbox",
|
|
@@ -1326,19 +1521,19 @@ function BookingsTable({
|
|
|
1326
1521
|
onChange: () => toggleRowSelected(booking.id)
|
|
1327
1522
|
}
|
|
1328
1523
|
) }),
|
|
1329
|
-
/* @__PURE__ */
|
|
1330
|
-
/* @__PURE__ */
|
|
1331
|
-
/* @__PURE__ */
|
|
1332
|
-
/* @__PURE__ */
|
|
1524
|
+
/* @__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 }) }),
|
|
1525
|
+
/* @__PURE__ */ jsx11("td", { className: "px-3 py-2", children: messages[`booking.status.${booking.status === "no_show" ? "noShow" : booking.status}`] }),
|
|
1526
|
+
/* @__PURE__ */ jsx11("td", { className: "px-3 py-2", children: booking.startsAt.toLocaleString(locale) }),
|
|
1527
|
+
/* @__PURE__ */ jsx11("td", { className: "px-3 py-2", children: booking.endsAt.toLocaleString(locale) })
|
|
1333
1528
|
]
|
|
1334
1529
|
},
|
|
1335
1530
|
booking.id
|
|
1336
1531
|
)) })
|
|
1337
1532
|
] }),
|
|
1338
|
-
visibleBookings.length === 0 && /* @__PURE__ */
|
|
1533
|
+
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
1534
|
] }),
|
|
1340
|
-
pagination && pagination.totalPages > 1 && /* @__PURE__ */
|
|
1341
|
-
/* @__PURE__ */
|
|
1535
|
+
pagination && pagination.totalPages > 1 && /* @__PURE__ */ jsxs10("div", { className: "flex items-center justify-end gap-3", children: [
|
|
1536
|
+
/* @__PURE__ */ jsx11(
|
|
1342
1537
|
"button",
|
|
1343
1538
|
{
|
|
1344
1539
|
type: "button",
|
|
@@ -1346,15 +1541,15 @@ function BookingsTable({
|
|
|
1346
1541
|
disabled: state.page <= 1,
|
|
1347
1542
|
onClick: () => goToPage(state.page - 1),
|
|
1348
1543
|
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__ */
|
|
1544
|
+
children: /* @__PURE__ */ jsx11(ArrowLeft, { "aria-hidden": "true", className: "w-4 h-4" })
|
|
1350
1545
|
}
|
|
1351
1546
|
),
|
|
1352
|
-
/* @__PURE__ */
|
|
1547
|
+
/* @__PURE__ */ jsxs10("span", { className: "text-sm text-gray-500 dark:text-gray-400", children: [
|
|
1353
1548
|
state.page,
|
|
1354
1549
|
" / ",
|
|
1355
1550
|
pagination.totalPages
|
|
1356
1551
|
] }),
|
|
1357
|
-
/* @__PURE__ */
|
|
1552
|
+
/* @__PURE__ */ jsx11(
|
|
1358
1553
|
"button",
|
|
1359
1554
|
{
|
|
1360
1555
|
type: "button",
|
|
@@ -1362,7 +1557,7 @@ function BookingsTable({
|
|
|
1362
1557
|
disabled: state.page >= pagination.totalPages,
|
|
1363
1558
|
onClick: () => goToPage(state.page + 1),
|
|
1364
1559
|
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__ */
|
|
1560
|
+
children: /* @__PURE__ */ jsx11(ArrowRight, { "aria-hidden": "true", className: "w-4 h-4" })
|
|
1366
1561
|
}
|
|
1367
1562
|
)
|
|
1368
1563
|
] })
|
|
@@ -1391,7 +1586,7 @@ function useBookingsTableState() {
|
|
|
1391
1586
|
}
|
|
1392
1587
|
|
|
1393
1588
|
// src/workspace/BookingsArea.tsx
|
|
1394
|
-
import { jsx as
|
|
1589
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1395
1590
|
var PAGE_SIZE = 20;
|
|
1396
1591
|
function BookingsArea() {
|
|
1397
1592
|
const { locale } = useSchedulingConfig();
|
|
@@ -1406,14 +1601,19 @@ function BookingsArea() {
|
|
|
1406
1601
|
sortDirection: tableState.sortColumn ? tableState.sortDirection : void 0
|
|
1407
1602
|
});
|
|
1408
1603
|
const confirmBooking = useConfirmBooking();
|
|
1604
|
+
const { data: resourcesData } = useResources({ pageSize: MAX_PAGE_SIZE3 });
|
|
1409
1605
|
const [selectedBookingId, setSelectedBookingId] = useState8(void 0);
|
|
1410
1606
|
const selectedBooking = data?.data.find((booking) => booking.id === selectedBookingId);
|
|
1607
|
+
const selectedBookingResourceTimezone = resourcesData?.data.find(
|
|
1608
|
+
(resource) => resource.id === selectedBooking?.resourceIds[0]
|
|
1609
|
+
)?.timezone;
|
|
1411
1610
|
function bulkConfirm(ids) {
|
|
1412
1611
|
for (const id of ids) confirmBooking.mutate(id);
|
|
1413
1612
|
}
|
|
1414
|
-
return /* @__PURE__ */
|
|
1415
|
-
isError && /* @__PURE__ */
|
|
1416
|
-
|
|
1613
|
+
return /* @__PURE__ */ jsxs11("div", { className: "flex flex-1 min-h-0 min-w-0 flex-col p-4 space-y-4", children: [
|
|
1614
|
+
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"] }),
|
|
1615
|
+
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"] }),
|
|
1616
|
+
isLoading ? /* @__PURE__ */ jsx12("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.loading"] }) : /* @__PURE__ */ jsx12(
|
|
1417
1617
|
BookingsTable,
|
|
1418
1618
|
{
|
|
1419
1619
|
bookings: data?.data ?? [],
|
|
@@ -1424,24 +1624,37 @@ function BookingsArea() {
|
|
|
1424
1624
|
bulkActions: [{ key: "confirm", label: messages["booking.confirm"], onRun: bulkConfirm }]
|
|
1425
1625
|
}
|
|
1426
1626
|
),
|
|
1427
|
-
selectedBooking && /* @__PURE__ */
|
|
1627
|
+
selectedBooking && /* @__PURE__ */ jsx12(
|
|
1628
|
+
BookingDrawer,
|
|
1629
|
+
{
|
|
1630
|
+
booking: selectedBooking,
|
|
1631
|
+
resourceTimezone: selectedBookingResourceTimezone,
|
|
1632
|
+
onClose: () => setSelectedBookingId(void 0)
|
|
1633
|
+
},
|
|
1634
|
+
selectedBooking.id
|
|
1635
|
+
)
|
|
1428
1636
|
] });
|
|
1429
1637
|
}
|
|
1430
1638
|
|
|
1431
1639
|
// src/workspace/ResourcesArea.tsx
|
|
1432
1640
|
import { Plus as Plus3, Trash2 as Trash23 } from "lucide-react";
|
|
1433
1641
|
import { useState as useState10 } from "react";
|
|
1642
|
+
import { MAX_PAGE_SIZE as MAX_PAGE_SIZE4 } from "@adatechnology/scheduling-contracts";
|
|
1434
1643
|
|
|
1435
1644
|
// src/components/ResourceForm.tsx
|
|
1436
|
-
import { useState as useState9 } from "react";
|
|
1645
|
+
import { useId as useId2, useState as useState9 } from "react";
|
|
1437
1646
|
import { RESOURCE_KIND } from "@adatechnology/scheduling-contracts";
|
|
1438
|
-
import { jsx as
|
|
1647
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
1439
1648
|
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
1649
|
var LABEL_CLASS = "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1";
|
|
1441
1650
|
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
1651
|
function ResourceForm({ initialValues, onSubmit }) {
|
|
1443
1652
|
const { locale } = useSchedulingConfig();
|
|
1444
1653
|
const messages = resolveSchedulingMessages(locale);
|
|
1654
|
+
const formId = useId2();
|
|
1655
|
+
const nameId = `${formId}-name`;
|
|
1656
|
+
const kindId = `${formId}-kind`;
|
|
1657
|
+
const timezoneId = `${formId}-timezone`;
|
|
1445
1658
|
const [name, setName] = useState9(initialValues?.name ?? "");
|
|
1446
1659
|
const [kind, setKind] = useState9(initialValues?.kind ?? RESOURCE_KIND.PERSON);
|
|
1447
1660
|
const [timezone, setTimezone] = useState9(initialValues?.timezone ?? "America/Sao_Paulo");
|
|
@@ -1456,13 +1669,13 @@ function ResourceForm({ initialValues, onSubmit }) {
|
|
|
1456
1669
|
setSubmitting(false);
|
|
1457
1670
|
}
|
|
1458
1671
|
}
|
|
1459
|
-
return /* @__PURE__ */
|
|
1460
|
-
/* @__PURE__ */
|
|
1461
|
-
/* @__PURE__ */
|
|
1462
|
-
/* @__PURE__ */
|
|
1672
|
+
return /* @__PURE__ */ jsxs12("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
|
|
1673
|
+
/* @__PURE__ */ jsxs12("div", { children: [
|
|
1674
|
+
/* @__PURE__ */ jsx13("label", { htmlFor: nameId, className: LABEL_CLASS, children: messages["resource.name"] }),
|
|
1675
|
+
/* @__PURE__ */ jsx13(
|
|
1463
1676
|
"input",
|
|
1464
1677
|
{
|
|
1465
|
-
id:
|
|
1678
|
+
id: nameId,
|
|
1466
1679
|
type: "text",
|
|
1467
1680
|
required: true,
|
|
1468
1681
|
value: name,
|
|
@@ -1471,29 +1684,29 @@ function ResourceForm({ initialValues, onSubmit }) {
|
|
|
1471
1684
|
}
|
|
1472
1685
|
)
|
|
1473
1686
|
] }),
|
|
1474
|
-
/* @__PURE__ */
|
|
1475
|
-
/* @__PURE__ */
|
|
1476
|
-
/* @__PURE__ */
|
|
1687
|
+
/* @__PURE__ */ jsxs12("div", { children: [
|
|
1688
|
+
/* @__PURE__ */ jsx13("label", { htmlFor: kindId, className: LABEL_CLASS, children: messages["resource.kind"] }),
|
|
1689
|
+
/* @__PURE__ */ jsxs12(
|
|
1477
1690
|
"select",
|
|
1478
1691
|
{
|
|
1479
|
-
id:
|
|
1692
|
+
id: kindId,
|
|
1480
1693
|
value: kind,
|
|
1481
1694
|
onChange: (event) => setKind(event.target.value),
|
|
1482
1695
|
className: INPUT_CLASS2,
|
|
1483
1696
|
children: [
|
|
1484
|
-
/* @__PURE__ */
|
|
1485
|
-
/* @__PURE__ */
|
|
1486
|
-
/* @__PURE__ */
|
|
1697
|
+
/* @__PURE__ */ jsx13("option", { value: RESOURCE_KIND.PERSON, children: messages["resource.kind.person"] }),
|
|
1698
|
+
/* @__PURE__ */ jsx13("option", { value: RESOURCE_KIND.ROOM, children: messages["resource.kind.room"] }),
|
|
1699
|
+
/* @__PURE__ */ jsx13("option", { value: RESOURCE_KIND.EQUIPMENT, children: messages["resource.kind.equipment"] })
|
|
1487
1700
|
]
|
|
1488
1701
|
}
|
|
1489
1702
|
)
|
|
1490
1703
|
] }),
|
|
1491
|
-
/* @__PURE__ */
|
|
1492
|
-
/* @__PURE__ */
|
|
1493
|
-
/* @__PURE__ */
|
|
1704
|
+
/* @__PURE__ */ jsxs12("div", { children: [
|
|
1705
|
+
/* @__PURE__ */ jsx13("label", { htmlFor: timezoneId, className: LABEL_CLASS, children: messages["resource.timezone"] }),
|
|
1706
|
+
/* @__PURE__ */ jsx13(
|
|
1494
1707
|
"input",
|
|
1495
1708
|
{
|
|
1496
|
-
id:
|
|
1709
|
+
id: timezoneId,
|
|
1497
1710
|
type: "text",
|
|
1498
1711
|
required: true,
|
|
1499
1712
|
value: timezone,
|
|
@@ -1503,47 +1716,47 @@ function ResourceForm({ initialValues, onSubmit }) {
|
|
|
1503
1716
|
}
|
|
1504
1717
|
)
|
|
1505
1718
|
] }),
|
|
1506
|
-
initialValues && /* @__PURE__ */
|
|
1507
|
-
/* @__PURE__ */
|
|
1719
|
+
initialValues && /* @__PURE__ */ jsxs12("label", { className: "flex items-center gap-2 text-sm text-gray-700 dark:text-gray-300 min-h-11", children: [
|
|
1720
|
+
/* @__PURE__ */ jsx13("input", { type: "checkbox", checked: active, onChange: (event) => setActive(event.target.checked) }),
|
|
1508
1721
|
messages["resource.active"]
|
|
1509
1722
|
] }),
|
|
1510
|
-
/* @__PURE__ */
|
|
1723
|
+
/* @__PURE__ */ jsx13("button", { type: "submit", disabled: submitting, className: BUTTON_PRIMARY, children: messages["common.save"] })
|
|
1511
1724
|
] });
|
|
1512
1725
|
}
|
|
1513
1726
|
|
|
1514
1727
|
// src/components/ResourceList.tsx
|
|
1515
|
-
import { jsx as
|
|
1728
|
+
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1516
1729
|
function ResourceList({ resources, onSelect }) {
|
|
1517
1730
|
const { locale } = useSchedulingConfig();
|
|
1518
1731
|
const messages = resolveSchedulingMessages(locale);
|
|
1519
1732
|
if (resources.length === 0) {
|
|
1520
|
-
return /* @__PURE__ */
|
|
1733
|
+
return /* @__PURE__ */ jsx14("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.empty"] });
|
|
1521
1734
|
}
|
|
1522
|
-
return /* @__PURE__ */
|
|
1735
|
+
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
1736
|
"button",
|
|
1524
1737
|
{
|
|
1525
1738
|
type: "button",
|
|
1526
1739
|
onClick: () => onSelect(resource),
|
|
1527
1740
|
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
1741
|
children: [
|
|
1529
|
-
/* @__PURE__ */
|
|
1530
|
-
/* @__PURE__ */
|
|
1531
|
-
/* @__PURE__ */
|
|
1532
|
-
!resource.active && /* @__PURE__ */
|
|
1742
|
+
/* @__PURE__ */ jsx14("span", { className: "flex-1 font-medium text-gray-900 dark:text-gray-100", children: resource.name }),
|
|
1743
|
+
/* @__PURE__ */ jsx14("span", { className: "text-gray-500 dark:text-gray-400", children: messages[`resource.kind.${resource.kind}`] }),
|
|
1744
|
+
/* @__PURE__ */ jsx14("span", { className: "text-gray-500 dark:text-gray-400", children: resource.timezone }),
|
|
1745
|
+
!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
1746
|
]
|
|
1534
1747
|
}
|
|
1535
1748
|
) }, resource.id)) });
|
|
1536
1749
|
}
|
|
1537
1750
|
|
|
1538
1751
|
// src/workspace/ResourcesArea.tsx
|
|
1539
|
-
import { jsx as
|
|
1752
|
+
import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1540
1753
|
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
1754
|
var BUTTON_PRIMARY2 = `${BUTTON_CLASS2} bg-brand-600 text-white hover:bg-brand-700`;
|
|
1542
1755
|
var BUTTON_DANGER = `${BUTTON_CLASS2} text-red-700 hover:bg-red-50`;
|
|
1543
1756
|
function ResourcesArea() {
|
|
1544
1757
|
const { locale } = useSchedulingConfig();
|
|
1545
1758
|
const messages = resolveSchedulingMessages(locale);
|
|
1546
|
-
const { data, isLoading, isError } = useResources();
|
|
1759
|
+
const { data, isLoading, isError } = useResources({ pageSize: MAX_PAGE_SIZE4 });
|
|
1547
1760
|
const createResource = useCreateResource();
|
|
1548
1761
|
const updateResource = useUpdateResource();
|
|
1549
1762
|
const deleteResource = useDeleteResource();
|
|
@@ -1561,21 +1774,21 @@ function ResourcesArea() {
|
|
|
1561
1774
|
} catch {
|
|
1562
1775
|
}
|
|
1563
1776
|
}
|
|
1564
|
-
return /* @__PURE__ */
|
|
1565
|
-
/* @__PURE__ */
|
|
1566
|
-
/* @__PURE__ */
|
|
1777
|
+
return /* @__PURE__ */ jsxs14("div", { className: "flex flex-1 min-h-0 min-w-0 flex-col p-4 space-y-4", children: [
|
|
1778
|
+
/* @__PURE__ */ jsx15("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxs14("button", { type: "button", onClick: () => setDraft(null), className: `${BUTTON_PRIMARY2} ml-auto`, children: [
|
|
1779
|
+
/* @__PURE__ */ jsx15(Plus3, { "aria-hidden": "true", className: "w-4 h-4" }),
|
|
1567
1780
|
messages["resource.newResource"]
|
|
1568
1781
|
] }) }),
|
|
1569
|
-
isError && /* @__PURE__ */
|
|
1570
|
-
(createResource.isError || updateResource.isError || deleteResource.isError) && /* @__PURE__ */
|
|
1571
|
-
isLoading ? /* @__PURE__ */
|
|
1572
|
-
isDraftOpen && /* @__PURE__ */
|
|
1782
|
+
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"] }),
|
|
1783
|
+
(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"] }),
|
|
1784
|
+
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 }),
|
|
1785
|
+
isDraftOpen && /* @__PURE__ */ jsx15(
|
|
1573
1786
|
SidePanel,
|
|
1574
1787
|
{
|
|
1575
1788
|
title: isEditing ? messages["resource.editTitle"] : messages["resource.createTitle"],
|
|
1576
1789
|
closeLabel: messages["common.close"],
|
|
1577
1790
|
onClose: () => setDraft(void 0),
|
|
1578
|
-
headerActions: isEditing ? /* @__PURE__ */
|
|
1791
|
+
headerActions: isEditing ? /* @__PURE__ */ jsxs14(
|
|
1579
1792
|
"button",
|
|
1580
1793
|
{
|
|
1581
1794
|
type: "button",
|
|
@@ -1585,12 +1798,12 @@ function ResourcesArea() {
|
|
|
1585
1798
|
},
|
|
1586
1799
|
className: BUTTON_DANGER,
|
|
1587
1800
|
children: [
|
|
1588
|
-
/* @__PURE__ */
|
|
1801
|
+
/* @__PURE__ */ jsx15(Trash23, { "aria-hidden": "true", className: "w-4 h-4" }),
|
|
1589
1802
|
messages["common.remove"]
|
|
1590
1803
|
]
|
|
1591
1804
|
}
|
|
1592
1805
|
) : void 0,
|
|
1593
|
-
children: /* @__PURE__ */
|
|
1806
|
+
children: /* @__PURE__ */ jsx15(
|
|
1594
1807
|
ResourceForm,
|
|
1595
1808
|
{
|
|
1596
1809
|
...draft ? { initialValues: draft } : {},
|
|
@@ -1606,10 +1819,11 @@ function ResourcesArea() {
|
|
|
1606
1819
|
// src/workspace/ServicesArea.tsx
|
|
1607
1820
|
import { Plus as Plus4, Trash2 as Trash24 } from "lucide-react";
|
|
1608
1821
|
import { useState as useState12 } from "react";
|
|
1822
|
+
import { MAX_PAGE_SIZE as MAX_PAGE_SIZE5 } from "@adatechnology/scheduling-contracts";
|
|
1609
1823
|
|
|
1610
1824
|
// src/components/ServiceForm.tsx
|
|
1611
1825
|
import { useState as useState11 } from "react";
|
|
1612
|
-
import { jsx as
|
|
1826
|
+
import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1613
1827
|
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
1828
|
var LABEL_CLASS2 = "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1";
|
|
1615
1829
|
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 +1845,10 @@ function ServiceForm({ initialValues, onSubmit }) {
|
|
|
1631
1845
|
setSubmitting(false);
|
|
1632
1846
|
}
|
|
1633
1847
|
}
|
|
1634
|
-
return /* @__PURE__ */
|
|
1635
|
-
/* @__PURE__ */
|
|
1636
|
-
/* @__PURE__ */
|
|
1637
|
-
/* @__PURE__ */
|
|
1848
|
+
return /* @__PURE__ */ jsxs15("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
|
|
1849
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
1850
|
+
/* @__PURE__ */ jsx16("label", { htmlFor: "scheduling-service-name", className: LABEL_CLASS2, children: messages["service.name"] }),
|
|
1851
|
+
/* @__PURE__ */ jsx16(
|
|
1638
1852
|
"input",
|
|
1639
1853
|
{
|
|
1640
1854
|
id: "scheduling-service-name",
|
|
@@ -1646,9 +1860,9 @@ function ServiceForm({ initialValues, onSubmit }) {
|
|
|
1646
1860
|
}
|
|
1647
1861
|
)
|
|
1648
1862
|
] }),
|
|
1649
|
-
/* @__PURE__ */
|
|
1650
|
-
/* @__PURE__ */
|
|
1651
|
-
/* @__PURE__ */
|
|
1863
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
1864
|
+
/* @__PURE__ */ jsx16("label", { htmlFor: "scheduling-service-duration", className: LABEL_CLASS2, children: messages["service.durationMinutes"] }),
|
|
1865
|
+
/* @__PURE__ */ jsx16(
|
|
1652
1866
|
"input",
|
|
1653
1867
|
{
|
|
1654
1868
|
id: "scheduling-service-duration",
|
|
@@ -1661,10 +1875,10 @@ function ServiceForm({ initialValues, onSubmit }) {
|
|
|
1661
1875
|
}
|
|
1662
1876
|
)
|
|
1663
1877
|
] }),
|
|
1664
|
-
/* @__PURE__ */
|
|
1665
|
-
/* @__PURE__ */
|
|
1666
|
-
/* @__PURE__ */
|
|
1667
|
-
/* @__PURE__ */
|
|
1878
|
+
/* @__PURE__ */ jsxs15("div", { className: "grid grid-cols-2 gap-3", children: [
|
|
1879
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
1880
|
+
/* @__PURE__ */ jsx16("label", { htmlFor: "scheduling-service-buffer-before", className: LABEL_CLASS2, children: messages["service.bufferBeforeMinutes"] }),
|
|
1881
|
+
/* @__PURE__ */ jsx16(
|
|
1668
1882
|
"input",
|
|
1669
1883
|
{
|
|
1670
1884
|
id: "scheduling-service-buffer-before",
|
|
@@ -1676,9 +1890,9 @@ function ServiceForm({ initialValues, onSubmit }) {
|
|
|
1676
1890
|
}
|
|
1677
1891
|
)
|
|
1678
1892
|
] }),
|
|
1679
|
-
/* @__PURE__ */
|
|
1680
|
-
/* @__PURE__ */
|
|
1681
|
-
/* @__PURE__ */
|
|
1893
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
1894
|
+
/* @__PURE__ */ jsx16("label", { htmlFor: "scheduling-service-buffer-after", className: LABEL_CLASS2, children: messages["service.bufferAfterMinutes"] }),
|
|
1895
|
+
/* @__PURE__ */ jsx16(
|
|
1682
1896
|
"input",
|
|
1683
1897
|
{
|
|
1684
1898
|
id: "scheduling-service-buffer-after",
|
|
@@ -1691,49 +1905,49 @@ function ServiceForm({ initialValues, onSubmit }) {
|
|
|
1691
1905
|
)
|
|
1692
1906
|
] })
|
|
1693
1907
|
] }),
|
|
1694
|
-
initialValues && /* @__PURE__ */
|
|
1695
|
-
/* @__PURE__ */
|
|
1908
|
+
initialValues && /* @__PURE__ */ jsxs15("label", { className: "flex items-center gap-2 text-sm text-gray-700 dark:text-gray-300 min-h-11", children: [
|
|
1909
|
+
/* @__PURE__ */ jsx16("input", { type: "checkbox", checked: active, onChange: (event) => setActive(event.target.checked) }),
|
|
1696
1910
|
messages["service.active"]
|
|
1697
1911
|
] }),
|
|
1698
|
-
/* @__PURE__ */
|
|
1912
|
+
/* @__PURE__ */ jsx16("button", { type: "submit", disabled: submitting, className: BUTTON_PRIMARY3, children: messages["common.save"] })
|
|
1699
1913
|
] });
|
|
1700
1914
|
}
|
|
1701
1915
|
|
|
1702
1916
|
// src/components/ServiceList.tsx
|
|
1703
|
-
import { jsx as
|
|
1917
|
+
import { jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1704
1918
|
function ServiceList({ services, onSelect }) {
|
|
1705
1919
|
const { locale } = useSchedulingConfig();
|
|
1706
1920
|
const messages = resolveSchedulingMessages(locale);
|
|
1707
1921
|
if (services.length === 0) {
|
|
1708
|
-
return /* @__PURE__ */
|
|
1922
|
+
return /* @__PURE__ */ jsx17("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.empty"] });
|
|
1709
1923
|
}
|
|
1710
|
-
return /* @__PURE__ */
|
|
1924
|
+
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
1925
|
"button",
|
|
1712
1926
|
{
|
|
1713
1927
|
type: "button",
|
|
1714
1928
|
onClick: () => onSelect(service),
|
|
1715
1929
|
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
1930
|
children: [
|
|
1717
|
-
/* @__PURE__ */
|
|
1718
|
-
/* @__PURE__ */
|
|
1931
|
+
/* @__PURE__ */ jsx17("span", { className: "flex-1 font-medium text-gray-900 dark:text-gray-100", children: service.name }),
|
|
1932
|
+
/* @__PURE__ */ jsxs16("span", { className: "text-gray-500 dark:text-gray-400", children: [
|
|
1719
1933
|
service.durationMinutes,
|
|
1720
1934
|
" min"
|
|
1721
1935
|
] }),
|
|
1722
|
-
!service.active && /* @__PURE__ */
|
|
1936
|
+
!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
1937
|
]
|
|
1724
1938
|
}
|
|
1725
1939
|
) }, service.id)) });
|
|
1726
1940
|
}
|
|
1727
1941
|
|
|
1728
1942
|
// src/workspace/ServicesArea.tsx
|
|
1729
|
-
import { jsx as
|
|
1943
|
+
import { jsx as jsx18, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1730
1944
|
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
1945
|
var BUTTON_PRIMARY4 = `${BUTTON_CLASS3} bg-brand-600 text-white hover:bg-brand-700`;
|
|
1732
1946
|
var BUTTON_DANGER2 = `${BUTTON_CLASS3} text-red-700 hover:bg-red-50`;
|
|
1733
1947
|
function ServicesArea() {
|
|
1734
1948
|
const { locale } = useSchedulingConfig();
|
|
1735
1949
|
const messages = resolveSchedulingMessages(locale);
|
|
1736
|
-
const { data, isLoading, isError } = useServices();
|
|
1950
|
+
const { data, isLoading, isError } = useServices({ pageSize: MAX_PAGE_SIZE5 });
|
|
1737
1951
|
const createService = useCreateService();
|
|
1738
1952
|
const updateService = useUpdateService();
|
|
1739
1953
|
const deleteService = useDeleteService();
|
|
@@ -1751,21 +1965,21 @@ function ServicesArea() {
|
|
|
1751
1965
|
} catch {
|
|
1752
1966
|
}
|
|
1753
1967
|
}
|
|
1754
|
-
return /* @__PURE__ */
|
|
1755
|
-
/* @__PURE__ */
|
|
1756
|
-
/* @__PURE__ */
|
|
1968
|
+
return /* @__PURE__ */ jsxs17("div", { className: "flex flex-1 min-h-0 min-w-0 flex-col p-4 space-y-4", children: [
|
|
1969
|
+
/* @__PURE__ */ jsx18("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxs17("button", { type: "button", onClick: () => setDraft(null), className: `${BUTTON_PRIMARY4} ml-auto`, children: [
|
|
1970
|
+
/* @__PURE__ */ jsx18(Plus4, { "aria-hidden": "true", className: "w-4 h-4" }),
|
|
1757
1971
|
messages["service.newService"]
|
|
1758
1972
|
] }) }),
|
|
1759
|
-
isError && /* @__PURE__ */
|
|
1760
|
-
(createService.isError || updateService.isError || deleteService.isError) && /* @__PURE__ */
|
|
1761
|
-
isLoading ? /* @__PURE__ */
|
|
1762
|
-
isDraftOpen && /* @__PURE__ */
|
|
1973
|
+
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"] }),
|
|
1974
|
+
(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"] }),
|
|
1975
|
+
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 }),
|
|
1976
|
+
isDraftOpen && /* @__PURE__ */ jsx18(
|
|
1763
1977
|
SidePanel,
|
|
1764
1978
|
{
|
|
1765
1979
|
title: isEditing ? messages["service.editTitle"] : messages["service.createTitle"],
|
|
1766
1980
|
closeLabel: messages["common.close"],
|
|
1767
1981
|
onClose: () => setDraft(void 0),
|
|
1768
|
-
headerActions: isEditing ? /* @__PURE__ */
|
|
1982
|
+
headerActions: isEditing ? /* @__PURE__ */ jsxs17(
|
|
1769
1983
|
"button",
|
|
1770
1984
|
{
|
|
1771
1985
|
type: "button",
|
|
@@ -1775,12 +1989,12 @@ function ServicesArea() {
|
|
|
1775
1989
|
},
|
|
1776
1990
|
className: BUTTON_DANGER2,
|
|
1777
1991
|
children: [
|
|
1778
|
-
/* @__PURE__ */
|
|
1992
|
+
/* @__PURE__ */ jsx18(Trash24, { "aria-hidden": "true", className: "w-4 h-4" }),
|
|
1779
1993
|
messages["common.remove"]
|
|
1780
1994
|
]
|
|
1781
1995
|
}
|
|
1782
1996
|
) : void 0,
|
|
1783
|
-
children: /* @__PURE__ */
|
|
1997
|
+
children: /* @__PURE__ */ jsx18(
|
|
1784
1998
|
ServiceForm,
|
|
1785
1999
|
{
|
|
1786
2000
|
...draft ? { initialValues: draft } : {},
|
|
@@ -1810,7 +2024,7 @@ function isSchedulingWorkspaceArea(value) {
|
|
|
1810
2024
|
}
|
|
1811
2025
|
|
|
1812
2026
|
// src/workspace/WorkspaceAreaNav.tsx
|
|
1813
|
-
import { jsx as
|
|
2027
|
+
import { jsx as jsx19, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1814
2028
|
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
2029
|
var ITEM_ACTIVE = "border-brand-600 text-brand-700 dark:text-brand-400";
|
|
1816
2030
|
var ITEM_IDLE = "border-transparent text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100";
|
|
@@ -1829,9 +2043,9 @@ function WorkspaceAreaNav({ area, labels, onSelect }) {
|
|
|
1829
2043
|
[SCHEDULING_WORKSPACE_AREA.SERVICES, labels.servicesTab],
|
|
1830
2044
|
[SCHEDULING_WORKSPACE_AREA.AVAILABILITY, labels.availabilityTab]
|
|
1831
2045
|
];
|
|
1832
|
-
return /* @__PURE__ */
|
|
2046
|
+
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
2047
|
const Icon = AREA_ICON[value];
|
|
1834
|
-
return /* @__PURE__ */
|
|
2048
|
+
return /* @__PURE__ */ jsxs18(
|
|
1835
2049
|
"button",
|
|
1836
2050
|
{
|
|
1837
2051
|
type: "button",
|
|
@@ -1839,7 +2053,7 @@ function WorkspaceAreaNav({ area, labels, onSelect }) {
|
|
|
1839
2053
|
"aria-current": value === area ? "page" : void 0,
|
|
1840
2054
|
className: `${ITEM_BASE} ${value === area ? ITEM_ACTIVE : ITEM_IDLE} whitespace-nowrap`,
|
|
1841
2055
|
children: [
|
|
1842
|
-
/* @__PURE__ */
|
|
2056
|
+
/* @__PURE__ */ jsx19(Icon, { "aria-hidden": "true", className: "w-4 h-4 shrink-0" }),
|
|
1843
2057
|
label
|
|
1844
2058
|
]
|
|
1845
2059
|
},
|
|
@@ -1849,7 +2063,7 @@ function WorkspaceAreaNav({ area, labels, onSelect }) {
|
|
|
1849
2063
|
}
|
|
1850
2064
|
|
|
1851
2065
|
// src/workspace/SchedulingWorkspace.tsx
|
|
1852
|
-
import { jsx as
|
|
2066
|
+
import { jsx as jsx20, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1853
2067
|
var AREA_COMPONENT = {
|
|
1854
2068
|
[SCHEDULING_WORKSPACE_AREA.AGENDA]: AgendaArea,
|
|
1855
2069
|
[SCHEDULING_WORKSPACE_AREA.BOOKINGS]: BookingsArea,
|
|
@@ -1871,13 +2085,13 @@ function SchedulingWorkspace({
|
|
|
1871
2085
|
setInternalArea(next);
|
|
1872
2086
|
onAreaChange?.(next);
|
|
1873
2087
|
}
|
|
1874
|
-
return /* @__PURE__ */
|
|
1875
|
-
/* @__PURE__ */
|
|
1876
|
-
/* @__PURE__ */
|
|
2088
|
+
return /* @__PURE__ */ jsxs19("div", { className: "flex flex-col h-full", children: [
|
|
2089
|
+
/* @__PURE__ */ jsxs19("header", { className: "flex flex-wrap items-center gap-3 px-4 py-3", children: [
|
|
2090
|
+
/* @__PURE__ */ jsx20("h1", { className: "text-lg font-semibold text-gray-900 dark:text-gray-100 mr-auto", children: labels.title }),
|
|
1877
2091
|
renderHeaderActions?.()
|
|
1878
2092
|
] }),
|
|
1879
|
-
/* @__PURE__ */
|
|
1880
|
-
/* @__PURE__ */
|
|
2093
|
+
/* @__PURE__ */ jsx20(WorkspaceAreaNav, { area, labels, onSelect: handleSelectArea }),
|
|
2094
|
+
/* @__PURE__ */ jsx20("div", { className: "relative flex flex-1 min-h-0 overflow-hidden", children: /* @__PURE__ */ jsx20(AreaComponent, {}) })
|
|
1881
2095
|
] });
|
|
1882
2096
|
}
|
|
1883
2097
|
export {
|