From 76a36ed35f7fbba5808f8eaf2bc93306cc25123f Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Fri, 5 Mar 2021 04:03:56 +1100 Subject: [PATCH] Time zone support --- crabfit-backend/routes/createEvent.js | 12 +- crabfit-backend/routes/stats.js | 7 +- crabfit-backend/swagger.yaml | 12 +- crabfit-frontend/public/favicon.ico | Bin 38319 -> 32793 bytes crabfit-frontend/public/logo192.png | Bin 5075 -> 4610 bytes crabfit-frontend/public/logo512.png | Bin 14698 -> 13461 bytes .../AvailabilityEditor/AvailabilityEditor.tsx | 94 +++++---- .../availabilityEditorStyle.ts | 15 +- .../AvailabilityViewer/AvailabilityViewer.tsx | 75 ++++--- .../availabilityViewerStyle.ts | 41 ++-- .../CalendarField/calendarFieldStyle.ts | 1 - .../TimeRangeField/TimeRangeField.tsx | 5 +- .../TimeRangeField/timeRangeFieldStyle.ts | 1 + crabfit-frontend/src/pages/Event/Event.tsx | 190 ++++++++++++------ .../src/pages/Event/eventStyle.ts | 4 +- crabfit-frontend/src/pages/Home/Home.tsx | 47 ++++- 16 files changed, 315 insertions(+), 189 deletions(-) diff --git a/crabfit-backend/routes/createEvent.js b/crabfit-backend/routes/createEvent.js index 72de815..ef821ff 100644 --- a/crabfit-backend/routes/createEvent.js +++ b/crabfit-backend/routes/createEvent.js @@ -3,7 +3,7 @@ const dayjs = require('dayjs'); const adjectives = require('../res/adjectives.json'); const crabs = require('../res/crabs.json'); -String.prototype.capitalize = () => this.charAt(0).toUpperCase() + this.slice(1); +const capitalize = (string) => string.charAt(0).toUpperCase() + string.slice(1); const generateId = (name) => { const id = name.trim().toLowerCase().replace(/[^A-Za-z0-9 ]/g, '').replace(/\s+/g, '-'); @@ -12,7 +12,7 @@ const generateId = (name) => { }; const generateName = () => { - return `${adjectives[Math.floor(Math.random() * adjectives.length)].capitalize()} ${crabs[Math.floor(Math.random() * crabs.length)]} Crab`; + return `${capitalize(adjectives[Math.floor(Math.random() * adjectives.length)])} ${crabs[Math.floor(Math.random() * crabs.length)]} Crab`; }; module.exports = async (req, res) => { @@ -28,9 +28,7 @@ module.exports = async (req, res) => { data: { name: name, created: currentTime, - startTime: event.startTime, - endTime: event.endTime, - dates: event.dates, + times: event.times, }, }; @@ -40,9 +38,7 @@ module.exports = async (req, res) => { id: eventId, name: name, created: currentTime, - startTime: event.startTime, - endTime: event.endTime, - dates: event.dates, + times: event.times, }); } catch (e) { console.error(e); diff --git a/crabfit-backend/routes/stats.js b/crabfit-backend/routes/stats.js index 25a7363..921adf6 100644 --- a/crabfit-backend/routes/stats.js +++ b/crabfit-backend/routes/stats.js @@ -5,10 +5,11 @@ module.exports = async (req, res) => { let personCount = null; try { - const query = req.datastore.createQuery(['__Stat_Kind__']); + const eventQuery = req.datastore.createQuery(['__Stat_Kind__']).filter('kind_name', 'Event'); + const personQuery = req.datastore.createQuery(['__Stat_Kind__']).filter('kind_name', 'Person'); - eventCount = (await req.datastore.runQuery(query.filter('kind_name', 'Event')))[0][0].count; - personCount = (await req.datastore.runQuery(query.filter('kind_name', 'Person')))[0][0].count; + eventCount = (await req.datastore.runQuery(eventQuery))[0][0].count; + personCount = (await req.datastore.runQuery(personQuery))[0][0].count; } catch (e) { console.error(e); } diff --git a/crabfit-backend/swagger.yaml b/crabfit-backend/swagger.yaml index 1794145..5dee8c1 100644 --- a/crabfit-backend/swagger.yaml +++ b/crabfit-backend/swagger.yaml @@ -18,11 +18,7 @@ definitions: type: "string" created: type: "integer" - startTime: - type: "string" - endTime: - type: "string" - dates: + times: type: "array" items: type: "string" @@ -82,11 +78,7 @@ paths: properties: name: type: "string" - startTime: - type: "integer" - endTime: - type: "integer" - dates: + times: type: "array" items: type: "string" diff --git a/crabfit-frontend/public/favicon.ico b/crabfit-frontend/public/favicon.ico index 093c5b09d602a541cca4cc1d3a08f14e2eea2565..bf79c38bc671d17cfd15d89a63ac7c4a98f6add9 100644 GIT binary patch literal 32793 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 F`+v)8l(ql> literal 38319 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�rbTUjO9zIGl6UtpbwY=8h{vp--l6c;U2=f7WdawIino+0>(TK zppM0yFgMH*bHzBYPY}2d;5f_?=M48P-jy-{j^hFHfM5BV4@DSjc3drpysX)^&(*WIi%{wf*ikJKwX?8TvM8#Z5t>t zZ>lb}MBm#0%6FHP?@+5I(WC0)`eVKqfo1@6q4rTr%o%e>-2cY^YoI-E>81#X;U{07D=1ARtWB1_LIYiscz-(YEfOCcOHs0p= zdOq|~?{8bE4@{wp^R5h_{aHXGK(&MW6MbPH?xReA+BdPh0DZVmP}ltzdN}S0faeBt z!JKf+#GG+0u#fd8=pR8Jcz2}hjtl()L-b~eZv8u?sj0}naTng`o(@v zfNFnYiED}Zpq?gx&)bPQ)Ha?=%nfs)=0(jD<(NCpPd0$-IFUS%JqM`vCYHD_>;Q~K z82FWL67=KQMV~RiL|eEYBmuOw8W;p7>R=o1HY))2P`?S7Ob=yvj_v>x^TIafjJbaX zrW*e{Iqvo40LC&4z-QZ3W5Ryw;Xb)JiQYSq;X4!BG6cQ>Q`vI*smBjx)i3m>8c&sD z?!Q_ys@_y3u7xFlG0y;6fvI#)|J1|xiL^=d-hxcwr;Z7fQ{C-&ZXAE=2}1b{n9Aqx z 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 GbN&NxGiHzg diff --git a/crabfit-frontend/public/logo192.png b/crabfit-frontend/public/logo192.png index c011b9bea1640f263a9269b3e0526afebe2cd48d..70f0a2cb593cea7c7963e8224a324c929ef9df23 100644 GIT binary patch literal 4610 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 diff --git a/crabfit-frontend/public/logo512.png b/crabfit-frontend/public/logo512.png index 5fba454b6f97aab7d443880b30d62b9d39bd302c..82acb670d80f35095e6391af248faae1674c5863 100644 GIT binary patch literal 13461 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 literal 14698 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%0Dhqz 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 diff --git a/crabfit-frontend/src/components/AvailabilityEditor/AvailabilityEditor.tsx b/crabfit-frontend/src/components/AvailabilityEditor/AvailabilityEditor.tsx index 6e38ebd..621f1e0 100644 --- a/crabfit-frontend/src/components/AvailabilityEditor/AvailabilityEditor.tsx +++ b/crabfit-frontend/src/components/AvailabilityEditor/AvailabilityEditor.tsx @@ -7,6 +7,7 @@ import { Wrapper, Container, Date, + Times, DateLabel, DayLabel, Spacer, @@ -20,8 +21,9 @@ dayjs.extend(localeData); dayjs.extend(customParseFormat); const AvailabilityEditor = ({ - dates, times, + timeLabels, + dates, value = [], onChange, ...props @@ -45,9 +47,9 @@ const AvailabilityEditor = ({ - {!!times.length && times.concat([`${parseInt(times[times.length-1].slice(0, 2))+1}00`]).map((time, i) => - - {time.slice(-2) === '00' && {dayjs().hour(time.slice(0, 2)).minute(time.slice(-2)).format('h A')}} + {!!timeLabels.length && timeLabels.map((label, i) => + + {label.label?.length !== '' && {label.label}} )} @@ -56,47 +58,59 @@ const AvailabilityEditor = ({ const last = dates.length === x+1 || dayjs(dates[x+1], 'DDMMYYYY').diff(parsedDate, 'day') > 1; return ( - + {parsedDate.format('MMM D')} {parsedDate.format('ddd')} - {times.map((time, y) => - {last && dates.length !== x+1 && ( diff --git a/crabfit-frontend/src/components/AvailabilityEditor/availabilityEditorStyle.ts b/crabfit-frontend/src/components/AvailabilityEditor/availabilityEditorStyle.ts index 0046eb1..6e43d71 100644 --- a/crabfit-frontend/src/components/AvailabilityEditor/availabilityEditorStyle.ts +++ b/crabfit-frontend/src/components/AvailabilityEditor/availabilityEditorStyle.ts @@ -2,20 +2,23 @@ import styled from '@emotion/styled'; export const Time = styled.div` height: 10px; - border-left: 1px solid ${props => props.theme.primaryDark}; + margin: 1px; + background-color: ${props => props.theme.background}; touch-action: none; - ${props => props.time.slice(-2) === '00' && ` - border-top: 1px solid ${props.theme.primaryDark}; + ${props => props.time.slice(2, 4) !== '00' && ` + margin-top: -1px; + border-top: 2px solid transparent; `} - ${props => props.time.slice(-2) === '30' && ` - border-top: 1px dotted ${props.theme.primaryDark}; + ${props => props.time.slice(2, 4) === '30' && ` + margin-top: -1px; + border-top: 2px dotted ${props.theme.text}; `} ${props => (props.selected || (props.mode === 'add' && props.selecting)) && ` background-color: ${props.theme.primary}; `}; ${props => props.mode === 'remove' && props.selecting && ` - background-color: initial; + background-color: ${props.theme.background}; `}; `; diff --git a/crabfit-frontend/src/components/AvailabilityViewer/AvailabilityViewer.tsx b/crabfit-frontend/src/components/AvailabilityViewer/AvailabilityViewer.tsx index 2e4904f..1a3e77e 100644 --- a/crabfit-frontend/src/components/AvailabilityViewer/AvailabilityViewer.tsx +++ b/crabfit-frontend/src/components/AvailabilityViewer/AvailabilityViewer.tsx @@ -7,6 +7,7 @@ import { Wrapper, Container, Date, + Times, DateLabel, DayLabel, Time, @@ -24,8 +25,9 @@ dayjs.extend(localeData); dayjs.extend(customParseFormat); const AvailabilityViewer = ({ - dates, times, + timeLabels, + dates, people = [], min = 0, max = 0, @@ -37,9 +39,9 @@ const AvailabilityViewer = ({ - {!!times.length && times.concat([`${parseInt(times[times.length-1].slice(0, 2))+1}00`]).map((time, i) => - - {time.slice(-2) === '00' && {dayjs().hour(time.slice(0, 2)).minute(time.slice(-2)).format('h A')}} + {!!timeLabels.length && timeLabels.map((label, i) => + + {label.label?.length !== '' && {label.label}} )} @@ -48,38 +50,47 @@ const AvailabilityViewer = ({ const last = dates.length === i+1 || dayjs(dates[i+1], 'DDMMYYYY').diff(parsedDate, 'day') > 1; return ( - + {parsedDate.format('MMM D')} {parsedDate.format('ddd')} - {times.map((time, i) => { - const peopleHere = people.filter(person => person.availability.includes(`${time}-${date}`)).map(person => person.name); + + {timeLabels.map((timeLabel, i) => { + if (!timeLabel.time) return null; + if (!times.includes(`${timeLabel.time}-${date}`)) { + return ( + + ); + } + const time = `${timeLabel.time}-${date}`; + const peopleHere = people.filter(person => person.availability.includes(time)).map(person => person.name); - return ( - {last && dates.length !== i+1 && ( diff --git a/crabfit-frontend/src/components/AvailabilityViewer/availabilityViewerStyle.ts b/crabfit-frontend/src/components/AvailabilityViewer/availabilityViewerStyle.ts index 907ddac..4023a30 100644 --- a/crabfit-frontend/src/components/AvailabilityViewer/availabilityViewerStyle.ts +++ b/crabfit-frontend/src/components/AvailabilityViewer/availabilityViewerStyle.ts @@ -10,6 +10,7 @@ export const Container = styled.div` box-sizing: border-box; min-width: 100%; align-items: flex-end; + justify-content: center; padding: 0 calc(calc(100% - 600px) / 2); @media (max-width: 660px) { @@ -24,13 +25,12 @@ export const Date = styled.div` width: 60px; min-width: 60px; margin-bottom: 10px; +`; - & .time:last-of-type { - border-bottom: 1px solid ${props => props.theme.primaryDark}; - } - &.last > .time { - border-right: 1px solid ${props => props.theme.primaryDark}; - } +export const Times = styled.div` + display: flex; + flex-direction: column; + background-color: ${props => props.theme.text}; `; export const DateLabel = styled.label` @@ -49,18 +49,22 @@ export const DayLabel = styled.label` export const Time = styled.div` height: 10px; - border-left: 1px solid ${props => props.theme.primaryDark}; + margin: 1px; + background-color: ${props => props.theme.background}; - ${props => props.time.slice(-2) === '00' && ` - border-top: 1px solid ${props.theme.primaryDark}; + ${props => props.time.slice(2, 4) !== '00' && ` + margin-top: -1px; + border-top: 2px solid transparent; `} - ${props => props.time.slice(-2) === '30' && ` - border-top: 1px dotted ${props.theme.primaryDark}; + ${props => props.time.slice(2, 4) === '30' && ` + margin-top: -1px; + border-top: 2px dotted ${props.theme.text}; `} - background-color: ${props => `${props.theme.primary}${Math.round(((props.peopleCount-props.minPeople)/(props.maxPeople-props.minPeople))*255).toString(16)}`}; - count: ${props => props.peopleCount}; - max: ${props => props.maxPeople}; + background-image: linear-gradient( + ${props => `${props.theme.primary}${Math.round(((props.peopleCount-props.minPeople)/(props.maxPeople-props.minPeople))*255).toString(16)}`}, + ${props => `${props.theme.primary}${Math.round(((props.peopleCount-props.minPeople)/(props.maxPeople-props.minPeople))*255).toString(16)}`} + ); `; export const Spacer = styled.div` @@ -110,13 +114,8 @@ export const TimeLabels = styled.div` export const TimeSpace = styled.div` height: 10px; position: relative; - - ${props => props.time.slice(-2) === '00' && ` - border-top: 1px solid transparent; - `} - ${props => props.time.slice(-2) === '30' && ` - border-top: 1px dotted transparent; - `} + border-top: 2px solid transparent; + background: ${props => props.theme.background}; `; export const TimeLabel = styled.label` diff --git a/crabfit-frontend/src/components/CalendarField/calendarFieldStyle.ts b/crabfit-frontend/src/components/CalendarField/calendarFieldStyle.ts index 1789310..e415def 100644 --- a/crabfit-frontend/src/components/CalendarField/calendarFieldStyle.ts +++ b/crabfit-frontend/src/components/CalendarField/calendarFieldStyle.ts @@ -82,7 +82,6 @@ export const Date = styled.div` ${props => props.isToday && ` font-weight: 900; color: ${props.theme.primaryDark}; - text-decoration: underline; `} ${props => (props.selected || (props.mode === 'add' && props.selecting)) && ` color: ${props.otherMonth ? 'rgba(255,255,255,.5)' : '#FFF'}; diff --git a/crabfit-frontend/src/components/TimeRangeField/TimeRangeField.tsx b/crabfit-frontend/src/components/TimeRangeField/TimeRangeField.tsx index fb5fce3..d044b4d 100644 --- a/crabfit-frontend/src/components/TimeRangeField/TimeRangeField.tsx +++ b/crabfit-frontend/src/components/TimeRangeField/TimeRangeField.tsx @@ -81,12 +81,13 @@ const TimeRangeField = ({ id={id} type="hidden" ref={register} - value={JSON.stringify(start > end ? {start: end, end: start} : {start, end})} + value={JSON.stringify({start, end})} {...props} /> - end ? end : start} end={start > end ? start : end} /> + end ? 24 : end} /> + {start > end && end ? 0 : start} end={end} />} props.end * 4.1666666666666666}%); top: 0; background-color: ${props => props.theme.primary}; + border-radius: 2px; `; diff --git a/crabfit-frontend/src/pages/Event/Event.tsx b/crabfit-frontend/src/pages/Event/Event.tsx index 45242a6..f82317d 100644 --- a/crabfit-frontend/src/pages/Event/Event.tsx +++ b/crabfit-frontend/src/pages/Event/Event.tsx @@ -1,6 +1,11 @@ import { Link } from 'react-router-dom'; import { useForm } from 'react-hook-form'; -import { useState, useEffect, useCallback } from 'react'; +import { useState, useEffect } from 'react'; + +import dayjs from 'dayjs'; +import utc from 'dayjs/plugin/utc'; +import timezone from 'dayjs/plugin/timezone'; +import customParseFormat from 'dayjs/plugin/customParseFormat'; import { Center, @@ -33,6 +38,10 @@ import api from 'services'; import logo from 'res/logo.svg'; import timezones from 'res/timezones.json'; +dayjs.extend(utc); +dayjs.extend(timezone); +dayjs.extend(customParseFormat); + const Event = (props) => { const { register, handleSubmit } = useForm(); const { id } = props.match.params; @@ -46,37 +55,19 @@ const Event = (props) => { const [event, setEvent] = useState(null); const [people, setPeople] = useState([]); + const [times, setTimes] = useState([]); + const [timeLabels, setTimeLabels] = useState([]); + const [dates, setDates] = useState([]); const [min, setMin] = useState(0); const [max, setMax] = useState(0); - const fetchPeople = useCallback(async () => { - try { - const response = await api.get(`/event/${id}/people`); - setPeople(response.data.people); - } catch (e) { - console.error(e); - } - }, [id]); - useEffect(() => { const fetchEvent = async () => { try { const response = await api.get(`/event/${id}`); - let times = []; - for (let i = response.data.startTime; i < response.data.endTime; i++) { - let hour = `${i}`.padStart(2, '0'); - times.push( - `${hour}00`, - `${hour}15`, - `${hour}30`, - `${hour}45`, - ); - } - setEvent({ - ...response.data, - times, - }); + setEvent(response.data); + document.title = `${response.data.name} | Crab Fit`; setIsLoading(false); } catch (e) { console.error(e); @@ -85,28 +76,49 @@ const Event = (props) => { }; fetchEvent(); - fetchPeople(); - }, [fetchPeople, id]); + }, [id]); useEffect(() => { + const fetchPeople = async () => { + try { + const response = await api.get(`/event/${id}/people`); + const adjustedPeople = response.data.people.map(person => ({ + ...person, + availability: person.availability.map(date => dayjs(date, 'HHmm-DDMMYYYY').utc(true).tz(timezone).format('HHmm-DDMMYYYY')), + })); + setPeople(adjustedPeople); + } catch (e) { + console.error(e); + } + } + if (tab === 'group') { fetchPeople(); } - }, [fetchPeople, tab]); + }, [tab, id, timezone]); + + // Convert to timezone and expand minute segments + useEffect(() => { + if (event) { + setTimes(event.times.reduce( + (allTimes, time) => { + const date = dayjs(time, 'HHmm-DDMMYYYY').utc(true).tz(timezone); + return [ + ...allTimes, + date.minute(0).format('HHmm-DDMMYYYY'), + date.minute(15).format('HHmm-DDMMYYYY'), + date.minute(30).format('HHmm-DDMMYYYY'), + date.minute(45).format('HHmm-DDMMYYYY'), + ]; + }, + [] + ).sort((a, b) => dayjs(a, 'HHmm-DDMMYYYY').diff(dayjs(b, 'HHmm-DDMMYYYY')))); + } + }, [event, timezone]); useEffect(() => { - if (event && !!people.length) { - const datetimes = event.dates.reduce( - (dates, date) => { - let times = []; - event.times.forEach(time => { - times.push(`${time}-${date}`); - }); - return [...dates, ...times]; - } - , [] - ); - setMin(datetimes.reduce((min, time) => { + if (!!times.length && !!people.length) { + setMin(times.reduce((min, time) => { let total = people.reduce( (total, person) => person.availability.includes(time) ? total+1 : total, 0 @@ -115,7 +127,7 @@ const Event = (props) => { }, Infinity )); - setMax(datetimes.reduce((max, time) => { + setMax(times.reduce((max, time) => { let total = people.reduce( (total, person) => person.availability.includes(time) ? total+1 : total, 0 @@ -125,7 +137,63 @@ const Event = (props) => { -Infinity )); } - }, [event, people]); + }, [times, people]); + + useEffect(() => { + if (!!times.length) { + setTimeLabels(times.reduce((labels, datetime) => { + const time = datetime.substring(0, 4); + if (labels.includes(time)) return labels; + return [...labels, time]; + }, []) + .sort((a, b) => parseInt(a) - parseInt(b)) + .reduce((labels, time, i, allTimes) => { + if (time.substring(2) === '30') return [...labels, { label: '', time }]; + if (allTimes.length - 1 === i) return [ + ...labels, + { label: '', time }, + { label: dayjs(time, 'HHmm').add(1, 'hour').format('h A'), time: null } + ]; + if (allTimes.length - 1 > i && parseInt(allTimes[i+1].substring(0, 2))-1 > parseInt(time.substring(0, 2))) return [ + ...labels, + { label: '', time }, + { label: dayjs(time, 'HHmm').add(1, 'hour').format('h A'), time: 'space' }, + { label: '', time: 'space' }, + { label: '', time: 'space' }, + ]; + if (time.substring(2) !== '00') return [...labels, { label: '', time }]; + return [...labels, { label: dayjs(time, 'HHmm').format('h A'), time }]; + }, [])); + + setDates(times.reduce((allDates, time) => { + if (time.substring(2, 4) !== '00') return allDates; + const date = time.substring(5); + if (allDates.includes(date)) return allDates; + return [...allDates, date]; + }, [])); + } + }, [times]); + + useEffect(() => { + const fetchUser = async () => { + try { + const response = await api.post(`/event/${id}/people/${user.name}`, { person: { password } }); + const adjustedUser = { + ...response.data, + availability: response.data.availability.map(date => dayjs(date, 'HHmm-DDMMYYYY').utc(true).tz(timezone).format('HHmm-DDMMYYYY')), + }; + setUser(adjustedUser); + } catch (e) { + console.log(e); + } + }; + + if (user) { + console.log('FETCHING', timezone); + fetchUser(); + } + // eslint-disable-next-line + }, [timezone]); const onSubmit = async data => { setIsLoginLoading(true); @@ -137,7 +205,11 @@ const Event = (props) => { }, }); setPassword(data.password); - setUser(response.data); + const adjustedUser = { + ...response.data, + availability: response.data.availability.map(date => dayjs(date, 'HHmm-DDMMYYYY').utc(true).tz(timezone).format('HHmm-DDMMYYYY')), + }; + setUser(adjustedUser); setTab('you'); } catch (e) { if (e.status === 401) { @@ -178,10 +250,10 @@ const Event = (props) => { {event?.name} - {!!event?.name && `https://crab.fit/${id}`} + https://crab.fit/{id} {!!event?.name && - <>Copy the link to this page, or share via Email. + <>Copy the link to this page, or share via email. } @@ -230,7 +302,7 @@ const Event = (props) => { id="timezone" inline value={timezone} - onChange={value => setTimezone(value)} + onChange={event => setTimezone(event.currentTarget.value)} options={timezones} /> @@ -272,8 +344,9 @@ const Event = (props) => {
Hover or tap the calendar below to see who is available
p.availability.length > 0)} min={min} max={max} @@ -285,20 +358,23 @@ const Event = (props) => {
Click and drag the calendar below to set your availabilities
{ const oldAvailability = [...user.availability]; + const utcAvailability = availability.map(date => dayjs.tz(date, 'HHmm-DDMMYYYY', timezone).utc().format('HHmm-DDMMYYYY')); setUser({ ...user, availability }); - const response = await api.patch(`/event/${id}/people/${user.name}`, { - person: { - password, - availability, - }, - }); - if (response.status !== 200) { - console.log(response); + try { + await api.patch(`/event/${id}/people/${user.name}`, { + person: { + password, + availability: utcAvailability, + }, + }); + } catch (e) { + console.log(e); setUser({ ...user, oldAvailability }); } }} diff --git a/crabfit-frontend/src/pages/Event/eventStyle.ts b/crabfit-frontend/src/pages/Event/eventStyle.ts index f082645..5cc8afd 100644 --- a/crabfit-frontend/src/pages/Event/eventStyle.ts +++ b/crabfit-frontend/src/pages/Event/eventStyle.ts @@ -40,7 +40,7 @@ export const EventName = styled.h1` content: ''; display: inline-block; height: 1em; - width: 300px; + width: 400px; max-width: 100%; background-color: ${props.theme.loading}; border-radius: 3px; @@ -83,7 +83,7 @@ export const ShareInfo = styled.p` content: ''; display: inline-block; height: 1em; - width: 500px; + width: 300px; max-width: 100%; background-color: ${props.theme.loading}; border-radius: 3px; diff --git a/crabfit-frontend/src/pages/Home/Home.tsx b/crabfit-frontend/src/pages/Home/Home.tsx index dd860d8..b160592 100644 --- a/crabfit-frontend/src/pages/Home/Home.tsx +++ b/crabfit-frontend/src/pages/Home/Home.tsx @@ -5,6 +5,7 @@ import { useForm } from 'react-hook-form'; import dayjs from 'dayjs'; import utc from 'dayjs/plugin/utc'; import timezone from 'dayjs/plugin/timezone'; +import customParseFormat from 'dayjs/plugin/customParseFormat'; import { TextField, @@ -40,6 +41,7 @@ import timezones from 'res/timezones.json'; dayjs.extend(utc); dayjs.extend(timezone); +dayjs.extend(customParseFormat); const Home = () => { const { register, handleSubmit } = useForm({ @@ -73,18 +75,49 @@ const Home = () => { setIsLoading(true); setError(null); try { - const times = JSON.parse(data.times); + const { start, end } = JSON.parse(data.times); const dates = JSON.parse(data.dates); - const start = dayjs().tz(data.timezone).hour(times.start); - const end = dayjs().tz(data.timezone).hour(times.end); + if (dates.length === 0) { + return setError(`You haven't selected any dates!`); + } + if (start === end) { + return setError(`The start and end times can't be the same`); + } + + let times = dates.reduce((times, date) => { + let day = []; + for (let i = start; i < (start > end ? 24 : end); i++) { + day.push( + dayjs.tz(date, 'DDMMYYYY', data.timezone) + .hour(i) + .minute(0) + .utc() + .format('HHmm-DDMMYYYY') + ); + } + if (start > end) { + for (let i = 0; i < end; i++) { + day.push( + dayjs.tz(date, 'DDMMYYYY', data.timezone) + .hour(i) + .minute(0) + .utc() + .format('HHmm-DDMMYYYY') + ); + } + } + return [...times, ...day]; + }, []); + + if (times.length === 0) { + return setError(`You don't have any time selected`); + } const response = await api.post('/event', { event: { name: data.name, - startTime: start.utc().hour(), - endTime: end.utc().hour(), - dates: dates, + times: times, }, }); push(`/${response.data.id}`); @@ -164,7 +197,7 @@ const Home = () => { Events created - {stats.peopleCount ?? '10+'} + {stats.personCount ?? '10+'} Availabilities entered