From 3811565658bda66c23de64756d4cbca2b18b2758 Mon Sep 17 00:00:00 2001 From: Andrei Tan Date: Wed, 5 Apr 2023 20:37:08 -0700 Subject: [PATCH 1/8] basic quick shift --- src/pages/testing/index.tsx | 7 +- .../QuickShift/NewQuickShiftCard.tsx | 57 +++ src/sprintFiles/QuickShift/QuickShiftBtn.tsx | 39 ++ .../QuickShift/ScheduledShiftForm.tsx | 427 ++++++++++++++++++ .../QuickShift/ShiftForm.module.css | 46 ++ .../QuickShift/scheduledShiftApiSlice.ts | 101 +++++ 6 files changed, 676 insertions(+), 1 deletion(-) create mode 100644 src/sprintFiles/QuickShift/NewQuickShiftCard.tsx create mode 100644 src/sprintFiles/QuickShift/QuickShiftBtn.tsx create mode 100644 src/sprintFiles/QuickShift/ScheduledShiftForm.tsx create mode 100644 src/sprintFiles/QuickShift/ShiftForm.module.css create mode 100644 src/sprintFiles/QuickShift/scheduledShiftApiSlice.ts diff --git a/src/pages/testing/index.tsx b/src/pages/testing/index.tsx index 1dc3c1e..d2952fd 100644 --- a/src/pages/testing/index.tsx +++ b/src/pages/testing/index.tsx @@ -1,6 +1,11 @@ // use this to test your stuff +import QuickShiftBtn from '@/sprintFiles/QuickShift/QuickShiftBtn' const index = () => { - return
inex
+ return ( +
+ +
+ ) } export default index diff --git a/src/sprintFiles/QuickShift/NewQuickShiftCard.tsx b/src/sprintFiles/QuickShift/NewQuickShiftCard.tsx new file mode 100644 index 0000000..2a2ad03 --- /dev/null +++ b/src/sprintFiles/QuickShift/NewQuickShiftCard.tsx @@ -0,0 +1,57 @@ +import { + Button, + Dialog, + Typography, + DialogContent, + DialogTitle, +} from '@mui/material' +import { useState } from 'react' +import ScheduledShiftForm from './ScheduledShiftForm' + +//Quick Shift == New Shift card that deals wi +//TODOS: Look below +// Split quickshift card into shift card and quickshiftbtn. +// Have an assigned user. Well-defined date. +// no categories +// select a single day +// skips the shift step of creating schedule. +// will only create a scheduled shift, NOT a SHIFT object. +function NewQuickShiftCard({ + setOpen, + open, +}: { + setOpen: (value: React.SetStateAction) => void + open: boolean +}) { + // const [shiftValues, setShiftValues] = useState(null) + const handleClose = () => { + setOpen(false) + } + + const handleOpen = () => { + setOpen(true) + } + return ( + <> + + + Create Quick Shift + + + + + + + ) +} +export default NewQuickShiftCard diff --git a/src/sprintFiles/QuickShift/QuickShiftBtn.tsx b/src/sprintFiles/QuickShift/QuickShiftBtn.tsx new file mode 100644 index 0000000..bc51f5f --- /dev/null +++ b/src/sprintFiles/QuickShift/QuickShiftBtn.tsx @@ -0,0 +1,39 @@ +import { + Button, + Dialog, + Typography, + DialogContent, + DialogTitle, +} from '@mui/material' +import React from 'react' +import { useState } from 'react' +import NewQuickShiftCard from './NewQuickShiftCard' + +//Quick Shift == New Shift card that deals wi +//TODOS: Look below +// Split quickshift card into shift card and quickshiftbtn. +// Have an assigned user. Well-defined date. +// no categories +// select a single day +// skips the shift step of creating schedule. +// will only create a scheduled shift, NOT a SHIFT object. +function QuickShiftBtn() { + const [open, setOpen] = useState(false) + // const [shiftValues, setShiftValues] = useState(null) + const handleClose = () => { + setOpen(false) + } + + const handleOpen = () => { + setOpen(true) + } + return ( + + + + + ) +} +export default QuickShiftBtn diff --git a/src/sprintFiles/QuickShift/ScheduledShiftForm.tsx b/src/sprintFiles/QuickShift/ScheduledShiftForm.tsx new file mode 100644 index 0000000..665316a --- /dev/null +++ b/src/sprintFiles/QuickShift/ScheduledShiftForm.tsx @@ -0,0 +1,427 @@ +import { Formik, Form, FormikHelpers } from 'formik' +import { Stack, Button, Typography } from '@mui/material' +import { LocalizationProvider } from '@mui/x-date-pickers' +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs' +import { MobileTimePicker } from '@mui/x-date-pickers/MobileTimePicker' + +import dayjs from 'dayjs' +import * as Yup from 'yup' +import { + TextInput, + SelectInput, +} from '../../components/shared/forms/CustomFormikFields' +import { useSelector } from 'react-redux' +import React from 'react' +import { RootState } from '../../store/store' +import { EntityId } from '@reduxjs/toolkit' +import { Shift } from '../../types/schema' +import styles from './ShiftForm.module.css' +import { + selectScheduledShiftById, + useAddNewScheduledShiftMutation, + useUpdateScheduledShiftMutation, +} from './scheduledShiftApiSlice' + +//TODO: NOTE FROM ANDREI - scheduledshift objects are referred to as shifts in this file. Too many random changes if we rename it to scheduledShifts. +// TODO: If you have time ig you could change, but sounds like a waste to me. +//** Yup allows us to define a schema, transform a value to match, and/or assert the shape of an existing value. */ +//** Here, we are defining what kind of inputs we are expecting and attaching error msgs for when the input is not what we want. */ +const ShiftSchema = Yup.object({ + name: Yup.string() + .typeError('Must be a string') + .required('Name is required') + .min(1, 'Name must have at least 1 characters'), + category: Yup.string().required('Category is required'), + members: Yup.number() + .typeError('Must be a number') + .positive('Must be greater than zero') + .integer() + .required('Members is required'), + hours: Yup.number() + .typeError('Must be a number') + .required('Hours is required'), + possibleDays: Yup.array() + .of(Yup.string()) + .required('Possible days is required') + .min(1, 'Possible days is required'), + timeWindowStartTime: Yup.string().required('Start time is required'), + timeWindowEndTime: Yup.string().required('End time is required'), + verificationBuffer: Yup.number() + .typeError('Must be a number') + .required('Buffer hours is required'), + verification: Yup.string().required('Verification type is required'), + description: Yup.string() + .typeError('Must be a string') + .required('Description is required'), + assignedUser: Yup.string(), +}) + +const daysList = [ + 'monday', + 'tuesday', + 'wednesday', + 'thursday', + 'friday', + 'saturday', + 'unday', +] + +const shiftCategories = [ + 'cook dinner', + 'clean bathroom', + 'wash dishes', + 'clean basement', +] +const verificationOptions = ['Verification required', 'No verification'] +const timeWindows = [ + '12:00 AM', + '12:30 AM', + '1:00 AM', + '1:30 AM', + '2:00 AM', + '3:30 AM', + '4:00 AM', + '4:30 AM', + '5:00 AM', + '5:30 AM', + '6:00 AM', + '6:30 AM', + '7:00 AM', + '7:30 AM', + '8:00 AM', + '8:30 AM', + '9:00 AM', + '9:30 AM', + '10:00 AM', + '10:30 AM', + '11:00 AM', + '11:30 AM', + '12:00 PM', + '12:30 PM', + '1:00 PM', + '1:30 PM', + '2:00 PM', + '3:30 PM', + '4:00 PM', + '4:30 PM', + '5:00 PM', + '5:30 PM', + '6:00 PM', + '6:30 PM', + '7:00 PM', + '7:30 PM', + '8:00 PM', + '8:30 PM', + '9:00 PM', + '9:30 PM', + '10:00 PM', + '10:30 PM', + '11:00 PM', + '11:30 PM', +] + +const parseTimeToNumber = (time: string) => { + let hour = 0 + let minute = 0 + let AM = 'AM' + if (time.length === 8) { + // ex: 12:00 AM + hour = parseInt(time.slice(0, 2)) + minute = parseInt(time.slice(3, 5)) + AM = time.slice(6, 8) + } else { + // ex: 1:00 AM + hour = parseInt(time.slice(0, 1)) + minute = parseInt(time.slice(2, 4)) + AM = time.slice(5, 7) + } + if (AM === 'AM' && hour === 12) { + hour = 0 + } + // parses time to match our 0-2400 scale for time + return AM == 'AM' ? hour * 100 + minute : (hour + 12) * 100 + minute +} + +export const parseTimefromNumber = (time: number) => { + let meridian = 'AM' + if (time == 0) { + return '12:00 AM' + } + if (time > 1159) { + meridian = 'PM' + } + if (time > 1259) { + time = time - 1200 + } + const timeString = String(time) + let hours + if (timeString.length > 3) { + hours = timeString.slice(0, 2) + } else { + hours = timeString.slice(0, 1) + } + const minutes = timeString.slice(-2) + if (Number(minutes) > 0) { + return hours + ':' + minutes + ' ' + meridian + } + return hours + ':' + '00' + ' ' + meridian +} + +const verifyToString = (bool: boolean) => { + if (bool) { + return 'Verification required' + } + return 'No Verification' +} + +const emptyShift = { + name: '', + category: '', + members: 1, + hours: 0, + possibleDays: [], + timeWindowStartTime: '12:00 AM', + timeWindowEndTime: '11:30 PM', + verificationBuffer: 0, + verification: 'Verification required', + description: '', + assignedUser: '', +} + +const ScheduledShiftForm = ({ + setOpen, + shiftId, + isNewShift, +}: { + setOpen: (value: React.SetStateAction) => void + shiftId?: string + isNewShift: boolean +}) => { + //* Get API helpers to create or update a shift + const [ + addNewScheduledShift, + { + // isLoading: isLoadingNewShift, + // isSuccess: isSuccessNewShift, + // isError: isErrorNewShift, + // error: errorNewShift, + }, + ] = useAddNewScheduledShiftMutation() + const [ + updateScheduledShift, + { + // isLoading: isLoadingUpdateShift, + // isSuccess: isSuccessUpdateShift, + // isError: isErrorUpdateShift, + // error: errorUpdateShift, + }, + ] = useUpdateScheduledShiftMutation() + + const shift: ScheduledShift = useSelector( + (state: RootState) => + selectScheduledShiftById('EUC')(state, shiftId as EntityId) as Shift + ) + + const onSubmit = async ( + values: { + name: string + category: string + hours: number + timeWindowStartTime: dayjs.Dayjs + timeWindowEndTime: dayjs.Dayjs + possibleDays: string[] + description: string + verificationBuffer: number + }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + formikBag: FormikHelpers + ) => { + const { + name, + category, + hours, + possibleDays, + timeWindowStartTime, + timeWindowEndTime, + verificationBuffer, + verification, + description, + } = values + + const startTime = parseTimeToNumber(timeWindowStartTime) + const endTime = parseTimeToNumber(timeWindowEndTime) + + let result + const timeWindow = [startTime, endTime] + const timeWindowDisplay = timeWindowStartTime + ' - ' + timeWindowEndTime + const data = { data: {}, houseId: '', shiftId: '' } + const verificationBool = + verification === 'Verification required' ? true : false + data.data = { + name, + category, + hours, + possibleDays, + timeWindow, + timeWindowDisplay, + verificationBuffer, + verificationBool, + description, + } + data.houseId = 'EUC' + data.shiftId = shiftId ? shiftId : '' + // console.log('data: ', data) + if (isNewShift || !shiftId) { + result = await addNewScheduledShift(data) + } else { + result = await updateScheduledShift(data) + } + if (result) { + console.log('success with shift: ', result) + } + + formikBag.resetForm() + setOpen(false) + } + + return ( + <> + + {({ isSubmitting }) => ( +
+
+ Shift Name + +
+ +
+ Category + +
+
+
+ Members + +
+
+ Value (hours) + +
+
+
+ Days (select as many as applicable) + +
+
+
+ Start Time + +
+
+ End Time + +
+
+ Buffer Hours + +
+
+
+ Verification + +
+
+ Description + +
+
+ + +
+
+ )} +
+ + ) +} + +export default ScheduledShiftForm diff --git a/src/sprintFiles/QuickShift/ShiftForm.module.css b/src/sprintFiles/QuickShift/ShiftForm.module.css new file mode 100644 index 0000000..b5924ea --- /dev/null +++ b/src/sprintFiles/QuickShift/ShiftForm.module.css @@ -0,0 +1,46 @@ +.shiftBox { + padding: 5%; +} + +.title { + padding-bottom: 2%; + float: left; + display: block; +} + +.close { + float: right; + padding-bottom: 5%; + display: block; +} + +.line { + width: 95%; +} + +.content { +} + +.formField { + width: 100%; + padding-bottom: 1%; + padding-right: 3%; + float: left; +} + +.flex { + width: 100%; + display: flex; + justify-content: space-between; +} + +.submit { + float: right; + margin-bottom: 10px; + margin-right: 5%; +} + +.clear { + float: left; + margin-bottom: 10px; +} diff --git a/src/sprintFiles/QuickShift/scheduledShiftApiSlice.ts b/src/sprintFiles/QuickShift/scheduledShiftApiSlice.ts new file mode 100644 index 0000000..df44e5c --- /dev/null +++ b/src/sprintFiles/QuickShift/scheduledShiftApiSlice.ts @@ -0,0 +1,101 @@ +import { createSelector, createEntityAdapter, EntityId } from '@reduxjs/toolkit' +import { ScheduledShift } from '../../types/schema' +import { apiSlice } from '../../store/api/apiSlice' +import { RootState } from '../../store/store' + +const scheduledShiftsAdapter = createEntityAdapter({}) + +const initialState = scheduledShiftsAdapter.getInitialState() + +export const scheduledShiftsApiSlice = apiSlice.injectEndpoints({ + endpoints: (builder) => ({ + getScheduledShifts: builder.query({ + query: (houseId) => ({ + url: `houses/${houseId}/scheduledShifts`, + method: 'GET', + data: { body: 'hello world' }, + params: { queryType: 'scheduledshifts' }, + // validateStatus: (response, result) => { + // console.log('response: ', response, ' -- result: ', result) + // return response.status === 200 && !result.isError + // }, + }), + // keepUnusedDataFor: 60, + transformResponse: (responseData: ScheduledShift[]) => { + const loaddedShifts = responseData.map((entity) => { + entity.id = entity.id + return entity + }) + console.debug(loaddedShifts) + return scheduledShiftsAdapter.setAll(initialState, loaddedShifts) + }, + providesTags: (result) => { + if (result?.ids) { + return [ + { type: 'ScheduledShift', id: 'LIST' }, + ...result.ids.map((id) => ({ + type: 'ScheduledShift' as const, + id, + })), + ] + } else return [{ type: 'ScheduledShift', id: 'LIST' }] + }, + }), + addNewScheduledShift: builder.mutation({ + query: (data) => ({ + url: `houses/${data.houseId}/scheduledShifts`, + method: 'POST', + body: { + ...data.data, + }, + }), + invalidatesTags: [{ type: 'ScheduledShift', id: 'LIST' }], + }), + updateScheduledShift: builder.mutation({ + query: (data) => ({ + url: `houses/${data.houseId}/scheduledShifts/${data.shiftId}`, + method: 'PATCH', + body: { + ...data.data, + }, + }), + invalidatesTags: (result, error, arg) => [ + { type: 'ScheduledShift', id: arg.id }, + ], + }), + // deleteScheduledShifts: builder.mutation({ + // query: (data) => ({ + // url: `houses/${data.houseId}/scheduledShifts/${data.shiftId}`, + // method: 'DELETE', + // }), + // invalidatesTags: (result, error, arg) => [{ type: 'Shift', id: arg.id }], + // }), + }), +}) + +export const { + useGetScheduledShiftsQuery, + useAddNewScheduledShiftMutation, + useUpdateScheduledShiftMutation, + // useDeleteScheduledShiftsMutation, +} = scheduledShiftsApiSlice + +// Creates memoized selector to get normalized state based on the query parameter +const selectScheduledShiftsData = createSelector( + (state: RootState, queryParameter: string) => + scheduledShiftsApiSlice.endpoints.getScheduledShifts.select(queryParameter)( + state + ), + (scheduledShiftsResult) => scheduledShiftsResult.data ?? initialState +) + +// Creates memoized selector to get a shift by its ID based on the query parameter +export const selectScheduledShiftById = (queryParameter: string) => + createSelector( + (state: RootState) => selectScheduledShiftsData(state, queryParameter), + (_: unknown, scheduledShiftId: EntityId) => scheduledShiftId, + ( + data: { entities: { [x: string]: unknown } }, + scheduledShiftId: string | number + ) => data.entities[scheduledShiftId] + ) From 2faae8cdb96901a17e022f777556c847d3c7903b Mon Sep 17 00:00:00 2001 From: Andrei Tan Date: Wed, 19 Apr 2023 20:02:46 -0700 Subject: [PATCH 2/8] format on card matching figma, need figma updates --- .../QuickShift/NewQuickShiftCard.tsx | 2 +- ...eduledShiftForm.tsx => QuickShiftForm.tsx} | 50 +++++++++---------- .../QuickShift/scheduledShiftApiSlice.ts | 46 +++++++++++------ src/types/schema.ts | 20 ++++++++ 4 files changed, 76 insertions(+), 42 deletions(-) rename src/sprintFiles/QuickShift/{ScheduledShiftForm.tsx => QuickShiftForm.tsx} (92%) diff --git a/src/sprintFiles/QuickShift/NewQuickShiftCard.tsx b/src/sprintFiles/QuickShift/NewQuickShiftCard.tsx index 2a2ad03..fbaa4f9 100644 --- a/src/sprintFiles/QuickShift/NewQuickShiftCard.tsx +++ b/src/sprintFiles/QuickShift/NewQuickShiftCard.tsx @@ -6,7 +6,7 @@ import { DialogTitle, } from '@mui/material' import { useState } from 'react' -import ScheduledShiftForm from './ScheduledShiftForm' +import ScheduledShiftForm from './QuickShiftForm' //Quick Shift == New Shift card that deals wi //TODOS: Look below diff --git a/src/sprintFiles/QuickShift/ScheduledShiftForm.tsx b/src/sprintFiles/QuickShift/QuickShiftForm.tsx similarity index 92% rename from src/sprintFiles/QuickShift/ScheduledShiftForm.tsx rename to src/sprintFiles/QuickShift/QuickShiftForm.tsx index 665316a..1e06960 100644 --- a/src/sprintFiles/QuickShift/ScheduledShiftForm.tsx +++ b/src/sprintFiles/QuickShift/QuickShiftForm.tsx @@ -14,18 +14,26 @@ import { useSelector } from 'react-redux' import React from 'react' import { RootState } from '../../store/store' import { EntityId } from '@reduxjs/toolkit' -import { Shift } from '../../types/schema' +import { ScheduledShift, Shift } from '../../types/schema' import styles from './ShiftForm.module.css' import { selectScheduledShiftById, useAddNewScheduledShiftMutation, useUpdateScheduledShiftMutation, } from './scheduledShiftApiSlice' +import { + selectShiftById, + useAddNewShiftMutation, + useUpdateShiftMutation, +} from '@/features/shift/shiftApiSlice' //TODO: NOTE FROM ANDREI - scheduledshift objects are referred to as shifts in this file. Too many random changes if we rename it to scheduledShifts. // TODO: If you have time ig you could change, but sounds like a waste to me. +//TODO: Greg wants scheduled shift objects to hold a shift copy within themselves. Have it be saved as string in FB, as Shift in-browser. //** Yup allows us to define a schema, transform a value to match, and/or assert the shape of an existing value. */ -//** Here, we are defining what kind of inputs we are expecting and attaching error msgs for when the input is not what we want. */ +//** Here, we are defining what kind of inputs we are expecting and attaching error msgs for when the input is not what we want. * +//Todo: Needs a calendar. QUick shifts have a specific person, specific date. +//TODO: members panel will become a dropdown const ShiftSchema = Yup.object({ name: Yup.string() .typeError('Must be a string') @@ -63,7 +71,7 @@ const daysList = [ 'thursday', 'friday', 'saturday', - 'unday', + 'sunday', ] const shiftCategories = [ @@ -188,7 +196,7 @@ const emptyShift = { assignedUser: '', } -const ScheduledShiftForm = ({ +const QuickShiftForm = ({ setOpen, shiftId, isNewShift, @@ -199,27 +207,27 @@ const ScheduledShiftForm = ({ }) => { //* Get API helpers to create or update a shift const [ - addNewScheduledShift, + addNewShift, { // isLoading: isLoadingNewShift, // isSuccess: isSuccessNewShift, // isError: isErrorNewShift, // error: errorNewShift, }, - ] = useAddNewScheduledShiftMutation() + ] = useAddNewShiftMutation() const [ - updateScheduledShift, + updateShift, { // isLoading: isLoadingUpdateShift, // isSuccess: isSuccessUpdateShift, // isError: isErrorUpdateShift, // error: errorUpdateShift, }, - ] = useUpdateScheduledShiftMutation() + ] = useUpdateShiftMutation() - const shift: ScheduledShift = useSelector( + const shift: Shift = useSelector( (state: RootState) => - selectScheduledShiftById('EUC')(state, shiftId as EntityId) as Shift + selectShiftById('EUC')(state, shiftId as EntityId) as Shift ) const onSubmit = async ( @@ -272,9 +280,9 @@ const ScheduledShiftForm = ({ data.shiftId = shiftId ? shiftId : '' // console.log('data: ', data) if (isNewShift || !shiftId) { - result = await addNewScheduledShift(data) + result = await addNewShift(data) } else { - result = await updateScheduledShift(data) + result = await updateShift(data) } if (result) { console.log('success with shift: ', result) @@ -320,18 +328,6 @@ const ScheduledShiftForm = ({ Shift Name - -
- Category - -
Members @@ -405,14 +401,14 @@ const ScheduledShiftForm = ({ disabled={isSubmitting} className={styles.submit} > - {isNewShift || !shiftId ? 'Submit' : 'Update'} + Save @@ -424,4 +420,4 @@ const ScheduledShiftForm = ({ ) } -export default ScheduledShiftForm +export default QuickShiftForm diff --git a/src/sprintFiles/QuickShift/scheduledShiftApiSlice.ts b/src/sprintFiles/QuickShift/scheduledShiftApiSlice.ts index df44e5c..2ea7731 100644 --- a/src/sprintFiles/QuickShift/scheduledShiftApiSlice.ts +++ b/src/sprintFiles/QuickShift/scheduledShiftApiSlice.ts @@ -1,7 +1,8 @@ import { createSelector, createEntityAdapter, EntityId } from '@reduxjs/toolkit' -import { ScheduledShift } from '../../types/schema' +import { fbScheduledShift, ScheduledShift } from '../../types/schema' import { apiSlice } from '../../store/api/apiSlice' import { RootState } from '../../store/store' +import dayjs from 'dayjs' const scheduledShiftsAdapter = createEntityAdapter({}) @@ -21,13 +22,26 @@ export const scheduledShiftsApiSlice = apiSlice.injectEndpoints({ // }, }), // keepUnusedDataFor: 60, - transformResponse: (responseData: ScheduledShift[]) => { - const loaddedShifts = responseData.map((entity) => { - entity.id = entity.id - return entity + //Andrei Note: deal with the conversion of fbSched shift to a JS scheduled shift. + transformResponse: (responseData: fbScheduledShift[]) => { + const loadedShifts = responseData.map((entity) => { + let jsSchedShift: ScheduledShift = { + id: entity.id, + shiftID: entity.shiftID, + date: dayjs(entity.date), + assignedUser: entity.assignedUser, + status: entity.status, + options: entity.options, + verifiedBy: dayjs(entity.verifiedBy), + verifiedAt: dayjs(entity.verifiedAt), + unverifiedAt: dayjs(entity.unverifiedAt), + penaltyHours: entity.penaltyHours, + jsonCopy: entity.jsonCopy, + } + return jsSchedShift }) - console.debug(loaddedShifts) - return scheduledShiftsAdapter.setAll(initialState, loaddedShifts) + console.debug(loadedShifts) + return scheduledShiftsAdapter.setAll(initialState, loadedShifts) }, providesTags: (result) => { if (result?.ids) { @@ -42,13 +56,17 @@ export const scheduledShiftsApiSlice = apiSlice.injectEndpoints({ }, }), addNewScheduledShift: builder.mutation({ - query: (data) => ({ - url: `houses/${data.houseId}/scheduledShifts`, - method: 'POST', - body: { - ...data.data, - }, - }), + query: (data) => { + + + return ({ + url: `houses/${data.houseId}/scheduledShifts`, + method: 'POST', + body: { + ...data.data, + }, + }) + }, invalidatesTags: [{ type: 'ScheduledShift', id: 'LIST' }], }), updateScheduledShift: builder.mutation({ diff --git a/src/types/schema.ts b/src/types/schema.ts index 7fc1681..b3056a1 100644 --- a/src/types/schema.ts +++ b/src/types/schema.ts @@ -1,3 +1,5 @@ +import dayjs from 'dayjs' + export type User = { // this id is to help the standard table generalize the id attribute id?: string @@ -80,7 +82,24 @@ export type Shift = { } // TODO: add date, verifiedAt, and unverifiedBy attributes +//TODO : When getting date, verifiedBy, and verifiedAt, unverifiedAt : turn from string->date obj, when setting : turn from date obj -> string. +// Todo: Get: pull the string, then call JSON.parse on it (cast). Set: turn it into a string. export type ScheduledShift = { + id: string + shiftID: string + date: dayjs.Dayjs + assignedUser: string + status: string + options: string + verifiedBy: dayjs.Dayjs + verifiedAt: dayjs.Dayjs + unverifiedAt: dayjs.Dayjs + penaltyHours: number + jsonCopy: Shift //TODO : check if this fails +} + +//There's a difference between how objects are stored in Firebase vs in-browser. Look at note on ScheduledShift type for more info. +export type fbScheduledShift = { id: string shiftID: string date: string @@ -91,6 +110,7 @@ export type ScheduledShift = { verifiedAt: string unverifiedAt: string penaltyHours: number + jsonCopy: Shift //TODO : check if this fails } export type House = { From fc1d8eb02cae3b90fbd713f7b8c6bcc6143aab17 Mon Sep 17 00:00:00 2001 From: Andrei Tan Date: Sun, 23 Apr 2023 16:10:24 -0700 Subject: [PATCH 3/8] WIP: for debugging --- src/sprintFiles/QuickShift/QuickShiftForm.tsx | 566 +++++++++--------- .../QuickShift/scheduledShiftApiSlice.ts | 8 +- 2 files changed, 288 insertions(+), 286 deletions(-) diff --git a/src/sprintFiles/QuickShift/QuickShiftForm.tsx b/src/sprintFiles/QuickShift/QuickShiftForm.tsx index 1e06960..dc8944f 100644 --- a/src/sprintFiles/QuickShift/QuickShiftForm.tsx +++ b/src/sprintFiles/QuickShift/QuickShiftForm.tsx @@ -1,20 +1,27 @@ -import { Formik, Form, FormikHelpers } from 'formik' -import { Stack, Button, Typography } from '@mui/material' -import { LocalizationProvider } from '@mui/x-date-pickers' +import { Formik, Form, FormikHelpers, Field } from 'formik' +import { + Stack, + Button, + Typography, + TextField, + Autocomplete, +} from '@mui/material' +import { DatePicker, LocalizationProvider } from '@mui/x-date-pickers' import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs' import { MobileTimePicker } from '@mui/x-date-pickers/MobileTimePicker' +import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker' -import dayjs from 'dayjs' +import dayjs, { Dayjs } from 'dayjs' import * as Yup from 'yup' import { TextInput, SelectInput, } from '../../components/shared/forms/CustomFormikFields' import { useSelector } from 'react-redux' -import React from 'react' +import React, { useEffect, useState } from 'react' import { RootState } from '../../store/store' import { EntityId } from '@reduxjs/toolkit' -import { ScheduledShift, Shift } from '../../types/schema' +import { House, ScheduledShift, Shift, User } from '../../types/schema' import styles from './ShiftForm.module.css' import { selectScheduledShiftById, @@ -26,6 +33,11 @@ import { useAddNewShiftMutation, useUpdateShiftMutation, } from '@/features/shift/shiftApiSlice' +import { useGetShiftsQuery } from '@/features/shift/shiftApiSlice' +import { selectCurrentHouse } from '@/features/auth/authSlice' +import { useGetUsersQuery } from '@/features/user/userApiSlice' +import uuid from 'react-uuid' +import { formatMilitaryTime } from '@/utils/utils' //TODO: NOTE FROM ANDREI - scheduledshift objects are referred to as shifts in this file. Too many random changes if we rename it to scheduledShifts. // TODO: If you have time ig you could change, but sounds like a waste to me. @@ -34,166 +46,46 @@ import { //** Here, we are defining what kind of inputs we are expecting and attaching error msgs for when the input is not what we want. * //Todo: Needs a calendar. QUick shifts have a specific person, specific date. //TODO: members panel will become a dropdown +//Todo: search bar needs 100% match right now, implement reactive soon. const ShiftSchema = Yup.object({ name: Yup.string() - .typeError('Must be a string') .required('Name is required') .min(1, 'Name must have at least 1 characters'), - category: Yup.string().required('Category is required'), - members: Yup.number() - .typeError('Must be a number') - .positive('Must be greater than zero') - .integer() - .required('Members is required'), - hours: Yup.number() - .typeError('Must be a number') - .required('Hours is required'), - possibleDays: Yup.array() - .of(Yup.string()) - .required('Possible days is required') - .min(1, 'Possible days is required'), - timeWindowStartTime: Yup.string().required('Start time is required'), - timeWindowEndTime: Yup.string().required('End time is required'), - verificationBuffer: Yup.number() - .typeError('Must be a number') - .required('Buffer hours is required'), - verification: Yup.string().required('Verification type is required'), - description: Yup.string() - .typeError('Must be a string') - .required('Description is required'), + description: Yup.string(), + possibleDays: Yup.array().of(Yup.string()), + startTime: Yup.date().required('Start time is required'), + endTime: Yup.date().required('End time is required'), + category: Yup.string().required('Cagegory is required'), + hours: Yup.number().required('Hours credit is required'), + verificationBuffer: Yup.number(), assignedUser: Yup.string(), + assignedDay: Yup.string(), + member: Yup.string(), }) const daysList = [ - 'monday', - 'tuesday', - 'wednesday', - 'thursday', - 'friday', - 'saturday', - 'sunday', -] - -const shiftCategories = [ - 'cook dinner', - 'clean bathroom', - 'wash dishes', - 'clean basement', -] -const verificationOptions = ['Verification required', 'No verification'] -const timeWindows = [ - '12:00 AM', - '12:30 AM', - '1:00 AM', - '1:30 AM', - '2:00 AM', - '3:30 AM', - '4:00 AM', - '4:30 AM', - '5:00 AM', - '5:30 AM', - '6:00 AM', - '6:30 AM', - '7:00 AM', - '7:30 AM', - '8:00 AM', - '8:30 AM', - '9:00 AM', - '9:30 AM', - '10:00 AM', - '10:30 AM', - '11:00 AM', - '11:30 AM', - '12:00 PM', - '12:30 PM', - '1:00 PM', - '1:30 PM', - '2:00 PM', - '3:30 PM', - '4:00 PM', - '4:30 PM', - '5:00 PM', - '5:30 PM', - '6:00 PM', - '6:30 PM', - '7:00 PM', - '7:30 PM', - '8:00 PM', - '8:30 PM', - '9:00 PM', - '9:30 PM', - '10:00 PM', - '10:30 PM', - '11:00 PM', - '11:30 PM', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday', + 'Sunday', ] -const parseTimeToNumber = (time: string) => { - let hour = 0 - let minute = 0 - let AM = 'AM' - if (time.length === 8) { - // ex: 12:00 AM - hour = parseInt(time.slice(0, 2)) - minute = parseInt(time.slice(3, 5)) - AM = time.slice(6, 8) - } else { - // ex: 1:00 AM - hour = parseInt(time.slice(0, 1)) - minute = parseInt(time.slice(2, 4)) - AM = time.slice(5, 7) - } - if (AM === 'AM' && hour === 12) { - hour = 0 - } - // parses time to match our 0-2400 scale for time - return AM == 'AM' ? hour * 100 + minute : (hour + 12) * 100 + minute -} - -export const parseTimefromNumber = (time: number) => { - let meridian = 'AM' - if (time == 0) { - return '12:00 AM' - } - if (time > 1159) { - meridian = 'PM' - } - if (time > 1259) { - time = time - 1200 - } - const timeString = String(time) - let hours - if (timeString.length > 3) { - hours = timeString.slice(0, 2) - } else { - hours = timeString.slice(0, 1) - } - const minutes = timeString.slice(-2) - if (Number(minutes) > 0) { - return hours + ':' + minutes + ' ' + meridian - } - return hours + ':' + '00' + ' ' + meridian -} - -const verifyToString = (bool: boolean) => { - if (bool) { - return 'Verification required' - } - return 'No Verification' -} +// const shiftCategories = ['cook dinner', 'clean bathroom', 'wash dishes', 'clean basement'] const emptyShift = { name: '', category: '', - members: 1, - hours: 0, possibleDays: [], - timeWindowStartTime: '12:00 AM', - timeWindowEndTime: '11:30 PM', + startTime: dayjs('2023-04-17T12:00'), + endTime: dayjs('2023-04-17T18:30'), + hours: 0, + despription: '', verificationBuffer: 0, - verification: 'Verification required', - description: '', assignedUser: '', + assignedDay: '', } const QuickShiftForm = ({ @@ -205,6 +97,25 @@ const QuickShiftForm = ({ shiftId?: string isNewShift: boolean }) => { + // const authUser = useSelector(selectCurrentUser) as User + const currentHouse = useSelector(selectCurrentHouse) as House + + //** House shifts */ + const { data: shiftsData, isSuccess: isShiftsSuccess } = useGetShiftsQuery( + currentHouse.id + ) + + //** for editing shifts */ + const shift: Shift = useSelector( + (state: RootState) => + selectShiftById(currentHouse.id)(state, shiftId as EntityId) as Shift + ) + + //** Holds the house shifts categories */ + const [houseCategories, setHouseCategories] = useState([ + 'Uncategorized', + ]) + //* Get API helpers to create or update a shift const [ addNewShift, @@ -225,64 +136,99 @@ const QuickShiftForm = ({ }, ] = useUpdateShiftMutation() - const shift: Shift = useSelector( - (state: RootState) => - selectShiftById('EUC')(state, shiftId as EntityId) as Shift - ) + const [chosenDate, setDate] = useState(null) const onSubmit = async ( values: { name: string category: string hours: number - timeWindowStartTime: dayjs.Dayjs - timeWindowEndTime: dayjs.Dayjs + startTime: Dayjs + endTime: Dayjs possibleDays: string[] description: string verificationBuffer: number + assignedUser: string | undefined + assignedDay: string + member: string }, - // eslint-disable-next-line @typescript-eslint/no-explicit-any formikBag: FormikHelpers ) => { + console.log('Submiting ShiftForm: ', values) const { name, - category, + category: categoryString, hours, + description, possibleDays, - timeWindowStartTime, - timeWindowEndTime, + startTime: startTimeObject, + endTime: endTimeObject, verificationBuffer, - verification, - description, + assignedUser, + assignedDay, + member, } = values - const startTime = parseTimeToNumber(timeWindowStartTime) - const endTime = parseTimeToNumber(timeWindowEndTime) + const startTime = Number(startTimeObject.format('HHmm')) + const endTime = Number(endTimeObject.format('HHmm')) + let category + if (categoryString === undefined || categoryString === 'Uncategorized') { + category = '' + } else { + category = categoryString + } + + // console.log(dayjs('1900', 'HHmm').format('HHmm')) + // const num = 1900 + // console.log(dayjs(num.toString(), 'HHmm')) + // const dayString = possibleDays.join('') let result - const timeWindow = [startTime, endTime] - const timeWindowDisplay = timeWindowStartTime + ' - ' + timeWindowEndTime + const timeWindow = { startTime, endTime } + const id = uuid() + const timeWindowDisplay = + formatMilitaryTime(startTime) + ' - ' + formatMilitaryTime(endTime) const data = { data: {}, houseId: '', shiftId: '' } - const verificationBool = - verification === 'Verification required' ? true : false data.data = { - name, - category, - hours, - possibleDays, - timeWindow, - timeWindowDisplay, - verificationBuffer, - verificationBool, - description, + id: id, + date: chosenDate, + assignedUser: targetUser?.id, + status: 'live', + verifiedBy: '', + verifiedAt: '', + unverifiedAt: '', + penaltyHours: 0, + + // name, + // hours, + // date, + // description, + // timeWindow, + // verificationBuffer, + // timeWindowDisplay, + // assignedUser, + // assignedDay, + + // id, + // shiftId = id, + // date, + // assignedUser + // status: string + // options: string + // verifiedBy: dayjs.Dayjs + // verifiedAt: dayjs.Dayjs + // unverifiedAt: dayjs.Dayjs + // penaltyHours: number + // jsonCopy: Shift //TODO : check if this fails } - data.houseId = 'EUC' - data.shiftId = shiftId ? shiftId : '' + data.houseId = currentHouse.id + data.shiftId = id ? id : '' // console.log('data: ', data) + console.log({ formdata: data, formdatadta: data.data }) if (isNewShift || !shiftId) { - result = await addNewShift(data) + result = await useAddNewScheduledShiftMutation(data) } else { - result = await updateShift(data) + result = await useUpdateScheduledShiftMutation(data) } if (result) { console.log('success with shift: ', result) @@ -292,6 +238,54 @@ const QuickShiftForm = ({ setOpen(false) } + // React.useEffect(() => { + // console.log('This is the selected shift', shift) + // }, [shift]) + + const { + data: users, + // isLoading: isUsersLoading, + // isSuccess: isUsersSuccess, + // isError: isUsersError, + } = useGetUsersQuery({}) + + //Using this instead of setFieldValue in formik because of issues with the fields + //Will use the specific date that a quick shift must be in. + const [userOptions, setUserOptions] = useState(['']) + type labeledUser = { + label: string + id: String + } + const [targetUser, setTargetUser] = useState() + + useEffect(() => { + // console.log({ ents: users?.entities, ids: users?.ids, targuser: targetUser, userOpt: Val: inputValue}) + { + const tempOptions = [] + if (users == undefined) return + users.ids?.map((id: EntityId) => { + let user = users?.entities[id] + if (user != undefined) { + let userWithLabel = { + label: user.displayName, + id: user.id, + } //TODO: add an ID here as well. + // Object.assign(userWithLabel, user) + tempOptions.push(userWithLabel) + } + }) + setUserOptions(tempOptions) + setTargetUser(tempOptions[0]) + } + console.log('OPTIONS: ', { options: userOptions }) + }, [users]) + const [inputValue, setInputValue] = React.useState('') + /** + * 1. load in the options, push the labeled options to a user options list + * 2. use the userOptions to create the members list + * 3. when picking an option from the dropdown, change the member OBJECT to match + */ + return ( <> - {({ isSubmitting }) => ( -
-
- Shift Name - -
-
-
- Members - -
-
- Value (hours) - -
-
-
- Days (select as many as applicable) - -
-
-
- Start Time - { + console.log(values) + return ( + + + + + setDate(e)} /> + + + setFieldValue('startTime', newValue)} /> -
-
- End Time - { + setFieldValue('endTime', newValue) + }} /> -
-
- Buffer Hours - -
-
-
- Verification - -
-
- Description - -
-
- - -
-
- )} + + {targetUser != undefined ? ( + + {(fields) => ( + ( + + )} + // value={targetUser} + // onChange={(e) => { + // setTargetUser(e) + // }} + + // inputValue={inputValue} + // onInputChange={(event, newInputValue) => { + // setInputValue(newInputValue) + // }} + // value={values.member.label} + // onChange={(chosen) => { + // setFieldValue('member', chosen) + // }} + /> + )} + + ) : // ( + // + // )} + // // value={targetUser} + // // onChange={(e) => { + // // setTargetUser(e) + // // }} + + // // inputValue={inputValue} + // // onInputChange={(event, newInputValue) => { + // // setInputValue(newInputValue) + // // }} + // // value={values.member.label} + // // onChange={(chosen) => { + // // setFieldValue('member', chosen) + // // }} + // /> + null} + + + + + + + + + + + + ) + }}
) diff --git a/src/sprintFiles/QuickShift/scheduledShiftApiSlice.ts b/src/sprintFiles/QuickShift/scheduledShiftApiSlice.ts index 2ea7731..54f4a5d 100644 --- a/src/sprintFiles/QuickShift/scheduledShiftApiSlice.ts +++ b/src/sprintFiles/QuickShift/scheduledShiftApiSlice.ts @@ -57,15 +57,15 @@ export const scheduledShiftsApiSlice = apiSlice.injectEndpoints({ }), addNewScheduledShift: builder.mutation({ query: (data) => { + console.log({ data: data, datadata: data.data }) - - return ({ + return { url: `houses/${data.houseId}/scheduledShifts`, method: 'POST', body: { - ...data.data, + ...data.data, }, - }) + } }, invalidatesTags: [{ type: 'ScheduledShift', id: 'LIST' }], }), From 521619bc73420222bcb7d0cf733fa94cdd29a89d Mon Sep 17 00:00:00 2001 From: Andrei Tan Date: Sun, 23 Apr 2023 16:11:48 -0700 Subject: [PATCH 4/8] more debug --- src/sprintFiles/QuickShift/QuickShiftForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sprintFiles/QuickShift/QuickShiftForm.tsx b/src/sprintFiles/QuickShift/QuickShiftForm.tsx index dc8944f..9ca3f47 100644 --- a/src/sprintFiles/QuickShift/QuickShiftForm.tsx +++ b/src/sprintFiles/QuickShift/QuickShiftForm.tsx @@ -342,7 +342,7 @@ const QuickShiftForm = ({ {targetUser != undefined ? ( - {(fields) => ( + {({ fields }) => ( Date: Sun, 23 Apr 2023 17:09:17 -0700 Subject: [PATCH 5/8] debugging onSubmit --- src/sprintFiles/QuickShift/QuickShiftForm.tsx | 110 ++++++------------ 1 file changed, 33 insertions(+), 77 deletions(-) diff --git a/src/sprintFiles/QuickShift/QuickShiftForm.tsx b/src/sprintFiles/QuickShift/QuickShiftForm.tsx index 9ca3f47..96eeb54 100644 --- a/src/sprintFiles/QuickShift/QuickShiftForm.tsx +++ b/src/sprintFiles/QuickShift/QuickShiftForm.tsx @@ -55,12 +55,12 @@ const ShiftSchema = Yup.object({ possibleDays: Yup.array().of(Yup.string()), startTime: Yup.date().required('Start time is required'), endTime: Yup.date().required('End time is required'), - category: Yup.string().required('Cagegory is required'), + // category: Yup.string().required('Cagegory is required'), hours: Yup.number().required('Hours credit is required'), verificationBuffer: Yup.number(), assignedUser: Yup.string(), assignedDay: Yup.string(), - member: Yup.string(), + member: Yup.object(), }) const daysList = [ @@ -151,9 +151,11 @@ const QuickShiftForm = ({ assignedUser: string | undefined assignedDay: string member: string + targetUser: labeledUser }, formikBag: FormikHelpers ) => { + console.log('submitting') console.log('Submiting ShiftForm: ', values) const { name, @@ -167,6 +169,7 @@ const QuickShiftForm = ({ assignedUser, assignedDay, member, + targetUser, } = values const startTime = Number(startTimeObject.format('HHmm')) @@ -198,28 +201,6 @@ const QuickShiftForm = ({ verifiedAt: '', unverifiedAt: '', penaltyHours: 0, - - // name, - // hours, - // date, - // description, - // timeWindow, - // verificationBuffer, - // timeWindowDisplay, - // assignedUser, - // assignedDay, - - // id, - // shiftId = id, - // date, - // assignedUser - // status: string - // options: string - // verifiedBy: dayjs.Dayjs - // verifiedAt: dayjs.Dayjs - // unverifiedAt: dayjs.Dayjs - // penaltyHours: number - // jsonCopy: Shift //TODO : check if this fails } data.houseId = currentHouse.id data.shiftId = id ? id : '' @@ -251,12 +232,12 @@ const QuickShiftForm = ({ //Using this instead of setFieldValue in formik because of issues with the fields //Will use the specific date that a quick shift must be in. - const [userOptions, setUserOptions] = useState(['']) + const [userOptions, setUserOptions] = useState(['', 'a', 'b', 'c', 'd']) type labeledUser = { label: string id: String } - const [targetUser, setTargetUser] = useState() + const [targetUser, setTargetUser] = useState(userOptions[0]) useEffect(() => { // console.log({ ents: users?.entities, ids: users?.ids, targuser: targetUser, userOpt: Val: inputValue}) @@ -292,7 +273,7 @@ const QuickShiftForm = ({ validationSchema={ShiftSchema} initialValues={{ name: shift ? shift.name : emptyShift.name, - category: shift ? shift.category : emptyShift.category, + // category: shift ? shift.category : emptyShift.category, hours: shift ? shift.hours : emptyShift.hours, startTime: shift ? dayjs(shift.timeWindow.startTime.toString(), 'HHmm') @@ -312,11 +293,13 @@ const QuickShiftForm = ({ assignedUser: shift ? shift.assignedUser : emptyShift.assignedUser, assignedDay: shift ? shift.assignedDay : emptyShift.assignedDay, member: { label: '', id: '' }, + memberId: '', }} onSubmit={onSubmit} > - {({ isSubmitting, values, setFieldValue }) => { - console.log(values) + {({ isSubmitting, values, setFieldValue, errors }) => { + console.log({ values: values }) + console.log({ errors: errors }) return (
@@ -341,54 +324,27 @@ const QuickShiftForm = ({ /> {targetUser != undefined ? ( - - {({ fields }) => ( - ( - - )} - // value={targetUser} - // onChange={(e) => { - // setTargetUser(e) - // }} - - // inputValue={inputValue} - // onInputChange={(event, newInputValue) => { - // setInputValue(newInputValue) - // }} - // value={values.member.label} - // onChange={(chosen) => { - // setFieldValue('member', chosen) - // }} - /> + ( + )} - - ) : // ( - // - // )} - // // value={targetUser} - // // onChange={(e) => { - // // setTargetUser(e) - // // }} - - // // inputValue={inputValue} - // // onInputChange={(event, newInputValue) => { - // // setInputValue(newInputValue) - // // }} - // // value={values.member.label} - // // onChange={(chosen) => { - // // setFieldValue('member', chosen) - // // }} - // /> - null} + value={undefined} + // onChange={(e) => { + // setTargetUser(e) + // }} + inputValue={inputValue} + onInputChange={(event, newInputValue) => { + setInputValue(newInputValue) + }} + onChange={(event: any, newValue: labeledUser) => { + setFieldValue('member', newValue) + }} + /> + ) : null} @@ -401,7 +357,7 @@ const QuickShiftForm = ({ fullWidth variant="contained" color="primary" - disabled={isSubmitting} + // disabled={isSubmitting} > {isNewShift || !shiftId ? 'Submit' : 'Update'} From a2f5d7427c9572109acdb840a3adea5673f64680 Mon Sep 17 00:00:00 2001 From: Andrei Tan Date: Wed, 26 Apr 2023 15:52:12 -0700 Subject: [PATCH 6/8] more debugging --- src/sprintFiles/QuickShift/QuickShiftForm.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sprintFiles/QuickShift/QuickShiftForm.tsx b/src/sprintFiles/QuickShift/QuickShiftForm.tsx index 96eeb54..4e704e4 100644 --- a/src/sprintFiles/QuickShift/QuickShiftForm.tsx +++ b/src/sprintFiles/QuickShift/QuickShiftForm.tsx @@ -40,7 +40,7 @@ import uuid from 'react-uuid' import { formatMilitaryTime } from '@/utils/utils' //TODO: NOTE FROM ANDREI - scheduledshift objects are referred to as shifts in this file. Too many random changes if we rename it to scheduledShifts. -// TODO: If you have time ig you could change, but sounds like a waste to me. + //TODO: Greg wants scheduled shift objects to hold a shift copy within themselves. Have it be saved as string in FB, as Shift in-browser. //** Yup allows us to define a schema, transform a value to match, and/or assert the shape of an existing value. */ //** Here, we are defining what kind of inputs we are expecting and attaching error msgs for when the input is not what we want. * @@ -58,9 +58,11 @@ const ShiftSchema = Yup.object({ // category: Yup.string().required('Cagegory is required'), hours: Yup.number().required('Hours credit is required'), verificationBuffer: Yup.number(), - assignedUser: Yup.string(), + assignedUser: Yup.string(), //unsure what this did in the original shift. assignedDay: Yup.string(), + member: Yup.object(), + date: Yup.date(), }) const daysList = [ @@ -171,6 +173,7 @@ const QuickShiftForm = ({ member, targetUser, } = values + console.log({ afterwards: values }) const startTime = Number(startTimeObject.format('HHmm')) const endTime = Number(endTimeObject.format('HHmm')) @@ -264,7 +267,9 @@ const QuickShiftForm = ({ /** * 1. load in the options, push the labeled options to a user options list * 2. use the userOptions to create the members list - * 3. when picking an option from the dropdown, change the member OBJECT to match + * 3. treat the form like a normal shift form. Except: Categories, assignedUser, possible days will be set to defaults. + * 4. when picking an option from the dropdown, change the member OBJECT to match + * 5. */ return ( @@ -298,8 +303,6 @@ const QuickShiftForm = ({ onSubmit={onSubmit} > {({ isSubmitting, values, setFieldValue, errors }) => { - console.log({ values: values }) - console.log({ errors: errors }) return ( From 149d6b4c665dd10a16f121b970ae0cf82cee0d35 Mon Sep 17 00:00:00 2001 From: Andrei Tan Date: Wed, 26 Apr 2023 19:01:10 -0700 Subject: [PATCH 7/8] horrendous debugging finished --- src/sprintFiles/QuickShift/QuickShiftForm.tsx | 108 +++++++++++------- .../QuickShift/scheduledShiftApiSlice.ts | 29 +++-- src/types/schema.ts | 1 - 3 files changed, 86 insertions(+), 52 deletions(-) diff --git a/src/sprintFiles/QuickShift/QuickShiftForm.tsx b/src/sprintFiles/QuickShift/QuickShiftForm.tsx index 4e704e4..3d596c6 100644 --- a/src/sprintFiles/QuickShift/QuickShiftForm.tsx +++ b/src/sprintFiles/QuickShift/QuickShiftForm.tsx @@ -39,14 +39,6 @@ import { useGetUsersQuery } from '@/features/user/userApiSlice' import uuid from 'react-uuid' import { formatMilitaryTime } from '@/utils/utils' -//TODO: NOTE FROM ANDREI - scheduledshift objects are referred to as shifts in this file. Too many random changes if we rename it to scheduledShifts. - -//TODO: Greg wants scheduled shift objects to hold a shift copy within themselves. Have it be saved as string in FB, as Shift in-browser. -//** Yup allows us to define a schema, transform a value to match, and/or assert the shape of an existing value. */ -//** Here, we are defining what kind of inputs we are expecting and attaching error msgs for when the input is not what we want. * -//Todo: Needs a calendar. QUick shifts have a specific person, specific date. -//TODO: members panel will become a dropdown -//Todo: search bar needs 100% match right now, implement reactive soon. const ShiftSchema = Yup.object({ name: Yup.string() .required('Name is required') @@ -58,10 +50,9 @@ const ShiftSchema = Yup.object({ // category: Yup.string().required('Cagegory is required'), hours: Yup.number().required('Hours credit is required'), verificationBuffer: Yup.number(), - assignedUser: Yup.string(), //unsure what this did in the original shift. assignedDay: Yup.string(), - member: Yup.object(), + assignedUser: Yup.object(), //reassign the assignedUser date: Yup.date(), }) @@ -86,10 +77,19 @@ const emptyShift = { hours: 0, despription: '', verificationBuffer: 0, - assignedUser: '', - assignedDay: '', + assignedUser: { label: '', id: '' }, + assignedDay: dayjs(), } +/** + * 1. Fill out the quick shift form like a shift form + * 2. Formik uses validation schema + setField value to track form changes + * 3. For any option, setFieldValue, TextField, and other formik components/funcs will update initialValues + * 4. When submit is pressed, initialValues is sent to onSubmit function. + * 5. onSubmit function accesses the field values from formik. Can manipulate as wanted + * 6. OnSubmit formats the field info to match a scheduled shift. Sends it to firebase + */ + const QuickShiftForm = ({ setOpen, shiftId, @@ -120,26 +120,33 @@ const QuickShiftForm = ({ //* Get API helpers to create or update a shift const [ - addNewShift, + addNewScheduledShift, { // isLoading: isLoadingNewShift, // isSuccess: isSuccessNewShift, // isError: isErrorNewShift, // error: errorNewShift, }, - ] = useAddNewShiftMutation() + ] = useAddNewScheduledShiftMutation() const [ - updateShift, + updateScheduledShift, { // isLoading: isLoadingUpdateShift, // isSuccess: isSuccessUpdateShift, // isError: isErrorUpdateShift, // error: errorUpdateShift, }, - ] = useUpdateShiftMutation() + ] = useUpdateScheduledShiftMutation() const [chosenDate, setDate] = useState(null) + /** + * + * Has part of the data formatted into JSONcopy, which is what the original shift should've looked like + * Note that JSONCopy won't match a Shift object in our firebase like a regular scheduled shift would + * Rest of info is stored in a defaulted scheduledShift. Bare min. info to fit a quickshift. + * + */ const onSubmit = async ( values: { name: string @@ -150,15 +157,12 @@ const QuickShiftForm = ({ possibleDays: string[] description: string verificationBuffer: number - assignedUser: string | undefined - assignedDay: string - member: string - targetUser: labeledUser + + assignedDay: Dayjs + assignedUser: labeledUser | undefined }, formikBag: FormikHelpers ) => { - console.log('submitting') - console.log('Submiting ShiftForm: ', values) const { name, category: categoryString, @@ -170,10 +174,7 @@ const QuickShiftForm = ({ verificationBuffer, assignedUser, assignedDay, - member, - targetUser, } = values - console.log({ afterwards: values }) const startTime = Number(startTimeObject.format('HHmm')) const endTime = Number(endTimeObject.format('HHmm')) @@ -184,35 +185,51 @@ const QuickShiftForm = ({ category = categoryString } - // console.log(dayjs('1900', 'HHmm').format('HHmm')) - // const num = 1900 - // console.log(dayjs(num.toString(), 'HHmm')) - - // const dayString = possibleDays.join('') let result const timeWindow = { startTime, endTime } - const id = uuid() const timeWindowDisplay = formatMilitaryTime(startTime) + ' - ' + formatMilitaryTime(endTime) const data = { data: {}, houseId: '', shiftId: '' } + const shiftObject = { + name, + category, + hours, + possibleDays, + description, + timeWindow, + verificationBuffer, + timeWindowDisplay, + assignedUser, + assignedDay, + } + data.data = { - id: id, - date: chosenDate, - assignedUser: targetUser?.id, + id: '', + shiftID: '', + date: assignedDay.toString(), + assignedUser: assignedUser, status: 'live', verifiedBy: '', verifiedAt: '', unverifiedAt: '', penaltyHours: 0, + jsonCopy: JSON.stringify(shiftObject), //TODO : check if this fails } + data.houseId = currentHouse.id - data.shiftId = id ? id : '' + data.shiftId = shiftId ? shiftId : '' // console.log('data: ', data) - console.log({ formdata: data, formdatadta: data.data }) + console.log({ + pushedData: data, + datadata: data.data, + isNewShift: isNewShift, + shiftId: shiftId, + }) + if (isNewShift || !shiftId) { - result = await useAddNewScheduledShiftMutation(data) + result = await addNewScheduledShift(data) } else { - result = await useUpdateScheduledShiftMutation(data) + result = await updateScheduledShift(data) } if (result) { console.log('success with shift: ', result) @@ -235,7 +252,7 @@ const QuickShiftForm = ({ //Using this instead of setFieldValue in formik because of issues with the fields //Will use the specific date that a quick shift must be in. - const [userOptions, setUserOptions] = useState(['', 'a', 'b', 'c', 'd']) + const [userOptions, setUserOptions] = useState([{ label: '', id: '' }]) type labeledUser = { label: string id: String @@ -258,6 +275,7 @@ const QuickShiftForm = ({ tempOptions.push(userWithLabel) } }) + emptyShift.assignedUser = tempOptions[0] setUserOptions(tempOptions) setTargetUser(tempOptions[0]) } @@ -297,8 +315,6 @@ const QuickShiftForm = ({ : emptyShift.verificationBuffer, assignedUser: shift ? shift.assignedUser : emptyShift.assignedUser, assignedDay: shift ? shift.assignedDay : emptyShift.assignedDay, - member: { label: '', id: '' }, - memberId: '', }} onSubmit={onSubmit} > @@ -308,7 +324,12 @@ const QuickShiftForm = ({ - setDate(e)} /> + + setFieldValue('assignedDay', newValue) + } + /> { - setFieldValue('member', newValue) + console.log({ newValue: newValue }) + setFieldValue('assignedUser', newValue) }} /> ) : null} diff --git a/src/sprintFiles/QuickShift/scheduledShiftApiSlice.ts b/src/sprintFiles/QuickShift/scheduledShiftApiSlice.ts index 54f4a5d..7095a9e 100644 --- a/src/sprintFiles/QuickShift/scheduledShiftApiSlice.ts +++ b/src/sprintFiles/QuickShift/scheduledShiftApiSlice.ts @@ -31,7 +31,6 @@ export const scheduledShiftsApiSlice = apiSlice.injectEndpoints({ date: dayjs(entity.date), assignedUser: entity.assignedUser, status: entity.status, - options: entity.options, verifiedBy: dayjs(entity.verifiedBy), verifiedAt: dayjs(entity.verifiedAt), unverifiedAt: dayjs(entity.unverifiedAt), @@ -57,6 +56,7 @@ export const scheduledShiftsApiSlice = apiSlice.injectEndpoints({ }), addNewScheduledShift: builder.mutation({ query: (data) => { + console.log({ apiData: data }) console.log({ data: data, datadata: data.data }) return { @@ -70,13 +70,26 @@ export const scheduledShiftsApiSlice = apiSlice.injectEndpoints({ invalidatesTags: [{ type: 'ScheduledShift', id: 'LIST' }], }), updateScheduledShift: builder.mutation({ - query: (data) => ({ - url: `houses/${data.houseId}/scheduledShifts/${data.shiftId}`, - method: 'PATCH', - body: { - ...data.data, - }, - }), + // query: (data) => ({ + // url: `houses/${data.houseId}/scheduledShifts/${data.shiftId}`, + // method: 'PATCH', + // body: { + // ...data.data, + // }, + // }), + query: (data) => { + console.log({ apiDataUpdate: data }) + console.log({ data: data, datadata: data.data }) + + return { + url: `houses/${data.houseId}/scheduledShifts/${data.shiftId}`, + method: 'PATCH', + body: { + ...data.data, + }, + } + }, + invalidatesTags: (result, error, arg) => [ { type: 'ScheduledShift', id: arg.id }, ], diff --git a/src/types/schema.ts b/src/types/schema.ts index b3056a1..a25ab9a 100644 --- a/src/types/schema.ts +++ b/src/types/schema.ts @@ -90,7 +90,6 @@ export type ScheduledShift = { date: dayjs.Dayjs assignedUser: string status: string - options: string verifiedBy: dayjs.Dayjs verifiedAt: dayjs.Dayjs unverifiedAt: dayjs.Dayjs From 0891f6e554fc7fe8697d5f6bdaa89ba981f7528d Mon Sep 17 00:00:00 2001 From: Andrei Tan Date: Sun, 30 Apr 2023 14:00:32 -0700 Subject: [PATCH 8/8] typing fixed --- src/sprintFiles/QuickShift/QuickShiftForm.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sprintFiles/QuickShift/QuickShiftForm.tsx b/src/sprintFiles/QuickShift/QuickShiftForm.tsx index 3d596c6..2aa1dfa 100644 --- a/src/sprintFiles/QuickShift/QuickShiftForm.tsx +++ b/src/sprintFiles/QuickShift/QuickShiftForm.tsx @@ -255,19 +255,19 @@ const QuickShiftForm = ({ const [userOptions, setUserOptions] = useState([{ label: '', id: '' }]) type labeledUser = { label: string - id: String + id: string } const [targetUser, setTargetUser] = useState(userOptions[0]) useEffect(() => { // console.log({ ents: users?.entities, ids: users?.ids, targuser: targetUser, userOpt: Val: inputValue}) { - const tempOptions = [] + const tempOptions: labeledUser[] = [] if (users == undefined) return users.ids?.map((id: EntityId) => { let user = users?.entities[id] if (user != undefined) { - let userWithLabel = { + let userWithLabel: labeledUser = { label: user.displayName, id: user.id, } //TODO: add an ID here as well.