@adatechnology/scheduling-ui 0.1.0-rc.5 → 0.1.0-rc.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -313,11 +313,11 @@ var DEFAULT_SCHEDULING_WORKSPACE_LABELS = {
313
313
  };
314
314
 
315
315
  // src/workspace/SchedulingWorkspace.tsx
316
- import { useState as useState13 } from "react";
316
+ import { useState as useState14 } from "react";
317
317
 
318
318
  // src/workspace/AgendaArea.tsx
319
319
  import { CalendarDays, ChevronLeft, ChevronRight } from "lucide-react";
320
- import { useEffect as useEffect2, useState as useState2 } from "react";
320
+ import { useEffect as useEffect3, useState as useState3 } from "react";
321
321
  import { MAX_PAGE_SIZE } from "@adatechnology/scheduling-contracts";
322
322
 
323
323
  // src/locales/pt-BR.json
@@ -424,7 +424,9 @@ var pt_BR_default = {
424
424
  "booking.emptyTitle": "Nenhuma reserva",
425
425
  "booking.emptyHint": "Ajuste os filtros de status ou aguarde novas solicita\xE7\xF5es.",
426
426
  "availability.selectResourceTitle": "Escolha um recurso",
427
- "availability.selectResourceHint": "As regras de disponibilidade s\xE3o definidas por recurso."
427
+ "availability.selectResourceHint": "As regras de disponibilidade s\xE3o definidas por recurso.",
428
+ "select.search": "Buscar\u2026",
429
+ "select.noResults": "Nenhum resultado"
428
430
  };
429
431
 
430
432
  // src/locales/en.json
@@ -531,7 +533,9 @@ var en_default = {
531
533
  "booking.emptyTitle": "No bookings",
532
534
  "booking.emptyHint": "Adjust the status filters or wait for new requests.",
533
535
  "availability.selectResourceTitle": "Pick a resource",
534
- "availability.selectResourceHint": "Availability rules are defined per resource."
536
+ "availability.selectResourceHint": "Availability rules are defined per resource.",
537
+ "select.search": "Search\u2026",
538
+ "select.noResults": "No results"
535
539
  };
536
540
 
537
541
  // src/locales/index.ts
@@ -680,7 +684,7 @@ function AgendaGrid({ bookings, days, now, onSelect }) {
680
684
  /* @__PURE__ */ jsxs(
681
685
  "div",
682
686
  {
683
- className: `${HEADER_CLASS} flex items-center gap-1 border-b border-gray-200 dark:border-gray-800 ${isToday ? "text-brand-700 dark:text-brand-300" : ""}`,
687
+ className: `${HEADER_CLASS} flex items-center gap-1 border-b border-gray-200 dark:border-gray-800 ${isToday ? "text-brand-700 dark:text-brand-400" : ""}`,
684
688
  children: [
685
689
  day.toLocaleDateString(locale, { weekday: "short", day: "2-digit", month: "2-digit" }),
686
690
  isToday && /* @__PURE__ */ jsx3("span", { className: "h-1.5 w-1.5 rounded-full bg-brand-600", "aria-hidden": "true" })
@@ -755,11 +759,256 @@ function AgendaGrid({ bookings, days, now, onSelect }) {
755
759
 
756
760
  // src/components/BookingDrawer.tsx
757
761
  import { XCircle } from "lucide-react";
758
- import { useState } from "react";
762
+ import { useState as useState2 } from "react";
759
763
  import { BOOKING_STATUS as BOOKING_STATUS2 } from "@adatechnology/scheduling-contracts";
760
764
 
761
765
  // src/components/DateTimeField.tsx
762
- import { useId } from "react";
766
+ import { useId as useId2, useMemo as useMemo3 } from "react";
767
+
768
+ // src/components/SelectField.tsx
769
+ import { Check, ChevronDown, Search } from "lucide-react";
770
+ import { useEffect, useId, useMemo as useMemo2, useRef, useState } from "react";
771
+
772
+ // src/components/selectFilter.util.ts
773
+ var COMBINING_MARKS = /[̀-ͯ]/g;
774
+ function normalizeForSearch(text) {
775
+ return text.normalize("NFD").replace(COMBINING_MARKS, "").toLowerCase().trim();
776
+ }
777
+ function filterSelectOptions(options, query) {
778
+ const needle = normalizeForSearch(query);
779
+ if (needle === "") return options;
780
+ return options.filter((option) => normalizeForSearch(option.label).includes(needle));
781
+ }
782
+ function findByPrefix(options, prefix) {
783
+ const needle = normalizeForSearch(prefix);
784
+ if (needle === "") return -1;
785
+ return options.findIndex((option) => normalizeForSearch(option.label).startsWith(needle));
786
+ }
787
+
788
+ // src/components/ui.constant.ts
789
+ var BUTTON_BASE = "inline-flex items-center justify-center gap-2 rounded-lg px-3 text-sm font-medium min-h-11 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-900 disabled:opacity-50 disabled:pointer-events-none";
790
+ var BUTTON_PRIMARY = `${BUTTON_BASE} bg-brand-600 text-white hover:bg-brand-700`;
791
+ var BUTTON_SECONDARY = `${BUTTON_BASE} border border-gray-300 bg-white text-gray-700 hover:bg-gray-50 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-200 dark:hover:bg-gray-800`;
792
+ var BUTTON_GHOST = `${BUTTON_BASE} text-gray-600 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-800`;
793
+ var BUTTON_DANGER = `${BUTTON_BASE} text-red-700 hover:bg-red-50 dark:text-red-400 dark:hover:bg-red-950/40`;
794
+ var ICON_BUTTON = `${BUTTON_SECONDARY} min-w-11 px-0`;
795
+ var FIELD_CONTROL = "min-h-11 rounded-lg border border-gray-300 bg-white px-3 text-sm text-gray-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100";
796
+ var FIELD_LABEL = "text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400";
797
+ var SURFACE_BORDER = "rounded-xl border border-gray-200 dark:border-gray-800";
798
+ var ROW_STRIPE = "bg-gray-50 dark:bg-gray-800/40";
799
+
800
+ // src/components/SelectField.tsx
801
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
802
+ var SEARCHABLE_THRESHOLD = 8;
803
+ var POPUP_MAX_HEIGHT = 288;
804
+ var TYPEAHEAD_RESET_MS = 700;
805
+ var OPTION_BASE = "flex w-full cursor-pointer items-center gap-2 px-3 py-2 text-left text-sm";
806
+ function SelectField({
807
+ label,
808
+ value,
809
+ options,
810
+ onChange,
811
+ emptyOptionLabel,
812
+ searchable,
813
+ hideLabel,
814
+ className
815
+ }) {
816
+ const { locale } = useSchedulingConfig();
817
+ const messages = resolveSchedulingMessages(locale);
818
+ const fieldId = useId();
819
+ const listboxId = `${fieldId}-listbox`;
820
+ const containerRef = useRef(null);
821
+ const triggerRef = useRef(null);
822
+ const searchRef = useRef(null);
823
+ const listRef = useRef(null);
824
+ const typeahead = useRef({ text: "", at: 0 });
825
+ const [isOpen, setIsOpen] = useState(false);
826
+ const [openUpward, setOpenUpward] = useState(false);
827
+ const [query, setQuery] = useState("");
828
+ const [highlighted, setHighlighted] = useState(0);
829
+ const allOptions = useMemo2(
830
+ () => emptyOptionLabel === void 0 ? options : [{ value: "", label: emptyOptionLabel }, ...options],
831
+ [emptyOptionLabel, options]
832
+ );
833
+ const withSearch = searchable ?? allOptions.length >= SEARCHABLE_THRESHOLD;
834
+ const visibleOptions = useMemo2(
835
+ () => withSearch ? filterSelectOptions(allOptions, query) : allOptions,
836
+ [allOptions, query, withSearch]
837
+ );
838
+ const selected = allOptions.find((option) => option.value === value);
839
+ function open() {
840
+ const rect = triggerRef.current?.getBoundingClientRect();
841
+ if (rect) {
842
+ const spaceBelow = window.innerHeight - rect.bottom;
843
+ setOpenUpward(spaceBelow < POPUP_MAX_HEIGHT && rect.top > spaceBelow);
844
+ }
845
+ setQuery("");
846
+ setHighlighted(Math.max(allOptions.findIndex((option) => option.value === value), 0));
847
+ setIsOpen(true);
848
+ }
849
+ function close(returnFocus = true) {
850
+ setIsOpen(false);
851
+ if (returnFocus) triggerRef.current?.focus();
852
+ }
853
+ function commit(option) {
854
+ onChange(option.value);
855
+ close();
856
+ }
857
+ useEffect(() => {
858
+ if (!isOpen) return;
859
+ function handlePointerDown(event) {
860
+ if (!containerRef.current?.contains(event.target)) setIsOpen(false);
861
+ }
862
+ document.addEventListener("pointerdown", handlePointerDown);
863
+ return () => document.removeEventListener("pointerdown", handlePointerDown);
864
+ }, [isOpen]);
865
+ useEffect(() => {
866
+ if (isOpen && withSearch) searchRef.current?.focus();
867
+ }, [isOpen, withSearch]);
868
+ useEffect(() => {
869
+ if (!isOpen) return;
870
+ listRef.current?.children[highlighted]?.scrollIntoView({ block: "nearest" });
871
+ }, [highlighted, isOpen]);
872
+ function jumpByTypeahead(key) {
873
+ if (withSearch || key.length !== 1 || !/\S/.test(key)) return false;
874
+ const now = Date.now();
875
+ const text = now - typeahead.current.at > TYPEAHEAD_RESET_MS ? key : typeahead.current.text + key;
876
+ typeahead.current = { text, at: now };
877
+ const index = findByPrefix(visibleOptions, text);
878
+ if (index >= 0) setHighlighted(index);
879
+ return index >= 0;
880
+ }
881
+ function handleKeyDown(event) {
882
+ if (!isOpen) {
883
+ if (["ArrowDown", "ArrowUp", "Enter", " "].includes(event.key)) {
884
+ event.preventDefault();
885
+ open();
886
+ }
887
+ return;
888
+ }
889
+ switch (event.key) {
890
+ case "Escape":
891
+ event.preventDefault();
892
+ close();
893
+ return;
894
+ case "Tab":
895
+ close(false);
896
+ return;
897
+ case "ArrowDown":
898
+ event.preventDefault();
899
+ setHighlighted((current) => Math.min(current + 1, visibleOptions.length - 1));
900
+ return;
901
+ case "ArrowUp":
902
+ event.preventDefault();
903
+ setHighlighted((current) => Math.max(current - 1, 0));
904
+ return;
905
+ case "Home":
906
+ event.preventDefault();
907
+ setHighlighted(0);
908
+ return;
909
+ case "End":
910
+ event.preventDefault();
911
+ setHighlighted(visibleOptions.length - 1);
912
+ return;
913
+ case "Enter": {
914
+ event.preventDefault();
915
+ const option = visibleOptions[highlighted];
916
+ if (option) commit(option);
917
+ return;
918
+ }
919
+ default:
920
+ if (jumpByTypeahead(event.key)) event.preventDefault();
921
+ }
922
+ }
923
+ return /* @__PURE__ */ jsxs2("div", { className: `flex flex-col gap-1 ${className ?? ""}`, children: [
924
+ /* @__PURE__ */ jsx4("span", { id: fieldId, className: hideLabel ? "sr-only" : FIELD_LABEL, children: label }),
925
+ /* @__PURE__ */ jsxs2("div", { ref: containerRef, className: "relative", children: [
926
+ /* @__PURE__ */ jsxs2(
927
+ "button",
928
+ {
929
+ ref: triggerRef,
930
+ type: "button",
931
+ role: "combobox",
932
+ "aria-controls": listboxId,
933
+ "aria-expanded": isOpen,
934
+ "aria-haspopup": "listbox",
935
+ "aria-labelledby": fieldId,
936
+ onClick: () => isOpen ? close(false) : open(),
937
+ onKeyDown: handleKeyDown,
938
+ className: `${FIELD_CONTROL} flex w-full items-center gap-2 text-left`,
939
+ children: [
940
+ /* @__PURE__ */ jsx4("span", { className: `flex-1 truncate ${selected ? "" : "text-gray-500 dark:text-gray-400"}`, children: selected?.label ?? emptyOptionLabel ?? "" }),
941
+ /* @__PURE__ */ jsx4(
942
+ ChevronDown,
943
+ {
944
+ "aria-hidden": "true",
945
+ className: `h-4 w-4 shrink-0 text-gray-400 transition-transform ${isOpen ? "rotate-180" : ""}`
946
+ }
947
+ )
948
+ ]
949
+ }
950
+ ),
951
+ isOpen && /* @__PURE__ */ jsxs2(
952
+ "div",
953
+ {
954
+ className: `absolute z-30 w-full min-w-max overflow-hidden rounded-lg border border-gray-200 bg-white shadow-lg dark:border-gray-700 dark:bg-gray-900 ${openUpward ? "bottom-full mb-1" : "top-full mt-1"}`,
955
+ children: [
956
+ withSearch && /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2 border-b border-gray-200 px-3 dark:border-gray-700", children: [
957
+ /* @__PURE__ */ jsx4(Search, { "aria-hidden": "true", className: "h-4 w-4 shrink-0 text-gray-400" }),
958
+ /* @__PURE__ */ jsx4(
959
+ "input",
960
+ {
961
+ ref: searchRef,
962
+ type: "text",
963
+ value: query,
964
+ onChange: (event) => {
965
+ setQuery(event.target.value);
966
+ setHighlighted(0);
967
+ },
968
+ onKeyDown: handleKeyDown,
969
+ "aria-label": messages["select.search"],
970
+ placeholder: messages["select.search"],
971
+ className: "min-h-11 w-full bg-transparent text-sm text-gray-900 outline-none placeholder:text-gray-400 dark:text-gray-100"
972
+ }
973
+ )
974
+ ] }),
975
+ /* @__PURE__ */ jsxs2(
976
+ "ul",
977
+ {
978
+ ref: listRef,
979
+ id: listboxId,
980
+ role: "listbox",
981
+ "aria-labelledby": fieldId,
982
+ className: "max-h-72 overflow-y-auto py-1",
983
+ children: [
984
+ visibleOptions.map((option, index) => {
985
+ const isSelected = option.value === value;
986
+ return /* @__PURE__ */ jsxs2(
987
+ "li",
988
+ {
989
+ role: "option",
990
+ "aria-selected": isSelected,
991
+ onPointerEnter: () => setHighlighted(index),
992
+ onClick: () => commit(option),
993
+ className: `${OPTION_BASE} ${index === highlighted ? "bg-brand-50 dark:bg-brand-900/30" : ""} ${isSelected ? "font-medium text-brand-800 dark:text-brand-200" : "text-gray-800 dark:text-gray-200"}`,
994
+ children: [
995
+ /* @__PURE__ */ jsx4("span", { className: "flex-1 truncate", children: option.label }),
996
+ isSelected && /* @__PURE__ */ jsx4(Check, { "aria-hidden": "true", className: "h-4 w-4 shrink-0" })
997
+ ]
998
+ },
999
+ option.value
1000
+ );
1001
+ }),
1002
+ visibleOptions.length === 0 && /* @__PURE__ */ jsx4("li", { className: "px-3 py-3 text-sm text-gray-500 dark:text-gray-400", children: messages["select.noResults"] })
1003
+ ]
1004
+ }
1005
+ )
1006
+ ]
1007
+ }
1008
+ )
1009
+ ] })
1010
+ ] });
1011
+ }
763
1012
 
764
1013
  // src/components/dateTimeParts.util.ts
765
1014
  var DATE_TIME_LOCAL_PATTERN = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})$/;
@@ -789,7 +1038,7 @@ function buildYearOptions(params) {
789
1038
  }
790
1039
 
791
1040
  // src/components/DateTimeField.tsx
792
- import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
1041
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
793
1042
  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";
794
1043
  var YEAR_WINDOW = { PAST: 1, FUTURE: 2 };
795
1044
  function partsOf(value, fallback) {
@@ -810,7 +1059,7 @@ function monthLabels(locale) {
810
1059
  function DateTimeField({ label, value, onChange, emptyDefault }) {
811
1060
  const { locale } = useSchedulingConfig();
812
1061
  const messages = resolveSchedulingMessages(locale);
813
- const groupId = useId();
1062
+ const groupId = useId2();
814
1063
  const today = emptyDefault ?? /* @__PURE__ */ new Date();
815
1064
  const parts = partsOf(value, today);
816
1065
  const years = buildYearOptions({
@@ -821,42 +1070,59 @@ function DateTimeField({ label, value, onChange, emptyDefault }) {
821
1070
  });
822
1071
  const days = daysInMonth({ year: parts.year, month: parts.month });
823
1072
  const months = monthLabels(locale);
1073
+ const yearOptions = useMemo3(
1074
+ () => years.map((year) => ({ value: String(year), label: String(year) })),
1075
+ [years]
1076
+ );
1077
+ const monthOptions = useMemo3(
1078
+ () => months.map((name, index) => ({ value: String(index + 1), label: name })),
1079
+ [months]
1080
+ );
1081
+ const dayOptions = useMemo3(
1082
+ () => Array.from({ length: days }, (_, index) => ({ value: String(index + 1), label: String(index + 1) })),
1083
+ [days]
1084
+ );
824
1085
  function change(patch) {
825
1086
  onChange(formatDateTimeParts({ ...parts, ...patch }));
826
1087
  }
827
- return /* @__PURE__ */ jsxs2("div", { role: "group", "aria-labelledby": groupId, className: "flex flex-wrap items-center gap-2", children: [
828
- /* @__PURE__ */ jsx4("span", { id: groupId, className: "sr-only", children: label }),
829
- /* @__PURE__ */ jsx4(
830
- "select",
1088
+ return /* @__PURE__ */ jsxs3("div", { role: "group", "aria-labelledby": groupId, className: "flex flex-wrap items-center gap-2", children: [
1089
+ /* @__PURE__ */ jsx5("span", { id: groupId, className: "sr-only", children: label }),
1090
+ /* @__PURE__ */ jsx5(
1091
+ SelectField,
831
1092
  {
832
- "aria-label": `${label} \u2014 ${messages["datetime.year"]}`,
833
- value: parts.year,
834
- onChange: (event) => change({ year: Number(event.target.value) }),
835
- className: FIELD_CLASS,
836
- children: years.map((year) => /* @__PURE__ */ jsx4("option", { value: year, children: year }, year))
1093
+ hideLabel: true,
1094
+ label: `${label} \u2014 ${messages["datetime.year"]}`,
1095
+ value: String(parts.year),
1096
+ options: yearOptions,
1097
+ onChange: (next) => change({ year: Number(next) }),
1098
+ className: "min-w-24"
837
1099
  }
838
1100
  ),
839
- /* @__PURE__ */ jsx4(
840
- "select",
1101
+ /* @__PURE__ */ jsx5(
1102
+ SelectField,
841
1103
  {
842
- "aria-label": `${label} \u2014 ${messages["datetime.month"]}`,
843
- value: parts.month,
844
- onChange: (event) => change({ month: Number(event.target.value) }),
845
- className: FIELD_CLASS,
846
- children: months.map((name, index) => /* @__PURE__ */ jsx4("option", { value: index + 1, children: name }, name))
1104
+ hideLabel: true,
1105
+ label: `${label} \u2014 ${messages["datetime.month"]}`,
1106
+ value: String(parts.month),
1107
+ options: monthOptions,
1108
+ onChange: (next) => change({ month: Number(next) }),
1109
+ searchable: false,
1110
+ className: "min-w-36"
847
1111
  }
848
1112
  ),
849
- /* @__PURE__ */ jsx4(
850
- "select",
1113
+ /* @__PURE__ */ jsx5(
1114
+ SelectField,
851
1115
  {
852
- "aria-label": `${label} \u2014 ${messages["datetime.day"]}`,
853
- value: Math.min(parts.day, days),
854
- onChange: (event) => change({ day: Number(event.target.value) }),
855
- className: FIELD_CLASS,
856
- children: Array.from({ length: days }, (_, index) => index + 1).map((day) => /* @__PURE__ */ jsx4("option", { value: day, children: day }, day))
1116
+ hideLabel: true,
1117
+ label: `${label} \u2014 ${messages["datetime.day"]}`,
1118
+ value: String(Math.min(parts.day, days)),
1119
+ options: dayOptions,
1120
+ onChange: (next) => change({ day: Number(next) }),
1121
+ searchable: false,
1122
+ className: "min-w-20"
857
1123
  }
858
1124
  ),
859
- /* @__PURE__ */ jsx4(
1125
+ /* @__PURE__ */ jsx5(
860
1126
  "input",
861
1127
  {
862
1128
  type: "time",
@@ -916,32 +1182,18 @@ function formatDateTimeLocalInTimeZone(instant, timeZone) {
916
1182
 
917
1183
  // src/components/SidePanel.tsx
918
1184
  import { X } from "lucide-react";
919
-
920
- // src/components/ui.constant.ts
921
- var BUTTON_BASE = "inline-flex items-center justify-center gap-2 rounded-lg px-3 text-sm font-medium min-h-11 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-900 disabled:opacity-50 disabled:pointer-events-none";
922
- var BUTTON_PRIMARY = `${BUTTON_BASE} bg-brand-600 text-white hover:bg-brand-700`;
923
- var BUTTON_SECONDARY = `${BUTTON_BASE} border border-gray-300 bg-white text-gray-700 hover:bg-gray-50 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-200 dark:hover:bg-gray-800`;
924
- var BUTTON_GHOST = `${BUTTON_BASE} text-gray-600 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-800`;
925
- var BUTTON_DANGER = `${BUTTON_BASE} text-red-700 hover:bg-red-50 dark:text-red-400 dark:hover:bg-red-950/40`;
926
- var ICON_BUTTON = `${BUTTON_SECONDARY} min-w-11 px-0`;
927
- var FIELD_CONTROL = "min-h-11 rounded-lg border border-gray-300 bg-white px-3 text-sm text-gray-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-500 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100";
928
- var FIELD_LABEL = "text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400";
929
- var SURFACE_BORDER = "rounded-xl border border-gray-200 dark:border-gray-800";
930
- var ROW_STRIPE = "bg-gray-50 dark:bg-gray-800/40";
931
-
932
- // src/components/SidePanel.tsx
933
- import { useEffect } from "react";
934
- import { Fragment, jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1185
+ import { useEffect as useEffect2 } from "react";
1186
+ import { Fragment, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
935
1187
  function SidePanel({ title, closeLabel, onClose, headerActions, children }) {
936
- useEffect(() => {
1188
+ useEffect2(() => {
937
1189
  function handleKeyDown(event) {
938
1190
  if (event.key === "Escape") onClose();
939
1191
  }
940
1192
  window.addEventListener("keydown", handleKeyDown);
941
1193
  return () => window.removeEventListener("keydown", handleKeyDown);
942
1194
  }, [onClose]);
943
- return /* @__PURE__ */ jsxs3(Fragment, { children: [
944
- /* @__PURE__ */ jsx5(
1195
+ return /* @__PURE__ */ jsxs4(Fragment, { children: [
1196
+ /* @__PURE__ */ jsx6(
945
1197
  "button",
946
1198
  {
947
1199
  type: "button",
@@ -951,29 +1203,29 @@ function SidePanel({ title, closeLabel, onClose, headerActions, children }) {
951
1203
  className: "absolute inset-0 z-10 bg-gray-900/30 backdrop-blur-[1px] wide:hidden"
952
1204
  }
953
1205
  ),
954
- /* @__PURE__ */ jsxs3(
1206
+ /* @__PURE__ */ jsxs4(
955
1207
  "section",
956
1208
  {
957
1209
  "aria-label": title,
958
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",
959
1211
  children: [
960
- /* @__PURE__ */ jsxs3("div", { className: "flex items-center gap-2 border-b border-gray-200 px-4 py-3 dark:border-gray-700", children: [
961
- /* @__PURE__ */ jsx5("h2", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100 mr-auto", children: title }),
1212
+ /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 border-b border-gray-200 px-4 py-3 dark:border-gray-700", children: [
1213
+ /* @__PURE__ */ jsx6("h2", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100 mr-auto", children: title }),
962
1214
  headerActions,
963
- /* @__PURE__ */ jsxs3(
1215
+ /* @__PURE__ */ jsxs4(
964
1216
  "button",
965
1217
  {
966
1218
  type: "button",
967
1219
  onClick: onClose,
968
1220
  className: BUTTON_GHOST,
969
1221
  children: [
970
- /* @__PURE__ */ jsx5(X, { "aria-hidden": "true", className: "w-4 h-4" }),
1222
+ /* @__PURE__ */ jsx6(X, { "aria-hidden": "true", className: "w-4 h-4" }),
971
1223
  closeLabel
972
1224
  ]
973
1225
  }
974
1226
  )
975
1227
  ] }),
976
- /* @__PURE__ */ jsx5("div", { className: "min-h-0 flex-1 overflow-y-auto p-4", children })
1228
+ /* @__PURE__ */ jsx6("div", { className: "min-h-0 flex-1 overflow-y-auto p-4", children })
977
1229
  ]
978
1230
  }
979
1231
  )
@@ -981,7 +1233,7 @@ function SidePanel({ title, closeLabel, onClose, headerActions, children }) {
981
1233
  }
982
1234
 
983
1235
  // src/components/BookingDrawer.tsx
984
- import { Fragment as Fragment2, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
1236
+ import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
985
1237
  var BROWSER_TIME_ZONE = Intl.DateTimeFormat().resolvedOptions().timeZone;
986
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";
987
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";
@@ -996,12 +1248,12 @@ function BookingDrawer({ booking, resourceTimezone, onClose }) {
996
1248
  const cancelBooking = useCancelBooking();
997
1249
  const rescheduleBooking = useRescheduleBooking();
998
1250
  const timezone = resourceTimezone ?? BROWSER_TIME_ZONE;
999
- const [isCancelling, setIsCancelling] = useState(false);
1000
- const [cancelledBy, setCancelledBy] = useState("");
1001
- const [cancellationReason, setCancellationReason] = useState("");
1002
- const [isRescheduling, setIsRescheduling] = useState(false);
1003
- const [start, setStart] = useState(() => formatDateTimeLocalInTimeZone(booking.startsAt, timezone));
1004
- const [end, setEnd] = useState(() => formatDateTimeLocalInTimeZone(booking.endsAt, timezone));
1251
+ const [isCancelling, setIsCancelling] = useState2(false);
1252
+ const [cancelledBy, setCancelledBy] = useState2("");
1253
+ const [cancellationReason, setCancellationReason] = useState2("");
1254
+ const [isRescheduling, setIsRescheduling] = useState2(false);
1255
+ const [start, setStart] = useState2(() => formatDateTimeLocalInTimeZone(booking.startsAt, timezone));
1256
+ const [end, setEnd] = useState2(() => formatDateTimeLocalInTimeZone(booking.endsAt, timezone));
1005
1257
  async function handleCancel() {
1006
1258
  if (!cancelledBy) return;
1007
1259
  try {
@@ -1029,31 +1281,31 @@ function BookingDrawer({ booking, resourceTimezone, onClose }) {
1029
1281
  }
1030
1282
  }
1031
1283
  const isTerminal = booking.status === BOOKING_STATUS2.CANCELLED || booking.status === BOOKING_STATUS2.COMPLETED || booking.status === BOOKING_STATUS2.NO_SHOW;
1032
- return /* @__PURE__ */ jsx6(SidePanel, { title: messages["booking.detailTitle"], closeLabel: messages["common.close"], onClose, children: /* @__PURE__ */ jsxs4("div", { className: "space-y-4", children: [
1033
- /* @__PURE__ */ jsxs4("div", { children: [
1034
- /* @__PURE__ */ jsx6("p", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: booking.title }),
1035
- /* @__PURE__ */ jsx6("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages[`booking.status.${booking.status === "no_show" ? "noShow" : booking.status}`] }),
1036
- /* @__PURE__ */ jsxs4("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: [
1284
+ return /* @__PURE__ */ jsx7(SidePanel, { title: messages["booking.detailTitle"], closeLabel: messages["common.close"], onClose, children: /* @__PURE__ */ jsxs5("div", { className: "space-y-4", children: [
1285
+ /* @__PURE__ */ jsxs5("div", { children: [
1286
+ /* @__PURE__ */ jsx7("p", { className: "text-base font-semibold text-gray-900 dark:text-gray-100", children: booking.title }),
1287
+ /* @__PURE__ */ jsx7("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages[`booking.status.${booking.status === "no_show" ? "noShow" : booking.status}`] }),
1288
+ /* @__PURE__ */ jsxs5("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: [
1037
1289
  booking.startsAt.toLocaleString(locale),
1038
1290
  " \u2192 ",
1039
1291
  booking.endsAt.toLocaleString(locale)
1040
1292
  ] })
1041
1293
  ] }),
1042
- (confirmBooking.isError || completeBooking.isError || markNoShow.isError || cancelBooking.isError || rescheduleBooking.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"] }),
1043
- !isTerminal && /* @__PURE__ */ jsxs4("div", { className: "flex flex-wrap gap-2", children: [
1044
- booking.status === BOOKING_STATUS2.REQUESTED && /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => confirmBooking.mutate(booking.id), className: PRIMARY_BUTTON_CLASS, children: messages["booking.confirm"] }),
1045
- booking.status === BOOKING_STATUS2.CONFIRMED && /* @__PURE__ */ jsxs4(Fragment2, { children: [
1046
- /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => completeBooking.mutate(booking.id), className: ACTION_BUTTON_CLASS, children: messages["booking.complete"] }),
1047
- /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => markNoShow.mutate(booking.id), className: ACTION_BUTTON_CLASS, children: messages["booking.markNoShow"] }),
1048
- /* @__PURE__ */ jsx6("button", { type: "button", onClick: () => setIsRescheduling(true), className: ACTION_BUTTON_CLASS, children: messages["booking.reschedule"] })
1294
+ (confirmBooking.isError || completeBooking.isError || markNoShow.isError || cancelBooking.isError || rescheduleBooking.isError) && /* @__PURE__ */ jsx7("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__ */ jsxs5("div", { className: "flex flex-wrap gap-2", children: [
1296
+ booking.status === BOOKING_STATUS2.REQUESTED && /* @__PURE__ */ jsx7("button", { type: "button", onClick: () => confirmBooking.mutate(booking.id), className: PRIMARY_BUTTON_CLASS, children: messages["booking.confirm"] }),
1297
+ booking.status === BOOKING_STATUS2.CONFIRMED && /* @__PURE__ */ jsxs5(Fragment2, { children: [
1298
+ /* @__PURE__ */ jsx7("button", { type: "button", onClick: () => completeBooking.mutate(booking.id), className: ACTION_BUTTON_CLASS, children: messages["booking.complete"] }),
1299
+ /* @__PURE__ */ jsx7("button", { type: "button", onClick: () => markNoShow.mutate(booking.id), className: ACTION_BUTTON_CLASS, children: messages["booking.markNoShow"] }),
1300
+ /* @__PURE__ */ jsx7("button", { type: "button", onClick: () => setIsRescheduling(true), className: ACTION_BUTTON_CLASS, children: messages["booking.reschedule"] })
1049
1301
  ] }),
1050
- /* @__PURE__ */ jsxs4("button", { type: "button", onClick: () => setIsCancelling(true), className: DANGER_BUTTON_CLASS, children: [
1051
- /* @__PURE__ */ jsx6(XCircle, { "aria-hidden": "true", className: "w-4 h-4" }),
1302
+ /* @__PURE__ */ jsxs5("button", { type: "button", onClick: () => setIsCancelling(true), className: DANGER_BUTTON_CLASS, children: [
1303
+ /* @__PURE__ */ jsx7(XCircle, { "aria-hidden": "true", className: "w-4 h-4" }),
1052
1304
  messages["booking.cancel"]
1053
1305
  ] })
1054
1306
  ] }),
1055
- isRescheduling && /* @__PURE__ */ jsxs4("div", { className: "space-y-2 rounded-lg border border-gray-200 dark:border-gray-700 p-3", children: [
1056
- /* @__PURE__ */ jsx6(
1307
+ isRescheduling && /* @__PURE__ */ jsxs5("div", { className: "space-y-2 rounded-lg border border-gray-200 dark:border-gray-700 p-3", children: [
1308
+ /* @__PURE__ */ jsx7(
1057
1309
  DateTimeField,
1058
1310
  {
1059
1311
  label: messages["booking.rescheduleStart"],
@@ -1061,11 +1313,11 @@ function BookingDrawer({ booking, resourceTimezone, onClose }) {
1061
1313
  onChange: setStart
1062
1314
  }
1063
1315
  ),
1064
- /* @__PURE__ */ jsx6(DateTimeField, { label: messages["booking.rescheduleEnd"], value: end, onChange: setEnd }),
1065
- /* @__PURE__ */ jsx6("button", { type: "button", onClick: handleReschedule, disabled: rescheduleBooking.isPending, className: PRIMARY_BUTTON_CLASS, children: messages["common.save"] })
1316
+ /* @__PURE__ */ jsx7(DateTimeField, { label: messages["booking.rescheduleEnd"], value: end, onChange: setEnd }),
1317
+ /* @__PURE__ */ jsx7("button", { type: "button", onClick: handleReschedule, disabled: rescheduleBooking.isPending, className: PRIMARY_BUTTON_CLASS, children: messages["common.save"] })
1066
1318
  ] }),
1067
- isCancelling && /* @__PURE__ */ jsxs4("div", { className: "space-y-2 rounded-lg border border-gray-200 dark:border-gray-700 p-3", children: [
1068
- /* @__PURE__ */ jsx6(
1319
+ isCancelling && /* @__PURE__ */ jsxs5("div", { className: "space-y-2 rounded-lg border border-gray-200 dark:border-gray-700 p-3", children: [
1320
+ /* @__PURE__ */ jsx7(
1069
1321
  "input",
1070
1322
  {
1071
1323
  type: "text",
@@ -1075,7 +1327,7 @@ function BookingDrawer({ booking, resourceTimezone, onClose }) {
1075
1327
  className: INPUT_CLASS
1076
1328
  }
1077
1329
  ),
1078
- /* @__PURE__ */ jsx6(
1330
+ /* @__PURE__ */ jsx7(
1079
1331
  "input",
1080
1332
  {
1081
1333
  type: "text",
@@ -1085,8 +1337,8 @@ function BookingDrawer({ booking, resourceTimezone, onClose }) {
1085
1337
  className: INPUT_CLASS
1086
1338
  }
1087
1339
  ),
1088
- /* @__PURE__ */ jsxs4("button", { type: "button", onClick: handleCancel, disabled: cancelBooking.isPending, className: DANGER_BUTTON_CLASS, children: [
1089
- /* @__PURE__ */ jsx6(XCircle, { "aria-hidden": "true", className: "w-4 h-4" }),
1340
+ /* @__PURE__ */ jsxs5("button", { type: "button", onClick: handleCancel, disabled: cancelBooking.isPending, className: DANGER_BUTTON_CLASS, children: [
1341
+ /* @__PURE__ */ jsx7(XCircle, { "aria-hidden": "true", className: "w-4 h-4" }),
1090
1342
  messages["booking.cancel"]
1091
1343
  ] })
1092
1344
  ] })
@@ -1094,28 +1346,30 @@ function BookingDrawer({ booking, resourceTimezone, onClose }) {
1094
1346
  }
1095
1347
 
1096
1348
  // src/components/ResourceSelect.tsx
1097
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
1349
+ import { useMemo as useMemo4 } from "react";
1350
+ import { jsx as jsx8 } from "react/jsx-runtime";
1098
1351
  function ResourceSelect({ label, emptyOptionLabel, resources, value, onChange }) {
1099
- return /* @__PURE__ */ jsxs5("label", { className: "flex flex-col gap-1", children: [
1100
- /* @__PURE__ */ jsx7("span", { className: FIELD_LABEL, children: label }),
1101
- /* @__PURE__ */ jsxs5(
1102
- "select",
1103
- {
1104
- value,
1105
- onChange: (event) => onChange(event.target.value),
1106
- className: `${FIELD_CONTROL} min-w-44`,
1107
- children: [
1108
- /* @__PURE__ */ jsx7("option", { value: "", children: emptyOptionLabel }),
1109
- resources.map((resource) => /* @__PURE__ */ jsx7("option", { value: resource.id, children: resource.name }, resource.id))
1110
- ]
1111
- }
1112
- )
1113
- ] });
1352
+ const options = useMemo4(
1353
+ () => resources.map((resource) => ({ value: resource.id, label: resource.name })),
1354
+ [resources]
1355
+ );
1356
+ return /* @__PURE__ */ jsx8(
1357
+ SelectField,
1358
+ {
1359
+ label,
1360
+ emptyOptionLabel,
1361
+ options,
1362
+ value,
1363
+ onChange,
1364
+ searchable: true,
1365
+ className: "min-w-52"
1366
+ }
1367
+ );
1114
1368
  }
1115
1369
 
1116
1370
  // src/components/StateFeedback.tsx
1117
1371
  import { AlertTriangle } from "lucide-react";
1118
- import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1372
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
1119
1373
  function ErrorBanner({ message }) {
1120
1374
  return /* @__PURE__ */ jsxs6(
1121
1375
  "p",
@@ -1123,7 +1377,7 @@ function ErrorBanner({ message }) {
1123
1377
  role: "alert",
1124
1378
  className: "flex items-start gap-2 rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-800 dark:border-red-900 dark:bg-red-950/50 dark:text-red-200",
1125
1379
  children: [
1126
- /* @__PURE__ */ jsx8(AlertTriangle, { "aria-hidden": "true", className: "mt-0.5 h-4 w-4 shrink-0" }),
1380
+ /* @__PURE__ */ jsx9(AlertTriangle, { "aria-hidden": "true", className: "mt-0.5 h-4 w-4 shrink-0" }),
1127
1381
  message
1128
1382
  ]
1129
1383
  }
@@ -1131,18 +1385,18 @@ function ErrorBanner({ message }) {
1131
1385
  }
1132
1386
  function EmptyState({ icon: Icon, title, hint, action }) {
1133
1387
  return /* @__PURE__ */ jsxs6("div", { className: `${SURFACE_BORDER} flex flex-col items-center gap-2 px-6 py-12 text-center`, children: [
1134
- /* @__PURE__ */ jsx8("span", { className: "flex h-12 w-12 items-center justify-center rounded-full bg-gray-100 text-gray-400 dark:bg-gray-800 dark:text-gray-500", children: /* @__PURE__ */ jsx8(Icon, { "aria-hidden": "true", className: "h-6 w-6" }) }),
1135
- /* @__PURE__ */ jsx8("p", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: title }),
1136
- hint && /* @__PURE__ */ jsx8("p", { className: "max-w-sm text-sm text-gray-500 dark:text-gray-400", children: hint }),
1137
- action && /* @__PURE__ */ jsx8("div", { className: "mt-2", children: action })
1388
+ /* @__PURE__ */ jsx9("span", { className: "flex h-12 w-12 items-center justify-center rounded-full bg-gray-100 text-gray-400 dark:bg-gray-800 dark:text-gray-500", children: /* @__PURE__ */ jsx9(Icon, { "aria-hidden": "true", className: "h-6 w-6" }) }),
1389
+ /* @__PURE__ */ jsx9("p", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: title }),
1390
+ hint && /* @__PURE__ */ jsx9("p", { className: "max-w-sm text-sm text-gray-500 dark:text-gray-400", children: hint }),
1391
+ action && /* @__PURE__ */ jsx9("div", { className: "mt-2", children: action })
1138
1392
  ] });
1139
1393
  }
1140
1394
  var SKELETON_ROW = "h-11 animate-pulse rounded-lg bg-gray-100 dark:bg-gray-800";
1141
1395
  function ListSkeleton({ label, rows = 5 }) {
1142
- return /* @__PURE__ */ jsx8("div", { "aria-busy": "true", "aria-label": label, role: "status", className: "space-y-2", children: Array.from({ length: rows }, (_row, index) => /* @__PURE__ */ jsx8("div", { className: SKELETON_ROW }, index)) });
1396
+ return /* @__PURE__ */ jsx9("div", { "aria-busy": "true", "aria-label": label, role: "status", className: "space-y-2", children: Array.from({ length: rows }, (_row, index) => /* @__PURE__ */ jsx9("div", { className: SKELETON_ROW }, index)) });
1143
1397
  }
1144
1398
  function BlockSkeleton({ label }) {
1145
- return /* @__PURE__ */ jsx8(
1399
+ return /* @__PURE__ */ jsx9(
1146
1400
  "div",
1147
1401
  {
1148
1402
  "aria-busy": "true",
@@ -1154,7 +1408,7 @@ function BlockSkeleton({ label }) {
1154
1408
  }
1155
1409
 
1156
1410
  // src/workspace/AgendaArea.tsx
1157
- import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
1411
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
1158
1412
  var DAY_IN_MS = 24 * 60 * 6e4;
1159
1413
  var NOW_TICK_MS = 6e4;
1160
1414
  function startOfWeek(date, weekStartsOn) {
@@ -1177,8 +1431,8 @@ function formatPeriod(days, locale) {
1177
1431
  return `${first.toLocaleDateString(locale, short)} \u2013 ${last.toLocaleDateString(locale, { ...short, year: "numeric" })}`;
1178
1432
  }
1179
1433
  function useNow() {
1180
- const [now, setNow] = useState2(() => /* @__PURE__ */ new Date());
1181
- useEffect2(() => {
1434
+ const [now, setNow] = useState3(() => /* @__PURE__ */ new Date());
1435
+ useEffect3(() => {
1182
1436
  const timer = window.setInterval(() => setNow(/* @__PURE__ */ new Date()), NOW_TICK_MS);
1183
1437
  return () => window.clearInterval(timer);
1184
1438
  }, []);
@@ -1189,10 +1443,10 @@ function AgendaArea() {
1189
1443
  const messages = resolveSchedulingMessages(locale);
1190
1444
  const now = useNow();
1191
1445
  const { data: resourcesPage } = useResources({ active: true, pageSize: MAX_PAGE_SIZE });
1192
- const [resourceId, setResourceId] = useState2("");
1193
- const [view, setView] = useState2("day");
1194
- const [anchorDate, setAnchorDate] = useState2(() => /* @__PURE__ */ new Date());
1195
- const [selectedBookingId, setSelectedBookingId] = useState2(void 0);
1446
+ const [resourceId, setResourceId] = useState3("");
1447
+ const [view, setView] = useState3("day");
1448
+ const [anchorDate, setAnchorDate] = useState3(() => /* @__PURE__ */ new Date());
1449
+ const [selectedBookingId, setSelectedBookingId] = useState3(void 0);
1196
1450
  const resources = resourcesPage?.data ?? [];
1197
1451
  const days = buildVisibleDays(anchorDate, view, weekStartsOn);
1198
1452
  const from = days[0];
@@ -1211,13 +1465,13 @@ function AgendaArea() {
1211
1465
  }
1212
1466
  function renderViewOption(value, label) {
1213
1467
  const isActive = view === value;
1214
- return /* @__PURE__ */ jsx9(
1468
+ return /* @__PURE__ */ jsx10(
1215
1469
  "button",
1216
1470
  {
1217
1471
  type: "button",
1218
1472
  onClick: () => setView(value),
1219
1473
  "aria-pressed": isActive,
1220
- className: `${BUTTON_BASE} flex-1 ${isActive ? "bg-white text-brand-700 shadow-sm dark:bg-gray-900 dark:text-brand-300" : "text-gray-600 dark:text-gray-400"}`,
1474
+ className: `${BUTTON_BASE} flex-1 ${isActive ? "bg-white text-brand-700 shadow-sm dark:bg-gray-900 dark:text-brand-400" : "text-gray-600 dark:text-gray-400"}`,
1221
1475
  children: label
1222
1476
  }
1223
1477
  );
@@ -1225,7 +1479,7 @@ function AgendaArea() {
1225
1479
  return /* @__PURE__ */ jsxs7("div", { className: "flex flex-1 min-h-0 min-w-0", children: [
1226
1480
  /* @__PURE__ */ jsxs7("div", { className: "flex flex-1 min-h-0 min-w-0 flex-col gap-4 overflow-y-auto p-4", children: [
1227
1481
  /* @__PURE__ */ jsxs7("div", { className: "flex flex-wrap items-end gap-3", children: [
1228
- /* @__PURE__ */ jsx9(
1482
+ /* @__PURE__ */ jsx10(
1229
1483
  ResourceSelect,
1230
1484
  {
1231
1485
  label: messages["agenda.resourceLabel"],
@@ -1236,29 +1490,29 @@ function AgendaArea() {
1236
1490
  }
1237
1491
  ),
1238
1492
  /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-1", children: [
1239
- /* @__PURE__ */ jsx9(
1493
+ /* @__PURE__ */ jsx10(
1240
1494
  "button",
1241
1495
  {
1242
1496
  type: "button",
1243
1497
  "aria-label": messages["agenda.previous"],
1244
1498
  onClick: () => shiftAnchor(-1),
1245
1499
  className: ICON_BUTTON,
1246
- children: /* @__PURE__ */ jsx9(ChevronLeft, { "aria-hidden": "true", className: "h-4 w-4" })
1500
+ children: /* @__PURE__ */ jsx10(ChevronLeft, { "aria-hidden": "true", className: "h-4 w-4" })
1247
1501
  }
1248
1502
  ),
1249
- /* @__PURE__ */ jsx9("button", { type: "button", onClick: () => setAnchorDate(/* @__PURE__ */ new Date()), className: BUTTON_SECONDARY, children: messages["agenda.today"] }),
1250
- /* @__PURE__ */ jsx9(
1503
+ /* @__PURE__ */ jsx10("button", { type: "button", onClick: () => setAnchorDate(/* @__PURE__ */ new Date()), className: BUTTON_SECONDARY, children: messages["agenda.today"] }),
1504
+ /* @__PURE__ */ jsx10(
1251
1505
  "button",
1252
1506
  {
1253
1507
  type: "button",
1254
1508
  "aria-label": messages["agenda.next"],
1255
1509
  onClick: () => shiftAnchor(1),
1256
1510
  className: ICON_BUTTON,
1257
- children: /* @__PURE__ */ jsx9(ChevronRight, { "aria-hidden": "true", className: "h-4 w-4" })
1511
+ children: /* @__PURE__ */ jsx10(ChevronRight, { "aria-hidden": "true", className: "h-4 w-4" })
1258
1512
  }
1259
1513
  )
1260
1514
  ] }),
1261
- /* @__PURE__ */ jsx9(
1515
+ /* @__PURE__ */ jsx10(
1262
1516
  "p",
1263
1517
  {
1264
1518
  "aria-live": "polite",
@@ -1267,18 +1521,18 @@ function AgendaArea() {
1267
1521
  }
1268
1522
  ),
1269
1523
  /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-1", children: [
1270
- /* @__PURE__ */ jsx9("span", { className: FIELD_LABEL, children: messages["agenda.viewLabel"] }),
1524
+ /* @__PURE__ */ jsx10("span", { className: FIELD_LABEL, children: messages["agenda.viewLabel"] }),
1271
1525
  /* @__PURE__ */ jsxs7("div", { className: "flex gap-1 rounded-lg bg-gray-100 p-1 dark:bg-gray-800", children: [
1272
1526
  renderViewOption("day", messages["agenda.viewDay"]),
1273
1527
  renderViewOption("week", messages["agenda.viewWeek"])
1274
1528
  ] })
1275
1529
  ] })
1276
1530
  ] }),
1277
- isError && /* @__PURE__ */ jsx9(ErrorBanner, { message: messages["common.loadFailure"] }),
1278
- bookingsPage && bookingsPage.total > bookingsPage.data.length && /* @__PURE__ */ jsx9("p", { className: "rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800 dark:border-amber-900 dark:bg-amber-950/50 dark:text-amber-200", children: messages["agenda.moreResults"] }),
1279
- isLoading && /* @__PURE__ */ jsx9(BlockSkeleton, { label: messages["common.loading"] }),
1280
- !isLoading && !isError && visibleBookings.length === 0 && /* @__PURE__ */ jsx9(EmptyState, { icon: CalendarDays, title: messages["agenda.emptyTitle"], hint: messages["agenda.empty"] }),
1281
- !isLoading && visibleBookings.length > 0 && /* @__PURE__ */ jsx9(
1531
+ isError && /* @__PURE__ */ jsx10(ErrorBanner, { message: messages["common.loadFailure"] }),
1532
+ bookingsPage && bookingsPage.total > bookingsPage.data.length && /* @__PURE__ */ jsx10("p", { className: "rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-800 dark:border-amber-900 dark:bg-amber-950/50 dark:text-amber-200", children: messages["agenda.moreResults"] }),
1533
+ isLoading && /* @__PURE__ */ jsx10(BlockSkeleton, { label: messages["common.loading"] }),
1534
+ !isLoading && !isError && visibleBookings.length === 0 && /* @__PURE__ */ jsx10(EmptyState, { icon: CalendarDays, title: messages["agenda.emptyTitle"], hint: messages["agenda.empty"] }),
1535
+ !isLoading && visibleBookings.length > 0 && /* @__PURE__ */ jsx10(
1282
1536
  AgendaGrid,
1283
1537
  {
1284
1538
  bookings: visibleBookings,
@@ -1288,7 +1542,7 @@ function AgendaArea() {
1288
1542
  }
1289
1543
  )
1290
1544
  ] }),
1291
- selectedBooking && /* @__PURE__ */ jsx9(
1545
+ selectedBooking && /* @__PURE__ */ jsx10(
1292
1546
  BookingDrawer,
1293
1547
  {
1294
1548
  booking: selectedBooking,
@@ -1302,13 +1556,13 @@ function AgendaArea() {
1302
1556
 
1303
1557
  // src/workspace/AvailabilityArea.tsx
1304
1558
  import { Clock } from "lucide-react";
1305
- import { useState as useState5 } from "react";
1559
+ import { useState as useState6 } from "react";
1306
1560
  import { MAX_PAGE_SIZE as MAX_PAGE_SIZE2 } from "@adatechnology/scheduling-contracts";
1307
1561
 
1308
1562
  // src/components/WeeklyRulesEditor.tsx
1309
1563
  import { Plus, Trash2 } from "lucide-react";
1310
- import { useState as useState3 } from "react";
1311
- import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
1564
+ import { useState as useState4, useMemo as useMemo5 } from "react";
1565
+ import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
1312
1566
  var WEEKDAYS = [0, 1, 2, 3, 4, 5, 6];
1313
1567
  function toDraft(rule) {
1314
1568
  return { weekday: rule.weekday, startsAtLocal: rule.startsAtLocal, endsAtLocal: rule.endsAtLocal };
@@ -1319,9 +1573,16 @@ function createEmptyDraft() {
1319
1573
  function WeeklyRulesEditor({ resourceId }) {
1320
1574
  const { locale } = useSchedulingConfig();
1321
1575
  const messages = resolveSchedulingMessages(locale);
1576
+ const weekdayOptions = useMemo5(
1577
+ () => WEEKDAYS.map((weekday) => ({
1578
+ value: String(weekday),
1579
+ label: messages[`availability.weekday.${weekday}`]
1580
+ })),
1581
+ [messages]
1582
+ );
1322
1583
  const { data, isSuccess: isRulesLoaded, isError: isRulesLoadError } = useAvailabilityRules(resourceId);
1323
1584
  const setAvailabilityRules = useSetAvailabilityRules();
1324
- const [draft, setDraft] = useState3(void 0);
1585
+ const [draft, setDraft] = useState4(void 0);
1325
1586
  const rules = draft ?? (data ? data.map(toDraft) : []);
1326
1587
  function updateRule(index, patch) {
1327
1588
  setDraft(rules.map((rule, ruleIndex) => ruleIndex === index ? { ...rule, ...patch } : rule));
@@ -1344,31 +1605,31 @@ function WeeklyRulesEditor({ resourceId }) {
1344
1605
  }
1345
1606
  if (isRulesLoadError) {
1346
1607
  return /* @__PURE__ */ jsxs8("section", { className: "space-y-3", children: [
1347
- /* @__PURE__ */ jsx10("h3", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: messages["availability.weeklyRulesTitle"] }),
1348
- /* @__PURE__ */ jsx10("p", { role: "alert", className: "text-sm text-red-700 bg-red-50 rounded-lg px-3 py-2", children: messages["common.loadFailure"] })
1608
+ /* @__PURE__ */ jsx11("h3", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: messages["availability.weeklyRulesTitle"] }),
1609
+ /* @__PURE__ */ jsx11("p", { role: "alert", className: "text-sm text-red-700 bg-red-50 rounded-lg px-3 py-2", children: messages["common.loadFailure"] })
1349
1610
  ] });
1350
1611
  }
1351
1612
  if (!isRulesLoaded) {
1352
1613
  return /* @__PURE__ */ jsxs8("section", { className: "space-y-3", children: [
1353
- /* @__PURE__ */ jsx10("h3", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: messages["availability.weeklyRulesTitle"] }),
1354
- /* @__PURE__ */ jsx10("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.loading"] })
1614
+ /* @__PURE__ */ jsx11("h3", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: messages["availability.weeklyRulesTitle"] }),
1615
+ /* @__PURE__ */ jsx11("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.loading"] })
1355
1616
  ] });
1356
1617
  }
1357
1618
  return /* @__PURE__ */ jsxs8("section", { className: "space-y-3", children: [
1358
- /* @__PURE__ */ jsx10("h3", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: messages["availability.weeklyRulesTitle"] }),
1359
- setAvailabilityRules.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"] }),
1360
- /* @__PURE__ */ jsx10("ul", { className: "space-y-2", children: rules.map((rule, index) => /* @__PURE__ */ jsxs8("li", { className: "flex items-center gap-2", children: [
1361
- /* @__PURE__ */ jsx10(
1362
- "select",
1619
+ /* @__PURE__ */ jsx11("h3", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: messages["availability.weeklyRulesTitle"] }),
1620
+ setAvailabilityRules.isError && /* @__PURE__ */ jsx11("p", { role: "alert", className: "text-sm text-red-700 bg-red-50 rounded-lg px-3 py-2", children: messages["common.actionFailure"] }),
1621
+ /* @__PURE__ */ jsx11("ul", { className: "space-y-2", children: rules.map((rule, index) => /* @__PURE__ */ jsxs8("li", { className: "flex items-center gap-2", children: [
1622
+ /* @__PURE__ */ jsx11(
1623
+ SelectField,
1363
1624
  {
1364
- "aria-label": messages["availability.weekdayLabel"],
1365
- value: rule.weekday,
1366
- onChange: (event) => updateRule(index, { weekday: Number(event.target.value) }),
1367
- className: "min-h-11 rounded-lg border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 text-sm",
1368
- children: WEEKDAYS.map((weekday) => /* @__PURE__ */ jsx10("option", { value: weekday, children: messages[`availability.weekday.${weekday}`] }, weekday))
1625
+ hideLabel: true,
1626
+ label: messages["availability.weekdayLabel"],
1627
+ value: String(rule.weekday),
1628
+ options: weekdayOptions,
1629
+ onChange: (next) => updateRule(index, { weekday: Number(next) })
1369
1630
  }
1370
1631
  ),
1371
- /* @__PURE__ */ jsx10(
1632
+ /* @__PURE__ */ jsx11(
1372
1633
  "input",
1373
1634
  {
1374
1635
  "aria-label": messages["availability.startsAtLocal"],
@@ -1378,7 +1639,7 @@ function WeeklyRulesEditor({ resourceId }) {
1378
1639
  className: "min-h-11 rounded-lg border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 text-sm"
1379
1640
  }
1380
1641
  ),
1381
- /* @__PURE__ */ jsx10(
1642
+ /* @__PURE__ */ jsx11(
1382
1643
  "input",
1383
1644
  {
1384
1645
  "aria-label": messages["availability.endsAtLocal"],
@@ -1388,14 +1649,14 @@ function WeeklyRulesEditor({ resourceId }) {
1388
1649
  className: "min-h-11 rounded-lg border border-gray-300 dark:border-gray-700 bg-white dark:bg-gray-900 px-2 text-sm"
1389
1650
  }
1390
1651
  ),
1391
- /* @__PURE__ */ jsx10(
1652
+ /* @__PURE__ */ jsx11(
1392
1653
  "button",
1393
1654
  {
1394
1655
  type: "button",
1395
1656
  onClick: () => removeRule(index),
1396
1657
  "aria-label": messages["availability.removeRule"],
1397
1658
  className: "min-h-11 min-w-11 inline-flex items-center justify-center rounded-lg text-red-700 hover:bg-red-50",
1398
- children: /* @__PURE__ */ jsx10(Trash2, { "aria-hidden": "true", className: "w-4 h-4" })
1659
+ children: /* @__PURE__ */ jsx11(Trash2, { "aria-hidden": "true", className: "w-4 h-4" })
1399
1660
  }
1400
1661
  )
1401
1662
  ] }, index)) }),
@@ -1407,12 +1668,12 @@ function WeeklyRulesEditor({ resourceId }) {
1407
1668
  onClick: addRule,
1408
1669
  className: "inline-flex items-center gap-2 min-h-11 px-3 py-2 rounded-lg text-sm font-medium border border-gray-300 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800",
1409
1670
  children: [
1410
- /* @__PURE__ */ jsx10(Plus, { "aria-hidden": "true", className: "w-4 h-4" }),
1671
+ /* @__PURE__ */ jsx11(Plus, { "aria-hidden": "true", className: "w-4 h-4" }),
1411
1672
  messages["availability.addRule"]
1412
1673
  ]
1413
1674
  }
1414
1675
  ),
1415
- /* @__PURE__ */ jsx10(
1676
+ /* @__PURE__ */ jsx11(
1416
1677
  "button",
1417
1678
  {
1418
1679
  type: "button",
@@ -1428,21 +1689,28 @@ function WeeklyRulesEditor({ resourceId }) {
1428
1689
 
1429
1690
  // src/components/AvailabilityExceptionsEditor.tsx
1430
1691
  import { Plus as Plus2, Trash2 as Trash22 } from "lucide-react";
1431
- import { useState as useState4 } from "react";
1692
+ import { useState as useState5, useMemo as useMemo6 } from "react";
1432
1693
  import { AVAILABILITY_EXCEPTION_KIND } from "@adatechnology/scheduling-contracts";
1433
- import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
1694
+ import { jsx as jsx12, jsxs as jsxs9 } from "react/jsx-runtime";
1434
1695
  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";
1435
1696
  function AvailabilityExceptionsEditor({ resourceId, timezone }) {
1436
1697
  const { locale } = useSchedulingConfig();
1437
1698
  const messages = resolveSchedulingMessages(locale);
1699
+ const kindOptions = useMemo6(
1700
+ () => [
1701
+ { value: AVAILABILITY_EXCEPTION_KIND.BLOCK, label: messages["availability.exceptionKind.blocked"] },
1702
+ { value: AVAILABILITY_EXCEPTION_KIND.EXTRA, label: messages["availability.exceptionKind.extra"] }
1703
+ ],
1704
+ [messages]
1705
+ );
1438
1706
  const { data, isLoading, isError: isLoadError } = useAvailabilityExceptions(resourceId);
1439
1707
  const addException = useAddAvailabilityException();
1440
1708
  const removeException = useRemoveAvailabilityException();
1441
1709
  const emptyValue = () => formatDateTimeLocalInTimeZone(/* @__PURE__ */ new Date(), timezone);
1442
- const [from, setFrom] = useState4(emptyValue);
1443
- const [until, setUntil] = useState4(emptyValue);
1444
- const [kind, setKind] = useState4(AVAILABILITY_EXCEPTION_KIND.BLOCK);
1445
- const [reason, setReason] = useState4("");
1710
+ const [from, setFrom] = useState5(emptyValue);
1711
+ const [until, setUntil] = useState5(emptyValue);
1712
+ const [kind, setKind] = useState5(AVAILABILITY_EXCEPTION_KIND.BLOCK);
1713
+ const [reason, setReason] = useState5("");
1446
1714
  async function handleAdd() {
1447
1715
  if (!from || !until) return;
1448
1716
  try {
@@ -1462,11 +1730,11 @@ function AvailabilityExceptionsEditor({ resourceId, timezone }) {
1462
1730
  }
1463
1731
  }
1464
1732
  return /* @__PURE__ */ jsxs9("section", { className: "space-y-3", children: [
1465
- /* @__PURE__ */ jsx11("h3", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: messages["availability.exceptionsTitle"] }),
1466
- (addException.isError || removeException.isError) && /* @__PURE__ */ jsx11("p", { role: "alert", className: "text-sm text-red-700 bg-red-50 rounded-lg px-3 py-2", children: messages["common.actionFailure"] }),
1467
- isLoadError && /* @__PURE__ */ jsx11("p", { role: "alert", className: "text-sm text-red-700 bg-red-50 rounded-lg px-3 py-2", children: messages["common.loadFailure"] }),
1468
- isLoading && /* @__PURE__ */ jsx11("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.loading"] }),
1469
- /* @__PURE__ */ jsx11("ul", { className: "space-y-2", children: (data ?? []).map((exception) => /* @__PURE__ */ jsxs9("li", { className: "flex items-center gap-2 text-sm", children: [
1733
+ /* @__PURE__ */ jsx12("h3", { className: "text-sm font-semibold text-gray-900 dark:text-gray-100", children: messages["availability.exceptionsTitle"] }),
1734
+ (addException.isError || removeException.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"] }),
1735
+ isLoadError && /* @__PURE__ */ jsx12("p", { role: "alert", className: "text-sm text-red-700 bg-red-50 rounded-lg px-3 py-2", children: messages["common.loadFailure"] }),
1736
+ isLoading && /* @__PURE__ */ jsx12("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.loading"] }),
1737
+ /* @__PURE__ */ jsx12("ul", { className: "space-y-2", children: (data ?? []).map((exception) => /* @__PURE__ */ jsxs9("li", { className: "flex items-center gap-2 text-sm", children: [
1470
1738
  /* @__PURE__ */ jsxs9("span", { className: "flex-1", children: [
1471
1739
  messages[`availability.exceptionKind.${exception.kind === "block" ? "blocked" : "extra"}`],
1472
1740
  " \u2014",
@@ -1476,19 +1744,19 @@ function AvailabilityExceptionsEditor({ resourceId, timezone }) {
1476
1744
  exception.during.end.toLocaleString(locale),
1477
1745
  exception.reason ? ` (${exception.reason})` : ""
1478
1746
  ] }),
1479
- /* @__PURE__ */ jsx11(
1747
+ /* @__PURE__ */ jsx12(
1480
1748
  "button",
1481
1749
  {
1482
1750
  type: "button",
1483
1751
  onClick: () => removeException.mutate({ id: exception.id, resourceId }),
1484
1752
  "aria-label": messages["availability.removeException"],
1485
1753
  className: "min-h-11 min-w-11 inline-flex items-center justify-center rounded-lg text-red-700 hover:bg-red-50",
1486
- children: /* @__PURE__ */ jsx11(Trash22, { "aria-hidden": "true", className: "w-4 h-4" })
1754
+ children: /* @__PURE__ */ jsx12(Trash22, { "aria-hidden": "true", className: "w-4 h-4" })
1487
1755
  }
1488
1756
  )
1489
1757
  ] }, exception.id)) }),
1490
1758
  /* @__PURE__ */ jsxs9("div", { className: "flex flex-wrap items-center gap-2", children: [
1491
- /* @__PURE__ */ jsx11(
1759
+ /* @__PURE__ */ jsx12(
1492
1760
  DateTimeField,
1493
1761
  {
1494
1762
  label: messages["availability.exceptionFrom"],
@@ -1496,7 +1764,7 @@ function AvailabilityExceptionsEditor({ resourceId, timezone }) {
1496
1764
  onChange: setFrom
1497
1765
  }
1498
1766
  ),
1499
- /* @__PURE__ */ jsx11(
1767
+ /* @__PURE__ */ jsx12(
1500
1768
  DateTimeField,
1501
1769
  {
1502
1770
  label: messages["availability.exceptionUntil"],
@@ -1504,20 +1772,17 @@ function AvailabilityExceptionsEditor({ resourceId, timezone }) {
1504
1772
  onChange: setUntil
1505
1773
  }
1506
1774
  ),
1507
- /* @__PURE__ */ jsxs9(
1508
- "select",
1775
+ /* @__PURE__ */ jsx12(
1776
+ SelectField,
1509
1777
  {
1510
- "aria-label": messages["availability.exceptionKind.blocked"],
1778
+ hideLabel: true,
1779
+ label: messages["availability.exceptionsTitle"],
1511
1780
  value: kind,
1512
- onChange: (event) => setKind(event.target.value),
1513
- className: SELECT_CLASS,
1514
- children: [
1515
- /* @__PURE__ */ jsx11("option", { value: AVAILABILITY_EXCEPTION_KIND.BLOCK, children: messages["availability.exceptionKind.blocked"] }),
1516
- /* @__PURE__ */ jsx11("option", { value: AVAILABILITY_EXCEPTION_KIND.EXTRA, children: messages["availability.exceptionKind.extra"] })
1517
- ]
1781
+ options: kindOptions,
1782
+ onChange: (next) => setKind(next)
1518
1783
  }
1519
1784
  ),
1520
- /* @__PURE__ */ jsx11(
1785
+ /* @__PURE__ */ jsx12(
1521
1786
  "input",
1522
1787
  {
1523
1788
  "aria-label": messages["availability.exceptionReason"],
@@ -1536,7 +1801,7 @@ function AvailabilityExceptionsEditor({ resourceId, timezone }) {
1536
1801
  disabled: addException.isPending,
1537
1802
  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",
1538
1803
  children: [
1539
- /* @__PURE__ */ jsx11(Plus2, { "aria-hidden": "true", className: "w-4 h-4" }),
1804
+ /* @__PURE__ */ jsx12(Plus2, { "aria-hidden": "true", className: "w-4 h-4" }),
1540
1805
  messages["availability.addException"]
1541
1806
  ]
1542
1807
  }
@@ -1546,7 +1811,7 @@ function AvailabilityExceptionsEditor({ resourceId, timezone }) {
1546
1811
  }
1547
1812
 
1548
1813
  // src/components/AvailabilityEditor.tsx
1549
- import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
1814
+ import { jsx as jsx13, jsxs as jsxs10 } from "react/jsx-runtime";
1550
1815
  function AvailabilityEditor({ resourceId, timezone }) {
1551
1816
  const { locale } = useSchedulingConfig();
1552
1817
  const messages = resolveSchedulingMessages(locale);
@@ -1558,22 +1823,22 @@ function AvailabilityEditor({ resourceId, timezone }) {
1558
1823
  ] }),
1559
1824
  timezone
1560
1825
  ] }),
1561
- /* @__PURE__ */ jsx12(WeeklyRulesEditor, { resourceId }),
1562
- /* @__PURE__ */ jsx12(AvailabilityExceptionsEditor, { resourceId, timezone })
1826
+ /* @__PURE__ */ jsx13(WeeklyRulesEditor, { resourceId }),
1827
+ /* @__PURE__ */ jsx13(AvailabilityExceptionsEditor, { resourceId, timezone })
1563
1828
  ] });
1564
1829
  }
1565
1830
 
1566
1831
  // src/workspace/AvailabilityArea.tsx
1567
- import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
1832
+ import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
1568
1833
  function AvailabilityArea() {
1569
1834
  const { locale } = useSchedulingConfig();
1570
1835
  const messages = resolveSchedulingMessages(locale);
1571
1836
  const { data, isLoading, isError } = useResources({ active: true, pageSize: MAX_PAGE_SIZE2 });
1572
- const [resourceId, setResourceId] = useState5("");
1837
+ const [resourceId, setResourceId] = useState6("");
1573
1838
  const resources = data?.data ?? [];
1574
1839
  const selectedResource = resources.find((resource) => resource.id === resourceId);
1575
1840
  return /* @__PURE__ */ jsxs11("div", { className: "flex flex-1 min-h-0 min-w-0 flex-col gap-4 overflow-y-auto p-4", children: [
1576
- /* @__PURE__ */ jsx13(
1841
+ /* @__PURE__ */ jsx14(
1577
1842
  ResourceSelect,
1578
1843
  {
1579
1844
  label: messages["agenda.resourceLabel"],
@@ -1583,9 +1848,9 @@ function AvailabilityArea() {
1583
1848
  onChange: setResourceId
1584
1849
  }
1585
1850
  ),
1586
- isError && /* @__PURE__ */ jsx13(ErrorBanner, { message: messages["common.loadFailure"] }),
1587
- isLoading && /* @__PURE__ */ jsx13(ListSkeleton, { label: messages["common.loading"], rows: 3 }),
1588
- !isLoading && !isError && !selectedResource && /* @__PURE__ */ jsx13(
1851
+ isError && /* @__PURE__ */ jsx14(ErrorBanner, { message: messages["common.loadFailure"] }),
1852
+ isLoading && /* @__PURE__ */ jsx14(ListSkeleton, { label: messages["common.loading"], rows: 3 }),
1853
+ !isLoading && !isError && !selectedResource && /* @__PURE__ */ jsx14(
1589
1854
  EmptyState,
1590
1855
  {
1591
1856
  icon: Clock,
@@ -1593,7 +1858,7 @@ function AvailabilityArea() {
1593
1858
  hint: messages["availability.selectResourceHint"]
1594
1859
  }
1595
1860
  ),
1596
- selectedResource && /* @__PURE__ */ jsx13(
1861
+ selectedResource && /* @__PURE__ */ jsx14(
1597
1862
  AvailabilityEditor,
1598
1863
  {
1599
1864
  resourceId: selectedResource.id,
@@ -1606,12 +1871,12 @@ function AvailabilityArea() {
1606
1871
 
1607
1872
  // src/workspace/BookingsArea.tsx
1608
1873
  import { ClipboardList } from "lucide-react";
1609
- import { useState as useState8 } from "react";
1874
+ import { useState as useState9 } from "react";
1610
1875
  import { MAX_PAGE_SIZE as MAX_PAGE_SIZE3 } from "@adatechnology/scheduling-contracts";
1611
1876
 
1612
1877
  // src/components/BookingsTable.tsx
1613
1878
  import { ArrowDown, ArrowLeft, ArrowRight, ArrowUp, ArrowUpDown } from "lucide-react";
1614
- import { useState as useState6 } from "react";
1879
+ import { useState as useState7 } from "react";
1615
1880
  import { BOOKING_STATUS as BOOKING_STATUS4 } from "@adatechnology/scheduling-contracts";
1616
1881
 
1617
1882
  // src/components/bookingsTableState.util.ts
@@ -1661,7 +1926,7 @@ function filterBookingsByStatus(bookings, statusFilters) {
1661
1926
  }
1662
1927
 
1663
1928
  // src/components/BookingsTable.tsx
1664
- import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
1929
+ import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
1665
1930
  var ALL_STATUSES = Object.values(BOOKING_STATUS4);
1666
1931
  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";
1667
1932
  var CHECKBOX_CELL_CLASS = "px-3 py-2";
@@ -1680,7 +1945,7 @@ function BookingsTable({
1680
1945
  }) {
1681
1946
  const { locale } = useSchedulingConfig();
1682
1947
  const messages = resolveSchedulingMessages(locale);
1683
- const [selected, setSelected] = useState6(/* @__PURE__ */ new Set());
1948
+ const [selected, setSelected] = useState7(/* @__PURE__ */ new Set());
1684
1949
  const visibleBookings = filterBookingsByStatus(bookings, state.statusFilters);
1685
1950
  const allSelected = visibleBookings.length > 0 && visibleBookings.every((booking) => selected.has(booking.id));
1686
1951
  function toggleSort(column) {
@@ -1710,12 +1975,12 @@ function BookingsTable({
1710
1975
  setSelected(next);
1711
1976
  }
1712
1977
  function renderSortIcon(column) {
1713
- if (state.sortColumn !== column) return /* @__PURE__ */ jsx14(ArrowUpDown, { "aria-hidden": "true", className: "w-3 h-3" });
1714
- return state.sortDirection === "asc" ? /* @__PURE__ */ jsx14(ArrowUp, { "aria-hidden": "true", className: "w-3 h-3" }) : /* @__PURE__ */ jsx14(ArrowDown, { "aria-hidden": "true", className: "w-3 h-3" });
1978
+ if (state.sortColumn !== column) return /* @__PURE__ */ jsx15(ArrowUpDown, { "aria-hidden": "true", className: "w-3 h-3" });
1979
+ return state.sortDirection === "asc" ? /* @__PURE__ */ jsx15(ArrowUp, { "aria-hidden": "true", className: "w-3 h-3" }) : /* @__PURE__ */ jsx15(ArrowDown, { "aria-hidden": "true", className: "w-3 h-3" });
1715
1980
  }
1716
1981
  function renderHeader(column, labelKey) {
1717
1982
  const ariaSort = state.sortColumn !== column ? "none" : state.sortDirection === "asc" ? "ascending" : "descending";
1718
- return /* @__PURE__ */ jsx14("th", { scope: "col", className: "px-3 py-2", "aria-sort": ariaSort, children: /* @__PURE__ */ jsxs12("button", { type: "button", onClick: () => toggleSort(column), className: HEADER_BUTTON_CLASS, children: [
1983
+ return /* @__PURE__ */ jsx15("th", { scope: "col", className: "px-3 py-2", "aria-sort": ariaSort, children: /* @__PURE__ */ jsxs12("button", { type: "button", onClick: () => toggleSort(column), className: HEADER_BUTTON_CLASS, children: [
1719
1984
  messages[labelKey],
1720
1985
  renderSortIcon(column)
1721
1986
  ] }) });
@@ -1723,7 +1988,7 @@ function BookingsTable({
1723
1988
  return /* @__PURE__ */ jsxs12("div", { className: "space-y-3", children: [
1724
1989
  /* @__PURE__ */ jsxs12("div", { className: "flex flex-wrap items-center gap-3", children: [
1725
1990
  /* @__PURE__ */ jsxs12("fieldset", { className: "flex flex-wrap items-center gap-2", children: [
1726
- /* @__PURE__ */ jsx14("legend", { className: "sr-only", children: messages["booking.filterByStatus"] }),
1991
+ /* @__PURE__ */ jsx15("legend", { className: "sr-only", children: messages["booking.filterByStatus"] }),
1727
1992
  ALL_STATUSES.map((status) => {
1728
1993
  const isActive = state.statusFilters.includes(status);
1729
1994
  return /* @__PURE__ */ jsxs12(
@@ -1731,7 +1996,7 @@ function BookingsTable({
1731
1996
  {
1732
1997
  className: `flex cursor-pointer items-center gap-1.5 rounded-full border px-3 py-1.5 text-sm transition-colors ${isActive ? "border-brand-500 bg-brand-50 text-brand-800 dark:bg-brand-900/40 dark:text-brand-200" : "border-gray-300 text-gray-600 hover:bg-gray-50 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-800"}`,
1733
1998
  children: [
1734
- /* @__PURE__ */ jsx14(
1999
+ /* @__PURE__ */ jsx15(
1735
2000
  "input",
1736
2001
  {
1737
2002
  type: "checkbox",
@@ -1747,17 +2012,17 @@ function BookingsTable({
1747
2012
  );
1748
2013
  })
1749
2014
  ] }),
1750
- !isBookingsTableStateDefault(state) && /* @__PURE__ */ jsx14(
2015
+ !isBookingsTableStateDefault(state) && /* @__PURE__ */ jsx15(
1751
2016
  "button",
1752
2017
  {
1753
2018
  type: "button",
1754
2019
  onClick: () => onStateChange?.(DEFAULT_BOOKINGS_TABLE_STATE),
1755
- className: "min-h-11 px-3 text-sm font-medium text-brand-700 hover:underline dark:text-brand-300",
2020
+ className: "min-h-11 px-3 text-sm font-medium text-brand-700 hover:underline dark:text-brand-400",
1756
2021
  children: messages["common.clearFilters"]
1757
2022
  }
1758
2023
  )
1759
2024
  ] }),
1760
- selected.size > 0 && bulkActions.length > 0 && /* @__PURE__ */ jsx14("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__ */ jsx14(
2025
+ selected.size > 0 && bulkActions.length > 0 && /* @__PURE__ */ jsx15("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__ */ jsx15(
1761
2026
  "button",
1762
2027
  {
1763
2028
  type: "button",
@@ -1769,8 +2034,8 @@ function BookingsTable({
1769
2034
  )) }),
1770
2035
  /* @__PURE__ */ jsxs12("div", { className: `${SURFACE_BORDER} overflow-x-auto`, children: [
1771
2036
  /* @__PURE__ */ jsxs12("table", { className: "min-w-full text-sm", children: [
1772
- /* @__PURE__ */ jsx14("thead", { className: "border-b border-gray-200 bg-gray-50 dark:border-gray-800 dark:bg-gray-800/60", children: /* @__PURE__ */ jsxs12("tr", { children: [
1773
- /* @__PURE__ */ jsx14("th", { scope: "col", className: CHECKBOX_CELL_CLASS, children: /* @__PURE__ */ jsx14(
2037
+ /* @__PURE__ */ jsx15("thead", { className: "border-b border-gray-200 bg-gray-50 dark:border-gray-800 dark:bg-gray-800/60", children: /* @__PURE__ */ jsxs12("tr", { children: [
2038
+ /* @__PURE__ */ jsx15("th", { scope: "col", className: CHECKBOX_CELL_CLASS, children: /* @__PURE__ */ jsx15(
1774
2039
  "input",
1775
2040
  {
1776
2041
  type: "checkbox",
@@ -1784,12 +2049,12 @@ function BookingsTable({
1784
2049
  renderHeader("startsAt", "booking.column.startsAt"),
1785
2050
  renderHeader("endsAt", "booking.column.endsAt")
1786
2051
  ] }) }),
1787
- /* @__PURE__ */ jsx14("tbody", { children: visibleBookings.map((booking, index) => /* @__PURE__ */ jsxs12(
2052
+ /* @__PURE__ */ jsx15("tbody", { children: visibleBookings.map((booking, index) => /* @__PURE__ */ jsxs12(
1788
2053
  "tr",
1789
2054
  {
1790
2055
  className: `${index % 2 === 1 ? ROW_STRIPE : ""} hover:bg-brand-50/50 dark:hover:bg-brand-900/10`,
1791
2056
  children: [
1792
- /* @__PURE__ */ jsx14("td", { className: CHECKBOX_CELL_CLASS, children: /* @__PURE__ */ jsx14(
2057
+ /* @__PURE__ */ jsx15("td", { className: CHECKBOX_CELL_CLASS, children: /* @__PURE__ */ jsx15(
1793
2058
  "input",
1794
2059
  {
1795
2060
  type: "checkbox",
@@ -1798,19 +2063,19 @@ function BookingsTable({
1798
2063
  onChange: () => toggleRowSelected(booking.id)
1799
2064
  }
1800
2065
  ) }),
1801
- /* @__PURE__ */ jsx14("td", { className: "px-3 py-2", children: /* @__PURE__ */ jsx14("button", { type: "button", onClick: () => onRowClick?.(booking), className: "min-h-11 text-left hover:underline", children: booking.title }) }),
1802
- /* @__PURE__ */ jsx14("td", { className: "px-3 py-2", children: /* @__PURE__ */ jsx14(BookingStatusBadge, { status: booking.status }) }),
1803
- /* @__PURE__ */ jsx14("td", { className: "px-3 py-2 tabular-nums whitespace-nowrap", children: booking.startsAt.toLocaleString(locale) }),
1804
- /* @__PURE__ */ jsx14("td", { className: "px-3 py-2 tabular-nums whitespace-nowrap", children: booking.endsAt.toLocaleString(locale) })
2066
+ /* @__PURE__ */ jsx15("td", { className: "px-3 py-2", children: /* @__PURE__ */ jsx15("button", { type: "button", onClick: () => onRowClick?.(booking), className: "min-h-11 text-left hover:underline", children: booking.title }) }),
2067
+ /* @__PURE__ */ jsx15("td", { className: "px-3 py-2", children: /* @__PURE__ */ jsx15(BookingStatusBadge, { status: booking.status }) }),
2068
+ /* @__PURE__ */ jsx15("td", { className: "px-3 py-2 tabular-nums whitespace-nowrap", children: booking.startsAt.toLocaleString(locale) }),
2069
+ /* @__PURE__ */ jsx15("td", { className: "px-3 py-2 tabular-nums whitespace-nowrap", children: booking.endsAt.toLocaleString(locale) })
1805
2070
  ]
1806
2071
  },
1807
2072
  booking.id
1808
2073
  )) })
1809
2074
  ] }),
1810
- visibleBookings.length === 0 && /* @__PURE__ */ jsx14("p", { className: "px-3 py-8 text-center text-sm text-gray-500 dark:text-gray-400", children: messages["common.empty"] })
2075
+ visibleBookings.length === 0 && /* @__PURE__ */ jsx15("p", { className: "px-3 py-8 text-center text-sm text-gray-500 dark:text-gray-400", children: messages["common.empty"] })
1811
2076
  ] }),
1812
2077
  pagination && pagination.totalPages > 1 && /* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-end gap-3", children: [
1813
- /* @__PURE__ */ jsx14(
2078
+ /* @__PURE__ */ jsx15(
1814
2079
  "button",
1815
2080
  {
1816
2081
  type: "button",
@@ -1818,7 +2083,7 @@ function BookingsTable({
1818
2083
  disabled: state.page <= 1,
1819
2084
  onClick: () => goToPage(state.page - 1),
1820
2085
  className: ICON_BUTTON,
1821
- children: /* @__PURE__ */ jsx14(ArrowLeft, { "aria-hidden": "true", className: "w-4 h-4" })
2086
+ children: /* @__PURE__ */ jsx15(ArrowLeft, { "aria-hidden": "true", className: "w-4 h-4" })
1822
2087
  }
1823
2088
  ),
1824
2089
  /* @__PURE__ */ jsxs12("span", { className: "text-sm tabular-nums text-gray-500 dark:text-gray-400", children: [
@@ -1826,7 +2091,7 @@ function BookingsTable({
1826
2091
  " / ",
1827
2092
  pagination.totalPages
1828
2093
  ] }),
1829
- /* @__PURE__ */ jsx14(
2094
+ /* @__PURE__ */ jsx15(
1830
2095
  "button",
1831
2096
  {
1832
2097
  type: "button",
@@ -1834,7 +2099,7 @@ function BookingsTable({
1834
2099
  disabled: state.page >= pagination.totalPages,
1835
2100
  onClick: () => goToPage(state.page + 1),
1836
2101
  className: ICON_BUTTON,
1837
- children: /* @__PURE__ */ jsx14(ArrowRight, { "aria-hidden": "true", className: "w-4 h-4" })
2102
+ children: /* @__PURE__ */ jsx15(ArrowRight, { "aria-hidden": "true", className: "w-4 h-4" })
1838
2103
  }
1839
2104
  )
1840
2105
  ] })
@@ -1842,15 +2107,15 @@ function BookingsTable({
1842
2107
  }
1843
2108
 
1844
2109
  // src/hooks/useBookingsTableState.hook.ts
1845
- import { useEffect as useEffect3, useState as useState7 } from "react";
2110
+ import { useEffect as useEffect4, useState as useState8 } from "react";
1846
2111
  var OWNED_PARAM_KEYS = ["sortBy", "sortDirection", "status", "page"];
1847
2112
  function readInitialState() {
1848
2113
  if (typeof window === "undefined") return DEFAULT_BOOKINGS_TABLE_STATE;
1849
2114
  return parseBookingsTableState(window.location.search);
1850
2115
  }
1851
2116
  function useBookingsTableState() {
1852
- const [state, setState] = useState7(readInitialState);
1853
- useEffect3(() => {
2117
+ const [state, setState] = useState8(readInitialState);
2118
+ useEffect4(() => {
1854
2119
  if (typeof window === "undefined") return;
1855
2120
  const params = new URLSearchParams(window.location.search);
1856
2121
  for (const key of OWNED_PARAM_KEYS) params.delete(key);
@@ -1863,7 +2128,7 @@ function useBookingsTableState() {
1863
2128
  }
1864
2129
 
1865
2130
  // src/workspace/BookingsArea.tsx
1866
- import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
2131
+ import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
1867
2132
  var PAGE_SIZE = 20;
1868
2133
  function BookingsArea() {
1869
2134
  const { locale } = useSchedulingConfig();
@@ -1879,7 +2144,7 @@ function BookingsArea() {
1879
2144
  });
1880
2145
  const confirmBooking = useConfirmBooking();
1881
2146
  const { data: resourcesData } = useResources({ pageSize: MAX_PAGE_SIZE3 });
1882
- const [selectedBookingId, setSelectedBookingId] = useState8(void 0);
2147
+ const [selectedBookingId, setSelectedBookingId] = useState9(void 0);
1883
2148
  const selectedBooking = data?.data.find((booking) => booking.id === selectedBookingId);
1884
2149
  const selectedBookingResourceTimezone = resourcesData?.data.find(
1885
2150
  (resource) => resource.id === selectedBooking?.resourceIds[0]
@@ -1889,10 +2154,10 @@ function BookingsArea() {
1889
2154
  }
1890
2155
  return /* @__PURE__ */ jsxs13("div", { className: "flex flex-1 min-h-0 min-w-0", children: [
1891
2156
  /* @__PURE__ */ jsxs13("div", { className: "flex flex-1 min-h-0 min-w-0 flex-col gap-4 overflow-y-auto p-4", children: [
1892
- isError && /* @__PURE__ */ jsx15(ErrorBanner, { message: messages["common.loadFailure"] }),
1893
- confirmBooking.isError && /* @__PURE__ */ jsx15(ErrorBanner, { message: messages["common.actionFailure"] }),
1894
- isLoading && /* @__PURE__ */ jsx15(ListSkeleton, { label: messages["common.loading"], rows: 8 }),
1895
- !isLoading && !isError && (data?.data.length ?? 0) === 0 && tableState.statusFilters.length === 0 && /* @__PURE__ */ jsx15(
2157
+ isError && /* @__PURE__ */ jsx16(ErrorBanner, { message: messages["common.loadFailure"] }),
2158
+ confirmBooking.isError && /* @__PURE__ */ jsx16(ErrorBanner, { message: messages["common.actionFailure"] }),
2159
+ isLoading && /* @__PURE__ */ jsx16(ListSkeleton, { label: messages["common.loading"], rows: 8 }),
2160
+ !isLoading && !isError && (data?.data.length ?? 0) === 0 && tableState.statusFilters.length === 0 && /* @__PURE__ */ jsx16(
1896
2161
  EmptyState,
1897
2162
  {
1898
2163
  icon: ClipboardList,
@@ -1900,7 +2165,7 @@ function BookingsArea() {
1900
2165
  hint: messages["booking.emptyHint"]
1901
2166
  }
1902
2167
  ),
1903
- !isLoading && ((data?.data.length ?? 0) > 0 || tableState.statusFilters.length > 0) && /* @__PURE__ */ jsx15(
2168
+ !isLoading && ((data?.data.length ?? 0) > 0 || tableState.statusFilters.length > 0) && /* @__PURE__ */ jsx16(
1904
2169
  BookingsTable,
1905
2170
  {
1906
2171
  bookings: data?.data ?? [],
@@ -1912,7 +2177,7 @@ function BookingsArea() {
1912
2177
  }
1913
2178
  )
1914
2179
  ] }),
1915
- selectedBooking && /* @__PURE__ */ jsx15(
2180
+ selectedBooking && /* @__PURE__ */ jsx16(
1916
2181
  BookingDrawer,
1917
2182
  {
1918
2183
  booking: selectedBooking,
@@ -1926,28 +2191,41 @@ function BookingsArea() {
1926
2191
 
1927
2192
  // src/workspace/ResourcesArea.tsx
1928
2193
  import { Plus as Plus3, Trash2 as Trash23, Users } from "lucide-react";
1929
- import { useState as useState10 } from "react";
2194
+ import { useState as useState11 } from "react";
1930
2195
  import { MAX_PAGE_SIZE as MAX_PAGE_SIZE4 } from "@adatechnology/scheduling-contracts";
1931
2196
 
1932
2197
  // src/components/ResourceForm.tsx
1933
- import { useId as useId2, useState as useState9 } from "react";
2198
+ import { useId as useId3, useMemo as useMemo7, useState as useState10 } from "react";
1934
2199
  import { RESOURCE_KIND } from "@adatechnology/scheduling-contracts";
1935
- import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
2200
+ import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
1936
2201
  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";
1937
2202
  var LABEL_CLASS = "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1";
1938
2203
  var BUTTON_PRIMARY2 = "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";
2204
+ var FALLBACK_TIMEZONES = ["America/Sao_Paulo", "America/Manaus", "America/Belem", "UTC"];
2205
+ function buildTimezoneOptions(current) {
2206
+ const supported = Intl.supportedValuesOf?.("timeZone") ?? FALLBACK_TIMEZONES;
2207
+ const zones = supported.includes(current) ? supported : [current, ...supported];
2208
+ return zones.map((zone) => ({ value: zone, label: zone.replace(/_/g, " ") }));
2209
+ }
1939
2210
  function ResourceForm({ initialValues, onSubmit }) {
1940
2211
  const { locale } = useSchedulingConfig();
1941
2212
  const messages = resolveSchedulingMessages(locale);
1942
- const formId = useId2();
2213
+ const formId = useId3();
1943
2214
  const nameId = `${formId}-name`;
1944
- const kindId = `${formId}-kind`;
1945
- const timezoneId = `${formId}-timezone`;
1946
- const [name, setName] = useState9(initialValues?.name ?? "");
1947
- const [kind, setKind] = useState9(initialValues?.kind ?? RESOURCE_KIND.PERSON);
1948
- const [timezone, setTimezone] = useState9(initialValues?.timezone ?? "America/Sao_Paulo");
1949
- const [active, setActive] = useState9(initialValues?.active ?? true);
1950
- const [submitting, setSubmitting] = useState9(false);
2215
+ const [name, setName] = useState10(initialValues?.name ?? "");
2216
+ const [kind, setKind] = useState10(initialValues?.kind ?? RESOURCE_KIND.PERSON);
2217
+ const [timezone, setTimezone] = useState10(initialValues?.timezone ?? "America/Sao_Paulo");
2218
+ const [active, setActive] = useState10(initialValues?.active ?? true);
2219
+ const [submitting, setSubmitting] = useState10(false);
2220
+ const kindOptions = useMemo7(
2221
+ () => [
2222
+ { value: RESOURCE_KIND.PERSON, label: messages["resource.kind.person"] },
2223
+ { value: RESOURCE_KIND.ROOM, label: messages["resource.kind.room"] },
2224
+ { value: RESOURCE_KIND.EQUIPMENT, label: messages["resource.kind.equipment"] }
2225
+ ],
2226
+ [messages]
2227
+ );
2228
+ const timezoneOptions = useMemo7(() => buildTimezoneOptions(timezone), [timezone]);
1951
2229
  async function handleSubmit(event) {
1952
2230
  event.preventDefault();
1953
2231
  setSubmitting(true);
@@ -1959,8 +2237,8 @@ function ResourceForm({ initialValues, onSubmit }) {
1959
2237
  }
1960
2238
  return /* @__PURE__ */ jsxs14("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
1961
2239
  /* @__PURE__ */ jsxs14("div", { children: [
1962
- /* @__PURE__ */ jsx16("label", { htmlFor: nameId, className: LABEL_CLASS, children: messages["resource.name"] }),
1963
- /* @__PURE__ */ jsx16(
2240
+ /* @__PURE__ */ jsx17("label", { htmlFor: nameId, className: LABEL_CLASS, children: messages["resource.name"] }),
2241
+ /* @__PURE__ */ jsx17(
1964
2242
  "input",
1965
2243
  {
1966
2244
  id: nameId,
@@ -1972,72 +2250,59 @@ function ResourceForm({ initialValues, onSubmit }) {
1972
2250
  }
1973
2251
  )
1974
2252
  ] }),
1975
- /* @__PURE__ */ jsxs14("div", { children: [
1976
- /* @__PURE__ */ jsx16("label", { htmlFor: kindId, className: LABEL_CLASS, children: messages["resource.kind"] }),
1977
- /* @__PURE__ */ jsxs14(
1978
- "select",
1979
- {
1980
- id: kindId,
1981
- value: kind,
1982
- onChange: (event) => setKind(event.target.value),
1983
- className: INPUT_CLASS2,
1984
- children: [
1985
- /* @__PURE__ */ jsx16("option", { value: RESOURCE_KIND.PERSON, children: messages["resource.kind.person"] }),
1986
- /* @__PURE__ */ jsx16("option", { value: RESOURCE_KIND.ROOM, children: messages["resource.kind.room"] }),
1987
- /* @__PURE__ */ jsx16("option", { value: RESOURCE_KIND.EQUIPMENT, children: messages["resource.kind.equipment"] })
1988
- ]
1989
- }
1990
- )
1991
- ] }),
1992
- /* @__PURE__ */ jsxs14("div", { children: [
1993
- /* @__PURE__ */ jsx16("label", { htmlFor: timezoneId, className: LABEL_CLASS, children: messages["resource.timezone"] }),
1994
- /* @__PURE__ */ jsx16(
1995
- "input",
1996
- {
1997
- id: timezoneId,
1998
- type: "text",
1999
- required: true,
2000
- value: timezone,
2001
- onChange: (event) => setTimezone(event.target.value),
2002
- placeholder: "America/Sao_Paulo",
2003
- className: INPUT_CLASS2
2004
- }
2005
- )
2006
- ] }),
2253
+ /* @__PURE__ */ jsx17(
2254
+ SelectField,
2255
+ {
2256
+ label: messages["resource.kind"],
2257
+ value: kind,
2258
+ options: kindOptions,
2259
+ onChange: (next) => setKind(next)
2260
+ }
2261
+ ),
2262
+ /* @__PURE__ */ jsx17(
2263
+ SelectField,
2264
+ {
2265
+ label: messages["resource.timezone"],
2266
+ value: timezone,
2267
+ options: timezoneOptions,
2268
+ onChange: setTimezone,
2269
+ searchable: true
2270
+ }
2271
+ ),
2007
2272
  initialValues && /* @__PURE__ */ jsxs14("label", { className: "flex items-center gap-2 text-sm text-gray-700 dark:text-gray-300 min-h-11", children: [
2008
- /* @__PURE__ */ jsx16("input", { type: "checkbox", checked: active, onChange: (event) => setActive(event.target.checked) }),
2273
+ /* @__PURE__ */ jsx17("input", { type: "checkbox", checked: active, onChange: (event) => setActive(event.target.checked) }),
2009
2274
  messages["resource.active"]
2010
2275
  ] }),
2011
- /* @__PURE__ */ jsx16("button", { type: "submit", disabled: submitting, className: BUTTON_PRIMARY2, children: messages["common.save"] })
2276
+ /* @__PURE__ */ jsx17("button", { type: "submit", disabled: submitting, className: BUTTON_PRIMARY2, children: messages["common.save"] })
2012
2277
  ] });
2013
2278
  }
2014
2279
 
2015
2280
  // src/components/ResourceList.tsx
2016
- import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
2281
+ import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
2017
2282
  function ResourceList({ resources, onSelect }) {
2018
2283
  const { locale } = useSchedulingConfig();
2019
2284
  const messages = resolveSchedulingMessages(locale);
2020
2285
  if (resources.length === 0) {
2021
- return /* @__PURE__ */ jsx17("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.empty"] });
2286
+ return /* @__PURE__ */ jsx18("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.empty"] });
2022
2287
  }
2023
- return /* @__PURE__ */ jsx17("ul", { className: `${SURFACE_BORDER} divide-y divide-gray-200 overflow-hidden dark:divide-gray-800`, children: resources.map((resource, index) => /* @__PURE__ */ jsx17("li", { className: index % 2 === 1 ? ROW_STRIPE : void 0, children: /* @__PURE__ */ jsxs15(
2288
+ return /* @__PURE__ */ jsx18("ul", { className: `${SURFACE_BORDER} divide-y divide-gray-200 overflow-hidden dark:divide-gray-800`, children: resources.map((resource, index) => /* @__PURE__ */ jsx18("li", { className: index % 2 === 1 ? ROW_STRIPE : void 0, children: /* @__PURE__ */ jsxs15(
2024
2289
  "button",
2025
2290
  {
2026
2291
  type: "button",
2027
2292
  onClick: () => onSelect(resource),
2028
2293
  className: "flex w-full items-center gap-3 px-4 py-3 min-h-11 text-left text-sm transition-colors hover:bg-brand-50/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-brand-500 dark:hover:bg-brand-900/20",
2029
2294
  children: [
2030
- /* @__PURE__ */ jsx17("span", { className: "flex-1 font-medium text-gray-900 dark:text-gray-100", children: resource.name }),
2031
- /* @__PURE__ */ jsx17("span", { className: "text-gray-500 dark:text-gray-400", children: messages[`resource.kind.${resource.kind}`] }),
2032
- /* @__PURE__ */ jsx17("span", { className: "text-gray-500 dark:text-gray-400", children: resource.timezone }),
2033
- !resource.active && /* @__PURE__ */ jsx17("span", { className: "rounded-full bg-gray-200 px-2 py-0.5 text-xs font-medium text-gray-600 dark:bg-gray-700 dark:text-gray-300", children: messages["resource.inactive"] })
2295
+ /* @__PURE__ */ jsx18("span", { className: "flex-1 font-medium text-gray-900 dark:text-gray-100", children: resource.name }),
2296
+ /* @__PURE__ */ jsx18("span", { className: "text-gray-500 dark:text-gray-400", children: messages[`resource.kind.${resource.kind}`] }),
2297
+ /* @__PURE__ */ jsx18("span", { className: "text-gray-500 dark:text-gray-400", children: resource.timezone }),
2298
+ !resource.active && /* @__PURE__ */ jsx18("span", { className: "rounded-full bg-gray-200 px-2 py-0.5 text-xs font-medium text-gray-600 dark:bg-gray-700 dark:text-gray-300", children: messages["resource.inactive"] })
2034
2299
  ]
2035
2300
  }
2036
2301
  ) }, resource.id)) });
2037
2302
  }
2038
2303
 
2039
2304
  // src/workspace/ResourcesArea.tsx
2040
- import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
2305
+ import { jsx as jsx19, jsxs as jsxs16 } from "react/jsx-runtime";
2041
2306
  function ResourcesArea() {
2042
2307
  const { locale } = useSchedulingConfig();
2043
2308
  const messages = resolveSchedulingMessages(locale);
@@ -2045,7 +2310,7 @@ function ResourcesArea() {
2045
2310
  const createResource = useCreateResource();
2046
2311
  const updateResource = useUpdateResource();
2047
2312
  const deleteResource = useDeleteResource();
2048
- const [draft, setDraft] = useState10(void 0);
2313
+ const [draft, setDraft] = useState11(void 0);
2049
2314
  const isDraftOpen = draft !== void 0;
2050
2315
  const isEditing = Boolean(draft);
2051
2316
  const resources = data?.data ?? [];
@@ -2062,17 +2327,17 @@ function ResourcesArea() {
2062
2327
  }
2063
2328
  function renderCreateButton() {
2064
2329
  return /* @__PURE__ */ jsxs16("button", { type: "button", onClick: () => setDraft(null), className: BUTTON_PRIMARY, children: [
2065
- /* @__PURE__ */ jsx18(Plus3, { "aria-hidden": "true", className: "h-4 w-4" }),
2330
+ /* @__PURE__ */ jsx19(Plus3, { "aria-hidden": "true", className: "h-4 w-4" }),
2066
2331
  messages["resource.newResource"]
2067
2332
  ] });
2068
2333
  }
2069
2334
  return /* @__PURE__ */ jsxs16("div", { className: "flex flex-1 min-h-0 min-w-0", children: [
2070
2335
  /* @__PURE__ */ jsxs16("div", { className: "flex flex-1 min-h-0 min-w-0 flex-col gap-4 overflow-y-auto p-4", children: [
2071
- /* @__PURE__ */ jsx18("div", { className: "flex justify-end", children: renderCreateButton() }),
2072
- isError && /* @__PURE__ */ jsx18(ErrorBanner, { message: messages["common.loadFailure"] }),
2073
- (createResource.isError || updateResource.isError || deleteResource.isError) && /* @__PURE__ */ jsx18(ErrorBanner, { message: messages["common.actionFailure"] }),
2074
- isLoading && /* @__PURE__ */ jsx18(ListSkeleton, { label: messages["common.loading"] }),
2075
- !isLoading && !isError && resources.length === 0 && /* @__PURE__ */ jsx18(
2336
+ /* @__PURE__ */ jsx19("div", { className: "flex justify-end", children: renderCreateButton() }),
2337
+ isError && /* @__PURE__ */ jsx19(ErrorBanner, { message: messages["common.loadFailure"] }),
2338
+ (createResource.isError || updateResource.isError || deleteResource.isError) && /* @__PURE__ */ jsx19(ErrorBanner, { message: messages["common.actionFailure"] }),
2339
+ isLoading && /* @__PURE__ */ jsx19(ListSkeleton, { label: messages["common.loading"] }),
2340
+ !isLoading && !isError && resources.length === 0 && /* @__PURE__ */ jsx19(
2076
2341
  EmptyState,
2077
2342
  {
2078
2343
  icon: Users,
@@ -2081,9 +2346,9 @@ function ResourcesArea() {
2081
2346
  action: renderCreateButton()
2082
2347
  }
2083
2348
  ),
2084
- !isLoading && resources.length > 0 && /* @__PURE__ */ jsx18(ResourceList, { resources, onSelect: setDraft })
2349
+ !isLoading && resources.length > 0 && /* @__PURE__ */ jsx19(ResourceList, { resources, onSelect: setDraft })
2085
2350
  ] }),
2086
- isDraftOpen && /* @__PURE__ */ jsx18(
2351
+ isDraftOpen && /* @__PURE__ */ jsx19(
2087
2352
  SidePanel,
2088
2353
  {
2089
2354
  title: isEditing ? messages["resource.editTitle"] : messages["resource.createTitle"],
@@ -2099,12 +2364,12 @@ function ResourcesArea() {
2099
2364
  },
2100
2365
  className: BUTTON_DANGER,
2101
2366
  children: [
2102
- /* @__PURE__ */ jsx18(Trash23, { "aria-hidden": "true", className: "h-4 w-4" }),
2367
+ /* @__PURE__ */ jsx19(Trash23, { "aria-hidden": "true", className: "h-4 w-4" }),
2103
2368
  messages["common.remove"]
2104
2369
  ]
2105
2370
  }
2106
2371
  ) : void 0,
2107
- children: /* @__PURE__ */ jsx18(
2372
+ children: /* @__PURE__ */ jsx19(
2108
2373
  ResourceForm,
2109
2374
  {
2110
2375
  ...draft ? { initialValues: draft } : {},
@@ -2119,24 +2384,24 @@ function ResourcesArea() {
2119
2384
 
2120
2385
  // src/workspace/ServicesArea.tsx
2121
2386
  import { Plus as Plus4, Trash2 as Trash24, Wrench } from "lucide-react";
2122
- import { useState as useState12 } from "react";
2387
+ import { useState as useState13 } from "react";
2123
2388
  import { MAX_PAGE_SIZE as MAX_PAGE_SIZE5 } from "@adatechnology/scheduling-contracts";
2124
2389
 
2125
2390
  // src/components/ServiceForm.tsx
2126
- import { useState as useState11 } from "react";
2127
- import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
2391
+ import { useState as useState12 } from "react";
2392
+ import { jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
2128
2393
  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";
2129
2394
  var LABEL_CLASS2 = "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1";
2130
2395
  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";
2131
2396
  function ServiceForm({ initialValues, onSubmit }) {
2132
2397
  const { locale } = useSchedulingConfig();
2133
2398
  const messages = resolveSchedulingMessages(locale);
2134
- const [name, setName] = useState11(initialValues?.name ?? "");
2135
- const [durationMinutes, setDurationMinutes] = useState11(initialValues?.durationMinutes ?? 30);
2136
- const [bufferBeforeMinutes, setBufferBeforeMinutes] = useState11(initialValues?.bufferBeforeMinutes ?? 0);
2137
- const [bufferAfterMinutes, setBufferAfterMinutes] = useState11(initialValues?.bufferAfterMinutes ?? 0);
2138
- const [active, setActive] = useState11(initialValues?.active ?? true);
2139
- const [submitting, setSubmitting] = useState11(false);
2399
+ const [name, setName] = useState12(initialValues?.name ?? "");
2400
+ const [durationMinutes, setDurationMinutes] = useState12(initialValues?.durationMinutes ?? 30);
2401
+ const [bufferBeforeMinutes, setBufferBeforeMinutes] = useState12(initialValues?.bufferBeforeMinutes ?? 0);
2402
+ const [bufferAfterMinutes, setBufferAfterMinutes] = useState12(initialValues?.bufferAfterMinutes ?? 0);
2403
+ const [active, setActive] = useState12(initialValues?.active ?? true);
2404
+ const [submitting, setSubmitting] = useState12(false);
2140
2405
  async function handleSubmit(event) {
2141
2406
  event.preventDefault();
2142
2407
  setSubmitting(true);
@@ -2148,8 +2413,8 @@ function ServiceForm({ initialValues, onSubmit }) {
2148
2413
  }
2149
2414
  return /* @__PURE__ */ jsxs17("form", { onSubmit: handleSubmit, className: "space-y-4", children: [
2150
2415
  /* @__PURE__ */ jsxs17("div", { children: [
2151
- /* @__PURE__ */ jsx19("label", { htmlFor: "scheduling-service-name", className: LABEL_CLASS2, children: messages["service.name"] }),
2152
- /* @__PURE__ */ jsx19(
2416
+ /* @__PURE__ */ jsx20("label", { htmlFor: "scheduling-service-name", className: LABEL_CLASS2, children: messages["service.name"] }),
2417
+ /* @__PURE__ */ jsx20(
2153
2418
  "input",
2154
2419
  {
2155
2420
  id: "scheduling-service-name",
@@ -2162,8 +2427,8 @@ function ServiceForm({ initialValues, onSubmit }) {
2162
2427
  )
2163
2428
  ] }),
2164
2429
  /* @__PURE__ */ jsxs17("div", { children: [
2165
- /* @__PURE__ */ jsx19("label", { htmlFor: "scheduling-service-duration", className: LABEL_CLASS2, children: messages["service.durationMinutes"] }),
2166
- /* @__PURE__ */ jsx19(
2430
+ /* @__PURE__ */ jsx20("label", { htmlFor: "scheduling-service-duration", className: LABEL_CLASS2, children: messages["service.durationMinutes"] }),
2431
+ /* @__PURE__ */ jsx20(
2167
2432
  "input",
2168
2433
  {
2169
2434
  id: "scheduling-service-duration",
@@ -2178,8 +2443,8 @@ function ServiceForm({ initialValues, onSubmit }) {
2178
2443
  ] }),
2179
2444
  /* @__PURE__ */ jsxs17("div", { className: "grid grid-cols-2 gap-3", children: [
2180
2445
  /* @__PURE__ */ jsxs17("div", { children: [
2181
- /* @__PURE__ */ jsx19("label", { htmlFor: "scheduling-service-buffer-before", className: LABEL_CLASS2, children: messages["service.bufferBeforeMinutes"] }),
2182
- /* @__PURE__ */ jsx19(
2446
+ /* @__PURE__ */ jsx20("label", { htmlFor: "scheduling-service-buffer-before", className: LABEL_CLASS2, children: messages["service.bufferBeforeMinutes"] }),
2447
+ /* @__PURE__ */ jsx20(
2183
2448
  "input",
2184
2449
  {
2185
2450
  id: "scheduling-service-buffer-before",
@@ -2192,8 +2457,8 @@ function ServiceForm({ initialValues, onSubmit }) {
2192
2457
  )
2193
2458
  ] }),
2194
2459
  /* @__PURE__ */ jsxs17("div", { children: [
2195
- /* @__PURE__ */ jsx19("label", { htmlFor: "scheduling-service-buffer-after", className: LABEL_CLASS2, children: messages["service.bufferAfterMinutes"] }),
2196
- /* @__PURE__ */ jsx19(
2460
+ /* @__PURE__ */ jsx20("label", { htmlFor: "scheduling-service-buffer-after", className: LABEL_CLASS2, children: messages["service.bufferAfterMinutes"] }),
2461
+ /* @__PURE__ */ jsx20(
2197
2462
  "input",
2198
2463
  {
2199
2464
  id: "scheduling-service-buffer-after",
@@ -2207,41 +2472,41 @@ function ServiceForm({ initialValues, onSubmit }) {
2207
2472
  ] })
2208
2473
  ] }),
2209
2474
  initialValues && /* @__PURE__ */ jsxs17("label", { className: "flex items-center gap-2 text-sm text-gray-700 dark:text-gray-300 min-h-11", children: [
2210
- /* @__PURE__ */ jsx19("input", { type: "checkbox", checked: active, onChange: (event) => setActive(event.target.checked) }),
2475
+ /* @__PURE__ */ jsx20("input", { type: "checkbox", checked: active, onChange: (event) => setActive(event.target.checked) }),
2211
2476
  messages["service.active"]
2212
2477
  ] }),
2213
- /* @__PURE__ */ jsx19("button", { type: "submit", disabled: submitting, className: BUTTON_PRIMARY3, children: messages["common.save"] })
2478
+ /* @__PURE__ */ jsx20("button", { type: "submit", disabled: submitting, className: BUTTON_PRIMARY3, children: messages["common.save"] })
2214
2479
  ] });
2215
2480
  }
2216
2481
 
2217
2482
  // src/components/ServiceList.tsx
2218
- import { jsx as jsx20, jsxs as jsxs18 } from "react/jsx-runtime";
2483
+ import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
2219
2484
  function ServiceList({ services, onSelect }) {
2220
2485
  const { locale } = useSchedulingConfig();
2221
2486
  const messages = resolveSchedulingMessages(locale);
2222
2487
  if (services.length === 0) {
2223
- return /* @__PURE__ */ jsx20("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.empty"] });
2488
+ return /* @__PURE__ */ jsx21("p", { className: "text-sm text-gray-500 dark:text-gray-400", children: messages["common.empty"] });
2224
2489
  }
2225
- return /* @__PURE__ */ jsx20("ul", { className: `${SURFACE_BORDER} divide-y divide-gray-200 overflow-hidden dark:divide-gray-800`, children: services.map((service, index) => /* @__PURE__ */ jsx20("li", { className: index % 2 === 1 ? ROW_STRIPE : void 0, children: /* @__PURE__ */ jsxs18(
2490
+ return /* @__PURE__ */ jsx21("ul", { className: `${SURFACE_BORDER} divide-y divide-gray-200 overflow-hidden dark:divide-gray-800`, children: services.map((service, index) => /* @__PURE__ */ jsx21("li", { className: index % 2 === 1 ? ROW_STRIPE : void 0, children: /* @__PURE__ */ jsxs18(
2226
2491
  "button",
2227
2492
  {
2228
2493
  type: "button",
2229
2494
  onClick: () => onSelect(service),
2230
2495
  className: "flex w-full items-center gap-3 px-4 py-3 min-h-11 text-left text-sm transition-colors hover:bg-brand-50/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-brand-500 dark:hover:bg-brand-900/20",
2231
2496
  children: [
2232
- /* @__PURE__ */ jsx20("span", { className: "flex-1 font-medium text-gray-900 dark:text-gray-100", children: service.name }),
2497
+ /* @__PURE__ */ jsx21("span", { className: "flex-1 font-medium text-gray-900 dark:text-gray-100", children: service.name }),
2233
2498
  /* @__PURE__ */ jsxs18("span", { className: "text-gray-500 dark:text-gray-400", children: [
2234
2499
  service.durationMinutes,
2235
2500
  " min"
2236
2501
  ] }),
2237
- !service.active && /* @__PURE__ */ jsx20("span", { className: "rounded-full bg-gray-200 px-2 py-0.5 text-xs font-medium text-gray-600 dark:bg-gray-700 dark:text-gray-300", children: messages["service.inactive"] })
2502
+ !service.active && /* @__PURE__ */ jsx21("span", { className: "rounded-full bg-gray-200 px-2 py-0.5 text-xs font-medium text-gray-600 dark:bg-gray-700 dark:text-gray-300", children: messages["service.inactive"] })
2238
2503
  ]
2239
2504
  }
2240
2505
  ) }, service.id)) });
2241
2506
  }
2242
2507
 
2243
2508
  // src/workspace/ServicesArea.tsx
2244
- import { jsx as jsx21, jsxs as jsxs19 } from "react/jsx-runtime";
2509
+ import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
2245
2510
  function ServicesArea() {
2246
2511
  const { locale } = useSchedulingConfig();
2247
2512
  const messages = resolveSchedulingMessages(locale);
@@ -2249,7 +2514,7 @@ function ServicesArea() {
2249
2514
  const createService = useCreateService();
2250
2515
  const updateService = useUpdateService();
2251
2516
  const deleteService = useDeleteService();
2252
- const [draft, setDraft] = useState12(void 0);
2517
+ const [draft, setDraft] = useState13(void 0);
2253
2518
  const isDraftOpen = draft !== void 0;
2254
2519
  const isEditing = Boolean(draft);
2255
2520
  const services = data?.data ?? [];
@@ -2266,17 +2531,17 @@ function ServicesArea() {
2266
2531
  }
2267
2532
  function renderCreateButton() {
2268
2533
  return /* @__PURE__ */ jsxs19("button", { type: "button", onClick: () => setDraft(null), className: BUTTON_PRIMARY, children: [
2269
- /* @__PURE__ */ jsx21(Plus4, { "aria-hidden": "true", className: "h-4 w-4" }),
2534
+ /* @__PURE__ */ jsx22(Plus4, { "aria-hidden": "true", className: "h-4 w-4" }),
2270
2535
  messages["service.newService"]
2271
2536
  ] });
2272
2537
  }
2273
2538
  return /* @__PURE__ */ jsxs19("div", { className: "flex flex-1 min-h-0 min-w-0", children: [
2274
2539
  /* @__PURE__ */ jsxs19("div", { className: "flex flex-1 min-h-0 min-w-0 flex-col gap-4 overflow-y-auto p-4", children: [
2275
- /* @__PURE__ */ jsx21("div", { className: "flex justify-end", children: renderCreateButton() }),
2276
- isError && /* @__PURE__ */ jsx21(ErrorBanner, { message: messages["common.loadFailure"] }),
2277
- (createService.isError || updateService.isError || deleteService.isError) && /* @__PURE__ */ jsx21(ErrorBanner, { message: messages["common.actionFailure"] }),
2278
- isLoading && /* @__PURE__ */ jsx21(ListSkeleton, { label: messages["common.loading"] }),
2279
- !isLoading && !isError && services.length === 0 && /* @__PURE__ */ jsx21(
2540
+ /* @__PURE__ */ jsx22("div", { className: "flex justify-end", children: renderCreateButton() }),
2541
+ isError && /* @__PURE__ */ jsx22(ErrorBanner, { message: messages["common.loadFailure"] }),
2542
+ (createService.isError || updateService.isError || deleteService.isError) && /* @__PURE__ */ jsx22(ErrorBanner, { message: messages["common.actionFailure"] }),
2543
+ isLoading && /* @__PURE__ */ jsx22(ListSkeleton, { label: messages["common.loading"] }),
2544
+ !isLoading && !isError && services.length === 0 && /* @__PURE__ */ jsx22(
2280
2545
  EmptyState,
2281
2546
  {
2282
2547
  icon: Wrench,
@@ -2285,9 +2550,9 @@ function ServicesArea() {
2285
2550
  action: renderCreateButton()
2286
2551
  }
2287
2552
  ),
2288
- !isLoading && services.length > 0 && /* @__PURE__ */ jsx21(ServiceList, { services, onSelect: setDraft })
2553
+ !isLoading && services.length > 0 && /* @__PURE__ */ jsx22(ServiceList, { services, onSelect: setDraft })
2289
2554
  ] }),
2290
- isDraftOpen && /* @__PURE__ */ jsx21(
2555
+ isDraftOpen && /* @__PURE__ */ jsx22(
2291
2556
  SidePanel,
2292
2557
  {
2293
2558
  title: isEditing ? messages["service.editTitle"] : messages["service.createTitle"],
@@ -2303,12 +2568,12 @@ function ServicesArea() {
2303
2568
  },
2304
2569
  className: BUTTON_DANGER,
2305
2570
  children: [
2306
- /* @__PURE__ */ jsx21(Trash24, { "aria-hidden": "true", className: "h-4 w-4" }),
2571
+ /* @__PURE__ */ jsx22(Trash24, { "aria-hidden": "true", className: "h-4 w-4" }),
2307
2572
  messages["common.remove"]
2308
2573
  ]
2309
2574
  }
2310
2575
  ) : void 0,
2311
- children: /* @__PURE__ */ jsx21(
2576
+ children: /* @__PURE__ */ jsx22(
2312
2577
  ServiceForm,
2313
2578
  {
2314
2579
  ...draft ? { initialValues: draft } : {},
@@ -2338,9 +2603,9 @@ function isSchedulingWorkspaceArea(value) {
2338
2603
  }
2339
2604
 
2340
2605
  // src/workspace/WorkspaceAreaNav.tsx
2341
- import { jsx as jsx22, jsxs as jsxs20 } from "react/jsx-runtime";
2606
+ import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
2342
2607
  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 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-brand-500";
2343
- var ITEM_ACTIVE = "border-brand-600 text-brand-700 dark:text-brand-300";
2608
+ var ITEM_ACTIVE = "border-brand-600 text-brand-700 dark:text-brand-400";
2344
2609
  var ITEM_IDLE = "border-transparent text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100";
2345
2610
  var AREA_ICON = {
2346
2611
  [SCHEDULING_WORKSPACE_AREA.AGENDA]: CalendarDays2,
@@ -2357,7 +2622,7 @@ function WorkspaceAreaNav({ area, labels, onSelect }) {
2357
2622
  [SCHEDULING_WORKSPACE_AREA.SERVICES, labels.servicesTab],
2358
2623
  [SCHEDULING_WORKSPACE_AREA.AVAILABILITY, labels.availabilityTab]
2359
2624
  ];
2360
- return /* @__PURE__ */ jsx22("nav", { "aria-label": labels.areaNav, className: "flex shrink-0 gap-1 overflow-x-auto border-b border-gray-200 px-4 dark:border-gray-800", children: items.map(([value, label]) => {
2625
+ return /* @__PURE__ */ jsx23("nav", { "aria-label": labels.areaNav, className: "flex shrink-0 gap-1 overflow-x-auto border-b border-gray-200 px-4 dark:border-gray-800", children: items.map(([value, label]) => {
2361
2626
  const Icon = AREA_ICON[value];
2362
2627
  return /* @__PURE__ */ jsxs20(
2363
2628
  "button",
@@ -2367,7 +2632,7 @@ function WorkspaceAreaNav({ area, labels, onSelect }) {
2367
2632
  "aria-current": value === area ? "page" : void 0,
2368
2633
  className: `${ITEM_BASE} ${value === area ? ITEM_ACTIVE : ITEM_IDLE} whitespace-nowrap`,
2369
2634
  children: [
2370
- /* @__PURE__ */ jsx22(Icon, { "aria-hidden": "true", className: "w-4 h-4 shrink-0" }),
2635
+ /* @__PURE__ */ jsx23(Icon, { "aria-hidden": "true", className: "w-4 h-4 shrink-0" }),
2371
2636
  label
2372
2637
  ]
2373
2638
  },
@@ -2377,7 +2642,7 @@ function WorkspaceAreaNav({ area, labels, onSelect }) {
2377
2642
  }
2378
2643
 
2379
2644
  // src/workspace/SchedulingWorkspace.tsx
2380
- import { jsx as jsx23, jsxs as jsxs21 } from "react/jsx-runtime";
2645
+ import { jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
2381
2646
  var AREA_COMPONENT = {
2382
2647
  [SCHEDULING_WORKSPACE_AREA.AGENDA]: AgendaArea,
2383
2648
  [SCHEDULING_WORKSPACE_AREA.BOOKINGS]: BookingsArea,
@@ -2392,7 +2657,7 @@ function SchedulingWorkspace({
2392
2657
  onAreaChange
2393
2658
  }) {
2394
2659
  const labels = { ...DEFAULT_SCHEDULING_WORKSPACE_LABELS, ...labelsOverride };
2395
- const [internalArea, setInternalArea] = useState13(SCHEDULING_WORKSPACE_AREA.AGENDA);
2660
+ const [internalArea, setInternalArea] = useState14(SCHEDULING_WORKSPACE_AREA.AGENDA);
2396
2661
  const area = areaProp ?? internalArea;
2397
2662
  const AreaComponent = AREA_COMPONENT[area];
2398
2663
  function handleSelectArea(next) {
@@ -2401,11 +2666,11 @@ function SchedulingWorkspace({
2401
2666
  }
2402
2667
  return /* @__PURE__ */ jsxs21("div", { className: "flex h-full flex-col bg-white text-gray-900 dark:bg-gray-900 dark:text-gray-100", children: [
2403
2668
  /* @__PURE__ */ jsxs21("header", { className: "flex shrink-0 flex-wrap items-center gap-3 px-4 pb-2 pt-4", children: [
2404
- /* @__PURE__ */ jsx23("h1", { className: "mr-auto text-xl font-semibold tracking-tight text-gray-900 dark:text-gray-100", children: labels.title }),
2669
+ /* @__PURE__ */ jsx24("h1", { className: "mr-auto text-xl font-semibold tracking-tight text-gray-900 dark:text-gray-100", children: labels.title }),
2405
2670
  renderHeaderActions?.()
2406
2671
  ] }),
2407
- /* @__PURE__ */ jsx23(WorkspaceAreaNav, { area, labels, onSelect: handleSelectArea }),
2408
- /* @__PURE__ */ jsx23("div", { className: "relative flex flex-1 min-h-0 overflow-hidden", children: /* @__PURE__ */ jsx23(AreaComponent, {}) })
2672
+ /* @__PURE__ */ jsx24(WorkspaceAreaNav, { area, labels, onSelect: handleSelectArea }),
2673
+ /* @__PURE__ */ jsx24("div", { className: "relative flex flex-1 min-h-0 overflow-hidden", children: /* @__PURE__ */ jsx24(AreaComponent, {}) })
2409
2674
  ] });
2410
2675
  }
2411
2676
  export {