react-native-resource-calendar 1.0.7 → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,7 +18,7 @@ Expo compatibility.
18
18
  ---
19
19
 
20
20
  ## 🎬 Demo
21
- https://github.com/user-attachments/assets/48841509-c801-4d77-948b-f108ff57ad34
21
+ https://github.com/user-attachments/assets/68fe0283-73ce-4689-8241-6587b817ecbd
22
22
 
23
23
  ---
24
24
 
@@ -71,141 +71,14 @@ Follow these steps to get started quickly with **React Native Resource Calendar*
71
71
 
72
72
  ```tsx
73
73
  import React from 'react';
74
- import {Button, StyleSheet, View} from 'react-native';
75
- import {Calendar, DraggedEventDraft, useCalendarBinding} from "react-native-resource-calendar";
76
-
77
- const resourceData = [
78
- {
79
- id: 1,
80
- name: "Alice Johnson",
81
- avatar: "https://randomuser.me/api/portraits/women/11.jpg",
82
- events: [
83
- {
84
- id: 101,
85
- resourceId: 1,
86
- from: 8 * 60, // 8:00 AM
87
- to: 9 * 60, // 9:00 AM
88
- title: "Physical Therapy",
89
- description: "Post-surgery recovery session",
90
- meta: {client: "John Doe"},
91
- },
92
- {
93
- id: 102,
94
- resourceId: 1,
95
- from: 10 * 60,
96
- to: 11 * 60,
97
- title: "Mobility Assessment",
98
- description: "Initial consultation",
99
- },
100
- ],
101
- disabledBlocks: [
102
- {
103
- id: 1001,
104
- resourceId: 1,
105
- from: 12 * 60, // 12:00 PM
106
- to: 13 * 60, // 1:00 PM
107
- title: "Lunch Break",
108
- },
109
- ],
110
- disableIntervals: [
111
- {
112
- resourceId: 1,
113
- from: 17 * 60, // 5:00 PM
114
- to: 24 * 60, // 12:00 AM
115
- },
116
- ],
117
- },
118
- {
119
- id: 2,
120
- name: "Bob Martinez",
121
- avatar: "https://randomuser.me/api/portraits/men/22.jpg",
122
- events: [
123
- {
124
- id: 201,
125
- resourceId: 2,
126
- from: 9 * 60 + 30, // 9:30 AM
127
- to: 10 * 60 + 30, // 10:30 AM
128
- title: "Personal Training",
129
- meta: {client: "Alex Kim"},
130
- },
131
- {
132
- id: 202,
133
- resourceId: 2,
134
- from: 15 * 60,
135
- to: 16 * 60,
136
- title: "Endurance Coaching",
137
- },
138
- ],
139
- disabledBlocks: [
140
- {
141
- id: 2001,
142
- resourceId: 2,
143
- from: 13 * 60,
144
- to: 14 * 60,
145
- title: "Staff Meeting",
146
- },
147
- ],
148
- disableIntervals: [
149
- {
150
- resourceId: 2,
151
- from: 7 * 60,
152
- to: 8 * 60,
153
- },
154
- ],
155
- },
156
- {
157
- id: 3,
158
- name: "Charlie Kim",
159
- avatar: "https://randomuser.me/api/portraits/men/33.jpg",
160
- events: [
161
- {
162
- id: 301,
163
- resourceId: 3,
164
- from: 11 * 60,
165
- to: 12 * 60,
166
- title: "Sports Massage",
167
- },
168
- {
169
- id: 302,
170
- resourceId: 3,
171
- from: 14 * 60 + 15,
172
- to: 15 * 60,
173
- title: "Deep Tissue Massage",
174
- },
175
- ],
176
- disabledBlocks: [
177
- {
178
- id: 3001,
179
- resourceId: 3,
180
- from: 12 * 60,
181
- to: 13 * 60,
182
- title: "Lunch",
183
- },
184
- ],
185
- },
186
- {
187
- id: 4,
188
- name: "Diana Ross",
189
- avatar: "https://randomuser.me/api/portraits/women/44.jpg",
190
- events: [
191
- {
192
- id: 401,
193
- resourceId: 4,
194
- from: 13 * 60,
195
- to: 14 * 60,
196
- title: "Nutrition Plan Review",
197
- description: "Discuss dietary adjustments",
198
- },
199
- ],
200
- disableIntervals: [
201
- {
202
- resourceId: 4,
203
- from: 18 * 60,
204
- to: 24 * 60,
205
- },
206
- ],
207
- },
208
- ];
74
+ import {StyleSheet, TouchableOpacity, View} from 'react-native';
75
+ import {Calendar, DraggedEventDraft, Event, LayoutMode, useCalendarBinding} from "react-native-resource-calendar";
76
+ import {SafeAreaView} from "react-native-safe-area-context";
77
+ import {ThemedText} from "@/components/ThemedText";
78
+ import {resourceData} from "@/app/(tabs)/fakeData";
79
+ import EventTopRight from "@/components/EventTopRight";
80
+ import {FontAwesome} from "@expo/vector-icons";
81
+ import {statusColor} from "@/utilities/helpers";
209
82
 
210
83
  export default function App() {
211
84
  const {
@@ -217,7 +90,10 @@ export default function App() {
217
90
  const setSelectedEvent = useSetSelectedEvent();
218
91
  const draggedEventDraft = useGetDraggedEventDraft();
219
92
  const [date, setDate] = React.useState(new Date());
220
- const [resources, setResources] = React.useState(resourceData)
93
+ const [resources, setResources] = React.useState(resourceData);
94
+ const [hourHeight, setHourHeight] = React.useState(120);
95
+ const [numberOfColumns, setNumberOfColumns] = React.useState(3);
96
+ const [layoutMode, setLayoutMode] = React.useState<LayoutMode>('stacked');
221
97
 
222
98
  const updateResourcesOnDrag = React.useCallback(
223
99
  (draft: DraggedEventDraft) => {
@@ -257,39 +133,101 @@ export default function App() {
257
133
  [setResources]
258
134
  );
259
135
 
136
+ const eventStyleOverrides = (event: Event) => {
137
+ const bg = statusColor(event.meta?.status)
138
+ return {container: {backgroundColor: bg}};
139
+ };
140
+
141
+ const randomPropsGenerator = () => {
142
+ const randomHourHeight = Math.floor(Math.random() * (120 - 60 + 1)) + 60;
143
+ const randomNumberOfColumns = Math.floor(Math.random() * (5 - 1 + 1)) + 1;
144
+ setHourHeight(randomHourHeight);
145
+ setNumberOfColumns(randomNumberOfColumns);
146
+ setLayoutMode(layoutMode === 'stacked' ? 'columns' : 'stacked');
147
+ }
148
+
260
149
  return (
261
- <CalendarBindingProvider>
262
- <View style={{flex: 1}}>
263
- <Calendar
264
- resources={resources}
265
- date={date}
266
- startMinutes={8 * 60}
267
- numberOfColumns={3}
268
- />
269
- {
270
- selectedEvent && <View style={{
271
- flexDirection: 'row',
272
- justifyContent: 'space-between'
273
- }}>
274
- <Button
275
- title="Cancel"
276
- onPress={() => {
277
- setSelectedEvent(null);
278
- }}
279
- />
280
- <Button
281
- title="Save"
282
- onPress={() => {
283
- if (draggedEventDraft) {
284
- updateResourcesOnDrag(draggedEventDraft!);
285
- }
286
- setSelectedEvent(null);
287
- }}
288
- />
289
- </View>
290
- }
150
+ <SafeAreaView style={{backgroundColor: "#fff", flex: 1}} edges={["top"]}>
151
+ <Calendar
152
+ theme={{
153
+ typography: {
154
+ fontFamily: 'NunitoSans',
155
+ },
156
+ }}
157
+ resources={resources}
158
+ date={date}
159
+ startMinutes={8 * 60}
160
+ numberOfColumns={numberOfColumns}
161
+ hourHeight={hourHeight}
162
+ eventSlots={{
163
+ // Body: ({event, ctx}) => <EventBody event={event} ctx={ctx}/>,
164
+ TopRight: ({event, ctx}) => <EventTopRight event={event} ctx={ctx}/>,
165
+ }}
166
+ eventStyleOverrides={eventStyleOverrides}
167
+ overLappingLayoutMode={layoutMode}
168
+ />
169
+ {
170
+ selectedEvent && <View style={styles.bar}>
171
+ <TouchableOpacity
172
+ style={styles.button}
173
+ onPress={() => {
174
+ setSelectedEvent(null);
175
+ }}
176
+ >
177
+ <ThemedText type={'defaultSemiBold'} style={{
178
+ color: "#4d959c"
179
+ }}>
180
+ Cancel
181
+ </ThemedText>
182
+ </TouchableOpacity>
183
+ <TouchableOpacity
184
+ style={[styles.button, {backgroundColor: "#4d959c"}]}
185
+ onPress={() => {
186
+ if (draggedEventDraft) {
187
+ updateResourcesOnDrag(draggedEventDraft!);
188
+ }
189
+ setSelectedEvent(null);
190
+ }}
191
+ >
192
+ <ThemedText type={'defaultSemiBold'}
193
+ style={{
194
+ color: "#fff"
195
+ }}
196
+ >
197
+ Save
198
+ </ThemedText>
199
+ </TouchableOpacity>
200
+ </View>
201
+ }
202
+ <View style={{
203
+ right: 20,
204
+ bottom: 40,
205
+ position: "absolute",
206
+ gap: 12
207
+ }}>
208
+ <TouchableOpacity
209
+ style={styles.floatingButton}
210
+ onPress={() => {
211
+ setDate(new Date());
212
+ }}
213
+ >
214
+ <View
215
+ style={{
216
+ width: 16,
217
+ height: 16,
218
+ backgroundColor: "#4d959c",
219
+ borderRadius: 99
220
+ }}
221
+ />
222
+ </TouchableOpacity>
223
+ <TouchableOpacity
224
+ style={styles.floatingButton}
225
+ onPress={randomPropsGenerator}
226
+ >
227
+ <FontAwesome name="random" size={16} color="#4d959c"/>
228
+ </TouchableOpacity>
291
229
  </View>
292
- </CalendarBindingProvider>
230
+ </SafeAreaView>
293
231
  );
294
232
  }
295
233
  ```
@@ -373,3 +311,9 @@ type CalendarTheme = {
373
311
  };
374
312
  };
375
313
  ```
314
+
315
+ ---
316
+
317
+ ## 💫 Support the Project
318
+
319
+ If you find this project helpful or interesting, please consider giving it a **⭐️** on GitHub!
package/dist/index.d.mts CHANGED
@@ -5,6 +5,7 @@ type ResourceId = number;
5
5
  type Event = {
6
6
  id: number;
7
7
  resourceId: ResourceId;
8
+ date: string;
8
9
  from: number;
9
10
  to: number;
10
11
  title?: string;
@@ -16,12 +17,14 @@ type Event = {
16
17
  type DisabledBlock = {
17
18
  id: number;
18
19
  resourceId: ResourceId;
20
+ date: string;
19
21
  from: number;
20
22
  to: number;
21
23
  title?: string;
22
24
  };
23
25
  type DisabledInterval = {
24
26
  resourceId: ResourceId;
27
+ date: string;
25
28
  from: number;
26
29
  to: number;
27
30
  };
@@ -33,6 +36,7 @@ type Resource = {
33
36
  type DraggedEventDraft = {
34
37
  event: Event;
35
38
  from: number;
39
+ date: string;
36
40
  to: number;
37
41
  resourceId: ResourceId;
38
42
  };
@@ -46,6 +50,7 @@ type LayoutMode = "columns" | "stacked";
46
50
  type EventRenderContext = {
47
51
  hourHeight: number;
48
52
  };
53
+ type CalendarMode = 'day' | '3days' | 'week';
49
54
 
50
55
  type EventSlots = {
51
56
  TopRight?: React$1.ComponentType<{
@@ -88,9 +93,12 @@ interface CalendarProps {
88
93
  isEventDisabled?: FlagFn;
89
94
  theme?: CalendarTheme;
90
95
  overLappingLayoutMode?: LayoutMode;
96
+ mode?: CalendarMode;
97
+ activeResourceId?: number;
91
98
  }
92
99
  declare const Calendar: React$1.FC<CalendarProps>;
93
100
 
101
+ type DayKey = string;
94
102
  type SetDayDataPayload = {
95
103
  events?: Record<ResourceId, Event[]>;
96
104
  disabledBlocks?: Record<ResourceId, DisabledBlock[]>;
@@ -102,13 +110,15 @@ type CalendarStoreBinding = {
102
110
  children: React.ReactNode;
103
111
  }>;
104
112
  useResourceById: (id: ResourceId) => Resource;
105
- useEventsFor: (resourceId: ResourceId) => ReadonlyArray<Event>;
106
- useDisabledBlocksFor: (resourceId: ResourceId) => ReadonlyArray<DisabledBlock>;
107
- useDisabledIntervalsFor: (resourceId: ResourceId) => ReadonlyArray<DisabledInterval>;
113
+ useEventsFor: (resourceId: ResourceId, dayDate: Date) => ReadonlyArray<Event>;
114
+ useDisabledBlocksFor: (resourceId: ResourceId, dayDate: Date) => ReadonlyArray<DisabledBlock>;
115
+ useDisabledIntervalsFor: (resourceId: ResourceId, dayDate: Date) => ReadonlyArray<DisabledInterval>;
108
116
  useUpsertResources: () => (rs: Array<Pick<Resource, 'id' | 'name' | 'avatar'>>) => void;
109
- useSetDayData: () => (payload: SetDayDataPayload) => void;
117
+ useSetDayDataFor: () => (dayKey: DayKey, payload: SetDayDataPayload) => void;
110
118
  useGetSelectedEvent: () => Event | null;
111
119
  useSetSelectedEvent: () => (ev: Event | null) => void;
120
+ useSetDate: () => (date: Date) => void;
121
+ useGetDate: () => Date;
112
122
  useGetDraggedEventDraft: () => DraggedEventDraft | null;
113
123
  useSetDraggedEventDraft: () => (draft: DraggedEventDraft | null) => void;
114
124
  };
package/dist/index.d.ts CHANGED
@@ -5,6 +5,7 @@ type ResourceId = number;
5
5
  type Event = {
6
6
  id: number;
7
7
  resourceId: ResourceId;
8
+ date: string;
8
9
  from: number;
9
10
  to: number;
10
11
  title?: string;
@@ -16,12 +17,14 @@ type Event = {
16
17
  type DisabledBlock = {
17
18
  id: number;
18
19
  resourceId: ResourceId;
20
+ date: string;
19
21
  from: number;
20
22
  to: number;
21
23
  title?: string;
22
24
  };
23
25
  type DisabledInterval = {
24
26
  resourceId: ResourceId;
27
+ date: string;
25
28
  from: number;
26
29
  to: number;
27
30
  };
@@ -33,6 +36,7 @@ type Resource = {
33
36
  type DraggedEventDraft = {
34
37
  event: Event;
35
38
  from: number;
39
+ date: string;
36
40
  to: number;
37
41
  resourceId: ResourceId;
38
42
  };
@@ -46,6 +50,7 @@ type LayoutMode = "columns" | "stacked";
46
50
  type EventRenderContext = {
47
51
  hourHeight: number;
48
52
  };
53
+ type CalendarMode = 'day' | '3days' | 'week';
49
54
 
50
55
  type EventSlots = {
51
56
  TopRight?: React$1.ComponentType<{
@@ -88,9 +93,12 @@ interface CalendarProps {
88
93
  isEventDisabled?: FlagFn;
89
94
  theme?: CalendarTheme;
90
95
  overLappingLayoutMode?: LayoutMode;
96
+ mode?: CalendarMode;
97
+ activeResourceId?: number;
91
98
  }
92
99
  declare const Calendar: React$1.FC<CalendarProps>;
93
100
 
101
+ type DayKey = string;
94
102
  type SetDayDataPayload = {
95
103
  events?: Record<ResourceId, Event[]>;
96
104
  disabledBlocks?: Record<ResourceId, DisabledBlock[]>;
@@ -102,13 +110,15 @@ type CalendarStoreBinding = {
102
110
  children: React.ReactNode;
103
111
  }>;
104
112
  useResourceById: (id: ResourceId) => Resource;
105
- useEventsFor: (resourceId: ResourceId) => ReadonlyArray<Event>;
106
- useDisabledBlocksFor: (resourceId: ResourceId) => ReadonlyArray<DisabledBlock>;
107
- useDisabledIntervalsFor: (resourceId: ResourceId) => ReadonlyArray<DisabledInterval>;
113
+ useEventsFor: (resourceId: ResourceId, dayDate: Date) => ReadonlyArray<Event>;
114
+ useDisabledBlocksFor: (resourceId: ResourceId, dayDate: Date) => ReadonlyArray<DisabledBlock>;
115
+ useDisabledIntervalsFor: (resourceId: ResourceId, dayDate: Date) => ReadonlyArray<DisabledInterval>;
108
116
  useUpsertResources: () => (rs: Array<Pick<Resource, 'id' | 'name' | 'avatar'>>) => void;
109
- useSetDayData: () => (payload: SetDayDataPayload) => void;
117
+ useSetDayDataFor: () => (dayKey: DayKey, payload: SetDayDataPayload) => void;
110
118
  useGetSelectedEvent: () => Event | null;
111
119
  useSetSelectedEvent: () => (ev: Event | null) => void;
120
+ useSetDate: () => (date: Date) => void;
121
+ useGetDate: () => Date;
112
122
  useGetDraggedEventDraft: () => DraggedEventDraft | null;
113
123
  useSetDraggedEventDraft: () => (draft: DraggedEventDraft | null) => void;
114
124
  };