From c5e70885ee516bafff00d7539acbd6fc10ba3f40 Mon Sep 17 00:00:00 2001 From: Vincent Cai <72774400+vcai122@users.noreply.github.com> Date: Tue, 27 Feb 2024 11:22:55 -0500 Subject: [PATCH] Fix bugs (post update date, poll choice order, color) (#245) * fix bugs (post update date, poll choice order, color * fix for loop commit problem --- frontend/components/form/FormHeader.tsx | 49 ++++++++++++++--------- frontend/components/styles/DatePicker.tsx | 12 +++--- frontend/pages/polls/[...pollId].tsx | 1 - frontend/pages/posts/[...postId].tsx | 10 ++++- frontend/utils/utils.ts | 10 +++-- 5 files changed, 50 insertions(+), 32 deletions(-) diff --git a/frontend/components/form/FormHeader.tsx b/frontend/components/form/FormHeader.tsx index 479ae39e..24dd8db2 100644 --- a/frontend/components/form/FormHeader.tsx +++ b/frontend/components/form/FormHeader.tsx @@ -28,47 +28,54 @@ const FormHeader = ({ createMode, state, prevOptionIds }: iFormHeaderProps) => { const [, setSuccess] = useLocalStorage('success', null) const [error, setError] = useState(null) - const onSubmit = async () => { - if ( - !isPost(state) && - (state.options[0]?.choice === '' || state.options[1]?.choice === '') - ) { - setError('Polls must have at least 2 options') - return + const getBody = () => { + if (!isPost(state)) { + return state } - const form_data = new FormData() if (isPost(state)) { Object.entries(state).forEach(([key, value]) => { if (key === 'start_date' || key === 'expire_date') { - const val = value.toISOString() + const val = (value as Date)?.toISOString() form_data.append(key, val) } else if (key !== 'image') { - form_data.append(key, value.toString()) + form_data.append(key, value?.toString()) } else { form_data.append(key, value) } }) } + return form_data + } + + const onSubmit = async () => { + if ( + !isPost(state) && + (state.options[0]?.choice === '' || state.options[1]?.choice === '') + ) { + setError('Polls must have at least 2 options') + return + } const res = await doApiRequest(`/api/portal/${route}/`, { method: 'POST', - body: isPost(state) ? form_data : state, + body: getBody(), }) if (res.ok) { // post each poll option if creating a poll if (!isPost(state)) { const pollRes = await res.json() - state.options.map((option) => - doApiRequest('/api/portal/options/', { + for (const option of state.options) { + /* eslint-disable no-await-in-loop */ + await doApiRequest('/api/portal/options/', { method: 'POST', body: { poll: pollRes.id, choice: option.choice, }, }) - ) + } } // redirect to dashboard after submitting with success message @@ -104,15 +111,16 @@ const FormHeader = ({ createMode, state, prevOptionIds }: iFormHeaderProps) => { } const res = await doApiRequest(`/api/portal/${route}/${state.id}/`, { method: 'PATCH', - body: isPost(state) ? form_data : state, + body: getBody(), }) if (res.ok) { if (!isPost(state)) { - const currOptionIds = state.options.map((option) => { + for (const option of state.options) { + /* eslint-disable no-await-in-loop */ // post new poll option if (!prevOptionIds?.includes(option.id)) { - doApiRequest('/api/portal/options/', { + await doApiRequest('/api/portal/options/', { method: 'POST', body: { poll: state.id, @@ -121,7 +129,7 @@ const FormHeader = ({ createMode, state, prevOptionIds }: iFormHeaderProps) => { }) } else { // update existing poll option - doApiRequest(`/api/portal/options/${option.id}/`, { + await doApiRequest(`/api/portal/options/${option.id}/`, { method: 'PATCH', body: { poll: state.id, @@ -129,8 +137,9 @@ const FormHeader = ({ createMode, state, prevOptionIds }: iFormHeaderProps) => { }, }) } - return option.id - }) + } + + const currOptionIds = state.options.map((option) => option.id) prevOptionIds?.forEach((optionId) => { if (!currOptionIds.includes(optionId)) { diff --git a/frontend/components/styles/DatePicker.tsx b/frontend/components/styles/DatePicker.tsx index eaca35a0..3ff1bfc7 100644 --- a/frontend/components/styles/DatePicker.tsx +++ b/frontend/components/styles/DatePicker.tsx @@ -38,13 +38,13 @@ const DatePickerForm = ({ ? [moment(startDate), moment(expireDate)] : undefined } - onChange={(dates) => + onChange={(dates) => { dates && - updateState({ - start_date: dates[0]?.toDate(), - expire_date: dates[1]?.toDate(), - }) - } + updateState({ + start_date: dates[0]?.toDate(), + expire_date: dates[1]?.toDate(), + }) + }} style={{ fontFamily: 'inherit', padding: '0.5rem', diff --git a/frontend/pages/polls/[...pollId].tsx b/frontend/pages/polls/[...pollId].tsx index 81964239..84eb0076 100644 --- a/frontend/pages/polls/[...pollId].tsx +++ b/frontend/pages/polls/[...pollId].tsx @@ -25,7 +25,6 @@ const PollPage = ({ filters, }: iPollPageProps & { user: User }) => { const [state, setState] = useState(poll || initialPoll) - const updateState = useCallback((newState) => { setState((currentState) => ({ ...currentState, ...newState })) }, []) diff --git a/frontend/pages/posts/[...postId].tsx b/frontend/pages/posts/[...postId].tsx index e1f22a31..f841ad72 100644 --- a/frontend/pages/posts/[...postId].tsx +++ b/frontend/pages/posts/[...postId].tsx @@ -22,7 +22,15 @@ const PostPage = ({ post, filters, }: iPostPageProps & { user: User }) => { - const [state, setState] = useState(post || initialPost) + const [state, setState] = useState( + post + ? { + ...post, + start_date: new Date(post.start_date!), // deserialize date strings since they have to be sent as strings + expire_date: new Date(post.expire_date!), + } + : initialPost + ) const updateState = useCallback((newState) => { setState((currentState) => ({ ...currentState, ...newState })) diff --git a/frontend/utils/utils.ts b/frontend/utils/utils.ts index dbc25563..f7e0908e 100644 --- a/frontend/utils/utils.ts +++ b/frontend/utils/utils.ts @@ -29,10 +29,12 @@ export const setStatuses = (contentList: PostType[] | PollType[]) => { // returns a rgb string from a string input. used for generating colors for polls // based on string hash for consistent colors export const stringToRGB = (str: string) => { - const hash = Array.from(str).reduce((acc, char) => { - acc = (acc << 5) - acc + char.charCodeAt(0) - return acc & acc - }, 0) + const hash = Array.from(str) + .reverse() // good heuristic + .reduce((acc, char) => { + acc = (acc << 5) - acc + char.charCodeAt(0) + return acc & acc + }, 0) const rgb = Array.from({ length: 3 }, (_, i) => (hash >> (i * 8)) & 255) return `rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})` }