react-native-resource-calendar 1.0.8 → 1.0.10

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.mjs CHANGED
@@ -1,12 +1,12 @@
1
- import * as React18 from 'react';
2
- import React18__default, { createContext, useState, useEffect, useMemo, useContext, useRef, useCallback } from 'react';
1
+ import * as React19 from 'react';
2
+ import React19__default, { createContext, useState, useEffect, useMemo, useContext, useRef, useCallback } from 'react';
3
3
  import { Gesture, GestureDetector } from 'react-native-gesture-handler';
4
4
  import Animated2, { useAnimatedRef, useSharedValue, runOnJS, withSpring, useFrameCallback, scrollTo, useAnimatedScrollHandler, useAnimatedStyle, useAnimatedProps } from 'react-native-reanimated';
5
5
  import { InteractionManager, View, StyleSheet, Text, TouchableOpacity, TextInput, useWindowDimensions, Platform, Dimensions, Image } from 'react-native';
6
6
  import { FlashList } from '@shopify/flash-list';
7
7
  import * as Haptics from 'expo-haptics';
8
8
  import { toZonedTime } from 'date-fns-tz';
9
- import { isSameDay, format, getHours, getMinutes, set, setSeconds, setMinutes, setHours } from 'date-fns';
9
+ import { isSameDay, format, getHours, getMinutes, set, addDays, setSeconds, setMinutes, setHours } from 'date-fns';
10
10
  import { isUndefined } from 'lodash';
11
11
  import { createStore } from 'zustand';
12
12
  import { shallow } from 'zustand/shallow';
@@ -270,8 +270,16 @@ function computeEventFrames(events, containerWidthPx, mode, options) {
270
270
  });
271
271
  }
272
272
  }
273
+ var findResourceIndexFor = (rid, resourceIds) => Math.max(0, Math.min(
274
+ resourceIds.length - 1,
275
+ resourceIds.findIndex((id) => id === rid)
276
+ ));
277
+ var findDayIndexFor = (date, days) => Math.max(0, Math.min(
278
+ days.length - 1,
279
+ days.findIndex((d) => date === format(d, "yyyy-MM-dd"))
280
+ ));
273
281
  var Col = ({ children, divider, space, style }) => {
274
- return /* @__PURE__ */ React18__default.createElement(View, { style: [{ flexDirection: "column" }, style] }, React18__default.Children.toArray(children).map((child, index) => /* @__PURE__ */ React18__default.createElement(React18__default.Fragment, { key: index }, child, index !== React18__default.Children.toArray(children).length - 1 && divider, index !== React18__default.Children.toArray(children).length - 1 && /* @__PURE__ */ React18__default.createElement(View, { style: { height: space, width: "100%" } }))));
282
+ return /* @__PURE__ */ React19__default.createElement(View, { style: [{ flexDirection: "column" }, style] }, React19__default.Children.toArray(children).map((child, index) => /* @__PURE__ */ React19__default.createElement(React19__default.Fragment, { key: index }, child, index !== React19__default.Children.toArray(children).length - 1 && divider, index !== React19__default.Children.toArray(children).length - 1 && /* @__PURE__ */ React19__default.createElement(View, { style: { height: space, width: "100%" } }))));
275
283
  };
276
284
  var Col_default = Col;
277
285
 
@@ -315,11 +323,11 @@ var CalendarThemeProvider = ({ theme, children }) => {
315
323
  ...theme,
316
324
  typography: { ...defaultTheme.typography, ...theme?.typography }
317
325
  };
318
- return /* @__PURE__ */ React18__default.createElement(ThemeCtx.Provider, { value: mergedTheme }, children);
326
+ return /* @__PURE__ */ React19__default.createElement(ThemeCtx.Provider, { value: mergedTheme }, children);
319
327
  };
320
328
 
321
329
  // src/components/TimeLabels.tsx
322
- var TimeLabels = React18.forwardRef(({
330
+ var TimeLabels = React19.forwardRef(({
323
331
  timezone,
324
332
  hourHeight = 120,
325
333
  startMinutes = 0,
@@ -359,7 +367,7 @@ var TimeLabels = React18.forwardRef(({
359
367
  }
360
368
  });
361
369
  }, [date, isToday, APPOINTMENT_BLOCK_HEIGHT, startMinutes, hourHeight]);
362
- return /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement(Col_default, null, Array.from({ length: 24 }).map((_, index) => /* @__PURE__ */ React18.createElement(View, { key: index, style: [styles.timeLabel, { height: hourHeight }] }, /* @__PURE__ */ React18.createElement(
370
+ return /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement(Col_default, null, Array.from({ length: 24 }).map((_, index) => /* @__PURE__ */ React19.createElement(View, { key: index, style: [styles.timeLabel, { height: hourHeight }] }, /* @__PURE__ */ React19.createElement(
363
371
  Text,
364
372
  {
365
373
  allowFontScaling: false,
@@ -371,7 +379,7 @@ var TimeLabels = React18.forwardRef(({
371
379
  }
372
380
  },
373
381
  indexToDate(index).split(" ")[0]
374
- ), /* @__PURE__ */ React18.createElement(
382
+ ), /* @__PURE__ */ React19.createElement(
375
383
  Text,
376
384
  {
377
385
  allowFontScaling: false,
@@ -383,10 +391,10 @@ var TimeLabels = React18.forwardRef(({
383
391
  }
384
392
  },
385
393
  indexToDate(index).split(" ")[1]
386
- ))), isToday && /* @__PURE__ */ React18.createElement(View, { style: [styles.currentTime, {
394
+ ))), isToday && /* @__PURE__ */ React19.createElement(View, { style: [styles.currentTime, {
387
395
  top: currentTimeYPosition - 13,
388
396
  width: TIME_LABEL_WIDTH
389
- }] }, /* @__PURE__ */ React18.createElement(
397
+ }] }, /* @__PURE__ */ React19.createElement(
390
398
  Text,
391
399
  {
392
400
  allowFontScaling: false,
@@ -399,7 +407,7 @@ var TimeLabels = React18.forwardRef(({
399
407
  }
400
408
  },
401
409
  currentTime
402
- ))), isToday && /* @__PURE__ */ React18.createElement(View, { style: [styles.currentTimeLine, {
410
+ ))), isToday && /* @__PURE__ */ React19.createElement(View, { style: [styles.currentTimeLine, {
403
411
  pointerEvents: "none",
404
412
  top: currentTimeYPosition,
405
413
  width: totalTimelineWidth,
@@ -435,11 +443,11 @@ var Hidden = ({ isHidden, children }) => {
435
443
  if (isHidden) {
436
444
  return null;
437
445
  }
438
- return /* @__PURE__ */ React18__default.createElement(React18__default.Fragment, null, children);
446
+ return /* @__PURE__ */ React19__default.createElement(React19__default.Fragment, null, children);
439
447
  };
440
448
  var Hidden_default = Hidden;
441
449
  var Center = ({ children, style }) => {
442
- return /* @__PURE__ */ React18__default.createElement(
450
+ return /* @__PURE__ */ React19__default.createElement(
443
451
  View,
444
452
  {
445
453
  style: [{
@@ -460,7 +468,7 @@ var Badge = ({
460
468
  textColor = "white"
461
469
  }) => {
462
470
  const titleFace = useResolvedFont({ fontWeight: "600" });
463
- return /* @__PURE__ */ React18__default.createElement(View, { style: [styles2.badge, { backgroundColor: color }, style] }, children ? children : /* @__PURE__ */ React18__default.createElement(
471
+ return /* @__PURE__ */ React19__default.createElement(View, { style: [styles2.badge, { backgroundColor: color }, style] }, children ? children : /* @__PURE__ */ React19__default.createElement(
464
472
  Text,
465
473
  {
466
474
  allowFontScaling: false,
@@ -484,13 +492,16 @@ var styles2 = StyleSheet.create({
484
492
  });
485
493
  var Badge_default = Badge;
486
494
  var createCalendarStore = () => createStore((set2) => ({
495
+ date: /* @__PURE__ */ new Date(),
487
496
  resourcesById: {},
488
- eventsByResource: {},
489
- disabledBlocksByResource: {},
490
- disabledIntervalsByResource: {},
497
+ // NEW multi-day
498
+ eventsByDay: {},
499
+ disabledBlocksByDay: {},
500
+ disabledIntervalsByDay: {},
491
501
  selectedEvent: null,
492
502
  draggedEventDraft: null,
493
503
  setSelectedEvent: (evt) => set2({ selectedEvent: evt }),
504
+ setDate: (date) => set2({ date }),
494
505
  upsertResources: (rs) => set2((s) => {
495
506
  const next = { ...s.resourcesById };
496
507
  let changed = false;
@@ -503,23 +514,19 @@ var createCalendarStore = () => createStore((set2) => ({
503
514
  }
504
515
  return changed ? { resourcesById: next } : {};
505
516
  }),
506
- setDayData: ({ events, disabledBlocks, disableIntervals }) => set2((s) => ({
507
- eventsByResource: events ?? s.eventsByResource,
508
- disabledBlocksByResource: disabledBlocks ?? s.disabledBlocksByResource,
509
- disabledIntervalsByResource: disableIntervals ?? s.disabledIntervalsByResource
517
+ // NEW: multi-day write
518
+ setDayDataFor: (dayKey, { events, disabledBlocks, disableIntervals }) => set2((s) => ({
519
+ eventsByDay: events ? { ...s.eventsByDay, [dayKey]: events } : s.eventsByDay,
520
+ disabledBlocksByDay: disabledBlocks ? { ...s.disabledBlocksByDay, [dayKey]: disabledBlocks } : s.disabledBlocksByDay,
521
+ disabledIntervalsByDay: disableIntervals ? { ...s.disabledIntervalsByDay, [dayKey]: disableIntervals } : s.disabledIntervalsByDay
510
522
  })),
511
- setDraggedEventDraft: (draft) => set2({ draggedEventDraft: draft }),
512
- clearDay: () => set2({
513
- eventsByResource: {},
514
- disabledBlocksByResource: {},
515
- disabledIntervalsByResource: {}
516
- })
523
+ setDraggedEventDraft: (draft) => set2({ draggedEventDraft: draft })
517
524
  }));
518
525
  var StoreContext = createContext(null);
519
526
  var Provider = ({ children }) => {
520
527
  const ref = useRef(void 0);
521
528
  if (!ref.current) ref.current = createCalendarStore();
522
- return /* @__PURE__ */ React18__default.createElement(StoreContext.Provider, { value: ref.current }, children);
529
+ return /* @__PURE__ */ React19__default.createElement(StoreContext.Provider, { value: ref.current }, children);
523
530
  };
524
531
  var useBound = (selector, eq) => {
525
532
  const store = useContext(StoreContext);
@@ -529,13 +536,24 @@ var useBound = (selector, eq) => {
529
536
  var useResourceById = (id) => useBound((s) => s.resourcesById[id]);
530
537
  var useGetSelectedEvent = () => useBound((s) => s.selectedEvent);
531
538
  var useSetSelectedEvent = () => useBound((s) => s.setSelectedEvent);
532
- var useEventsFor = (resourceId) => useBound((s) => s.eventsByResource[resourceId] ?? [], shallow);
539
+ var useEventsFor = (resourceId, dayDate) => useBound((s) => {
540
+ const key = format(dayDate, "yyyy-MM-dd");
541
+ return s.eventsByDay?.[key]?.[resourceId] ?? [];
542
+ }, shallow);
533
543
  var useGetDraggedEventDraft = () => useBound((s) => s.draggedEventDraft);
534
- var useDisabledBlocksFor = (resourceId) => useBound((s) => s.disabledBlocksByResource[resourceId] ?? [], shallow);
535
- var useDisabledIntervalsFor = (resourceId) => useBound((s) => s.disabledIntervalsByResource[resourceId] ?? [], shallow);
544
+ var useDisabledBlocksFor = (resourceId, dayDate) => useBound((s) => {
545
+ const key = format(dayDate, "yyyy-MM-dd");
546
+ return s.disabledBlocksByDay?.[key]?.[resourceId] ?? [];
547
+ }, shallow);
548
+ var useDisabledIntervalsFor = (resourceId, dayDate) => useBound((s) => {
549
+ const key = format(dayDate, "yyyy-MM-dd");
550
+ return s.disabledIntervalsByDay?.[key]?.[resourceId] ?? [];
551
+ }, shallow);
536
552
  var useUpsertResources = () => useBound((s) => s.upsertResources);
537
- var useSetDayData = () => useBound((s) => s.setDayData);
553
+ var useSetDayDataFor = () => useBound((s) => s.setDayDataFor);
538
554
  var useSetDraggedEventDraft = () => useBound((s) => s.setDraggedEventDraft);
555
+ var useSetDate = () => useBound((s) => s.setDate);
556
+ var useGetDate = () => useBound((s) => s.date);
539
557
  var zustandBinding = {
540
558
  Provider,
541
559
  useResourceById,
@@ -543,7 +561,9 @@ var zustandBinding = {
543
561
  useDisabledBlocksFor,
544
562
  useDisabledIntervalsFor,
545
563
  useUpsertResources,
546
- useSetDayData,
564
+ useSetDate,
565
+ useGetDate,
566
+ useSetDayDataFor,
547
567
  useGetSelectedEvent,
548
568
  useSetSelectedEvent,
549
569
  useGetDraggedEventDraft,
@@ -560,19 +580,19 @@ var useCalendarBinding = () => {
560
580
  var CalendarBindingProvider = ({ binding, children }) => {
561
581
  const active = binding ?? zustandBinding;
562
582
  const StoreProvider = active.Provider;
563
- return /* @__PURE__ */ React18__default.createElement(BindingCtx.Provider, { value: active }, /* @__PURE__ */ React18__default.createElement(StoreProvider, null, children));
583
+ return /* @__PURE__ */ React19__default.createElement(BindingCtx.Provider, { value: active }, /* @__PURE__ */ React19__default.createElement(StoreProvider, null, children));
564
584
  };
565
585
 
566
586
  // src/components/ResourcesComponent.tsx
567
- var ResourceComponent = ({ id, onResourcePress, APPOINTMENT_BLOCK_WIDTH }) => {
587
+ var ResourceComponent = ({ id, onResourcePress, APPOINTMENT_BLOCK_WIDTH, date }) => {
568
588
  const { useResourceById: useResourceById2, useEventsFor: useEventsFor2 } = useCalendarBinding();
569
589
  const resource = useResourceById2(id);
570
- const events = useEventsFor2(id);
590
+ const events = useEventsFor2(id, date);
571
591
  const titleFace = useResolvedFont({ fontWeight: "700" });
572
- return /* @__PURE__ */ React18.createElement(Col_default, { style: [{
592
+ return /* @__PURE__ */ React19.createElement(Col_default, { style: [{
573
593
  alignItems: "center",
574
594
  width: APPOINTMENT_BLOCK_WIDTH
575
- }] }, /* @__PURE__ */ React18.createElement(View, { style: { position: "relative" } }, /* @__PURE__ */ React18.createElement(
595
+ }] }, /* @__PURE__ */ React19.createElement(View, { style: { position: "relative" } }, /* @__PURE__ */ React19.createElement(
576
596
  StaffAvatar,
577
597
  {
578
598
  onPress: () => {
@@ -580,12 +600,12 @@ var ResourceComponent = ({ id, onResourcePress, APPOINTMENT_BLOCK_WIDTH }) => {
580
600
  onResourcePress(resource);
581
601
  },
582
602
  name: resource?.name,
583
- circleSize: 40,
603
+ circleSize: Math.min(40, APPOINTMENT_BLOCK_WIDTH - 12),
584
604
  fontSize: 16,
585
605
  badge: events?.length,
586
606
  image: resource?.avatar
587
607
  }
588
- )), /* @__PURE__ */ React18.createElement(
608
+ )), /* @__PURE__ */ React19.createElement(
589
609
  Text,
590
610
  {
591
611
  style: {
@@ -599,11 +619,12 @@ var ResourceComponent = ({ id, onResourcePress, APPOINTMENT_BLOCK_WIDTH }) => {
599
619
  resource?.name
600
620
  ));
601
621
  };
602
- var ResourcesComponent = ({ resourceIds, onResourcePress, APPOINTMENT_BLOCK_WIDTH }) => {
603
- return /* @__PURE__ */ React18.createElement(React18.Fragment, null, resourceIds?.map((id) => {
604
- return /* @__PURE__ */ React18.createElement(
622
+ var ResourcesComponent = ({ resourceIds, onResourcePress, APPOINTMENT_BLOCK_WIDTH, date }) => {
623
+ return /* @__PURE__ */ React19.createElement(React19.Fragment, null, resourceIds?.map((id) => {
624
+ return /* @__PURE__ */ React19.createElement(
605
625
  ResourceComponent,
606
626
  {
627
+ date,
607
628
  key: id,
608
629
  id,
609
630
  APPOINTMENT_BLOCK_WIDTH,
@@ -626,17 +647,17 @@ function StaffAvatar({
626
647
  textColor
627
648
  }) {
628
649
  const titleFace = useResolvedFont({ fontWeight: "700" });
629
- return /* @__PURE__ */ React18.createElement(
650
+ return /* @__PURE__ */ React19.createElement(
630
651
  TouchableOpacity,
631
652
  {
632
653
  disabled: isUndefined(onPress),
633
654
  onPress,
634
655
  style: containerStyle
635
656
  },
636
- /* @__PURE__ */ React18.createElement(Center_default, { style: {
657
+ /* @__PURE__ */ React19.createElement(Center_default, { style: {
637
658
  borderRadius: 9999,
638
659
  backgroundColor: ringColor
639
- } }, /* @__PURE__ */ React18.createElement(Hidden_default, { isHidden: isUndefined(badge) || Number(badge) == 0 }, /* @__PURE__ */ React18.createElement(
660
+ } }, /* @__PURE__ */ React19.createElement(Hidden_default, { isHidden: isUndefined(badge) || Number(badge) == 0 }, /* @__PURE__ */ React19.createElement(
640
661
  View,
641
662
  {
642
663
  style: [{
@@ -649,7 +670,7 @@ function StaffAvatar({
649
670
  padding: 2
650
671
  }, badgeStyle]
651
672
  },
652
- /* @__PURE__ */ React18.createElement(
673
+ /* @__PURE__ */ React19.createElement(
653
674
  Badge_default,
654
675
  {
655
676
  fontSize: 12,
@@ -657,18 +678,18 @@ function StaffAvatar({
657
678
  color: "#4d959c"
658
679
  }
659
680
  )
660
- )), /* @__PURE__ */ React18.createElement(Center_default, { style: {
681
+ )), /* @__PURE__ */ React19.createElement(Center_default, { style: {
661
682
  margin: 2,
662
683
  borderRadius: 9999,
663
684
  backgroundColor: "white"
664
- } }, /* @__PURE__ */ React18.createElement(Center_default, { style: {
685
+ } }, /* @__PURE__ */ React19.createElement(Center_default, { style: {
665
686
  margin: 2,
666
687
  borderRadius: 9999,
667
688
  height: circleSize,
668
689
  width: circleSize,
669
690
  backgroundColor: avatarColor || "#C9E5E8",
670
691
  overflow: "hidden"
671
- } }, image ? /* @__PURE__ */ React18.createElement(
692
+ } }, image ? /* @__PURE__ */ React19.createElement(
672
693
  Image,
673
694
  {
674
695
  resizeMode: "cover",
@@ -679,7 +700,7 @@ function StaffAvatar({
679
700
  ...StyleSheet.absoluteFillObject
680
701
  }
681
702
  }
682
- ) : /* @__PURE__ */ React18.createElement(
703
+ ) : /* @__PURE__ */ React19.createElement(
683
704
  Text,
684
705
  {
685
706
  allowFontScaling: false,
@@ -695,13 +716,12 @@ function StaffAvatar({
695
716
  );
696
717
  }
697
718
  var EventGridBlocksSkia = ({
698
- dateRef,
699
719
  handleBlockPress,
700
720
  hourHeight,
701
721
  APPOINTMENT_BLOCK_WIDTH
702
722
  }) => {
703
723
  const rowHeight = hourHeight / 4;
704
- const [pressedRow, setPressedRow] = React18.useState(null);
724
+ const [pressedRow, setPressedRow] = React19.useState(null);
705
725
  const timeLabels = useMemo(() => {
706
726
  const out = [];
707
727
  for (let h = 0; h < 24; h++) {
@@ -728,21 +748,20 @@ var EventGridBlocksSkia = ({
728
748
  const firstRects = rects.slice(0, midIndex);
729
749
  const secondRects = rects.slice(midIndex);
730
750
  const segmentHeight = rowHeight * firstRects.length;
731
- const onSlotPress = React18.useCallback(
751
+ const onSlotPress = React19.useCallback(
732
752
  (row) => {
733
753
  setPressedRow(null);
734
754
  const slot = timeLabels[row];
735
755
  if (slot) {
736
- const timestamp = combineDateAndTime(dateRef.current, slot);
737
- handleBlockPress(timestamp);
756
+ handleBlockPress(slot);
738
757
  }
739
758
  },
740
- [dateRef, handleBlockPress, timeLabels]
759
+ [handleBlockPress, timeLabels]
741
760
  );
742
- const onPressBegin = React18.useCallback((row) => {
761
+ const onPressBegin = React19.useCallback((row) => {
743
762
  setPressedRow(row);
744
763
  }, []);
745
- const onTouchesUp = React18.useCallback(() => {
764
+ const onTouchesUp = React19.useCallback(() => {
746
765
  setPressedRow(null);
747
766
  }, []);
748
767
  const longPressGesture = Gesture.LongPress().onBegin((e) => {
@@ -755,7 +774,7 @@ var EventGridBlocksSkia = ({
755
774
  "worklet";
756
775
  runOnJS(onTouchesUp)();
757
776
  });
758
- return /* @__PURE__ */ React18.createElement(GestureDetector, { gesture: longPressGesture }, /* @__PURE__ */ React18.createElement(View, null, /* @__PURE__ */ React18.createElement(Canvas, { style: { width: APPOINTMENT_BLOCK_WIDTH, height: segmentHeight } }, firstRects.map(({ x, y, width: w, height: h, row }, idx) => /* @__PURE__ */ React18.createElement(React18.Fragment, { key: idx }, /* @__PURE__ */ React18.createElement(
777
+ return /* @__PURE__ */ React19.createElement(GestureDetector, { gesture: longPressGesture }, /* @__PURE__ */ React19.createElement(View, null, /* @__PURE__ */ React19.createElement(Canvas, { style: { width: APPOINTMENT_BLOCK_WIDTH, height: segmentHeight } }, firstRects.map(({ x, y, width: w, height: h, row }, idx) => /* @__PURE__ */ React19.createElement(React19.Fragment, { key: idx }, /* @__PURE__ */ React19.createElement(
759
778
  Rect$1,
760
779
  {
761
780
  x,
@@ -765,7 +784,7 @@ var EventGridBlocksSkia = ({
765
784
  color: pressedRow === row ? "rgba(240,240,240,0.3)" : "rgba(240,240,240,0.6)",
766
785
  style: "fill"
767
786
  }
768
- ), /* @__PURE__ */ React18.createElement(Line$1, { p1: { x, y: y + h }, p2: { x: x + w, y: y + h }, color: "#ddd", strokeWidth: 1 })))), /* @__PURE__ */ React18.createElement(Canvas, { style: { width: APPOINTMENT_BLOCK_WIDTH, height: segmentHeight } }, secondRects.map(({ x, y, width: w, height: h, row }, idx) => /* @__PURE__ */ React18.createElement(React18.Fragment, { key: idx }, /* @__PURE__ */ React18.createElement(
787
+ ), /* @__PURE__ */ React19.createElement(Line$1, { p1: { x, y: y + h }, p2: { x: x + w, y: y + h }, color: "#ddd", strokeWidth: 1 })))), /* @__PURE__ */ React19.createElement(Canvas, { style: { width: APPOINTMENT_BLOCK_WIDTH, height: segmentHeight } }, secondRects.map(({ x, y, width: w, height: h, row }, idx) => /* @__PURE__ */ React19.createElement(React19.Fragment, { key: idx }, /* @__PURE__ */ React19.createElement(
769
788
  Rect$1,
770
789
  {
771
790
  x,
@@ -775,7 +794,7 @@ var EventGridBlocksSkia = ({
775
794
  color: pressedRow === row ? "rgba(240,240,240,0.3)" : "rgba(240,240,240,0.6)",
776
795
  style: "fill"
777
796
  }
778
- ), /* @__PURE__ */ React18.createElement(
797
+ ), /* @__PURE__ */ React19.createElement(
779
798
  Line$1,
780
799
  {
781
800
  p1: { x, y: y - segmentHeight + h },
@@ -785,36 +804,50 @@ var EventGridBlocksSkia = ({
785
804
  }
786
805
  ))))));
787
806
  };
788
- var StoreFeeder = ({ store, resources }) => {
807
+ var StoreFeeder = ({ store, resources, baseDate }) => {
789
808
  const upsertResources = store.useUpsertResources();
790
- const setDayData = store.useSetDayData();
809
+ const setDayDataFor = store.useSetDayDataFor();
810
+ const setDate = store.useSetDate();
811
+ const baseDateKey = useMemo(() => format(baseDate, "yyyy-MM-dd"), [baseDate]);
791
812
  useEffect(() => {
813
+ setDate(baseDate);
792
814
  upsertResources(resources.map((r) => ({ id: r.id, name: r.name, avatar: r.avatar })));
793
- const eventsByResource = {};
794
- const blocksByResource = {};
795
- const intervalsByResource = {};
815
+ const dayBuckets = /* @__PURE__ */ new Map();
796
816
  for (const r of resources) {
797
- if (r.events?.length) eventsByResource[r.id] = r.events;
798
- if (r.disabledBlocks?.length) blocksByResource[r.id] = r.disabledBlocks;
799
- if (r.disableIntervals?.length) intervalsByResource[r.id] = r.disableIntervals;
817
+ const push = (items, field) => {
818
+ if (!items?.length) return;
819
+ for (const it of items) {
820
+ const key = it.date ?? baseDateKey;
821
+ const bucket = dayBuckets.get(key) ?? dayBuckets.set(key, { events: {}, disabledBlocks: {}, disableIntervals: {} }).get(key);
822
+ const m = bucket[field];
823
+ (m[r.id] ||= []).push(it);
824
+ }
825
+ };
826
+ push(r.events, "events");
827
+ push(r.disabledBlocks, "disabledBlocks");
828
+ push(r.disableIntervals, "disableIntervals");
800
829
  }
801
- setDayData({
802
- events: eventsByResource,
803
- disabledBlocks: blocksByResource,
804
- disableIntervals: intervalsByResource
805
- });
806
- }, [resources, upsertResources, setDayData]);
830
+ for (const [dayKey, payload] of dayBuckets) {
831
+ setDayDataFor(dayKey, payload);
832
+ }
833
+ }, [resources, upsertResources, setDayDataFor, baseDateKey]);
807
834
  return null;
808
835
  };
809
836
  var DisabledInterval = ({ width, top, height }) => {
810
- return /* @__PURE__ */ React18__default.createElement(View, { style: [styles3.disabledBlock, { width, top, height }] }, /* @__PURE__ */ React18__default.createElement(Svg, { width, height: "100%" }, /* @__PURE__ */ React18__default.createElement(Defs, null, /* @__PURE__ */ React18__default.createElement(Pattern, { id: "diagonalHatch", patternUnits: "userSpaceOnUse", width: "10", height: "10" }, /* @__PURE__ */ React18__default.createElement(Line, { x1: "0", y1: "0", x2: "10", y2: "10", stroke: "rgba(150, 150, 150, 0.8)", strokeWidth: "1" }))), /* @__PURE__ */ React18__default.createElement(Rect, { width, height: "100%", fill: "url(#diagonalHatch)" })));
837
+ return /* @__PURE__ */ React19__default.createElement(View, { style: [styles3.disabledBlock, { width, top, height }] }, /* @__PURE__ */ React19__default.createElement(Svg, { width, height: "100%" }, /* @__PURE__ */ React19__default.createElement(Defs, null, /* @__PURE__ */ React19__default.createElement(Pattern, { id: "diagonalHatch", patternUnits: "userSpaceOnUse", width: "10", height: "10" }, /* @__PURE__ */ React19__default.createElement(Line, { x1: "0", y1: "0", x2: "10", y2: "10", stroke: "rgba(150, 150, 150, 0.8)", strokeWidth: "1" }))), /* @__PURE__ */ React19__default.createElement(Rect, { width, height: "100%", fill: "url(#diagonalHatch)" })));
811
838
  };
812
- var DisabledIntervals = React18__default.memo(({ id, APPOINTMENT_BLOCK_WIDTH, hourHeight }) => {
813
- const { useDisabledIntervalsFor: useDisabledIntervalsFor2 } = useCalendarBinding();
814
- const disabledIntervals = useDisabledIntervalsFor2(id);
815
- return /* @__PURE__ */ React18__default.createElement(React18__default.Fragment, null, disabledIntervals.map(
839
+ var DisabledIntervals = React19__default.memo(({
840
+ id,
841
+ APPOINTMENT_BLOCK_WIDTH,
842
+ hourHeight,
843
+ date: dateProp
844
+ }) => {
845
+ const { useDisabledIntervalsFor: useDisabledIntervalsFor2, useGetDate: useGetDate2 } = useCalendarBinding();
846
+ const date = useGetDate2();
847
+ const disabledIntervals = useDisabledIntervalsFor2(id, dateProp ?? date);
848
+ return /* @__PURE__ */ React19__default.createElement(React19__default.Fragment, null, disabledIntervals.map(
816
849
  (disabledInterval, index) => {
817
- return /* @__PURE__ */ React18__default.createElement(
850
+ return /* @__PURE__ */ React19__default.createElement(
818
851
  DisabledInterval,
819
852
  {
820
853
  key: `${index}-${disabledInterval.from}-${disabledInterval.to}`,
@@ -834,7 +867,7 @@ var styles3 = StyleSheet.create({
834
867
  });
835
868
  var DisabledIntervals_default = DisabledIntervals;
836
869
  var Row = ({ children, divider, space, style, ...props }) => {
837
- return /* @__PURE__ */ React18__default.createElement(View, { style: [{ flexDirection: "row" }, style], ...props }, React18__default.Children.toArray(children).map((child, index) => /* @__PURE__ */ React18__default.createElement(React18__default.Fragment, { key: index }, child, index !== React18__default.Children.toArray(children).length - 1 && divider, index !== React18__default.Children.toArray(children).length - 1 && /* @__PURE__ */ React18__default.createElement(View, { style: { width: space, height: "100%" } }))));
870
+ return /* @__PURE__ */ React19__default.createElement(View, { style: [{ flexDirection: "row" }, style], ...props }, React19__default.Children.toArray(children).map((child, index) => /* @__PURE__ */ React19__default.createElement(React19__default.Fragment, { key: index }, child, index !== React19__default.Children.toArray(children).length - 1 && divider, index !== React19__default.Children.toArray(children).length - 1 && /* @__PURE__ */ React19__default.createElement(View, { style: { width: space, height: "100%" } }))));
838
871
  };
839
872
  var Row_default = Row;
840
873
  var DisabledBlockComponent = ({
@@ -855,7 +888,7 @@ var DisabledBlockComponent = ({
855
888
  borderColor: "rgba(0,0,0,0.12)"
856
889
  };
857
890
  const titleFace = useResolvedFont({ fontWeight: "600" });
858
- return /* @__PURE__ */ React18__default.createElement(
891
+ return /* @__PURE__ */ React19__default.createElement(
859
892
  TouchableOpacity,
860
893
  {
861
894
  style: [styles4.event, dynamicStyle],
@@ -863,7 +896,7 @@ var DisabledBlockComponent = ({
863
896
  onDisabledBlockPress && onDisabledBlockPress(disabledBlock);
864
897
  }
865
898
  },
866
- /* @__PURE__ */ React18__default.createElement(Col_default, { style: { position: "relative" } }, /* @__PURE__ */ React18__default.createElement(Row_default, { style: { height: 18 } }, /* @__PURE__ */ React18__default.createElement(
899
+ /* @__PURE__ */ React19__default.createElement(Col_default, { style: { position: "relative" } }, /* @__PURE__ */ React19__default.createElement(Row_default, { style: { height: 18 } }, /* @__PURE__ */ React19__default.createElement(
867
900
  Text,
868
901
  {
869
902
  allowFontScaling: false,
@@ -876,7 +909,7 @@ var DisabledBlockComponent = ({
876
909
  minutesToTime(disabledBlock?.from),
877
910
  " - ",
878
911
  minutesToTime(disabledBlock?.to)
879
- )), /* @__PURE__ */ React18__default.createElement(
912
+ )), /* @__PURE__ */ React19__default.createElement(
880
913
  Text,
881
914
  {
882
915
  allowFontScaling: false,
@@ -890,21 +923,23 @@ var DisabledBlockComponent = ({
890
923
  ))
891
924
  );
892
925
  };
893
- var DisabledBlocks = React18__default.memo(({
926
+ var DisabledBlocks = React19__default.memo(({
894
927
  id,
895
928
  APPOINTMENT_BLOCK_WIDTH,
896
929
  hourHeight,
897
- onDisabledBlockPress
930
+ onDisabledBlockPress,
931
+ date: dateProp
898
932
  }) => {
899
- const { useDisabledBlocksFor: useDisabledBlocksFor2 } = useCalendarBinding();
900
- const disabledBlocks = useDisabledBlocksFor2(id);
933
+ const { useDisabledBlocksFor: useDisabledBlocksFor2, useGetDate: useGetDate2 } = useCalendarBinding();
934
+ const date = useGetDate2();
935
+ const disabledBlocks = useDisabledBlocksFor2(id, dateProp ?? date);
901
936
  const layoutMap = useMemo(() => {
902
937
  return columnsToPixels(computeDisabledBlockColumns(disabledBlocks), APPOINTMENT_BLOCK_WIDTH);
903
938
  }, [disabledBlocks]);
904
- return /* @__PURE__ */ React18__default.createElement(React18__default.Fragment, null, disabledBlocks.map(
939
+ return /* @__PURE__ */ React19__default.createElement(React19__default.Fragment, null, disabledBlocks.map(
905
940
  (disabledBlock, index) => {
906
941
  const key = disabledBlock.id;
907
- return /* @__PURE__ */ React18__default.createElement(
942
+ return /* @__PURE__ */ React19__default.createElement(
908
943
  DisabledBlockComponent,
909
944
  {
910
945
  hourHeight,
@@ -930,7 +965,7 @@ var styles4 = StyleSheet.create({
930
965
  }
931
966
  });
932
967
  var DisabledBlocks_default = DisabledBlocks;
933
- var EventBlock = React18__default.memo(({
968
+ var EventBlock = React19__default.memo(({
934
969
  event,
935
970
  onLongPress,
936
971
  onPress,
@@ -964,7 +999,7 @@ var EventBlock = React18__default.memo(({
964
999
  const Body = slots?.Body;
965
1000
  const titleFace = useResolvedFont({ fontWeight: "700" });
966
1001
  const timeFace = useResolvedFont({ fontWeight: "600" });
967
- return /* @__PURE__ */ React18__default.createElement(
1002
+ return /* @__PURE__ */ React19__default.createElement(
968
1003
  TouchableOpacity,
969
1004
  {
970
1005
  style: [styles5.event, resolved?.container, dynamicStyle],
@@ -976,7 +1011,7 @@ var EventBlock = React18__default.memo(({
976
1011
  onLongPress && onLongPress(event);
977
1012
  }
978
1013
  },
979
- /* @__PURE__ */ React18__default.createElement(Hidden_default, { isHidden: !disabled }, /* @__PURE__ */ React18__default.createElement(View, { style: {
1014
+ /* @__PURE__ */ React19__default.createElement(Hidden_default, { isHidden: !disabled }, /* @__PURE__ */ React19__default.createElement(View, { style: {
980
1015
  position: "absolute",
981
1016
  top: 0,
982
1017
  width: "150%",
@@ -984,7 +1019,7 @@ var EventBlock = React18__default.memo(({
984
1019
  zIndex: 1,
985
1020
  backgroundColor: "rgba(255, 255, 255, 0.5)"
986
1021
  } })),
987
- /* @__PURE__ */ React18__default.createElement(Col_default, { style: [{ position: "relative" }, resolved?.content] }, /* @__PURE__ */ React18__default.createElement(
1022
+ /* @__PURE__ */ React19__default.createElement(Col_default, { style: [{ position: "relative" }, resolved?.content] }, /* @__PURE__ */ React19__default.createElement(
988
1023
  TextInput,
989
1024
  {
990
1025
  editable: false,
@@ -1000,7 +1035,7 @@ var EventBlock = React18__default.memo(({
1000
1035
  },
1001
1036
  defaultValue: `${start} - ${end}`
1002
1037
  }
1003
- ), Body ? /* @__PURE__ */ React18__default.createElement(Body, { event, ctx: { hourHeight } }) : /* @__PURE__ */ React18__default.createElement(React18__default.Fragment, null, /* @__PURE__ */ React18__default.createElement(Row_default, { style: { alignItems: "center", height: 18 } }, /* @__PURE__ */ React18__default.createElement(
1038
+ ), Body ? /* @__PURE__ */ React19__default.createElement(Body, { event, ctx: { hourHeight } }) : /* @__PURE__ */ React19__default.createElement(React19__default.Fragment, null, /* @__PURE__ */ React19__default.createElement(Row_default, { style: { alignItems: "center", height: 18 } }, /* @__PURE__ */ React19__default.createElement(
1004
1039
  Text,
1005
1040
  {
1006
1041
  allowFontScaling: false,
@@ -1011,7 +1046,7 @@ var EventBlock = React18__default.memo(({
1011
1046
  }, resolved?.title]
1012
1047
  },
1013
1048
  event?.title
1014
- )), /* @__PURE__ */ React18__default.createElement(
1049
+ )), /* @__PURE__ */ React19__default.createElement(
1015
1050
  Text,
1016
1051
  {
1017
1052
  allowFontScaling: false,
@@ -1022,10 +1057,10 @@ var EventBlock = React18__default.memo(({
1022
1057
  }, resolved?.desc]
1023
1058
  },
1024
1059
  event?.description
1025
- )), /* @__PURE__ */ React18__default.createElement(Row_default, { style: {
1060
+ )), /* @__PURE__ */ React19__default.createElement(Row_default, { style: {
1026
1061
  position: "absolute",
1027
1062
  right: 2
1028
- } }, TopRight ? /* @__PURE__ */ React18__default.createElement(TopRight, { event, ctx: { hourHeight } }) : null))
1063
+ } }, TopRight ? /* @__PURE__ */ React19__default.createElement(TopRight, { event, ctx: { hourHeight } }) : null))
1029
1064
  );
1030
1065
  });
1031
1066
  var styles5 = StyleSheet.create({
@@ -1085,25 +1120,25 @@ var DraggableEvent = ({
1085
1120
  }
1086
1121
  ]
1087
1122
  };
1088
- }, [selectedEvent, eventHeight, APPOINTMENT_BLOCK_WIDTH]);
1123
+ }, [selectedEvent, APPOINTMENT_BLOCK_WIDTH]);
1089
1124
  const initialDisplayTime = useMemo(() => {
1090
1125
  const start = minutesToTime(positionToMinutes(eventStartedTop.value, hourHeight));
1091
1126
  const end = minutesToTime(positionToMinutes(eventStartedTop.value + eventHeight.value, hourHeight));
1092
1127
  return `${start} - ${end}`;
1093
- }, [eventHeight.value, hourHeight, eventStartedTop.value]);
1128
+ }, [hourHeight]);
1094
1129
  const animatedTimeProps = useAnimatedProps(() => {
1095
1130
  const start = minutesToTime(positionToMinutes(eventStartedTop.value, hourHeight));
1096
1131
  const end = minutesToTime(positionToMinutes(eventStartedTop.value + eventHeight.value, hourHeight));
1097
1132
  return {
1098
1133
  text: `${start} - ${end}`
1099
1134
  };
1100
- }, []);
1135
+ }, [hourHeight]);
1101
1136
  const resolved = typeof styleOverrides === "function" ? styleOverrides(selectedEvent) ?? {} : styleOverrides ?? {};
1102
1137
  const TopRight = slots?.TopRight;
1103
1138
  const Body = slots?.Body;
1104
1139
  const titleFace = useResolvedFont({ fontWeight: "700" });
1105
1140
  const timeFace = useResolvedFont({ fontWeight: "600" });
1106
- return /* @__PURE__ */ React18.createElement(Animated2.View, { style: [styles6.event, dynamicStyle, draggingAnimatedStyle, resolved?.container] }, /* @__PURE__ */ React18.createElement(Col_default, { style: [{ position: "relative" }, resolved?.content] }, /* @__PURE__ */ React18.createElement(
1141
+ return /* @__PURE__ */ React19.createElement(Animated2.View, { style: [styles6.event, dynamicStyle, draggingAnimatedStyle, resolved?.container] }, /* @__PURE__ */ React19.createElement(Col_default, { style: [{ position: "relative" }, resolved?.content] }, /* @__PURE__ */ React19.createElement(
1107
1142
  AnimatedTextInput,
1108
1143
  {
1109
1144
  editable: false,
@@ -1120,7 +1155,7 @@ var DraggableEvent = ({
1120
1155
  defaultValue: initialDisplayTime,
1121
1156
  animatedProps: animatedTimeProps
1122
1157
  }
1123
- ), Body ? /* @__PURE__ */ React18.createElement(Body, { event: selectedEvent, ctx: { hourHeight } }) : /* @__PURE__ */ React18.createElement(React18.Fragment, null, /* @__PURE__ */ React18.createElement(Row_default, { style: { alignItems: "center", height: 18 } }, /* @__PURE__ */ React18.createElement(
1158
+ ), Body ? /* @__PURE__ */ React19.createElement(Body, { event: selectedEvent, ctx: { hourHeight } }) : /* @__PURE__ */ React19.createElement(React19.Fragment, null, /* @__PURE__ */ React19.createElement(Row_default, { style: { alignItems: "center", height: 18 } }, /* @__PURE__ */ React19.createElement(
1124
1159
  Text,
1125
1160
  {
1126
1161
  allowFontScaling: false,
@@ -1131,7 +1166,7 @@ var DraggableEvent = ({
1131
1166
  }, resolved?.title]
1132
1167
  },
1133
1168
  selectedEvent?.title
1134
- )), /* @__PURE__ */ React18.createElement(
1169
+ )), /* @__PURE__ */ React19.createElement(
1135
1170
  Text,
1136
1171
  {
1137
1172
  allowFontScaling: false,
@@ -1142,14 +1177,14 @@ var DraggableEvent = ({
1142
1177
  }, resolved?.desc]
1143
1178
  },
1144
1179
  selectedEvent?.description
1145
- )), /* @__PURE__ */ React18.createElement(Row_default, { style: {
1180
+ )), /* @__PURE__ */ React19.createElement(Row_default, { style: {
1146
1181
  position: "absolute",
1147
1182
  right: 2
1148
- }, space: 2 }, TopRight ? /* @__PURE__ */ React18.createElement(TopRight, { event: selectedEvent, ctx: { hourHeight } }) : null)), /* @__PURE__ */ React18.createElement(Row_default, { style: {
1183
+ }, space: 2 }, TopRight ? /* @__PURE__ */ React19.createElement(TopRight, { event: selectedEvent, ctx: { hourHeight } }) : null)), /* @__PURE__ */ React19.createElement(Row_default, { style: {
1149
1184
  position: "absolute",
1150
1185
  alignSelf: "center",
1151
1186
  bottom: 0
1152
- } }, /* @__PURE__ */ React18.createElement(MaterialIcons, { name: "drag-handle", size: 12, color: "black" })));
1187
+ } }, /* @__PURE__ */ React19.createElement(MaterialIcons, { name: "drag-handle", size: 12, color: "black" })));
1153
1188
  };
1154
1189
  var styles6 = StyleSheet.create({
1155
1190
  event: {
@@ -1162,7 +1197,7 @@ var styles6 = StyleSheet.create({
1162
1197
  // Ensure events stay above the background blocks
1163
1198
  }
1164
1199
  });
1165
- var EventBlocks = React18__default.memo(({
1200
+ var EventBlocks = React19__default.memo(({
1166
1201
  id,
1167
1202
  onLongPress,
1168
1203
  onPress,
@@ -1171,10 +1206,12 @@ var EventBlocks = React18__default.memo(({
1171
1206
  eventRenderer,
1172
1207
  isEventDisabled,
1173
1208
  isEventSelected,
1174
- mode
1209
+ mode,
1210
+ date: dateProp
1175
1211
  }) => {
1176
- const { useEventsFor: useEventsFor2 } = useCalendarBinding();
1177
- const events = useEventsFor2(id);
1212
+ const { useEventsFor: useEventsFor2, useGetDate: useGetDate2 } = useCalendarBinding();
1213
+ const date = useGetDate2();
1214
+ const events = useEventsFor2(id, dateProp ?? date);
1178
1215
  const frameMap = useMemo(
1179
1216
  () => computeEventFrames(events, EVENT_BLOCK_WIDTH, mode),
1180
1217
  [events, mode, EVENT_BLOCK_WIDTH]
@@ -1184,7 +1221,7 @@ var EventBlocks = React18__default.memo(({
1184
1221
  (evt, index) => {
1185
1222
  const selected = isEventSelected?.(evt) ?? false;
1186
1223
  const disabled = isEventDisabled?.(evt) ?? false;
1187
- return /* @__PURE__ */ React18__default.createElement(
1224
+ return /* @__PURE__ */ React19__default.createElement(
1188
1225
  Renderer,
1189
1226
  {
1190
1227
  key: `${evt.from}-${evt.to}-${index}`,
@@ -1201,8 +1238,89 @@ var EventBlocks = React18__default.memo(({
1201
1238
  );
1202
1239
  });
1203
1240
  var EventBlocks_default = EventBlocks;
1204
-
1205
- // src/components/Calendar.tsx
1241
+ var DaysComponent = ({ onResourcePress, activeResourceId, mode, date, APPOINTMENT_BLOCK_WIDTH }) => {
1242
+ const { useResourceById: useResourceById2 } = useCalendarBinding();
1243
+ const resource = useResourceById2(activeResourceId);
1244
+ const titleFace = useResolvedFont({ fontWeight: "700" });
1245
+ const subTitleFace = useResolvedFont({ fontWeight: "600" });
1246
+ const isMultiDay = mode !== "day";
1247
+ const visibleDayCount = isMultiDay ? mode === "week" ? 7 : 3 : 1;
1248
+ const days = useMemo(
1249
+ () => Array.from({ length: visibleDayCount }, (_, i) => addDays(date, i)),
1250
+ [date, visibleDayCount]
1251
+ );
1252
+ return /* @__PURE__ */ React19.createElement(Row_default, null, /* @__PURE__ */ React19.createElement(Col_default, { style: { width: TIME_LABEL_WIDTH, alignItems: "center", paddingVertical: 4 } }, /* @__PURE__ */ React19.createElement(
1253
+ StaffAvatar,
1254
+ {
1255
+ onPress: () => {
1256
+ if (onResourcePress)
1257
+ onResourcePress(resource);
1258
+ },
1259
+ name: resource?.name,
1260
+ circleSize: TIME_LABEL_WIDTH - 12,
1261
+ fontSize: 16,
1262
+ image: resource?.avatar
1263
+ }
1264
+ ), /* @__PURE__ */ React19.createElement(
1265
+ Text,
1266
+ {
1267
+ style: {
1268
+ fontSize: 14,
1269
+ fontFamily: titleFace,
1270
+ fontWeight: "700"
1271
+ },
1272
+ numberOfLines: 1,
1273
+ allowFontScaling: false
1274
+ },
1275
+ resource?.name
1276
+ )), /* @__PURE__ */ React19.createElement(Row_default, { style: { flex: 1 } }, days.map((d, i) => {
1277
+ const selected = isSameDay(d, /* @__PURE__ */ new Date());
1278
+ return /* @__PURE__ */ React19.createElement(
1279
+ Col_default,
1280
+ {
1281
+ style: {
1282
+ alignItems: "center",
1283
+ justifyContent: "center",
1284
+ width: APPOINTMENT_BLOCK_WIDTH
1285
+ },
1286
+ space: 4,
1287
+ key: i
1288
+ },
1289
+ /* @__PURE__ */ React19.createElement(Center_default, { style: {
1290
+ backgroundColor: selected ? "#4d959c" : void 0,
1291
+ width: 30,
1292
+ height: 30,
1293
+ borderRadius: 999
1294
+ } }, /* @__PURE__ */ React19.createElement(
1295
+ Text,
1296
+ {
1297
+ style: {
1298
+ fontSize: 16,
1299
+ fontFamily: subTitleFace,
1300
+ fontWeight: "600",
1301
+ color: selected ? "#fff" : void 0
1302
+ },
1303
+ numberOfLines: 1,
1304
+ allowFontScaling: false
1305
+ },
1306
+ format(d, "d")
1307
+ )),
1308
+ /* @__PURE__ */ React19.createElement(
1309
+ Text,
1310
+ {
1311
+ style: {
1312
+ fontSize: 14,
1313
+ fontFamily: subTitleFace,
1314
+ fontWeight: "600"
1315
+ },
1316
+ numberOfLines: 1,
1317
+ allowFontScaling: false
1318
+ },
1319
+ format(d, "EEE")
1320
+ )
1321
+ );
1322
+ })));
1323
+ };
1206
1324
  var AnimatedFlashList = Animated2.createAnimatedComponent(FlashList);
1207
1325
  var CalendarInner = (props) => {
1208
1326
  const { width } = useWindowDimensions();
@@ -1210,7 +1328,7 @@ var CalendarInner = (props) => {
1210
1328
  const binding = useCalendarBinding();
1211
1329
  const {
1212
1330
  date,
1213
- numberOfColumns = 3,
1331
+ numberOfColumns: numberOfColumnsProp = 3,
1214
1332
  startMinutes,
1215
1333
  hourHeight = 120,
1216
1334
  snapIntervalInMinutes = 5,
@@ -1223,17 +1341,26 @@ var CalendarInner = (props) => {
1223
1341
  onDisabledBlockPress,
1224
1342
  eventSlots,
1225
1343
  eventStyleOverrides,
1226
- overLappingLayoutMode = "stacked"
1344
+ overLappingLayoutMode = "stacked",
1345
+ mode = "day",
1346
+ activeResourceId
1227
1347
  } = props;
1348
+ const numberOfColumns = mode === "day" ? numberOfColumnsProp : mode === "week" ? 7 : 3;
1349
+ const isMultiDay = mode !== "day";
1350
+ const visibleDayCount = isMultiDay ? mode === "week" ? 7 : 3 : 1;
1351
+ const days = useMemo(
1352
+ () => Array.from({ length: visibleDayCount }, (_, i) => addDays(date, i)),
1353
+ [date, visibleDayCount]
1354
+ );
1228
1355
  const snapInterval = hourHeight / 60 * snapIntervalInMinutes;
1229
- const onPressRef = React18__default.useRef(onEventPress);
1230
- const onLongPressRef = React18__default.useRef(onEventLongPress);
1356
+ const onPressRef = React19__default.useRef(onEventPress);
1357
+ const onLongPressRef = React19__default.useRef(onEventLongPress);
1231
1358
  const internalOnLongPress = useRef(null);
1232
- const onDisabledBlockPressRef = React18__default.useRef(onDisabledBlockPress);
1359
+ const onDisabledBlockPressRef = React19__default.useRef(onDisabledBlockPress);
1233
1360
  const selectedRef = useRef(props.isEventSelected);
1234
1361
  const disabledRef = useRef(props.isEventDisabled);
1235
1362
  const effectiveRenderer = useMemo(() => {
1236
- return (p) => /* @__PURE__ */ React18__default.createElement(
1363
+ return (p) => /* @__PURE__ */ React19__default.createElement(
1237
1364
  EventBlock_default,
1238
1365
  {
1239
1366
  ...p,
@@ -1270,8 +1397,8 @@ var CalendarInner = (props) => {
1270
1397
  }, [props.isEventDisabled]);
1271
1398
  const rendererRef = useRef(effectiveRenderer);
1272
1399
  const stableRenderer = useCallback((p) => rendererRef.current(p), []);
1273
- const stableOnPress = React18__default.useCallback((e) => onPressRef.current?.(e), []);
1274
- const stableOnDisabledBlockPress = React18__default.useCallback((b) => onDisabledBlockPressRef.current?.(b), []);
1400
+ const stableOnPress = React19__default.useCallback((e) => onPressRef.current?.(e), []);
1401
+ const stableOnDisabledBlockPress = React19__default.useCallback((b) => onDisabledBlockPressRef.current?.(b), []);
1275
1402
  const { useGetSelectedEvent: useGetSelectedEvent2, useSetSelectedEvent: useSetSelectedEvent2, useSetDraggedEventDraft: useSetDraggedEventDraft2, useGetDraggedEventDraft: useGetDraggedEventDraft2 } = useCalendarBinding();
1276
1403
  const selectedEvent = useGetSelectedEvent2();
1277
1404
  const setSelectedEvent = useSetSelectedEvent2();
@@ -1280,6 +1407,8 @@ var CalendarInner = (props) => {
1280
1407
  const hourHeightRef = useRef(hourHeight);
1281
1408
  const resourcesRef = useRef(resources);
1282
1409
  const apptWidthRef = useRef(APPOINTMENT_BLOCK_WIDTH);
1410
+ const isMultiDayRef = useRef(isMultiDay);
1411
+ const daysRef = useRef(days);
1283
1412
  useEffect(() => {
1284
1413
  hourHeightRef.current = hourHeight;
1285
1414
  }, [hourHeight]);
@@ -1289,6 +1418,12 @@ var CalendarInner = (props) => {
1289
1418
  useEffect(() => {
1290
1419
  apptWidthRef.current = APPOINTMENT_BLOCK_WIDTH;
1291
1420
  }, [APPOINTMENT_BLOCK_WIDTH]);
1421
+ useEffect(() => {
1422
+ isMultiDayRef.current = isMultiDay;
1423
+ }, [isMultiDay]);
1424
+ useEffect(() => {
1425
+ daysRef.current = days;
1426
+ }, [days]);
1292
1427
  useEffect(() => {
1293
1428
  if (!selectedEvent) {
1294
1429
  setDraggedEventDraft(null);
@@ -1318,6 +1453,32 @@ var CalendarInner = (props) => {
1318
1453
  const triggerHaptic = useCallback(() => {
1319
1454
  Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
1320
1455
  }, []);
1456
+ const resourceIds = useMemo(() => {
1457
+ const ids = resources?.map((item) => item?.id) || [];
1458
+ if (JSON.stringify(prevResourceIdsRef.current) !== JSON.stringify(ids)) {
1459
+ prevResourceIdsRef.current = ids;
1460
+ }
1461
+ return prevResourceIdsRef.current;
1462
+ }, [resources]);
1463
+ const finalizeDrag = React19__default.useCallback((colIndex, adjustedTop, height) => {
1464
+ const isMultiDay2 = mode !== "day";
1465
+ const landedResourceId = !isMultiDay2 ? resourceIds[colIndex] : activeResourceId ?? resourceIds[0];
1466
+ const landedDate = format(!isMultiDay2 ? date : days[colIndex], "yyyy-MM-dd");
1467
+ setDraggedEventDraft({
1468
+ event: selectedEvent,
1469
+ // ensure this is not stale (store/ref)
1470
+ from: positionToMinutes(adjustedTop, hourHeight),
1471
+ to: positionToMinutes(adjustedTop + height, hourHeight),
1472
+ resourceId: landedResourceId,
1473
+ date: landedDate
1474
+ });
1475
+ }, [mode, resourceIds, activeResourceId, selectedEvent, hourHeight, setDraggedEventDraft, days]);
1476
+ const columns = useMemo(() => {
1477
+ if (!isMultiDay) {
1478
+ return resourceIds.map((resourceId) => ({ kind: "resource", resourceId }));
1479
+ }
1480
+ return days.map((dayDate, dayIndex) => ({ kind: "day", dayIndex, dayDate }));
1481
+ }, [isMultiDay, resourceIds, days]);
1321
1482
  const panGesture = Gesture.Pan().manualActivation(!isIOS).enabled(layout !== null).shouldCancelWhenOutside(false).onTouchesMove((_evt, stateManager) => {
1322
1483
  "worklet";
1323
1484
  if (isIOS) return;
@@ -1425,9 +1586,8 @@ var CalendarInner = (props) => {
1425
1586
  const finalXOnScreen = panXAbs.value;
1426
1587
  const absoluteX = finalXOnScreen + scrollX.value;
1427
1588
  const newStaffIndex = Math.floor((absoluteX - TIME_LABEL_WIDTH) / APPOINTMENT_BLOCK_WIDTH);
1428
- const clampedStaffIndex = Math.max(0, Math.min(newStaffIndex, resources.length - 1));
1429
- const endedResource = resources[clampedStaffIndex];
1430
- const finalPanXValue = TIME_LABEL_WIDTH + clampedStaffIndex * APPOINTMENT_BLOCK_WIDTH - scrollX.value + APPOINTMENT_BLOCK_WIDTH / 2;
1589
+ const colIndex = Math.max(0, Math.min(newStaffIndex, columns.length - 1));
1590
+ const finalPanXValue = TIME_LABEL_WIDTH + colIndex * APPOINTMENT_BLOCK_WIDTH - scrollX.value + APPOINTMENT_BLOCK_WIDTH / 2;
1431
1591
  panYAbs.value = withSpring(finalPanYValue);
1432
1592
  panXAbs.value = withSpring(finalPanXValue);
1433
1593
  if (!isPulling.value) {
@@ -1437,12 +1597,7 @@ var CalendarInner = (props) => {
1437
1597
  startedX.value = finalPanXValue;
1438
1598
  isPulling.value = false;
1439
1599
  isDragging.value = false;
1440
- runOnJS(setDraggedEventDraft)({
1441
- event: selectedEvent,
1442
- from: positionToMinutes(adjustedFinalEventTop, hourHeight),
1443
- to: positionToMinutes(adjustedFinalEventTop + eventHeight.value, hourHeight),
1444
- resourceId: endedResource?.id
1445
- });
1600
+ runOnJS(finalizeDrag)(colIndex, adjustedFinalEventTop, eventHeight.value);
1446
1601
  });
1447
1602
  const scrollListTo = (x) => {
1448
1603
  flashListRef.current?.scrollToOffset({ offset: x, animated: false });
@@ -1507,10 +1662,17 @@ var CalendarInner = (props) => {
1507
1662
  startedY.value = panAbsValue;
1508
1663
  eventStartedTop.value = eventTop;
1509
1664
  const resources2 = resourcesRef.current;
1665
+ const days2 = daysRef.current;
1510
1666
  const APPOINTMENT_BLOCK_WIDTH2 = apptWidthRef.current;
1511
- const staffIndex = resources2.findIndex((r) => r.id === event.resourceId);
1667
+ const isMultiDay2 = isMultiDayRef.current;
1512
1668
  const leftmostColumnIndex = Math.round(scrollX.value / APPOINTMENT_BLOCK_WIDTH2);
1513
- const screenColumn = staffIndex - leftmostColumnIndex;
1669
+ let absoluteColIndex;
1670
+ if (!isMultiDay2) {
1671
+ absoluteColIndex = findResourceIndexFor(event.resourceId, resources2?.map((r) => r.id));
1672
+ } else {
1673
+ absoluteColIndex = findDayIndexFor(event.date, days2);
1674
+ }
1675
+ const screenColumn = absoluteColIndex - leftmostColumnIndex;
1514
1676
  const selectedAppointmentStartedX = TIME_LABEL_WIDTH + APPOINTMENT_BLOCK_WIDTH2 / 2 + APPOINTMENT_BLOCK_WIDTH2 * screenColumn;
1515
1677
  panXAbs.value = selectedAppointmentStartedX;
1516
1678
  startedX.value = selectedAppointmentStartedX;
@@ -1533,18 +1695,13 @@ var CalendarInner = (props) => {
1533
1695
  });
1534
1696
  const flashListScrollHandler = useAnimatedScrollHandler({
1535
1697
  onScroll: (event) => {
1536
- const offsetX = event?.contentOffset?.x;
1537
- scrollTo(headerScrollViewRef, offsetX, 0, false);
1538
- scrollX.value = offsetX;
1698
+ if (!isMultiDay) {
1699
+ const offsetX = event?.contentOffset?.x;
1700
+ scrollTo(headerScrollViewRef, offsetX, 0, false);
1701
+ scrollX.value = offsetX;
1702
+ }
1539
1703
  }
1540
1704
  });
1541
- const resourceIds = useMemo(() => {
1542
- const ids = resources?.map((item) => item?.id) || [];
1543
- if (JSON.stringify(prevResourceIdsRef.current) !== JSON.stringify(ids)) {
1544
- prevResourceIdsRef.current = ids;
1545
- }
1546
- return prevResourceIdsRef.current;
1547
- }, [resources]);
1548
1705
  const handleBlockPress = useCallback((resourceId, time) => {
1549
1706
  Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
1550
1707
  const resource = resources.find((r) => r.id === resourceId);
@@ -1564,34 +1721,38 @@ var CalendarInner = (props) => {
1564
1721
  useEffect(() => {
1565
1722
  dateRef.current = date;
1566
1723
  }, [date]);
1567
- const renderItem = useCallback(({ item }) => {
1568
- return /* @__PURE__ */ React18__default.createElement(View, { key: item, style: { width: APPOINTMENT_BLOCK_WIDTH } }, /* @__PURE__ */ React18__default.createElement(View, { style: styles7.timelineContainer }, /* @__PURE__ */ React18__default.createElement(
1724
+ const renderItem = useCallback(({ item, index }) => {
1725
+ const rid = !isMultiDay ? item : activeResourceId ?? resourceIds[0];
1726
+ const dayDate = !isMultiDay ? void 0 : item.dayDate;
1727
+ return /* @__PURE__ */ React19__default.createElement(View, { key: index, style: { width: APPOINTMENT_BLOCK_WIDTH } }, /* @__PURE__ */ React19__default.createElement(View, { style: styles7.timelineContainer }, /* @__PURE__ */ React19__default.createElement(
1569
1728
  EventGridBlocksSkia,
1570
1729
  {
1571
- dateRef,
1572
1730
  hourHeight,
1573
1731
  APPOINTMENT_BLOCK_WIDTH,
1574
- handleBlockPress: (date2) => handleBlockPress(item, date2)
1732
+ handleBlockPress: (time) => handleBlockPress(rid, combineDateAndTime(dayDate ?? dateRef.current, time))
1575
1733
  }
1576
- ), /* @__PURE__ */ React18__default.createElement(
1734
+ ), /* @__PURE__ */ React19__default.createElement(
1577
1735
  DisabledIntervals_default,
1578
1736
  {
1579
- id: item,
1737
+ id: rid,
1738
+ date: dayDate,
1580
1739
  APPOINTMENT_BLOCK_WIDTH,
1581
1740
  hourHeight
1582
1741
  }
1583
- ), /* @__PURE__ */ React18__default.createElement(
1742
+ ), /* @__PURE__ */ React19__default.createElement(
1584
1743
  DisabledBlocks_default,
1585
1744
  {
1586
- id: item,
1745
+ id: rid,
1746
+ date: dayDate,
1587
1747
  APPOINTMENT_BLOCK_WIDTH,
1588
1748
  hourHeight,
1589
1749
  onDisabledBlockPress: stableOnDisabledBlockPress
1590
1750
  }
1591
- ), /* @__PURE__ */ React18__default.createElement(
1751
+ ), /* @__PURE__ */ React19__default.createElement(
1592
1752
  EventBlocks_default,
1593
1753
  {
1594
- id: item,
1754
+ id: rid,
1755
+ date: dayDate,
1595
1756
  EVENT_BLOCK_WIDTH: APPOINTMENT_BLOCK_WIDTH,
1596
1757
  hourHeight,
1597
1758
  onPress: stableOnPress,
@@ -1603,6 +1764,8 @@ var CalendarInner = (props) => {
1603
1764
  }
1604
1765
  )));
1605
1766
  }, [
1767
+ isMultiDay,
1768
+ activeResourceId,
1606
1769
  resourceIds,
1607
1770
  APPOINTMENT_BLOCK_WIDTH,
1608
1771
  hourHeight,
@@ -1615,7 +1778,7 @@ var CalendarInner = (props) => {
1615
1778
  stableOnDisabledBlockPress,
1616
1779
  dateRef
1617
1780
  ]);
1618
- return /* @__PURE__ */ React18__default.createElement(React18__default.Fragment, null, /* @__PURE__ */ React18__default.createElement(StoreFeeder, { resources, store: binding }), /* @__PURE__ */ React18__default.createElement(View, { style: { flex: 1 } }, /* @__PURE__ */ React18__default.createElement(View, null, /* @__PURE__ */ React18__default.createElement(
1781
+ return /* @__PURE__ */ React19__default.createElement(React19__default.Fragment, null, /* @__PURE__ */ React19__default.createElement(StoreFeeder, { resources, store: binding, baseDate: date }), /* @__PURE__ */ React19__default.createElement(View, { style: { flex: 1 } }, !isMultiDay ? /* @__PURE__ */ React19__default.createElement(View, null, /* @__PURE__ */ React19__default.createElement(
1619
1782
  Animated2.ScrollView,
1620
1783
  {
1621
1784
  style: { backgroundColor: "white" },
@@ -1631,15 +1794,25 @@ var CalendarInner = (props) => {
1631
1794
  ref: headerScrollViewRef,
1632
1795
  scrollEnabled: false
1633
1796
  },
1634
- /* @__PURE__ */ React18__default.createElement(
1797
+ /* @__PURE__ */ React19__default.createElement(
1635
1798
  ResourcesComponent,
1636
1799
  {
1800
+ date: dateRef.current,
1637
1801
  resourceIds,
1638
1802
  APPOINTMENT_BLOCK_WIDTH,
1639
1803
  onResourcePress
1640
1804
  }
1641
1805
  )
1642
- )), /* @__PURE__ */ React18__default.createElement(GestureDetector, { gesture: panGesture }, /* @__PURE__ */ React18__default.createElement(
1806
+ )) : /* @__PURE__ */ React19__default.createElement(
1807
+ DaysComponent,
1808
+ {
1809
+ APPOINTMENT_BLOCK_WIDTH,
1810
+ date,
1811
+ mode,
1812
+ activeResourceId: activeResourceId ?? resourceIds[0],
1813
+ onResourcePress
1814
+ }
1815
+ ), /* @__PURE__ */ React19__default.createElement(GestureDetector, { gesture: panGesture }, /* @__PURE__ */ React19__default.createElement(
1643
1816
  Animated2.View,
1644
1817
  {
1645
1818
  key: numberOfColumns + width + hourHeight,
@@ -1649,7 +1822,7 @@ var CalendarInner = (props) => {
1649
1822
  overflow: "hidden"
1650
1823
  }
1651
1824
  },
1652
- selectedEvent && /* @__PURE__ */ React18__default.createElement(View, { style: {
1825
+ selectedEvent && /* @__PURE__ */ React19__default.createElement(View, { style: {
1653
1826
  position: "absolute",
1654
1827
  top: 0,
1655
1828
  left: TIME_LABEL_WIDTH,
@@ -1659,7 +1832,7 @@ var CalendarInner = (props) => {
1659
1832
  backgroundColor: "rgba(0, 0, 0, 0.1)",
1660
1833
  zIndex: 1
1661
1834
  } }),
1662
- /* @__PURE__ */ React18__default.createElement(
1835
+ /* @__PURE__ */ React19__default.createElement(
1663
1836
  Animated2.ScrollView,
1664
1837
  {
1665
1838
  scrollEnabled: !selectedEvent,
@@ -1672,7 +1845,7 @@ var CalendarInner = (props) => {
1672
1845
  style: styles7.container,
1673
1846
  contentContainerStyle: { flexDirection: "row", paddingRight: TIME_LABEL_WIDTH }
1674
1847
  },
1675
- /* @__PURE__ */ React18__default.createElement(
1848
+ /* @__PURE__ */ React19__default.createElement(
1676
1849
  TimeLabels,
1677
1850
  {
1678
1851
  startMinutes,
@@ -1684,7 +1857,7 @@ var CalendarInner = (props) => {
1684
1857
  ref: verticalScrollViewRef
1685
1858
  }
1686
1859
  ),
1687
- /* @__PURE__ */ React18__default.createElement(
1860
+ /* @__PURE__ */ React19__default.createElement(
1688
1861
  AnimatedFlashList,
1689
1862
  {
1690
1863
  extraData: numberOfColumns + width + hourHeight + (overLappingLayoutMode === "stacked" ? 1 : 0),
@@ -1693,7 +1866,7 @@ var CalendarInner = (props) => {
1693
1866
  onScroll: flashListScrollHandler,
1694
1867
  estimatedItemSize: APPOINTMENT_BLOCK_WIDTH,
1695
1868
  removeClippedSubviews: true,
1696
- data: resourceIds,
1869
+ data: !isMultiDay ? resourceIds : columns,
1697
1870
  horizontal: true,
1698
1871
  renderItem,
1699
1872
  keyExtractor: (item, index) => index + "",
@@ -1703,7 +1876,7 @@ var CalendarInner = (props) => {
1703
1876
  }
1704
1877
  )
1705
1878
  ),
1706
- selectedEvent && /* @__PURE__ */ React18__default.createElement(
1879
+ selectedEvent && /* @__PURE__ */ React19__default.createElement(
1707
1880
  DraggableEvent,
1708
1881
  {
1709
1882
  selectedEvent,
@@ -1720,7 +1893,7 @@ var CalendarInner = (props) => {
1720
1893
  ))));
1721
1894
  };
1722
1895
  var Calendar = ({ theme, ...rest }) => {
1723
- return /* @__PURE__ */ React18__default.createElement(CalendarThemeProvider, { theme }, /* @__PURE__ */ React18__default.createElement(CalendarInner, { ...rest }));
1896
+ return /* @__PURE__ */ React19__default.createElement(CalendarThemeProvider, { theme }, /* @__PURE__ */ React19__default.createElement(CalendarInner, { ...rest }));
1724
1897
  };
1725
1898
  var styles7 = StyleSheet.create({
1726
1899
  container: {