@arquimedes.co/eureka-forms 3.0.52-test → 3.0.53-new-steps

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.
Files changed (102) hide show
  1. package/dist/@Types/AvailabilityFormStep.d.ts +48 -0
  2. package/dist/@Types/AvailabilityFormStep.js +24 -0
  3. package/dist/@Types/BankAccountFormStep.d.ts +67 -0
  4. package/dist/@Types/BankAccountFormStep.js +14 -0
  5. package/dist/@Types/BookingFormStep.d.ts +166 -0
  6. package/dist/@Types/BookingFormStep.js +44 -0
  7. package/dist/@Types/CalendarFormStep.d.ts +192 -0
  8. package/dist/@Types/CalendarFormStep.js +48 -0
  9. package/dist/@Types/CommunicationChannelFormStep.d.ts +51 -0
  10. package/dist/@Types/CommunicationChannelFormStep.js +15 -0
  11. package/dist/@Types/ConsentFormStep.d.ts +36 -0
  12. package/dist/@Types/ConsentFormStep.js +8 -0
  13. package/dist/@Types/EntityFormFormStep.d.ts +66 -0
  14. package/dist/@Types/EntityFormFormStep.js +20 -0
  15. package/dist/@Types/EventFormStep.d.ts +52 -0
  16. package/dist/@Types/EventFormStep.js +13 -0
  17. package/dist/@Types/ExternalReferenceFormStep.d.ts +74 -0
  18. package/dist/@Types/ExternalReferenceFormStep.js +20 -0
  19. package/dist/@Types/FormStep.d.ts +7 -2
  20. package/dist/@Types/FormStep.js +2 -1
  21. package/dist/@Types/LocationFormStep.d.ts +159 -0
  22. package/dist/@Types/LocationFormStep.js +46 -0
  23. package/dist/@Types/NumericFormSteps.d.ts +108 -0
  24. package/dist/@Types/NumericFormSteps.js +20 -0
  25. package/dist/@Types/PredefinedSelectorFormStep.d.ts +51 -0
  26. package/dist/@Types/PredefinedSelectorFormStep.js +39 -0
  27. package/dist/@Types/StepRef.d.ts +135 -0
  28. package/dist/@Types/StepRef.js +49 -0
  29. package/dist/FormSteps/BookingStep/BookingStep.d.ts +17 -0
  30. package/dist/FormSteps/BookingStep/BookingStep.js +14 -0
  31. package/dist/FormSteps/BookingStep/MaterialBookingStep/MaterialBookingStep.d.ts +7 -0
  32. package/dist/FormSteps/BookingStep/MaterialBookingStep/MaterialBookingStep.js +32 -0
  33. package/dist/FormSteps/CalendarStep/CalendarStep.d.ts +7 -0
  34. package/dist/FormSteps/CalendarStep/CalendarStep.js +14 -0
  35. package/dist/FormSteps/CalendarStep/MaterialCalendarStep/MaterialCalendarStep.d.ts +7 -0
  36. package/dist/FormSteps/CalendarStep/MaterialCalendarStep/MaterialCalendarStep.js +31 -0
  37. package/dist/FormSteps/LocationStep/LocationStep.d.ts +10 -0
  38. package/dist/FormSteps/LocationStep/LocationStep.js +14 -0
  39. package/dist/FormSteps/LocationStep/MaterialLocationStep/MaterialLocationStep.d.ts +3 -0
  40. package/dist/FormSteps/LocationStep/MaterialLocationStep/MaterialLocationStep.js +47 -0
  41. package/dist/FormSteps/LocationStep/MaterialLocationStep/MaterialLocationStep.module.css +18 -0
  42. package/dist/FormSteps/NumberStep/MaterialNumberStep/MaterialNumberStep.d.ts +3 -0
  43. package/dist/FormSteps/NumberStep/MaterialNumberStep/MaterialNumberStep.js +168 -0
  44. package/dist/FormSteps/NumberStep/MaterialNumberStep/MaterialNumberStep.module.css +94 -0
  45. package/dist/FormSteps/NumberStep/NumberStep.d.ts +10 -0
  46. package/dist/FormSteps/NumberStep/NumberStep.js +14 -0
  47. package/dist/FormSteps/Step.js +16 -0
  48. package/dist/FormSteps/StepFunctions.js +14 -0
  49. package/dist/FormSteps/StepFunctions.test.js +54 -0
  50. package/dist/Icons/AddIcon.d.ts +3 -0
  51. package/dist/Icons/AddIcon.js +7 -0
  52. package/dist/Icons/EditIcon.d.ts +3 -0
  53. package/dist/Icons/EditIcon.js +7 -0
  54. package/dist/Icons/RemoveIcon.d.ts +3 -0
  55. package/dist/Icons/RemoveIcon.js +7 -0
  56. package/dist/Icons/ViewDayIcon.d.ts +3 -0
  57. package/dist/Icons/ViewDayIcon.js +7 -0
  58. package/dist/Icons/ViewWeekIcon.d.ts +3 -0
  59. package/dist/Icons/ViewWeekIcon.js +7 -0
  60. package/dist/Shared/ErkAddressAutocomplete/ErkAddressAutocomplete.d.ts +19 -0
  61. package/dist/Shared/ErkAddressAutocomplete/ErkAddressAutocomplete.js +80 -0
  62. package/dist/Shared/ErkAddressAutocomplete/ErkAddressAutocomplete.module.css +82 -0
  63. package/dist/Shared/ErkAddressAutocomplete/googlePlaces.d.ts +29 -0
  64. package/dist/Shared/ErkAddressAutocomplete/googlePlaces.js +139 -0
  65. package/dist/Shared/ErkBookingPicker/ErkBookingPicker.d.ts +31 -0
  66. package/dist/Shared/ErkBookingPicker/ErkBookingPicker.js +223 -0
  67. package/dist/Shared/ErkBookingPicker/ErkBookingPicker.module.css +608 -0
  68. package/dist/Shared/ErkBookingPicker/ErkBookingPicker.stories.d.ts +28 -0
  69. package/dist/Shared/ErkBookingPicker/ErkBookingPicker.stories.js +117 -0
  70. package/dist/Shared/ErkBookingPicker/ErkBookingPicker.stories.test.d.ts +1 -0
  71. package/dist/Shared/ErkBookingPicker/ErkBookingPicker.stories.test.js +49 -0
  72. package/dist/Shared/ErkBookingPicker/ErkBookingPicker.test.d.ts +1 -0
  73. package/dist/Shared/ErkBookingPicker/ErkBookingPicker.test.js +107 -0
  74. package/dist/Shared/ErkCalendar/CalendarFunctions.d.ts +28 -0
  75. package/dist/Shared/ErkCalendar/CalendarFunctions.js +121 -0
  76. package/dist/Shared/ErkCalendar/CalendarPopovers.d.ts +45 -0
  77. package/dist/Shared/ErkCalendar/CalendarPopovers.js +110 -0
  78. package/dist/Shared/ErkCalendar/ErkCalendar.d.ts +73 -0
  79. package/dist/Shared/ErkCalendar/ErkCalendar.js +293 -0
  80. package/dist/Shared/ErkCalendar/ErkCalendar.module.css +775 -0
  81. package/dist/Shared/ErkCalendar/ErkCalendar.test.d.ts +1 -0
  82. package/dist/Shared/ErkCalendar/ErkCalendar.test.js +171 -0
  83. package/dist/Shared/ErkDatePicker/ErkDatePicker.js +1 -3
  84. package/dist/Shared/ErkDateRangePicker/ErkDateRangePicker.d.ts +2 -3
  85. package/dist/Shared/ErkDateRangePicker/ErkDateRangePicker.js +1 -2
  86. package/dist/Shared/ErkLocationField/ErkLocationField.d.ts +23 -0
  87. package/dist/Shared/ErkLocationField/ErkLocationField.js +73 -0
  88. package/dist/Shared/ErkLocationField/ErkLocationField.module.css +29 -0
  89. package/dist/Shared/ErkLocationField/addressFields.d.ts +12 -0
  90. package/dist/Shared/ErkLocationField/addressFields.js +34 -0
  91. package/dist/Shared/ErkLocationField/locationRestrictions.d.ts +6 -0
  92. package/dist/Shared/ErkLocationField/locationRestrictions.js +51 -0
  93. package/dist/Shared/ErkLocationInput/ErkLocationInput.d.ts +15 -0
  94. package/dist/Shared/ErkLocationInput/ErkLocationInput.js +502 -0
  95. package/dist/Shared/ErkLocationInput/ErkLocationInput.module.css +115 -0
  96. package/dist/Shared/ErkNumberField/ErkNumberField.d.ts +42 -0
  97. package/dist/Shared/ErkNumberField/ErkNumberField.js +170 -0
  98. package/dist/constants/FormStepTypes.d.ts +5 -1
  99. package/dist/constants/FormStepTypes.js +4 -0
  100. package/dist/index.lib.d.ts +4 -2
  101. package/dist/index.lib.js +3 -1
  102. package/package.json +2 -1
@@ -0,0 +1,73 @@
1
+ import { CalendarDefaultView, CalendarEvent, CalendarEventCategory, CalendarEventTemplate, CalendarValue } from '../../@Types/CalendarFormStep';
2
+ /**
3
+ * Fuente adicional de eventos que se superpone al calendario propio —
4
+ * eventos a nivel de organización, de área, de proyecto, etc.
5
+ * Se muestran en solo lectura (se gestionan en su propio nivel) y se pueden
6
+ * ocultar/mostrar desde el sidebar ("Compartidos").
7
+ */
8
+ export interface CalendarSource {
9
+ id: string;
10
+ /** Nombre visible en el sidebar (ej: "Organización", "Área — Soporte"). */
11
+ name: string;
12
+ /** Color con el que se pintan sus eventos (si el evento no trae uno propio). */
13
+ color?: string;
14
+ events: CalendarEvent[];
15
+ }
16
+ /**
17
+ * Disponibilidad por defecto cuando un día no tiene ventanas explícitas —
18
+ * el sistema de días hábiles del app (semana laboral menos festivos, como
19
+ * `WorkingDaysCache`).
20
+ */
21
+ export interface BusinessDaysConfig {
22
+ /** Hora de inicio del horario hábil (HH:mm). */
23
+ start: string;
24
+ /** Hora de fin del horario hábil (HH:mm). */
25
+ end: string;
26
+ /** Días hábiles de la semana (0=Dom … 6=Sáb). @default [1,2,3,4,5] */
27
+ days?: number[];
28
+ /** Fechas no hábiles (festivos) `YYYY-MM-DD` — ej. del WorkingDaysCache. */
29
+ holidays?: string[];
30
+ }
31
+ export interface ErkCalendarProps {
32
+ value: CalendarValue | null;
33
+ onChange: (value: CalendarValue | null) => void;
34
+ /** Vista inicial. @default WEEK */
35
+ defaultView?: CalendarDefaultView;
36
+ /** Vistas disponibles en el switcher. @default day/week/month */
37
+ enabledViews?: CalendarDefaultView[];
38
+ /** Categorías que se pueden crear; vacío/undefined = todas. */
39
+ allowedCategories?: CalendarEventCategory[];
40
+ /** Plantillas de la organización (las `bookable` son tipos de espacio agendable). */
41
+ eventTemplates?: CalendarEventTemplate[];
42
+ /** Fuentes compartidas (organización, área, proyecto…) superpuestas en solo lectura. */
43
+ sources?: CalendarSource[];
44
+ /** Disponibilidad por defecto (días hábiles) cuando no hay ventanas explícitas. */
45
+ businessDays?: BusinessDaysConfig;
46
+ /** @default true */
47
+ showWeekends?: boolean;
48
+ /** Hora mínima visible (HH:mm). @default "00:00" */
49
+ minTime?: string;
50
+ /** Hora máxima visible (HH:mm). @default "23:00" */
51
+ maxTime?: string;
52
+ /** Permite recurrencia (RRULE diaria/semanal/mensual). @default true */
53
+ allowRecurring?: boolean;
54
+ /** Permite eventos de todo el día. @default true */
55
+ allowAllDay?: boolean;
56
+ /** Zona horaria que se guarda junto a los eventos. */
57
+ timezone?: string;
58
+ readOnly?: boolean;
59
+ error?: string;
60
+ }
61
+ /**
62
+ * Calendario completo reutilizable (vistas día/semana/mes/agenda) con sidebar:
63
+ * mini-calendario, creación rápida y listas de disponibilidad/eventos con
64
+ * visibilidad por categoría o plantilla.
65
+ *
66
+ * Las categorías de disponibilidad (laboral/presencial/virtual/específico) se
67
+ * pintan como franja rayada de fondo — son los espacios donde un booking puede
68
+ * agendar; si un día no tiene ventanas explícitas, `businessDays` pinta la
69
+ * disponibilidad por defecto del sistema de días hábiles. Los eventos usan
70
+ * ISO 8601 + RRULE (RFC 5545), el mismo estándar de Google/Outlook.
71
+ */
72
+ declare function ErkCalendar({ value, onChange, defaultView, enabledViews, allowedCategories, eventTemplates, sources, businessDays, showWeekends, minTime, maxTime, allowRecurring, allowAllDay, timezone, readOnly, error, }: ErkCalendarProps): JSX.Element;
73
+ export default ErkCalendar;
@@ -0,0 +1,293 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useCallback, useMemo, useState } from 'react';
3
+ import { addDays, addMonths, addWeeks, endOfMonth, endOfWeek, format, isSameDay, isSameMonth, isToday, startOfDay, startOfMonth, startOfWeek, } from 'date-fns';
4
+ import { es } from 'date-fns/locale';
5
+ import ArrowLeftIcon from '../../Icons/ArrowLeftIcon';
6
+ import ArrowRightIcon from '../../Icons/ArrowRightIcon';
7
+ import { CalendarDefaultView, CalendarEventCategory, } from '../../@Types/CalendarFormStep';
8
+ import ErkButton from '../ErkButton/ErkButton';
9
+ import { CATEGORY_COLORS, CATEGORY_LABELS, eventColor, eventLabel, isAvailability, isoToHHMM, minutesToHHMM, occursOnDay, parseTime, toMinutes, } from './CalendarFunctions';
10
+ import { CalendarCreatePopover, CalendarDetailPopover, } from './CalendarPopovers';
11
+ import styles from './ErkCalendar.module.css';
12
+ const CELL_HEIGHT = 56; // px por hora
13
+ const WEEK_START = 1; // lunes
14
+ const AGENDA_DAYS = 30;
15
+ const AVAILABILITY_CATS = [
16
+ CalendarEventCategory.WORKING,
17
+ CalendarEventCategory.PHYSICAL,
18
+ CalendarEventCategory.VIRTUAL,
19
+ ];
20
+ const EVENT_CATS = [
21
+ CalendarEventCategory.MEETING,
22
+ CalendarEventCategory.BUSY,
23
+ CalendarEventCategory.CUSTOM,
24
+ ];
25
+ const VIEW_LABELS = {
26
+ [CalendarDefaultView.DAY]: 'Día',
27
+ [CalendarDefaultView.WEEK]: 'Semana',
28
+ [CalendarDefaultView.MONTH]: 'Mes',
29
+ [CalendarDefaultView.AGENDA]: 'Agenda',
30
+ };
31
+ function capitalize(text) {
32
+ return text.charAt(0).toUpperCase() + text.slice(1);
33
+ }
34
+ /** Clave de visibilidad de un evento: su plantilla, o su categoría. */
35
+ function visibilityKey(event) {
36
+ return event.eventTemplateId ? `tpl:${event.eventTemplateId}` : `cat:${event.category}`;
37
+ }
38
+ /**
39
+ * Calendario completo reutilizable (vistas día/semana/mes/agenda) con sidebar:
40
+ * mini-calendario, creación rápida y listas de disponibilidad/eventos con
41
+ * visibilidad por categoría o plantilla.
42
+ *
43
+ * Las categorías de disponibilidad (laboral/presencial/virtual/específico) se
44
+ * pintan como franja rayada de fondo — son los espacios donde un booking puede
45
+ * agendar; si un día no tiene ventanas explícitas, `businessDays` pinta la
46
+ * disponibilidad por defecto del sistema de días hábiles. Los eventos usan
47
+ * ISO 8601 + RRULE (RFC 5545), el mismo estándar de Google/Outlook.
48
+ */
49
+ function ErkCalendar({ value, onChange, defaultView = CalendarDefaultView.WEEK, enabledViews, allowedCategories, eventTemplates, sources, businessDays, showWeekends = true, minTime = '00:00', maxTime = '23:00', allowRecurring = true, allowAllDay = true, timezone, readOnly = false, error, }) {
50
+ const views = useMemo(() => enabledViews?.length
51
+ ? enabledViews
52
+ : [CalendarDefaultView.DAY, CalendarDefaultView.WEEK, CalendarDefaultView.MONTH], [enabledViews]);
53
+ const categories = useMemo(() => allowedCategories?.length ? allowedCategories : Object.values(CalendarEventCategory), [allowedCategories]);
54
+ const availabilityCategories = AVAILABILITY_CATS.filter((c) => categories.includes(c));
55
+ const eventCategories = EVENT_CATS.filter((c) => categories.includes(c));
56
+ const bookableTemplates = eventTemplates?.filter((t) => t.bookable) ?? [];
57
+ const otherTemplates = eventTemplates?.filter((t) => !t.bookable) ?? [];
58
+ const [view, setView] = useState(views.includes(defaultView) ? defaultView : views[0]);
59
+ const [current, setCurrent] = useState(() => startOfDay(new Date()));
60
+ const [miniMonth, setMiniMonth] = useState(() => startOfMonth(new Date()));
61
+ const [hidden, setHidden] = useState(new Set());
62
+ const [createState, setCreateState] = useState(null);
63
+ const [detailState, setDetailState] = useState(null);
64
+ const events = value?.events ?? [];
65
+ const minHour = parseTime(minTime).h;
66
+ const maxHour = parseTime(maxTime).h + 1;
67
+ const hours = Array.from({ length: maxHour - minHour }, (_, i) => minHour + i);
68
+ // ------------------------------------------------------------------
69
+ // Value updates
70
+ // ------------------------------------------------------------------
71
+ const setEvents = useCallback((next) => {
72
+ onChange({ type: 'CALENDAR_VALUE', events: next, timezone: value?.timezone ?? timezone });
73
+ }, [onChange, value?.timezone, timezone]);
74
+ const addEvent = (event) => {
75
+ setEvents([...events, event]);
76
+ setCreateState(null);
77
+ };
78
+ const deleteEvent = (id) => {
79
+ setEvents(events.filter((e) => e.id !== id));
80
+ setDetailState(null);
81
+ };
82
+ // ------------------------------------------------------------------
83
+ // Visibility (sidebar toggles)
84
+ // ------------------------------------------------------------------
85
+ const toggleVisibility = (key) => {
86
+ setHidden((prev) => {
87
+ const next = new Set(prev);
88
+ if (next.has(key))
89
+ next.delete(key);
90
+ else
91
+ next.add(key);
92
+ return next;
93
+ });
94
+ };
95
+ const eventsForDay = (day) => [
96
+ ...events
97
+ .filter((e) => occursOnDay(e, day) && !hidden.has(visibilityKey(e)))
98
+ .map((event) => ({ event, own: true })),
99
+ ...(sources ?? [])
100
+ .filter((s) => !hidden.has(`src:${s.id}`))
101
+ .flatMap((s) => s.events
102
+ .filter((e) => occursOnDay(e, day))
103
+ .map((e) => ({
104
+ event: !e.color && s.color ? { ...e, color: s.color } : e,
105
+ own: false,
106
+ }))),
107
+ ];
108
+ // ------------------------------------------------------------------
109
+ // Business days fallback
110
+ // ------------------------------------------------------------------
111
+ const businessFallbackFor = (day, dayEvents) => {
112
+ if (!businessDays)
113
+ return false;
114
+ if (dayEvents.some(({ event }) => isAvailability(event.category)))
115
+ return false;
116
+ const days = businessDays.days ?? [1, 2, 3, 4, 5];
117
+ if (!days.includes(day.getDay()))
118
+ return false;
119
+ return !businessDays.holidays?.includes(format(day, 'yyyy-MM-dd'));
120
+ };
121
+ // ------------------------------------------------------------------
122
+ // Navigation
123
+ // ------------------------------------------------------------------
124
+ const weekStart = startOfWeek(current, { weekStartsOn: WEEK_START });
125
+ const weekEnd = endOfWeek(current, { weekStartsOn: WEEK_START });
126
+ const visibleDays = useMemo(() => {
127
+ if (view === CalendarDefaultView.DAY)
128
+ return [current];
129
+ const start = startOfWeek(current, { weekStartsOn: WEEK_START });
130
+ const days = Array.from({ length: 7 }, (_, i) => addDays(start, i));
131
+ return showWeekends ? days : days.filter((d) => d.getDay() !== 0 && d.getDay() !== 6);
132
+ }, [view, current, showWeekends]);
133
+ const shift = (dir) => {
134
+ if (view === CalendarDefaultView.MONTH)
135
+ setCurrent((d) => addMonths(d, dir));
136
+ else if (view === CalendarDefaultView.DAY)
137
+ setCurrent((d) => addDays(d, dir));
138
+ else
139
+ setCurrent((d) => addWeeks(d, dir));
140
+ };
141
+ const goToDay = (day) => {
142
+ setCurrent(day);
143
+ setMiniMonth(startOfMonth(day));
144
+ };
145
+ const rangeLabel = (() => {
146
+ if (view === CalendarDefaultView.MONTH)
147
+ return capitalize(format(current, 'MMMM yyyy', { locale: es }));
148
+ if (view === CalendarDefaultView.DAY)
149
+ return capitalize(format(current, 'EEEE d MMM', { locale: es }));
150
+ if (view === CalendarDefaultView.AGENDA)
151
+ return `Próximos ${AGENDA_DAYS} días`;
152
+ return `${format(weekStart, 'd MMM', { locale: es })} – ${format(weekEnd, 'd MMM', { locale: es })}`;
153
+ })();
154
+ // ------------------------------------------------------------------
155
+ // Create flow
156
+ // ------------------------------------------------------------------
157
+ const openCreateAt = (anchorEl, day, startMins) => {
158
+ if (readOnly)
159
+ return;
160
+ const clamped = Math.max(minHour * 60, Math.min(startMins, (maxHour - 1) * 60));
161
+ setCreateState({
162
+ anchorEl,
163
+ date: day,
164
+ startHHMM: minutesToHHMM(clamped),
165
+ endHHMM: minutesToHHMM(Math.min(clamped + 60, maxHour * 60)),
166
+ });
167
+ };
168
+ const handleGridClick = (e, day) => {
169
+ const rect = e.currentTarget.getBoundingClientRect();
170
+ const relY = e.clientY - rect.top;
171
+ const snapped = Math.round((relY / CELL_HEIGHT) * 2) * 30; // snap a 30 min
172
+ openCreateAt(e.currentTarget, day, minHour * 60 + snapped);
173
+ };
174
+ const handleNewEvent = (e) => {
175
+ openCreateAt(e.currentTarget, current, 9 * 60);
176
+ };
177
+ const openDetail = (e, event, own) => {
178
+ e.stopPropagation();
179
+ setDetailState({ anchorEl: e.currentTarget, event, own });
180
+ };
181
+ // ------------------------------------------------------------------
182
+ // Sidebar
183
+ // ------------------------------------------------------------------
184
+ const renderSidebarItem = (key, color, label) => (_jsxs("button", { type: "button", className: hidden.has(key) ? `${styles.sideItem} ${styles.sideItemOff}` : styles.sideItem, onClick: () => toggleVisibility(key), title: hidden.has(key) ? 'Mostrar' : 'Ocultar', children: [_jsx("span", { className: styles.catDot, style: { backgroundColor: color } }), label] }, key));
185
+ const renderMiniCalendar = () => {
186
+ const gridStart = startOfWeek(miniMonth, { weekStartsOn: WEEK_START });
187
+ const cells = Array.from({ length: 42 }, (_, i) => addDays(gridStart, i));
188
+ return (_jsxs("div", { className: styles.miniWrap, children: [_jsxs("div", { className: styles.miniHead, children: [_jsx("span", { className: styles.miniTitle, children: capitalize(format(miniMonth, 'MMMM yyyy', { locale: es })) }), _jsxs("span", { className: styles.miniNav, children: [_jsx("button", { type: "button", "aria-label": "Mes anterior", onClick: () => setMiniMonth((m) => addMonths(m, -1)), children: "\u2039" }), _jsx("button", { type: "button", "aria-label": "Mes siguiente", onClick: () => setMiniMonth((m) => addMonths(m, 1)), children: "\u203A" })] })] }), _jsxs("div", { className: styles.miniGrid, children: [['L', 'M', 'M', 'J', 'V', 'S', 'D'].map((d, i) => (_jsx("span", { className: styles.miniDow, children: d }, i))), cells.map((day) => {
189
+ const cls = [
190
+ styles.miniDay,
191
+ !isSameMonth(day, miniMonth) ? styles.miniDayMut : '',
192
+ isToday(day) ? styles.miniDayToday : '',
193
+ !isToday(day) && isSameDay(day, current) ? styles.miniDaySel : '',
194
+ ]
195
+ .filter(Boolean)
196
+ .join(' ');
197
+ return (_jsx("button", { type: "button", className: cls, onClick: () => goToDay(day), children: format(day, 'd') }, day.toISOString()));
198
+ })] })] }));
199
+ };
200
+ const renderSidebar = () => (_jsxs("aside", { className: styles.side, children: [!readOnly && (_jsx(ErkButton, { text: "+ Nuevo evento", sx: { width: '100%' }, onClick: handleNewEvent })), renderMiniCalendar(), (availabilityCategories.length > 0 || bookableTemplates.length > 0) && (_jsxs("div", { className: styles.sideList, children: [_jsx("span", { className: styles.sideLbl, children: "Disponibilidad" }), availabilityCategories.map((cat) => renderSidebarItem(`cat:${cat}`, CATEGORY_COLORS[cat], CATEGORY_LABELS[cat])), bookableTemplates.map((t) => renderSidebarItem(`tpl:${t.id}`, t.color ?? CATEGORY_COLORS[t.category], t.name))] })), (eventCategories.length > 0 || otherTemplates.length > 0) && (_jsxs("div", { className: styles.sideList, children: [_jsx("span", { className: styles.sideLbl, children: "Eventos" }), eventCategories.map((cat) => renderSidebarItem(`cat:${cat}`, CATEGORY_COLORS[cat], CATEGORY_LABELS[cat])), otherTemplates.map((t) => renderSidebarItem(`tpl:${t.id}`, t.color ?? CATEGORY_COLORS[t.category], t.name))] })), sources && sources.length > 0 && (_jsxs("div", { className: styles.sideList, children: [_jsx("span", { className: styles.sideLbl, children: "Compartidos" }), sources.map((s) => renderSidebarItem(`src:${s.id}`, s.color ?? '#98a2b3', s.name))] }))] }));
201
+ // ------------------------------------------------------------------
202
+ // Time grid (day / week)
203
+ // ------------------------------------------------------------------
204
+ const renderTimeGrid = () => {
205
+ const allDayByDay = visibleDays.map((day) => eventsForDay(day).filter(({ event }) => event.isAllDay));
206
+ const hasAllDay = allDayByDay.some((list) => list.length > 0);
207
+ return (_jsxs("div", { className: styles.cal, children: [_jsxs("div", { className: styles.calHead, style: { gridTemplateColumns: `54px repeat(${visibleDays.length}, 1fr)` }, children: [_jsx("div", { className: styles.gutter }), visibleDays.map((day) => (_jsxs("button", { type: "button", className: styles.dayHead, onClick: () => {
208
+ goToDay(day);
209
+ setView(CalendarDefaultView.DAY);
210
+ }, children: [_jsx("span", { className: styles.dayHeadDow, children: format(day, 'EEE', { locale: es }) }), _jsx("span", { className: isToday(day)
211
+ ? `${styles.dayHeadNum} ${styles.dayHeadToday}`
212
+ : styles.dayHeadNum, children: format(day, 'd') })] }, day.toISOString())))] }), hasAllDay && (_jsxs("div", { className: styles.allDayRow, style: { gridTemplateColumns: `54px repeat(${visibleDays.length}, 1fr)` }, children: [_jsx("div", { className: styles.allDayLbl, children: "D\u00EDa" }), allDayByDay.map((list, i) => (_jsx("div", { className: styles.allDayCell, children: list.map(({ event, own }) => (_jsx("button", { type: "button", className: styles.allDayChip, style: { backgroundColor: eventColor(event, eventTemplates) }, onClick: (e) => openDetail(e, event, own), children: eventLabel(event, eventTemplates) }, `${own ? 'own' : 'src'}-${event.id}`))) }, visibleDays[i].toISOString())))] })), _jsxs("div", { className: styles.grid, style: { gridTemplateColumns: `54px repeat(${visibleDays.length}, 1fr)` }, children: [_jsx("div", { className: styles.timeCol, children: hours.map((h) => (_jsx("div", { className: styles.hourLabel, style: { height: CELL_HEIGHT }, children: h > 0 ? `${h}:00` : '' }, h))) }), visibleDays.map((day) => {
213
+ const dayEvents = eventsForDay(day).filter(({ event }) => !event.isAllDay);
214
+ const fallback = businessFallbackFor(day, dayEvents);
215
+ return (_jsxs("div", { className: styles.dayCol, style: { height: hours.length * CELL_HEIGHT }, onClick: (e) => handleGridClick(e, day), children: [hours.map((h) => (_jsx("div", { className: styles.hourCell, style: { height: CELL_HEIGHT } }, h))), fallback && businessDays && (_jsx("div", { className: `${styles.avail} ${styles.availFallback}`, style: {
216
+ top: (toMinutes(businessDays.start) - minHour * 60) *
217
+ (CELL_HEIGHT / 60),
218
+ height: (toMinutes(businessDays.end) -
219
+ toMinutes(businessDays.start)) *
220
+ (CELL_HEIGHT / 60),
221
+ }, children: _jsx("span", { className: styles.availTag, children: "D\u00EDas h\u00E1biles" }) })), dayEvents.map(({ event, own }) => {
222
+ const key = `${own ? 'own' : 'src'}-${event.id}`;
223
+ const top = (toMinutes(isoToHHMM(event.start)) - minHour * 60) *
224
+ (CELL_HEIGHT / 60);
225
+ const height = Math.max((toMinutes(isoToHHMM(event.end)) -
226
+ toMinutes(isoToHHMM(event.start))) *
227
+ (CELL_HEIGHT / 60), 20);
228
+ const color = eventColor(event, eventTemplates);
229
+ if (isAvailability(event.category)) {
230
+ return (_jsx("div", { className: styles.avail, style: {
231
+ top,
232
+ height,
233
+ borderLeftColor: color,
234
+ backgroundImage: `repeating-linear-gradient(-45deg, ${color}1a, ${color}1a 6px, ${color}0d 6px, ${color}0d 12px)`,
235
+ }, onClick: (e) => openDetail(e, event, own), children: _jsx("span", { className: styles.availTag, style: { color }, children: eventLabel(event, eventTemplates) }) }, key));
236
+ }
237
+ const busy = event.category === CalendarEventCategory.BUSY;
238
+ return (_jsxs("div", { className: busy ? `${styles.event} ${styles.eventBusy}` : styles.event, style: busy
239
+ ? { top, height }
240
+ : { top, height, backgroundColor: color }, onClick: (e) => openDetail(e, event, own), children: [_jsx("span", { className: styles.eventTitle, children: eventLabel(event, eventTemplates) }), _jsxs("span", { className: styles.eventTime, children: [isoToHHMM(event.start), " \u2013 ", isoToHHMM(event.end)] })] }, key));
241
+ })] }, day.toISOString()));
242
+ })] })] }));
243
+ };
244
+ // ------------------------------------------------------------------
245
+ // Month view
246
+ // ------------------------------------------------------------------
247
+ const renderMonth = () => {
248
+ const gridStart = startOfWeek(startOfMonth(current), { weekStartsOn: WEEK_START });
249
+ const gridEnd = endOfWeek(endOfMonth(current), { weekStartsOn: WEEK_START });
250
+ const days = [];
251
+ for (let d = gridStart; d <= gridEnd; d = addDays(d, 1))
252
+ days.push(d);
253
+ const dows = ['Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb', 'Dom'];
254
+ return (_jsxs("div", { className: styles.monthGrid, children: [dows.map((lbl) => (_jsx("div", { className: styles.monthDow, children: lbl }, lbl))), days.map((day) => {
255
+ const dayEvents = eventsForDay(day);
256
+ return (_jsxs("button", { type: "button", className: isSameMonth(day, current)
257
+ ? styles.monthCell
258
+ : `${styles.monthCell} ${styles.monthCellOut}`, onClick: () => {
259
+ goToDay(day);
260
+ setView(CalendarDefaultView.DAY);
261
+ }, children: [_jsx("span", { className: isToday(day)
262
+ ? `${styles.monthNum} ${styles.dayHeadToday}`
263
+ : styles.monthNum, children: format(day, 'd') }), dayEvents.slice(0, 3).map(({ event, own }) => (_jsx("span", { className: styles.monthEvent, style: { backgroundColor: eventColor(event, eventTemplates) }, children: eventLabel(event, eventTemplates) }, `${own ? 'own' : 'src'}-${event.id}`))), dayEvents.length > 3 && (_jsxs("span", { className: styles.monthMore, children: ["+", dayEvents.length - 3, " m\u00E1s"] }))] }, day.toISOString()));
264
+ })] }));
265
+ };
266
+ // ------------------------------------------------------------------
267
+ // Agenda view
268
+ // ------------------------------------------------------------------
269
+ const renderAgenda = () => {
270
+ const days = Array.from({ length: AGENDA_DAYS }, (_, i) => addDays(current, i));
271
+ const withEvents = days
272
+ .map((day) => ({ day, dayEvents: eventsForDay(day) }))
273
+ .filter(({ dayEvents }) => dayEvents.length > 0);
274
+ if (withEvents.length === 0) {
275
+ return (_jsxs("div", { className: styles.agendaEmpty, children: ["Sin eventos en los pr\u00F3ximos ", AGENDA_DAYS, " d\u00EDas."] }));
276
+ }
277
+ return (_jsx("div", { className: styles.agenda, children: withEvents.map(({ day, dayEvents }) => (_jsxs("div", { className: styles.agendaDay, children: [_jsx("div", { className: styles.agendaDayLabel, children: capitalize(format(day, 'EEEE d MMM', { locale: es })) }), dayEvents
278
+ .slice()
279
+ .sort((a, b) => isoToHHMM(a.event.start).localeCompare(isoToHHMM(b.event.start)))
280
+ .map(({ event, own }) => (_jsxs("button", { type: "button", className: styles.agendaRow, onClick: (e) => openDetail(e, event, own), children: [_jsx("span", { className: styles.catDot, style: { backgroundColor: eventColor(event, eventTemplates) } }), _jsx("span", { className: styles.agendaTitle, children: eventLabel(event, eventTemplates) }), _jsx("span", { className: styles.agendaTime, children: event.isAllDay
281
+ ? 'Todo el día'
282
+ : `${isoToHHMM(event.start)} – ${isoToHHMM(event.end)}` })] }, `${own ? 'own' : 'src'}-${event.id}-${day.toISOString()}`)))] }, day.toISOString()))) }));
283
+ };
284
+ // ------------------------------------------------------------------
285
+ // Render
286
+ // ------------------------------------------------------------------
287
+ return (_jsxs("div", { className: styles.container, children: [_jsxs("div", { className: styles.app, children: [renderSidebar(), _jsxs("section", { className: styles.main, children: [_jsxs("div", { className: styles.toolbar, children: [_jsx(ErkButton, { text: "Hoy", variant: "outlined", onClick: () => goToDay(startOfDay(new Date())) }), _jsxs("div", { className: styles.navBtns, children: [_jsx("button", { type: "button", "aria-label": "Anterior", onClick: () => shift(-1), children: _jsx(ArrowLeftIcon, {}) }), _jsx("button", { type: "button", "aria-label": "Siguiente", onClick: () => shift(1), children: _jsx(ArrowRightIcon, {}) })] }), _jsx("span", { className: styles.range, children: rangeLabel }), _jsx("span", { className: styles.spacer }), views.length > 1 && (_jsx("div", { className: styles.views, children: views.map((v) => (_jsx("button", { type: "button", className: view === v ? styles.viewOn : undefined, onClick: () => setView(v), children: VIEW_LABELS[v] }, v))) }))] }), view === CalendarDefaultView.MONTH
288
+ ? renderMonth()
289
+ : view === CalendarDefaultView.AGENDA
290
+ ? renderAgenda()
291
+ : renderTimeGrid()] })] }), createState && (_jsx(CalendarCreatePopover, { state: createState, availabilityCategories: availabilityCategories, eventCategories: eventCategories, eventTemplates: eventTemplates, allowRecurring: allowRecurring, allowAllDay: allowAllDay, onClose: () => setCreateState(null), onCreate: addEvent })), detailState && (_jsx(CalendarDetailPopover, { state: detailState, eventTemplates: eventTemplates, readOnly: readOnly || !detailState.own, onClose: () => setDetailState(null), onDelete: deleteEvent })), error && _jsx("div", { className: styles.err, children: error })] }));
292
+ }
293
+ export default ErkCalendar;