From dde6f4de697fd9d0f3fc5e44b7560e1a3f01b85d Mon Sep 17 00:00:00 2001 From: haleymartin-6 <119809061+haleymartin-6@users.noreply.github.com> Date: Tue, 19 Mar 2024 12:08:48 -0400 Subject: [PATCH] Feature/calendar pt3 (#56) * feat: A really basic month calendar view utilizing js functions to get days in a month and tailwind * feat(MonthCalendarView.tsx): Added hardcoded tasks to be added on button press * style(MonthCalendarView.tsx): Refactored from not using Tailwind to using Tailwind * refactor: some code change stuff * fix(file-upload): refactor fileupload to use params instead of header Just found the params field today, this change is to go with general SWE practices that a header is a field of an HTTP request or response that passes additional context and metadata about the request or response. For example, a request message can use headers to indicate it's preferred media formats, while a response can use header to indicate the media format of the returned body. * feat: I NO LONGER NEED TO LOGIN * feat: fe requests using transquery * feat: install clsx bc I like it w/ tailwind * refactor: general cleanup for fe demo * docs: readme changes * ci: remove over complicated name * docs: readme update to remove bullets from contributing section * fix: remove extra fetch after post request for med noticed that it marked the data as stale which refetches it automatically then I also manually refetched * refactor: use tan stack in file and login service routes * test: fix test * docs(pull_request_template): revert changes * refactor: general import cleanup, removing default exports, and follow coding styles mentioned in slack * refactor: remove unused hook stuff from the useMedication api hook * refactor: combine all three popup hooks into one * refactor: revert prev commit (I didnt like it) * ci: try at separating ci stuff * ci: replace prettier with node package, add paths to fe and be CI stuff :))) * ci: fix fe format? * ci: pls work * refactor: general cleanup after merge * feat: just commit lol * feat: calendar examples idk * refactor: cleanup * feat: add pt.1 calendar to main router * updated calendar2.0 * feat: ... Update calendar and added my firebase credentials. * feat: updated calendar and firebase user info * feat: updated calendar and firebase user info * feat: updated calendar and code clean up --------- Co-authored-by: Matt McCoy Co-authored-by: narayansharma-21 <97.sharman@gmail.com> --- backend/db/migrations/1.user.sql | 4 +- backend/db/migrations/2.group.sql | 4 +- client/assets/calendar.svg | 6 + .../{TaskType => task-type}/BackButton.tsx | 2 +- .../{TaskType => task-type}/CloseButton.tsx | 0 .../navigation/AppStackBottomTabNavigator.tsx | 3 +- client/package.json | 6 + client/screens/Calendar.tsx | 155 ++++++++++++++++++ client/screens/TaskType.tsx | 4 +- client/screens/timelineEvents.tsx | 123 ++++++++++++++ 10 files changed, 301 insertions(+), 6 deletions(-) create mode 100644 client/assets/calendar.svg rename client/components/{TaskType => task-type}/BackButton.tsx (88%) rename client/components/{TaskType => task-type}/CloseButton.tsx (100%) create mode 100644 client/screens/Calendar.tsx create mode 100644 client/screens/timelineEvents.tsx diff --git a/backend/db/migrations/1.user.sql b/backend/db/migrations/1.user.sql index 51cab11..239164a 100644 --- a/backend/db/migrations/1.user.sql +++ b/backend/db/migrations/1.user.sql @@ -28,6 +28,8 @@ VALUES ('onrQs8HVGBVMPNz4Fk1uE94bSxg1', 'Danny', 'Rollo', 'dannyrollo4@gmail.com', '', ''), ('8Sy7xBkGiGQv4ZKphcQfY8PxAqw1', 'Narayan', 'Sharma', 'sharma.na@northeastern.edu', '', ''), ('iL7PnjS4axQffmlPceobjUUZ9DF2', 'Caitlin', 'Flynn', 'flynn.ca@northeastern.edu', '', ''), - ('5JgN2PQxCRM9VoCiiFPlQPNqkL32', 'Linwood', 'Blaisdell', 'blaisdell.l@northeastern.edu', '', '') + ('5JgN2PQxCRM9VoCiiFPlQPNqkL32', 'Linwood', 'Blaisdell', 'blaisdell.l@northeastern.edu', '', ''), + ('9rIMSUo6qNf8ToTABkCfNqnByRv1', 'Haley', 'Martin', 'martin.hal@northeastern.edu', '', '') + -- End Care-Wallet Team ; diff --git a/backend/db/migrations/2.group.sql b/backend/db/migrations/2.group.sql index a85d363..16116e9 100644 --- a/backend/db/migrations/2.group.sql +++ b/backend/db/migrations/2.group.sql @@ -49,6 +49,8 @@ VALUES (5, 'mPeo3d3MiXfnpPJADWgFD9ZcB2M2', 'SECONDARY'), (5, 'onrQs8HVGBVMPNz4Fk1uE94bSxg1', 'SECONDARY'), (5, '8Sy7xBkGiGQv4ZKphcQfY8PxAqw1', 'SECONDARY'), - (5, 'iL7PnjS4axQffmlPceobjUUZ9DF2', 'SECONDARY') + (5, 'iL7PnjS4axQffmlPceobjUUZ9DF2', 'SECONDARY'), + (5, '9rIMSUo6qNf8ToTABkCfNqnByRv1', 'SECONDARY') + -- End Care-Wallet Team ; diff --git a/client/assets/calendar.svg b/client/assets/calendar.svg new file mode 100644 index 0000000..51b365f --- /dev/null +++ b/client/assets/calendar.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/client/components/TaskType/BackButton.tsx b/client/components/task-type/BackButton.tsx similarity index 88% rename from client/components/TaskType/BackButton.tsx rename to client/components/task-type/BackButton.tsx index aab16bf..f8aad50 100644 --- a/client/components/TaskType/BackButton.tsx +++ b/client/components/task-type/BackButton.tsx @@ -4,7 +4,7 @@ import { useNavigation } from '@react-navigation/native'; import { IconButton } from 'react-native-paper'; import BackArrow from '../../assets/back-arrow.svg'; -import { AppStackNavigation } from '../../navigation/AppNavigation'; +import { AppStackNavigation } from '../../navigation/types'; export function BackButton() { const navigation = useNavigation(); diff --git a/client/components/TaskType/CloseButton.tsx b/client/components/task-type/CloseButton.tsx similarity index 100% rename from client/components/TaskType/CloseButton.tsx rename to client/components/task-type/CloseButton.tsx diff --git a/client/navigation/AppStackBottomTabNavigator.tsx b/client/navigation/AppStackBottomTabNavigator.tsx index 4b3fb45..107c485 100644 --- a/client/navigation/AppStackBottomTabNavigator.tsx +++ b/client/navigation/AppStackBottomTabNavigator.tsx @@ -7,6 +7,7 @@ import Bell from '../assets/bottom-nav/bell.svg'; import Calendar from '../assets/bottom-nav/calendar.svg'; import Home from '../assets/bottom-nav/home.svg'; import User from '../assets/bottom-nav/user.svg'; +import TimelineCalendarScreen from '../screens/Calendar'; import MedicationList from '../screens/MedicationList'; import PatientView from '../screens/Profile/PatientView'; import Profile from '../screens/Profile/Profile'; @@ -38,7 +39,7 @@ export function AppStackBottomTabNavigator() { tabBarIcon: ({ color }) => , tabBarLabel: () => }} - component={MedicationList} + component={TimelineCalendarScreen} /> CalendarUtils.getCalendarDateString(e.start)) + ); + + const marked = { + [`${getDate(-1)}`]: { marked: true }, + [`${getDate()}`]: { marked: true }, + [`${getDate(1)}`]: { marked: true }, + [`${getDate(2)}`]: { marked: true }, + [`${getDate(4)}`]: { marked: true } + }; + + const onDateChanged = (date: string, source: string) => { + console.log('TimelineCalendarScreen onDateChanged: ', date, source); + setCurrentDate(date); + }; + + const onMonthChange = (month: DateData, updateSource: UpdateSources) => { + console.log('TimelineCalendarScreen onMonthChange: ', month, updateSource); + }; + + const createNewEvent: TimelineProps['onBackgroundLongPress'] = ( + timeString, + timeObject + ) => { + const hourString = `${(timeObject.hour + 1).toString().padStart(2, '0')}`; + const minutesString = `${timeObject.minutes.toString().padStart(2, '0')}`; + + const newEvent = { + id: 'draft', + start: `${timeString}`, + end: `${timeObject.date} ${hourString}:${minutesString}:00`, + title: 'New Event', + color: 'white' + }; + + if (timeObject.date) { + if (eventsByDate[timeObject.date]) { + setEventsByDate((prevEvents) => ({ + ...prevEvents, + [timeObject.date as string]: [ + ...prevEvents[timeObject.date as string], + newEvent + ] + })); + } else { + setEventsByDate((prevEvents) => ({ + ...prevEvents, + [timeObject.date as string]: [newEvent] + })); + } + } + }; + + const approveNewEvent: TimelineProps['onBackgroundLongPressOut'] = ( + _timeString, + timeObject + ) => { + Alert.prompt('New Event', 'Enter event title', [ + { + text: 'Cancel', + onPress: () => { + if (timeObject.date) { + setEventsByDate((prevEvents) => ({ + ...prevEvents, + [timeObject.date as string]: _.filter( + prevEvents[timeObject.date as string], + (e) => e.id !== 'draft' + ) + })); + } + } + }, + { + text: 'Create', + onPress: (eventTitle) => { + if (timeObject.date) { + const draftEvent = _.find(eventsByDate[timeObject.date], { + id: 'draft' + }); + if (draftEvent) { + draftEvent.id = undefined; + draftEvent.title = eventTitle ?? 'New Event'; + draftEvent.color = 'lightgreen'; + setEventsByDate((prevEvents) => ({ + ...prevEvents, + [timeObject.date as string]: [ + ...prevEvents[timeObject.date as string] + ] + })); + } + } + } + } + ]); + }; + + const timelineProps: Partial = { + format24h: false, + onBackgroundLongPress: createNewEvent, + onBackgroundLongPressOut: approveNewEvent, + unavailableHours: [ + { start: 0, end: 6 }, + { start: 22, end: 24 } + ], + onEventPress: (e) => expandEvent(e), + overlapEventsSpacing: 8, + rightEdgeSpacing: 24 + }; + + return ( + + + + + ); +} + +function expandEvent(e: TimelineEventProps): void { + console.log('expand event', e.title); +} diff --git a/client/screens/TaskType.tsx b/client/screens/TaskType.tsx index 066ab6a..473045c 100644 --- a/client/screens/TaskType.tsx +++ b/client/screens/TaskType.tsx @@ -17,8 +17,8 @@ import DropDownPicker from 'react-native-dropdown-picker'; import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { Button, Text } from 'react-native-paper'; -import { BackButton } from '../components/TaskType/BackButton'; -import { CloseButton } from '../components/TaskType/CloseButton'; +import { BackButton } from '../components/task-type/BackButton'; +import { CloseButton } from '../components/task-type/CloseButton'; import { AppStackNavigation } from '../navigation/types'; import { Category, categoryToTypeMap, TypeOfTask } from '../types/type'; diff --git a/client/screens/timelineEvents.tsx b/client/screens/timelineEvents.tsx new file mode 100644 index 0000000..5d6293c --- /dev/null +++ b/client/screens/timelineEvents.tsx @@ -0,0 +1,123 @@ +import { CalendarUtils, TimelineEventProps } from 'react-native-calendars'; + +const EVENT_COLOR = '#e6add8'; +const today = new Date(); +export const getDate = (offset = 0) => + CalendarUtils.getCalendarDateString( + new Date().setDate(today.getDate() + offset) + ); + +export const timelineEvents: TimelineEventProps[] = [ + { + start: `${getDate(-1)} 09:20:00`, + end: `${getDate(-1)} 12:00:00`, + title: 'Merge Request to React Native Calendars', + summary: 'Merge Timeline Calendar to React Native Calendars' + }, + { + start: `${getDate()} 01:15:00`, + end: `${getDate()} 02:30:00`, + title: 'Meeting A', + summary: 'Summary for meeting A', + color: EVENT_COLOR + }, + { + start: `${getDate()} 01:30:00`, + end: `${getDate()} 02:30:00`, + title: 'Meeting B', + summary: 'Summary for meeting B', + color: EVENT_COLOR + }, + { + start: `${getDate()} 01:45:00`, + end: `${getDate()} 02:45:00`, + title: 'Meeting C', + summary: 'Summary for meeting C', + color: EVENT_COLOR + }, + { + start: `${getDate()} 02:40:00`, + end: `${getDate()} 03:10:00`, + title: 'Meeting D', + summary: 'Summary for meeting D', + color: EVENT_COLOR + }, + { + start: `${getDate()} 02:50:00`, + end: `${getDate()} 03:20:00`, + title: 'Meeting E', + summary: 'Summary for meeting E', + color: EVENT_COLOR + }, + { + start: `${getDate()} 04:30:00`, + end: `${getDate()} 05:30:00`, + title: 'Meeting F', + summary: 'Summary for meeting F', + color: EVENT_COLOR + }, + { + start: `${getDate(1)} 00:30:00`, + end: `${getDate(1)} 01:30:00`, + title: 'Visit Grand Mother', + summary: 'Visit Grand Mother and bring some fruits.', + color: 'lightblue' + }, + { + start: `${getDate(1)} 02:30:00`, + end: `${getDate(1)} 03:20:00`, + title: 'Meeting with Prof. Behjet Zuhaira', + summary: 'Meeting with Prof. Behjet at 130 in her office.', + color: EVENT_COLOR + }, + { + start: `${getDate(1)} 04:10:00`, + end: `${getDate(1)} 04:40:00`, + title: 'Tea Time with Dr. Hasan', + summary: 'Tea Time with Dr. Hasan, Talk about Project' + }, + { + start: `${getDate(1)} 01:05:00`, + end: `${getDate(1)} 01:35:00`, + title: 'Dr. Mariana Joseph', + summary: '3412 Piedmont Rd NE, GA 3032' + }, + { + start: `${getDate(1)} 14:30:00`, + end: `${getDate(1)} 16:30:00`, + title: 'Meeting Some Friends in ARMED', + summary: 'Arsalan, Hasnaat, Talha, Waleed, Bilal', + color: 'pink' + }, + { + start: `${getDate(2)} 01:40:00`, + end: `${getDate(2)} 02:25:00`, + title: 'Meet Sir Khurram Iqbal', + summary: 'Computer Science Dept. Comsats Islamabad', + color: 'orange' + }, + { + start: `${getDate(2)} 04:10:00`, + end: `${getDate(2)} 04:40:00`, + title: 'Tea Time with Colleagues', + summary: 'WeRplay' + }, + { + start: `${getDate(2)} 00:45:00`, + end: `${getDate(2)} 01:45:00`, + title: 'Lets Play Apex Legends', + summary: 'with Boys at Work' + }, + { + start: `${getDate(2)} 11:30:00`, + end: `${getDate(2)} 12:30:00`, + title: 'Dr. Mariana Joseph', + summary: '3412 Piedmont Rd NE, GA 3032' + }, + { + start: `${getDate(4)} 12:10:00`, + end: `${getDate(4)} 13:45:00`, + title: 'Merge Request to React Native Calendars', + summary: 'Merge Timeline Calendar to React Native Calendars' + } +];