@trii/components 2.0.64 → 2.0.65

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/cjs/index.js CHANGED
@@ -9912,6 +9912,30 @@ class AdapterDayjs {
9912
9912
  }
9913
9913
  }
9914
9914
 
9915
+ // ============================================
9916
+ // COMPONENTES EXTERNOS (evitan re-creación en cada render)
9917
+ // ============================================
9918
+ // Componente: Input Container con label
9919
+ const InputContainer = ({ title, children }) => (jsxRuntimeExports.jsxs(material.Box, { children: [jsxRuntimeExports.jsx(material.Box, { sx: { mb: 1, color: 'text.secondary', fontSize: '0.875rem', userSelect: 'none' }, children: title }), children] }));
9920
+ // Componente: Contact Search Input (declarado fuera para evitar pérdida de focus)
9921
+ const ContactSearchInput = React.memo(({ onChange, placeholder, isSearching, value }) => {
9922
+ return (jsxRuntimeExports.jsxs(material.Box, { sx: { position: 'relative' }, children: [jsxRuntimeExports.jsx(material.TextField, { fullWidth: true, size: "small", placeholder: placeholder, value: value, onChange: (e) => onChange(e.target.value), InputProps: {
9923
+ startAdornment: jsxRuntimeExports.jsx(iconsMaterial.Search, { fontSize: "small", sx: { mr: 1, color: 'text.secondary' } }),
9924
+ }, autoComplete: "off" }), isSearching && (jsxRuntimeExports.jsx(material.Box, { sx: {
9925
+ position: 'absolute',
9926
+ bottom: 0,
9927
+ left: 0,
9928
+ right: 0,
9929
+ height: 2,
9930
+ bgcolor: 'primary.main',
9931
+ animation: 'progress 1s infinite',
9932
+ '@keyframes progress': {
9933
+ '0%': { transform: 'translateX(-100%)' },
9934
+ '100%': { transform: 'translateX(100%)' },
9935
+ },
9936
+ } }))] }));
9937
+ });
9938
+ ContactSearchInput.displayName = 'ContactSearchInput';
9915
9939
  /**
9916
9940
  * ModalEvents - Componente reutilizable para crear/editar/visualizar eventos y tareas
9917
9941
  *
@@ -9922,22 +9946,33 @@ const ModalEvents = ({ open, onClose, mode, type: initialType, showTypeTabs = fa
9922
9946
  const [currentType, setCurrentType] = React.useState(initialType);
9923
9947
  const [localEventData, setLocalEventData] = React.useState(eventData || {});
9924
9948
  const [localTaskData, setLocalTaskData] = React.useState(taskData || {});
9925
- const [contactSearch, setContactSearch] = React.useState('');
9926
9949
  const [searchResults, setSearchResults] = React.useState([]);
9927
- React.useState(false);
9950
+ const [isSearching, setIsSearching] = React.useState(false);
9951
+ const [contactSearchValue, setContactSearchValue] = React.useState('');
9952
+ const contactSearchRef = React.useRef('');
9928
9953
  const debounceTimerRef = React.useRef(null);
9954
+ const wasOpenRef = React.useRef(false);
9929
9955
  const theme = material.useTheme();
9930
- // Sincronizar con props cuando cambian
9931
- React.useEffect(() => setCurrentType(initialType), [initialType]);
9932
- React.useEffect(() => { if (eventData)
9933
- setLocalEventData(eventData); }, [eventData]);
9934
- React.useEffect(() => { if (taskData)
9935
- setLocalTaskData(taskData); }, [taskData]);
9956
+ // Sincronizar con props SOLO cuando el modal se abre (no en cada cambio de props)
9957
+ React.useEffect(() => {
9958
+ if (open && !wasOpenRef.current) {
9959
+ // Modal acaba de abrirse - sincronizar datos
9960
+ setCurrentType(initialType);
9961
+ setLocalEventData(eventData || {});
9962
+ setLocalTaskData(taskData || {});
9963
+ setContactSearchValue('');
9964
+ contactSearchRef.current = '';
9965
+ setSearchResults([]);
9966
+ }
9967
+ wasOpenRef.current = open;
9968
+ }, [open, initialType, eventData, taskData]);
9936
9969
  // Restablecer datos locales al cerrar
9937
9970
  React.useEffect(() => {
9938
9971
  if (!open) {
9939
- setContactSearch('');
9972
+ setContactSearchValue('');
9973
+ contactSearchRef.current = '';
9940
9974
  setSearchResults([]);
9975
+ setIsSearching(false);
9941
9976
  if (debounceTimerRef.current)
9942
9977
  clearTimeout(debounceTimerRef.current);
9943
9978
  }
@@ -9996,6 +10031,15 @@ const ModalEvents = ({ open, onClose, mode, type: initialType, showTypeTabs = fa
9996
10031
  edit: 'Editar',
9997
10032
  duplicate: 'Duplicar',
9998
10033
  close: 'Cerrar',
10034
+ // Labels de recurrencia
10035
+ noRepeat: 'No repetir',
10036
+ everyDay: 'Todos los días',
10037
+ everyWeek: 'Cada semana',
10038
+ everyMonth: 'Cada mes',
10039
+ everyYear: 'Cada año',
10040
+ everyTwoDays: 'Cada 2 días',
10041
+ everyTwoWeeks: 'Cada 2 semanas',
10042
+ everyWeekday: 'Días laborables (Lun-Vie)',
9999
10043
  };
10000
10044
  const l = React.useMemo(() => ({
10001
10045
  ...defaultLabels,
@@ -10006,6 +10050,24 @@ const ModalEvents = ({ open, onClose, mode, type: initialType, showTypeTabs = fa
10006
10050
  const isViewMode = mode === 'view';
10007
10051
  const isCreateMode = mode === 'create';
10008
10052
  const canDelete = (mode === 'edit' || mode === 'view') && Boolean(currentData?.id);
10053
+ // Opciones de recurrencia
10054
+ const recurrenceOptions = React.useMemo(() => [
10055
+ { value: '', label: l.noRepeat },
10056
+ { value: 'FREQ=DAILY', label: l.everyDay },
10057
+ { value: 'FREQ=WEEKLY', label: l.everyWeek },
10058
+ { value: 'FREQ=MONTHLY', label: l.everyMonth },
10059
+ { value: 'FREQ=YEARLY', label: l.everyYear },
10060
+ { value: 'FREQ=DAILY;INTERVAL=2', label: l.everyTwoDays },
10061
+ { value: 'FREQ=WEEKLY;INTERVAL=2', label: l.everyTwoWeeks },
10062
+ { value: 'FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR', label: l.everyWeekday },
10063
+ ], [l]);
10064
+ // Helper para obtener label de recurrencia
10065
+ const getRecurrenceLabel = (value) => {
10066
+ if (!value)
10067
+ return l.noRepeat;
10068
+ const option = recurrenceOptions.find(opt => opt.value === value);
10069
+ return option ? option.label : value;
10070
+ };
10009
10071
  // Obtener título del modal
10010
10072
  const dialogTitle = React.useMemo(() => {
10011
10073
  if (isEvent) {
@@ -10070,13 +10132,20 @@ const ModalEvents = ({ open, onClose, mode, type: initialType, showTypeTabs = fa
10070
10132
  const updated = currentContacts.filter(c => c.id !== contactId);
10071
10133
  handleFieldChange('linkedContacts', updated);
10072
10134
  };
10073
- // Handler para búsqueda de contactos con debounce
10074
- const handleContactSearchChange = React.useCallback((query) => {
10075
- setContactSearch(query);
10135
+ // Handler para buscar contactos con debounce
10136
+ const handleContactSearchDebounced = React.useCallback((query) => {
10137
+ setContactSearchValue(query);
10138
+ contactSearchRef.current = query;
10076
10139
  if (debounceTimerRef.current) {
10077
10140
  clearTimeout(debounceTimerRef.current);
10078
10141
  }
10079
- if (onSearchContacts && query.length >= 2) {
10142
+ if (query.length < 2) {
10143
+ setSearchResults([]);
10144
+ setIsSearching(false);
10145
+ return;
10146
+ }
10147
+ if (onSearchContacts) {
10148
+ setIsSearching(true);
10080
10149
  debounceTimerRef.current = setTimeout(async () => {
10081
10150
  try {
10082
10151
  const results = await onSearchContacts(query);
@@ -10086,23 +10155,23 @@ const ModalEvents = ({ open, onClose, mode, type: initialType, showTypeTabs = fa
10086
10155
  console.error('Error searching contacts:', error);
10087
10156
  setSearchResults([]);
10088
10157
  }
10158
+ finally {
10159
+ setIsSearching(false);
10160
+ }
10089
10161
  }, searchDebounceMs);
10090
10162
  }
10091
- else if (query.length < 2) {
10092
- setSearchResults([]);
10093
- }
10094
10163
  }, [onSearchContacts, searchDebounceMs]);
10095
10164
  // Contactos filtrados
10096
10165
  const filteredContacts = React.useMemo(() => {
10097
10166
  if (onSearchContacts) {
10098
10167
  return searchResults;
10099
10168
  }
10100
- if (!contactSearch)
10169
+ const search = contactSearchValue.toLowerCase();
10170
+ if (!search)
10101
10171
  return [];
10102
- const search = contactSearch.toLowerCase();
10103
10172
  return contacts.filter(contact => contact.name.toLowerCase().includes(search) ||
10104
10173
  contact.email?.toLowerCase().includes(search));
10105
- }, [onSearchContacts, searchResults, contacts, contactSearch]);
10174
+ }, [onSearchContacts, searchResults, contacts, contactSearchValue]);
10106
10175
  // Calcular duración para eventos
10107
10176
  const duration = React.useMemo(() => {
10108
10177
  if (!isEvent || !localEventData.startDate || !localEventData.endDate)
@@ -10116,12 +10185,19 @@ const ModalEvents = ({ open, onClose, mode, type: initialType, showTypeTabs = fa
10116
10185
  const minutes = diff % 60;
10117
10186
  return minutes > 0 ? `${hours}h ${minutes}min` : `${hours}h`;
10118
10187
  }, [isEvent, localEventData.startDate, localEventData.endDate]);
10188
+ // Helper para renderizar valores en modo view
10189
+ const renderViewValue = (value) => {
10190
+ if (value === null || value === undefined || value === '') {
10191
+ return jsxRuntimeExports.jsx(material.Typography, { color: "text.secondary", children: "-" });
10192
+ }
10193
+ return jsxRuntimeExports.jsx(material.Typography, { children: value });
10194
+ };
10119
10195
  // ============================================
10120
10196
  // COMPONENTES INTERNOS
10121
10197
  // ============================================
10122
10198
  // Componente: Type Tabs
10123
10199
  const TypeTabs = () => {
10124
- if (!showTypeTabs || currentData?.title)
10200
+ if (!showTypeTabs)
10125
10201
  return null;
10126
10202
  return (jsxRuntimeExports.jsxs(material.Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [jsxRuntimeExports.jsx(material.Button, { variant: isEvent ? 'contained' : 'text', color: "secondary", size: "small", disableElevation: true, onClick: () => handleTypeChange('event'), sx: {
10127
10203
  textTransform: 'none',
@@ -10139,8 +10215,6 @@ const ModalEvents = ({ open, onClose, mode, type: initialType, showTypeTabs = fa
10139
10215
  fontWeight: 500,
10140
10216
  }, children: l.taskTab })] }));
10141
10217
  };
10142
- // Componente: Input Container con label
10143
- const InputContainer = ({ title, children }) => (jsxRuntimeExports.jsxs(material.Box, { children: [jsxRuntimeExports.jsx(material.Box, { sx: { mb: 1, color: 'text.secondary', fontSize: '0.875rem', userSelect: 'none' }, children: title }), children] }));
10144
10218
  // Componente: Date Time Picker Section
10145
10219
  const DateTimeSection = () => {
10146
10220
  if (!config.showDateTime)
@@ -10149,6 +10223,19 @@ const ModalEvents = ({ open, onClose, mode, type: initialType, showTypeTabs = fa
10149
10223
  const startDateDayjs = localEventData.startDate ? defaultDayjs(moment(localEventData.startDate).toISOString()) : null;
10150
10224
  const endDateDayjs = localEventData.endDate ? defaultDayjs(moment(localEventData.endDate).toISOString()) : null;
10151
10225
  const dueDateDayjs = localTaskData.dueDate ? defaultDayjs(moment(localTaskData.dueDate).toISOString()) : null;
10226
+ // Si estamos en modo view, mostrar solo info formateada
10227
+ if (isViewMode) {
10228
+ return (jsxRuntimeExports.jsx(material.Box, { sx: {
10229
+ display: 'flex',
10230
+ flexDirection: 'column',
10231
+ gap: 1.5,
10232
+ p: 2,
10233
+ borderRadius: 1,
10234
+ bgcolor: theme.palette.mode === 'dark'
10235
+ ? 'rgba(255, 255, 255, 0.05)'
10236
+ : 'rgba(0, 0, 0, 0.02)',
10237
+ }, children: jsxRuntimeExports.jsxs(material.Box, { sx: { display: 'flex', gap: 1.5, alignItems: 'flex-start' }, children: [jsxRuntimeExports.jsx(iconsMaterial.AccessTime, { sx: { mt: 0.5, color: 'text.secondary', fontSize: '1.25rem' } }), jsxRuntimeExports.jsxs(material.Box, { sx: { flex: 1 }, children: [isEvent ? (jsxRuntimeExports.jsx(material.Box, { sx: { display: 'flex', flexDirection: 'column', gap: 1 }, children: localEventData.startDate ? (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsx(material.Typography, { children: moment(localEventData.startDate).format('DD/MM/YYYY') }), !localEventData.allDay && (jsxRuntimeExports.jsxs(material.Typography, { children: [moment(localEventData.startDate).format('HH:mm'), " \u2013 ", moment(localEventData.endDate).format('HH:mm'), duration && jsxRuntimeExports.jsxs(material.Typography, { component: "span", variant: "caption", color: "text.secondary", children: [" (", duration, ")"] })] })), localEventData.allDay && (jsxRuntimeExports.jsx(material.Typography, { variant: "body2", color: "text.secondary", children: l.allDay }))] })) : (jsxRuntimeExports.jsx(material.Typography, { color: "text.secondary", children: "-" })) })) : (jsxRuntimeExports.jsx(material.Box, { children: localTaskData.dueDate ? (jsxRuntimeExports.jsx(material.Typography, { children: moment(localTaskData.dueDate).format('DD/MM/YYYY HH:mm') })) : (jsxRuntimeExports.jsx(material.Typography, { color: "text.secondary", children: "-" })) })), isEvent && localEventData.recurrence && config.showRecurrence && (jsxRuntimeExports.jsxs(material.Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, mt: 1 }, children: [jsxRuntimeExports.jsx(iconsMaterial.Repeat, { fontSize: "small", color: "action" }), jsxRuntimeExports.jsx(material.Typography, { variant: "body2", children: getRecurrenceLabel(localEventData.recurrence) })] }))] })] }) }));
10238
+ }
10152
10239
  return (jsxRuntimeExports.jsxs(material.Box, { sx: {
10153
10240
  display: 'flex',
10154
10241
  flexDirection: 'column',
@@ -10167,7 +10254,7 @@ const ModalEvents = ({ open, onClose, mode, type: initialType, showTypeTabs = fa
10167
10254
  handleFieldChange('endDate', moment(newStart).add(1, 'hour'));
10168
10255
  }
10169
10256
  }
10170
- }, disabled: isViewMode, slotProps: {
10257
+ }, slotProps: {
10171
10258
  textField: {
10172
10259
  size: 'small',
10173
10260
  fullWidth: true,
@@ -10180,14 +10267,14 @@ const ModalEvents = ({ open, onClose, mode, type: initialType, showTypeTabs = fa
10180
10267
  },
10181
10268
  },
10182
10269
  },
10183
- } }), jsxRuntimeExports.jsxs(material.Box, { sx: { display: 'flex', gap: 1, alignItems: 'center' }, children: [jsxRuntimeExports.jsx(xDatePickersPro.TimePicker, { label: l.startTime, value: startDateDayjs, onChange: (newTime) => {
10270
+ } }), jsxRuntimeExports.jsxs(material.Box, { sx: { display: 'flex', gap: 1, alignItems: 'baseline', marginTop: '15px' }, children: [jsxRuntimeExports.jsx(xDatePickersPro.TimePicker, { label: l.startTime, value: startDateDayjs, onChange: (newTime) => {
10184
10271
  if (newTime) {
10185
10272
  const newStart = moment(localEventData.startDate)
10186
10273
  .hours(newTime.hour())
10187
10274
  .minutes(newTime.minute());
10188
10275
  handleFieldChange('startDate', newStart);
10189
10276
  }
10190
- }, disabled: isViewMode || localEventData.allDay, ampm: false, slotProps: {
10277
+ }, disabled: localEventData.allDay, ampm: false, slotProps: {
10191
10278
  textField: {
10192
10279
  size: 'small',
10193
10280
  },
@@ -10206,7 +10293,7 @@ const ModalEvents = ({ open, onClose, mode, type: initialType, showTypeTabs = fa
10206
10293
  .minutes(newTime.minute());
10207
10294
  handleFieldChange('endDate', newEnd);
10208
10295
  }
10209
- }, disabled: isViewMode || localEventData.allDay, ampm: false, slotProps: {
10296
+ }, disabled: localEventData.allDay, ampm: false, slotProps: {
10210
10297
  textField: {
10211
10298
  size: 'small',
10212
10299
  fullWidth: true,
@@ -10227,7 +10314,7 @@ const ModalEvents = ({ open, onClose, mode, type: initialType, showTypeTabs = fa
10227
10314
  .date(newDate.date());
10228
10315
  handleFieldChange('dueDate', merged);
10229
10316
  }
10230
- }, disabled: isViewMode, slotProps: {
10317
+ }, slotProps: {
10231
10318
  textField: {
10232
10319
  size: 'small',
10233
10320
  },
@@ -10246,7 +10333,7 @@ const ModalEvents = ({ open, onClose, mode, type: initialType, showTypeTabs = fa
10246
10333
  .minutes(newTime.minute());
10247
10334
  handleFieldChange('dueDate', merged);
10248
10335
  }
10249
- }, disabled: isViewMode, ampm: false, slotProps: {
10336
+ }, ampm: false, slotProps: {
10250
10337
  textField: {
10251
10338
  size: 'small',
10252
10339
  },
@@ -10258,14 +10345,14 @@ const ModalEvents = ({ open, onClose, mode, type: initialType, showTypeTabs = fa
10258
10345
  },
10259
10346
  },
10260
10347
  },
10261
- }, sx: { flex: 1 } })] })) }) })] }), isEvent && (config.showAllDay || config.showRecurrence) && (jsxRuntimeExports.jsxs(material.Box, { sx: { display: 'flex', gap: 2, alignItems: 'center', pl: 5 }, children: [config.showAllDay && (jsxRuntimeExports.jsx(material.FormControlLabel, { control: jsxRuntimeExports.jsx(material.Checkbox, { checked: localEventData.allDay || false, onChange: (e) => handleFieldChange('allDay', e.target.checked), disabled: isViewMode, color: "secondary" }), label: l.allDay })), config.showRecurrence && (jsxRuntimeExports.jsxs(material.Box, { sx: { flex: 1, display: 'flex', alignItems: 'center', gap: 1 }, children: [jsxRuntimeExports.jsx(iconsMaterial.Repeat, { fontSize: "small" }), jsxRuntimeExports.jsx(material.FormControl, { fullWidth: true, size: "small", children: jsxRuntimeExports.jsxs(material.Select, { value: localEventData.recurrence || '', onChange: (e) => handleFieldChange('recurrence', e.target.value), disabled: isViewMode, displayEmpty: true, MenuProps: {
10348
+ }, sx: { flex: 1 } })] })) }) })] }), isEvent && (config.showAllDay || config.showRecurrence) && (jsxRuntimeExports.jsxs(material.Box, { sx: { display: 'flex', gap: 2, alignItems: 'center', pl: 5 }, children: [config.showAllDay && (jsxRuntimeExports.jsx(material.FormControlLabel, { control: jsxRuntimeExports.jsx(material.Checkbox, { checked: localEventData.allDay || false, onChange: (e) => handleFieldChange('allDay', e.target.checked), color: "secondary" }), label: l.allDay })), config.showRecurrence && (jsxRuntimeExports.jsxs(material.Box, { sx: { flex: 1, display: 'flex', alignItems: 'center', gap: 1 }, children: [jsxRuntimeExports.jsx(iconsMaterial.Repeat, { fontSize: "small" }), jsxRuntimeExports.jsx(material.FormControl, { fullWidth: true, size: "small", children: jsxRuntimeExports.jsx(material.Select, { value: localEventData.recurrence || '', onChange: (e) => handleFieldChange('recurrence', e.target.value), displayEmpty: true, MenuProps: {
10262
10349
  PaperProps: {
10263
10350
  sx: {
10264
10351
  //@ts-ignore
10265
10352
  backgroundColor: theme.palette.background.panel,
10266
10353
  },
10267
10354
  },
10268
- }, children: [jsxRuntimeExports.jsx(material.MenuItem, { value: "", children: "No repetir" }), jsxRuntimeExports.jsx(material.MenuItem, { value: "DAILY", children: "Diario" }), jsxRuntimeExports.jsx(material.MenuItem, { value: "WEEKLY", children: "Semanal" }), jsxRuntimeExports.jsx(material.MenuItem, { value: "MONTHLY", children: "Mensual" }), jsxRuntimeExports.jsx(material.MenuItem, { value: "YEARLY", children: "Anual" })] }) })] }))] }))] }));
10355
+ }, children: recurrenceOptions.map((option) => (jsxRuntimeExports.jsx(material.MenuItem, { value: option.value, children: option.label }, option.value))) }) })] }))] }))] }));
10269
10356
  };
10270
10357
  return (jsxRuntimeExports.jsxs(material.Dialog, { sx: {
10271
10358
  '& .MuiDialog-paper': {
@@ -10287,7 +10374,8 @@ const ModalEvents = ({ open, onClose, mode, type: initialType, showTypeTabs = fa
10287
10374
  '& .MuiInput-underline:before': { borderBottomColor: 'divider' },
10288
10375
  '& .MuiInput-underline:hover:before': { borderBottomColor: 'text.secondary' },
10289
10376
  '& .MuiInput-underline:after': { borderBottomWidth: 2 },
10290
- } })), jsxRuntimeExports.jsx(TypeTabs, {})] })), !isCreateMode && config.showTitle && (jsxRuntimeExports.jsx(InputContainer, { title: l.title, children: jsxRuntimeExports.jsx(material.TextField, { fullWidth: true, size: "small", value: currentData?.title || '', onChange: (e) => handleFieldChange('title', e.target.value), disabled: isViewMode, error: !!validationErrors.title, helperText: validationErrors.title }) })), config.showDescription && (jsxRuntimeExports.jsx(InputContainer, { title: l.description, children: jsxRuntimeExports.jsx(material.TextField, { fullWidth: true, multiline: true, rows: 3, size: "small", value: currentData?.description || '', onChange: (e) => handleFieldChange('description', e.target.value), disabled: isViewMode }) })), config.showCalendar && (jsxRuntimeExports.jsx(InputContainer, { title: l.calendar, children: jsxRuntimeExports.jsx(material.Autocomplete, { fullWidth: true, size: "small", options: calendars, getOptionLabel: (option) => option.title || option.name || '', value: calendars.find(cal => cal.id === currentData?.calendarId) || null, onChange: (_, newValue) => {
10377
+ } })), jsxRuntimeExports.jsx(TypeTabs, {})] })), !isCreateMode && config.showTitle && (jsxRuntimeExports.jsx(InputContainer, { title: l.title, children: isViewMode ? (renderViewValue(currentData?.title)) : (jsxRuntimeExports.jsx(material.TextField, { fullWidth: true, size: "small", value: currentData?.title || '', onChange: (e) => handleFieldChange('title', e.target.value), error: !!validationErrors.title, helperText: validationErrors.title })) })), config.showDescription && (jsxRuntimeExports.jsx(InputContainer, { title: l.description, children: isViewMode ? (renderViewValue(currentData?.description)) : (jsxRuntimeExports.jsx(material.TextField, { fullWidth: true, multiline: true, rows: 3, size: "small", value: currentData?.description || '', onChange: (e) => handleFieldChange('description', e.target.value) })) })), config.showCalendar && (jsxRuntimeExports.jsx(InputContainer, { title: l.calendar, children: isViewMode ? (renderViewValue(calendars.find(cal => cal.id === currentData?.calendarId)?.title ||
10378
+ calendars.find(cal => cal.id === currentData?.calendarId)?.name)) : (jsxRuntimeExports.jsx(material.Autocomplete, { fullWidth: true, size: "small", options: calendars, getOptionLabel: (option) => option.title || option.name || '', value: calendars.find(cal => cal.id === currentData?.calendarId) || null, onChange: (_, newValue) => {
10291
10379
  const previousCalendar = calendars.find(cal => cal.id === currentData?.calendarId);
10292
10380
  const currentColor = localEventData.color;
10293
10381
  handleFieldChange('calendarId', newValue?.id);
@@ -10300,20 +10388,26 @@ const ModalEvents = ({ open, onClose, mode, type: initialType, showTypeTabs = fa
10300
10388
  handleFieldChange('color', newValue.color);
10301
10389
  }
10302
10390
  }
10303
- }, disabled: isViewMode, slotProps: {
10391
+ }, slotProps: {
10304
10392
  paper: {
10305
10393
  sx: {
10306
10394
  //@ts-ignore
10307
10395
  backgroundColor: theme.palette.background.panel,
10308
10396
  },
10309
10397
  },
10310
- }, renderInput: (params) => (jsxRuntimeExports.jsx(material.TextField, { ...params, placeholder: l.calendarPlaceholder })) }) })), jsxRuntimeExports.jsx(DateTimeSection, {}), isEvent && config.showColor && (jsxRuntimeExports.jsx(InputContainer, { title: l.color, children: jsxRuntimeExports.jsx("input", { type: "color", value: localEventData.color || '#1976d2', onChange: (e) => handleFieldChange('color', e.target.value), disabled: isViewMode, style: {
10398
+ }, renderInput: (params) => (jsxRuntimeExports.jsx(material.TextField, { ...params, placeholder: l.calendarPlaceholder })) })) })), jsxRuntimeExports.jsx(DateTimeSection, {}), isEvent && config.showColor && (jsxRuntimeExports.jsx(InputContainer, { title: l.color, children: isViewMode ? (jsxRuntimeExports.jsxs(material.Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [jsxRuntimeExports.jsx(material.Box, { sx: {
10399
+ width: '24px',
10400
+ height: '24px',
10401
+ borderRadius: '4px',
10402
+ backgroundColor: localEventData.color || '#1976d2',
10403
+ border: '1px solid rgba(0, 0, 0, 0.23)',
10404
+ } }), jsxRuntimeExports.jsx(material.Typography, { children: localEventData.color || '#1976d2' })] })) : (jsxRuntimeExports.jsx("input", { type: "color", value: localEventData.color || '#1976d2', onChange: (e) => handleFieldChange('color', e.target.value), style: {
10311
10405
  width: '60px',
10312
10406
  height: '40px',
10313
10407
  border: '1px solid rgba(0, 0, 0, 0.23)',
10314
10408
  borderRadius: '4px',
10315
- cursor: isViewMode ? 'not-allowed' : 'pointer',
10316
- } }) })), config.showNotifications && (jsxRuntimeExports.jsxs(material.Box, { children: [jsxRuntimeExports.jsxs(material.Box, { sx: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 1 }, children: [jsxRuntimeExports.jsx(material.Typography, { variant: "body2", color: "text.secondary", children: l.notifications }), !isViewMode && (jsxRuntimeExports.jsx(material.Button, { size: "small", variant: "outlined", color: "secondary", startIcon: jsxRuntimeExports.jsx(iconsMaterial.Add, {}), onClick: handleAddNotification, children: l.addNotification }))] }), jsxRuntimeExports.jsx(material.Box, { sx: { display: 'flex', flexDirection: 'column', gap: 1.5 }, children: (currentData?.notifications || []).map((notification, index) => (jsxRuntimeExports.jsxs(material.Box, { sx: {
10409
+ cursor: 'pointer',
10410
+ } })) })), config.showNotifications && (jsxRuntimeExports.jsxs(material.Box, { children: [jsxRuntimeExports.jsxs(material.Box, { sx: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 1 }, children: [jsxRuntimeExports.jsx(material.Typography, { variant: "body2", color: "text.secondary", children: l.notifications }), !isViewMode && (jsxRuntimeExports.jsx(material.Button, { size: "small", variant: "outlined", color: "secondary", startIcon: jsxRuntimeExports.jsx(iconsMaterial.Add, {}), onClick: handleAddNotification, children: l.addNotification }))] }), (currentData?.notifications || []).length === 0 && isViewMode ? (jsxRuntimeExports.jsx(material.Typography, { color: "text.secondary", children: "-" })) : (jsxRuntimeExports.jsx(material.Box, { sx: { display: 'flex', flexDirection: 'column', gap: 1.5 }, children: (currentData?.notifications || []).map((notification, index) => (jsxRuntimeExports.jsx(material.Box, { sx: {
10317
10411
  display: 'flex',
10318
10412
  flexDirection: 'column',
10319
10413
  gap: 1,
@@ -10322,33 +10416,19 @@ const ModalEvents = ({ open, onClose, mode, type: initialType, showTypeTabs = fa
10322
10416
  bgcolor: theme.palette.mode === 'dark'
10323
10417
  ? 'rgba(255, 255, 255, 0.05)'
10324
10418
  : 'rgba(0, 0, 0, 0.02)',
10325
- }, children: [jsxRuntimeExports.jsxs(material.Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, flexWrap: 'wrap' }, children: [jsxRuntimeExports.jsx(material.Typography, { variant: "body2", children: "Enviar recordatorio" }), jsxRuntimeExports.jsx(material.TextField, { type: "number", size: "small", value: notification.value, onChange: (e) => {
10326
- const updated = [...(currentData?.notifications || [])];
10327
- updated[index] = { ...notification, value: parseInt(e.target.value) || 0 };
10328
- handleFieldChange('notifications', updated);
10329
- }, disabled: isViewMode, sx: { width: '70px' }, inputProps: { min: 0 } }), jsxRuntimeExports.jsx(material.FormControl, { size: "small", sx: { minWidth: '100px' }, children: jsxRuntimeExports.jsxs(material.Select, { value: notification.type, onChange: (e) => {
10330
- const updated = [...(currentData?.notifications || [])];
10331
- updated[index] = { ...notification, type: e.target.value };
10332
- handleFieldChange('notifications', updated);
10333
- }, disabled: isViewMode, children: [jsxRuntimeExports.jsx(material.MenuItem, { value: "minutes", children: "minuto/s" }), jsxRuntimeExports.jsx(material.MenuItem, { value: "hours", children: "hora/s" }), jsxRuntimeExports.jsx(material.MenuItem, { value: "days", children: "d\u00EDa/s" })] }) }), jsxRuntimeExports.jsx(material.Typography, { variant: "body2", children: "antes." })] }), jsxRuntimeExports.jsxs(material.Box, { sx: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' }, children: [jsxRuntimeExports.jsx(material.FormControlLabel, { control: jsxRuntimeExports.jsx(material.Checkbox, { checked: notification.sendToContact || false, onChange: (e) => {
10419
+ }, children: isViewMode ? (jsxRuntimeExports.jsxs(material.Typography, { variant: "body2", children: ["Enviar recordatorio ", notification.value, " ", notification.type === 'minutes' ? 'minuto/s' : notification.type === 'hours' ? 'hora/s' : 'd\u00eda/s', " antes", notification.sendToContact && ' a contacto externo'] })) : (jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [jsxRuntimeExports.jsxs(material.Box, { sx: { display: 'flex', alignItems: 'center', gap: 1, flexWrap: 'wrap' }, children: [jsxRuntimeExports.jsx(material.Typography, { variant: "body2", children: "Enviar recordatorio" }), jsxRuntimeExports.jsx(material.TextField, { type: "number", size: "small", value: notification.value, onChange: (e) => {
10334
10420
  const updated = [...(currentData?.notifications || [])];
10335
- updated[index] = { ...notification, sendToContact: e.target.checked };
10421
+ updated[index] = { ...notification, value: parseInt(e.target.value) || 0 };
10336
10422
  handleFieldChange('notifications', updated);
10337
- }, disabled: isViewMode, color: "secondary" }), label: "Enviar recordatorio a contacto externo" }), !isViewMode && (jsxRuntimeExports.jsx(material.IconButton, { size: "small", onClick: () => handleRemoveNotification(index), sx: { color: 'text.disabled' }, children: jsxRuntimeExports.jsx(iconsMaterial.Delete, {}) }))] })] }, index))) })] })), config.showLinkedContacts && (jsxRuntimeExports.jsxs(InputContainer, { title: l.linkedContacts, children: [!isViewMode && (jsxRuntimeExports.jsxs(material.Box, { sx: { position: 'relative' }, children: [jsxRuntimeExports.jsx(material.TextField, { fullWidth: true, size: "small", placeholder: l.searchContacts, value: contactSearch, onChange: (e) => handleContactSearchChange(e.target.value), InputProps: {
10338
- startAdornment: jsxRuntimeExports.jsx(iconsMaterial.Search, { fontSize: "small", sx: { mr: 1, color: 'text.secondary' } }),
10339
- } }), isSearchingContacts && (jsxRuntimeExports.jsx(material.Box, { sx: {
10340
- position: 'absolute',
10341
- bottom: 0,
10342
- left: 0,
10343
- right: 0,
10344
- height: 2,
10345
- bgcolor: 'primary.main',
10346
- animation: 'progress 1s infinite',
10347
- '@keyframes progress': {
10348
- '0%': { transform: 'translateX(-100%)' },
10349
- '100%': { transform: 'translateX(100%)' },
10350
- },
10351
- } }))] })), jsxRuntimeExports.jsx(material.Box, { sx: { mt: 1, display: 'flex', flexWrap: 'wrap', gap: 1 }, children: (currentData?.linkedContacts || []).map((contact) => (jsxRuntimeExports.jsxs(material.Box, { sx: {
10423
+ }, sx: { width: '70px' }, inputProps: { min: 0 } }), jsxRuntimeExports.jsx(material.FormControl, { size: "small", sx: { minWidth: '100px' }, children: jsxRuntimeExports.jsxs(material.Select, { value: notification.type, onChange: (e) => {
10424
+ const updated = [...(currentData?.notifications || [])];
10425
+ updated[index] = { ...notification, type: e.target.value };
10426
+ handleFieldChange('notifications', updated);
10427
+ }, children: [jsxRuntimeExports.jsx(material.MenuItem, { value: "minutes", children: "minuto/s" }), jsxRuntimeExports.jsx(material.MenuItem, { value: "hours", children: "hora/s" }), jsxRuntimeExports.jsx(material.MenuItem, { value: "days", children: "d\\u00eda/s" })] }) }), jsxRuntimeExports.jsx(material.Typography, { variant: "body2", children: "antes." })] }), jsxRuntimeExports.jsxs(material.Box, { sx: { display: 'flex', alignItems: 'center', justifyContent: 'space-between' }, children: [jsxRuntimeExports.jsx(material.FormControlLabel, { control: jsxRuntimeExports.jsx(material.Checkbox, { checked: notification.sendToContact || false, onChange: (e) => {
10428
+ const updated = [...(currentData?.notifications || [])];
10429
+ updated[index] = { ...notification, sendToContact: e.target.checked };
10430
+ handleFieldChange('notifications', updated);
10431
+ }, color: "secondary" }), label: "Enviar recordatorio a contacto externo" }), jsxRuntimeExports.jsx(material.IconButton, { size: "small", onClick: () => handleRemoveNotification(index), sx: { color: 'text.disabled' }, children: jsxRuntimeExports.jsx(iconsMaterial.Delete, {}) })] })] })) }, index))) }))] })), config.showLinkedContacts && (jsxRuntimeExports.jsxs(InputContainer, { title: l.linkedContacts, children: [!isViewMode && (jsxRuntimeExports.jsx(ContactSearchInput, { onChange: handleContactSearchDebounced, placeholder: l.searchContacts, isSearching: isSearching || isSearchingContacts, value: contactSearchValue })), (currentData?.linkedContacts || []).length === 0 && isViewMode ? (jsxRuntimeExports.jsx(material.Typography, { color: "text.secondary", children: "-" })) : (jsxRuntimeExports.jsx(material.Box, { sx: { mt: 1, display: 'flex', flexWrap: 'wrap', gap: 1 }, children: (currentData?.linkedContacts || []).map((contact) => (jsxRuntimeExports.jsxs(material.Box, { sx: {
10352
10432
  display: 'inline-flex',
10353
10433
  alignItems: 'center',
10354
10434
  gap: 0.5,
@@ -10356,24 +10436,32 @@ const ModalEvents = ({ open, onClose, mode, type: initialType, showTypeTabs = fa
10356
10436
  py: 0.5,
10357
10437
  bgcolor: 'action.hover',
10358
10438
  borderRadius: 1,
10359
- }, children: [jsxRuntimeExports.jsx(material.Typography, { variant: "body2", children: contact.name }), !isViewMode && (jsxRuntimeExports.jsx(material.IconButton, { size: "small", onClick: () => handleRemoveContact(contact.id), sx: { ml: 0.5 }, children: jsxRuntimeExports.jsx(iconsMaterial.Close, { fontSize: "small" }) }))] }, contact.id))) }), !isViewMode && contactSearch.length >= 2 && (jsxRuntimeExports.jsx(material.Box, { sx: { mt: 1, maxHeight: '200px', overflowY: 'auto', border: '1px solid', borderColor: 'divider', borderRadius: 1 }, children: isSearchingContacts ? (jsxRuntimeExports.jsx(material.Box, { sx: { p: 2, textAlign: 'center' }, children: jsxRuntimeExports.jsx(material.Typography, { variant: "body2", color: "text.secondary", children: "Buscando..." }) })) : filteredContacts.length > 0 ? (filteredContacts.map((contact) => (jsxRuntimeExports.jsxs(material.Box, { sx: {
10360
- p: 1,
10361
- cursor: 'pointer',
10362
- '&:hover': { bgcolor: 'action.hover' },
10363
- }, onClick: () => {
10439
+ }, children: [jsxRuntimeExports.jsx(material.Typography, { variant: "body2", children: contact.name }), !isViewMode && (jsxRuntimeExports.jsx(material.IconButton, { size: "small", onClick: () => handleRemoveContact(contact.id), sx: { ml: 0.5 }, children: jsxRuntimeExports.jsx(iconsMaterial.Close, { fontSize: "small" }) }))] }, contact.id))) })), !isViewMode && contactSearchValue.length >= 2 && (jsxRuntimeExports.jsx(material.List, { sx: {
10440
+ mt: 1,
10441
+ maxHeight: '200px',
10442
+ overflow: 'auto',
10443
+ border: '1px solid',
10444
+ borderColor: 'divider',
10445
+ borderRadius: 1,
10446
+ //@ts-ignore
10447
+ backgroundColor: theme.palette.background.panel,
10448
+ backgroundImage: 'linear-gradient(rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.12))',
10449
+ p: 0,
10450
+ }, children: (isSearching || isSearchingContacts) ? (jsxRuntimeExports.jsx(material.Box, { sx: { p: 2, textAlign: 'center' }, children: jsxRuntimeExports.jsx(material.Typography, { variant: "body2", color: "text.secondary", children: "Buscando..." }) })) : filteredContacts.length > 0 ? (filteredContacts.map((contact) => (jsxRuntimeExports.jsxs(material.ListItemButton, { onClick: () => {
10364
10451
  handleAddContact(contact);
10365
- setContactSearch('');
10452
+ setContactSearchValue('');
10453
+ contactSearchRef.current = '';
10366
10454
  setSearchResults([]);
10367
- }, children: [jsxRuntimeExports.jsx(material.Typography, { variant: "body2", children: contact.name }), contact.email && (jsxRuntimeExports.jsx(material.Typography, { variant: "caption", color: "text.secondary", children: contact.email }))] }, contact.id)))) : (jsxRuntimeExports.jsx(material.Box, { sx: { p: 2, textAlign: 'center' }, children: jsxRuntimeExports.jsx(material.Typography, { variant: "body2", color: "text.secondary", children: "No se encontraron contactos" }) })) }))] })), isEvent && config.showLocation && (slots.location ? slots.location({
10455
+ }, children: [jsxRuntimeExports.jsx(material.ListItemIcon, { children: jsxRuntimeExports.jsx(iconsMaterial.Person, { sx: { color: 'text.disabled' } }) }), jsxRuntimeExports.jsx(material.ListItemText, { primary: contact.name, secondary: contact.email })] }, contact.id)))) : (jsxRuntimeExports.jsx(material.Box, { sx: { p: 2, textAlign: 'center' }, children: jsxRuntimeExports.jsx(material.Typography, { variant: "body2", color: "text.secondary", children: "No se encontraron contactos" }) })) }))] })), isEvent && config.showLocation && (slots.location ? slots.location({
10368
10456
  disabled: isViewMode,
10369
10457
  mode,
10370
10458
  type: currentType,
10371
10459
  value: localEventData.location || '',
10372
10460
  onChange: (location) => handleFieldChange('location', location),
10373
10461
  placeholder: l.locationPlaceholder,
10374
- }) : (jsxRuntimeExports.jsx(InputContainer, { title: l.location, children: jsxRuntimeExports.jsx(material.TextField, { fullWidth: true, size: "small", placeholder: l.locationPlaceholder, value: localEventData.location || '', onChange: (e) => handleFieldChange('location', e.target.value), disabled: isViewMode, InputProps: {
10462
+ }) : (jsxRuntimeExports.jsx(InputContainer, { title: l.location, children: isViewMode ? (jsxRuntimeExports.jsxs(material.Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 }, children: [jsxRuntimeExports.jsx(iconsMaterial.Place, { fontSize: "small", sx: { color: 'text.secondary' } }), renderViewValue(localEventData.location)] })) : (jsxRuntimeExports.jsx(material.TextField, { fullWidth: true, size: "small", placeholder: l.locationPlaceholder, value: localEventData.location || '', onChange: (e) => handleFieldChange('location', e.target.value), InputProps: {
10375
10463
  startAdornment: jsxRuntimeExports.jsx(iconsMaterial.Place, { fontSize: "small", sx: { mr: 1, color: 'text.secondary' } }),
10376
- } }) })))] }), jsxRuntimeExports.jsxs(material.DialogActions, { sx: { px: 3, pb: 2 }, children: [jsxRuntimeExports.jsx(material.Button, { variant: "outlined", color: "secondary", size: "small", onClick: onClose, disabled: isSaving || isDeleting, children: l.cancel }), !isViewMode && (jsxRuntimeExports.jsx(material.Button, { variant: "contained", color: "primary", size: "small", onClick: handleSave, disabled: isSaving || isDeleting, children: isSaving ? 'Guardando...' : l.save }))] })] }));
10464
+ } })) })))] }), jsxRuntimeExports.jsxs(material.DialogActions, { sx: { px: 3, pb: 2 }, children: [jsxRuntimeExports.jsx(material.Button, { variant: "outlined", color: "secondary", size: "small", onClick: onClose, disabled: isSaving || isDeleting, children: l.cancel }), !isViewMode && (jsxRuntimeExports.jsx(material.Button, { variant: "contained", color: "primary", size: "small", onClick: handleSave, disabled: isSaving || isDeleting, children: isSaving ? 'Guardando...' : l.save }))] })] }));
10377
10465
  };
10378
10466
 
10379
10467
  exports.ContactInfoPopup = ContactInfoPopup;