Skip to content

Commit

Permalink
feat: drag to create/update
Browse files Browse the repository at this point in the history
  • Loading branch information
Howl authored and Howl committed Sep 17, 2024
1 parent 18c3420 commit 1f4b2db
Show file tree
Hide file tree
Showing 49 changed files with 3,181 additions and 771 deletions.
5 changes: 2 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,11 @@ $ npx expo install react-native-gesture-handler react-native-reanimated

## TODO:
- [ ] Drag/drop to create event
- [ ] Drag/drop to edit event
- [X] Drag/drop to edit event
- [X] Drag/drop to create event
- [ ] Update documentation
- [ ] Support all day events
- [ ] Month View
- [ ] Support RTL

[npm-shield]: https://img.shields.io/npm/v/@howljs/calendar-kit
[ko-fi-shield]: https://img.shields.io/static/v1.svg?label=%20&message=ko-fi&logo=ko-fi&color=13C3FF
Expand Down
2 changes: 1 addition & 1 deletion example/app.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"web": {
"favicon": "./assets/images/favicon.png"
},
"plugins": ["expo-router", "expo-secure-store"],
"plugins": ["expo-router"],
"scheme": "myapp"
}
}
9 changes: 3 additions & 6 deletions example/app/(drawer)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,10 @@ function CustomDrawerContent(props: DrawerContentComponentProps) {
return (
<DrawerContentScrollView {...props}>
<DrawerItem label="Day" onPress={() => _onPressItem('day', 1)} />
<DrawerItem label="3 Days" onPress={() => _onPressItem('day', 3)} />
<DrawerItem label="4 Days" onPress={() => _onPressItem('day', 4)} />
<DrawerItem label="3 Days" onPress={() => _onPressItem('week', 3)} />
<DrawerItem label="4 Days" onPress={() => _onPressItem('week', 4)} />
<DrawerItem label="Week" onPress={() => _onPressItem('week', 7)} />
<DrawerItem
label="Work week"
onPress={() => _onPressItem('workWeek', 5)}
/>
<DrawerItem label="Work week" onPress={() => _onPressItem('week', 5)} />
<View style={[styles.line, { backgroundColor: theme.colors.border }]} />
<View style={[styles.line, { backgroundColor: theme.colors.border }]} />
<DrawerItem
Expand Down
113 changes: 91 additions & 22 deletions example/app/(drawer)/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import CalendarKit, {
DragEventProps,
EventItem,
OutOfRangeProps,
PackedEvent,
type CalendarKitHandle,
type CalendarViewMode,
type LocaleConfigsProps,
} from '@howljs/calendar-kit';
import { useLocalSearchParams, useRouter } from 'expo-router';
import { WeekdayNumbers } from 'luxon';
import React, { useCallback, useMemo, useRef, useState } from 'react';
import {
StyleSheet,
Expand All @@ -19,16 +22,16 @@ import Header from '../../components/Header';
import OutOfRange from '../../components/OutOfRange';
import { useAppContext } from '../../context/AppProvider';

type SearchParams = { viewMode: CalendarViewMode; numberOfDays: string };
type SearchParams = { viewMode: string; numberOfDays: string };

const MIN_DATE = new Date(
new Date().getFullYear() - 2,
new Date().getFullYear() - 1,
new Date().getMonth(),
new Date().getDate()
).toISOString();

const MAX_DATE = new Date(
new Date().getFullYear() + 2,
new Date().getFullYear() + 1,
new Date().getMonth(),
new Date().getDate()
).toISOString();
Expand All @@ -54,8 +57,14 @@ const initialLocales: Record<string, LocaleConfigsProps> = {
},
};

const randomColor = () =>
`#${Math.floor(Math.random() * 16777215).toString(16)}`;
const randomColor = () => {
const letters = '0123456789ABCDEF';
let color = '#';
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
};

const minDate = new Date(
new Date().getFullYear(),
Expand All @@ -64,18 +73,16 @@ const minDate = new Date(
);

const generateEvents = () => {
return new Array(1000).fill(0).map((_, index) => {
return new Array(300).fill(0).map((_, index) => {
const randomDateByIndex = new Date(
minDate.getFullYear(),
minDate.getMonth(),
minDate.getDate() + Math.floor(index / 2),
Math.floor(Math.random() * 15),
Math.floor(Math.random() * 60)
Math.floor(Math.random() * 24),
Math.round((Math.random() * 60) / 15) * 15
);

const duration =
Math.floor(Math.random() * 3.5 * 60 * 60 * 1000) + 30 * 60 * 1000;

const duration = (Math.floor(Math.random() * 15) + 1) * 15 * 60 * 1000;
const endDate = new Date(randomDateByIndex.getTime() + duration);

return {
Expand All @@ -90,14 +97,15 @@ const generateEvents = () => {
};

const Calendar = () => {
const [events, setEvents] = useState(() => generateEvents());
const [events, setEvents] = useState<EventItem[]>(() => generateEvents());
const { bottom: safeBottom } = useSafeAreaInsets();
const colorScheme = useColorScheme();
const calendarRef = useRef<CalendarKitHandle>(null);
const { configs } = useAppContext();
const params = useLocalSearchParams<SearchParams>();
const router = useRouter();
const currentDate = useSharedValue(INITIAL_DATE);
const [selectedEvent, setSelectedEvent] = useState<DragEventProps>();

const _onChange = (date: string) => {
currentDate.value = date;
Expand Down Expand Up @@ -136,22 +144,41 @@ const Calendar = () => {
}, []);

const _onPressBackground = (date: string) => {
console.log(date);
// if (selectedEvent) {
// const startISO = new Date(date).toISOString();
// const duration =
// new Date(selectedEvent.end).getTime() -
// new Date(selectedEvent.start).getTime();
// const end = new Date(date).getTime() + duration;
// const endISO = new Date(end).toISOString();
// const newEvent = { ...selectedEvent, start: startISO, end: endISO };
// if (newEvent.id) {
// let newEvents = events.filter((item) => item.id !== newEvent.id);
// newEvents.push({ ...newEvent, id: newEvent.id });
// setEvents(newEvents);
// }
// setSelectedEvent(newEvent);
// }
console.log(new Date(date).toISOString());
setSelectedEvent(undefined);
};

const _renderEvent = useCallback(() => {
return <Text>Event</Text>;
const _renderEvent = useCallback((props: PackedEvent) => {
return <Text>{props.title}</Text>;
}, []);

const isWorkWeek = params.viewMode === 'week' && params.numberOfDays === '5';
const hideWeekDays: WeekdayNumbers[] = isWorkWeek ? [6, 7] : [];

return (
<View style={styles.container}>
<Header currentDate={currentDate} onPressToday={_onPressToday} />
<CalendarKit
ref={calendarRef}
viewMode={params.viewMode}
scrollByDay={params.viewMode === 'day'}
numberOfDays={Number(params.numberOfDays)}
firstDay={params.viewMode === 'workWeek' ? 1 : configs.startOfWeek}
scrollByDay={Number(params.numberOfDays) < 5}
firstDay={isWorkWeek ? 1 : configs.startOfWeek}
hideWeekDays={hideWeekDays}
initialLocales={initialLocales}
themeMode={
configs.themeMode === 'auto'
Expand All @@ -174,11 +201,53 @@ const Calendar = () => {
unavailableHours={unavailableHours}
highlightDates={highlightDates}
events={events}
onPressEvent={console.log}
onPressEvent={(event) => {
console.log(new Date(event.start as string).toLocaleString());
}}
renderEvent={_renderEvent}
scrollToNow
rightEdgeSpacing={4}
overlapEventsSpacing={1}
useHaptic
timezone="Asia/Tokyo"
allowDragToEdit
allowDragToCreate
onLongPressEvent={(event) => {
if (event.id !== selectedEvent?.id) {
setSelectedEvent(undefined);
}
}}
selectedEvent={selectedEvent}
start={60}
end={23 * 60}
defaultDuration={60}
onDragEventEnd={(event) => {
if (event.id) {
let newEvents = events.filter((item) => item.id !== event.id);
newEvents.push({ ...event, id: event.id });
setEvents(newEvents);
}
setSelectedEvent(event);
}}
onDragSelectedEventEnd={(event) => {
if (event.id) {
let newEvents = events.filter((item) => item.id !== event.id);
newEvents.push({ ...event, id: event.id });
setEvents(newEvents);
}
setSelectedEvent(event);
}}
onDragCreateEventEnd={(event) => {
const newEvent = {
...event,
id: `event_${events.length + 1}`,
title: `Event ${events.length + 1}`,
color: randomColor(),
};
const newEvents = [...events, newEvent];
setEvents(newEvents);
setSelectedEvent(newEvent);
}}
/>
<View style={[styles.actions, { paddingBottom: safeBottom }]}>
<TouchableOpacity
Expand All @@ -193,15 +262,15 @@ const Calendar = () => {
<TouchableOpacity
style={styles.btn}
onPress={() => {
calendarRef.current?.goToPrevPage(true, params.viewMode === 'day');
calendarRef.current?.goToPrevPage(true);
}}
>
<Text>Prev</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.btn}
onPress={() => {
calendarRef.current?.goToNextPage(true, params.viewMode === 'day');
calendarRef.current?.goToNextPage(true);
}}
>
<Text>Next</Text>
Expand Down
34 changes: 17 additions & 17 deletions example/assets/sampleData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ export const sampleData = [
},
start: {
dateTime: '2024-01-05T07:20:00+07:00',
timeZone: 'Asia/Ho_Chi_Minh',
timezone: 'Asia/Ho_Chi_Minh',
},
end: {
dateTime: '2024-01-05T09:00:00+07:00',
timeZone: 'Asia/Ho_Chi_Minh',
timezone: 'Asia/Ho_Chi_Minh',
},
transparency: 'transparent',
visibility: 'private',
Expand Down Expand Up @@ -72,11 +72,11 @@ export const sampleData = [
},
start: {
dateTime: '2024-01-08T09:45:00+07:00',
timeZone: 'Asia/Ho_Chi_Minh',
timezone: 'Asia/Ho_Chi_Minh',
},
end: {
dateTime: '2024-01-08T11:35:00+07:00',
timeZone: 'Asia/Ho_Chi_Minh',
timezone: 'Asia/Ho_Chi_Minh',
},
transparency: 'transparent',
visibility: 'private',
Expand Down Expand Up @@ -169,11 +169,11 @@ export const sampleData = [
},
start: {
dateTime: '2023-02-20T17:00:00+07:00',
timeZone: 'Asia/Tokyo',
timezone: 'Asia/Tokyo',
},
end: {
dateTime: '2023-02-20T17:30:00+07:00',
timeZone: 'Asia/Tokyo',
timezone: 'Asia/Tokyo',
},
recurrence: ['RRULE:FREQ=WEEKLY;UNTIL=20230702T145959Z;BYDAY=MO'],
iCalUID: '[email protected]',
Expand Down Expand Up @@ -278,7 +278,7 @@ export const sampleData = [
recurringEventId: 'en7h1e31k90rs5nfeumtebseqt_R20231211T100000',
originalStartTime: {
dateTime: '2024-01-01T17:00:00+07:00',
timeZone: 'UTC',
timezone: 'UTC',
},
},
{
Expand Down Expand Up @@ -313,11 +313,11 @@ export const sampleData = [
},
start: {
dateTime: '2024-01-02T20:00:00+07:00',
timeZone: 'Pacific/Niue',
timezone: 'Pacific/Niue',
},
end: {
dateTime: '2024-01-03T05:00:00+07:00',
timeZone: 'Pacific/Niue',
timezone: 'Pacific/Niue',
},
iCalUID: '[email protected]',
sequence: 1,
Expand Down Expand Up @@ -346,11 +346,11 @@ export const sampleData = [
},
start: {
dateTime: '2024-01-01T11:00:00+07:00',
timeZone: 'Asia/Ho_Chi_Minh',
timezone: 'Asia/Ho_Chi_Minh',
},
end: {
dateTime: '2024-01-01T13:00:00+07:00',
timeZone: 'Asia/Ho_Chi_Minh',
timezone: 'Asia/Ho_Chi_Minh',
},
recurrence: ['RRULE:FREQ=DAILY;UNTIL=20240108T165959Z'],
iCalUID: '[email protected]',
Expand Down Expand Up @@ -380,11 +380,11 @@ export const sampleData = [
},
start: {
dateTime: '2024-01-09T11:00:00+07:00',
timeZone: 'Asia/Ho_Chi_Minh',
timezone: 'Asia/Ho_Chi_Minh',
},
end: {
dateTime: '2024-01-09T13:00:00+07:00',
timeZone: 'Asia/Ho_Chi_Minh',
timezone: 'Asia/Ho_Chi_Minh',
},
recurrence: ['RRULE:FREQ=DAILY;UNTIL=20240116T165959Z'],
iCalUID: '[email protected]',
Expand Down Expand Up @@ -414,16 +414,16 @@ export const sampleData = [
},
start: {
dateTime: '2024-01-09T08:00:00+07:00',
timeZone: 'Asia/Ho_Chi_Minh',
timezone: 'Asia/Ho_Chi_Minh',
},
end: {
dateTime: '2024-01-09T10:00:00+07:00',
timeZone: 'Asia/Ho_Chi_Minh',
timezone: 'Asia/Ho_Chi_Minh',
},
recurringEventId: '44h162s48ar8t9f3jf2dihpl64_R20240109T040000',
originalStartTime: {
dateTime: '2024-01-09T11:00:00+07:00',
timeZone: 'Asia/Ho_Chi_Minh',
timezone: 'Asia/Ho_Chi_Minh',
},
iCalUID: '[email protected]',
sequence: 9,
Expand All @@ -440,7 +440,7 @@ export const sampleData = [
recurringEventId: '44h162s48ar8t9f3jf2dihpl64_R20240109T040000',
originalStartTime: {
dateTime: '2024-01-11T11:00:00+07:00',
timeZone: 'Asia/Ho_Chi_Minh',
timezone: 'Asia/Ho_Chi_Minh',
},
},
];
3 changes: 2 additions & 1 deletion example/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ const Header: FC<HeaderProps> = ({ currentDate, onPressToday }) => {
() => currentDate.value,
(value) => {
runOnJS(updateTitle)(value);
}
},
[]
);

const _onPressMenu = () => {
Expand Down
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,7 @@
}
},
"workspaces": [
"example",
"server"
"example"
],
"packageManager": "[email protected]",
"jest": {
Expand Down
Loading

0 comments on commit 1f4b2db

Please sign in to comment.