From 085dc389ca176ba6f1c8bf329a9e7a26f896ebef Mon Sep 17 00:00:00 2001 From: Ben Grant Date: Mon, 29 May 2023 01:21:40 +1000 Subject: [PATCH] Update packages --- frontend/package.json | 18 +- frontend/src/pages-old/Event/Event.jsx | 470 ------------------- frontend/src/pages-old/Event/Event.styles.js | 148 ------ frontend/yarn.lock | 278 ++++++----- 4 files changed, 174 insertions(+), 740 deletions(-) delete mode 100644 frontend/src/pages-old/Event/Event.jsx delete mode 100644 frontend/src/pages-old/Event/Event.styles.js diff --git a/frontend/package.json b/frontend/package.json index 5d9e442..03e8d54 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -21,23 +21,23 @@ "i18next-browser-languagedetector": "^7.0.1", "i18next-http-backend": "^2.2.1", "i18next-resources-to-backend": "^1.1.4", - "lucide-react": "^0.220.0", - "next": "^13.4.3", + "lucide-react": "^0.223.0", + "next": "^13.4.4", "react": "^18.2.0", "react-dom": "^18.2.0", - "react-hook-form": "^7.43.9", + "react-hook-form": "^7.44.1", "react-i18next": "^12.3.1", "zod": "^3.21.4", "zustand": "^4.3.8" }, "devDependencies": { - "@types/node": "^20.2.1", - "@types/react": "^18.2.6", + "@types/node": "^20.2.5", + "@types/react": "^18.2.7", "@types/react-dom": "^18.2.4", - "@typescript-eslint/eslint-plugin": "^5.59.6", - "@typescript-eslint/parser": "^5.59.6", - "eslint": "^8.40.0", - "eslint-config-next": "^13.4.3", + "@typescript-eslint/eslint-plugin": "^5.59.7", + "@typescript-eslint/parser": "^5.59.7", + "eslint": "^8.41.0", + "eslint-config-next": "^13.4.4", "eslint-plugin-simple-import-sort": "^10.0.0", "sass": "^1.62.1", "typescript": "^5.0.4", diff --git a/frontend/src/pages-old/Event/Event.jsx b/frontend/src/pages-old/Event/Event.jsx deleted file mode 100644 index 7e0f6ab..0000000 --- a/frontend/src/pages-old/Event/Event.jsx +++ /dev/null @@ -1,470 +0,0 @@ -import { useForm } from 'react-hook-form' -import { useState, useEffect } from 'react' -import { useTranslation, Trans } from 'react-i18next' -import { useParams } from 'react-router-dom' - -import dayjs from 'dayjs' -import utc from 'dayjs/plugin/utc' -import timezone from 'dayjs/plugin/timezone' -import customParseFormat from 'dayjs/plugin/customParseFormat' -import relativeTime from 'dayjs/plugin/relativeTime' - -import { - Footer, - TextField, - SelectField, - Button, - AvailabilityViewer, - AvailabilityEditor, - Error, - Logo, -} from '/src/components' - -import { StyledMain } from '../Home/Home.styles' - -import { - EventName, - EventDate, - LoginForm, - LoginSection, - Info, - ShareInfo, - Tabs, - Tab, -} from './Event.styles' - -import api from '/src/services' -import { useSettingsStore, useRecentsStore, useLocaleUpdateStore } from '/src/stores' - -import timezones from '/src/res/timezones.json' - -dayjs.extend(utc) -dayjs.extend(timezone) -dayjs.extend(customParseFormat) -dayjs.extend(relativeTime) - -const Event = () => { - const timeFormat = useSettingsStore(state => state.timeFormat) - const weekStart = useSettingsStore(state => state.weekStart) - - const addRecent = useRecentsStore(state => state.addRecent) - const removeRecent = useRecentsStore(state => state.removeRecent) - const locale = useLocaleUpdateStore(state => state.locale) - - const { t } = useTranslation(['common', 'event']) - - const { register, handleSubmit, setFocus, reset } = useForm() - const { id } = useParams() - const [timezone, setTimezone] = useState(Intl.DateTimeFormat().resolvedOptions().timeZone) - const [user, setUser] = useState(null) - const [password, setPassword] = useState(null) - const [tab, setTab] = useState(user ? 'you' : 'group') - const [isLoading, setIsLoading] = useState(true) - const [isLoginLoading, setIsLoginLoading] = useState(false) - const [error, setError] = useState(null) - 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 [copied, setCopied] = useState(null) - - useEffect(() => { - const fetchEvent = async () => { - try { - const event = await api.get(`/event/${id}`) - - setEvent(event) - addRecent({ - id: event.id, - created: event.created, - name: event.name, - }) - document.title = `${event.name} | Crab Fit` - } catch (e) { - console.error(e) - if (e.status === 404) { - removeRecent(id) - } - } finally { - setIsLoading(false) - } - } - - fetchEvent() - }, [id, addRecent, removeRecent]) - - useEffect(() => { - const fetchPeople = async () => { - try { - const { people } = await api.get(`/event/${id}/people`) - const adjustedPeople = people.map(person => ({ - ...person, - availability: (!!person.availability.length && person.availability[0].length === 13) - ? person.availability.map(date => dayjs(date, 'HHmm-DDMMYYYY').utc(true).tz(timezone).format('HHmm-DDMMYYYY')) - : person.availability.map(date => dayjs(date, 'HHmm').day(date.substring(5)).utc(true).tz(timezone).format('HHmm-d')), - })) - setPeople(adjustedPeople) - } catch (e) { - console.error(e) - } - } - - if (tab === 'group') { - fetchPeople() - } - }, [tab, id, timezone]) - - // Convert to timezone and expand minute segments - useEffect(() => { - if (event) { - const isSpecificDates = event.times[0].length === 13 - setTimes(event.times.reduce( - (allTimes, time) => { - const date = isSpecificDates ? - dayjs(time, 'HHmm-DDMMYYYY').utc(true).tz(timezone) - : dayjs(time, 'HHmm').day(time.substring(5)).utc(true).tz(timezone) - const format = isSpecificDates ? 'HHmm-DDMMYYYY' : 'HHmm-d' - return [ - ...allTimes, - date.minute(0).format(format), - date.minute(15).format(format), - date.minute(30).format(format), - date.minute(45).format(format), - ] - }, - [] - ).sort((a, b) => { - if (isSpecificDates) { - return dayjs(a, 'HHmm-DDMMYYYY').diff(dayjs(b, 'HHmm-DDMMYYYY')) - } else { - return dayjs(a, 'HHmm').day((parseInt(a.substring(5))-weekStart % 7 + 7) % 7) - .diff(dayjs(b, 'HHmm').day((parseInt(b.substring(5))-weekStart % 7 + 7) % 7)) - } - })) - } - }, [event, timezone, weekStart]) - - useEffect(() => { - if (!!times.length && !!people.length) { - setMin(times.reduce((min, time) => { - const total = people.reduce( - (total, person) => person.availability.includes(time) ? total+1 : total, - 0 - ) - return total < min ? total : min - }, Infinity)) - setMax(times.reduce((max, time) => { - const total = people.reduce( - (total, person) => person.availability.includes(time) ? total+1 : total, - 0 - ) - return total > max ? total : max - }, -Infinity)) - } - }, [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(timeFormat === '12h' ? 'h A' : 'HH'), 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(timeFormat === '12h' ? 'h A' : 'HH'), time: 'space' }, - { label: '', time: 'space' }, - { label: '', time: 'space' }, - ] - if (time.substring(2) !== '00') return [...labels, { label: '', time }] - return [...labels, { label: dayjs(time, 'HHmm').format(timeFormat === '12h' ? 'h A' : 'HH'), 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, timeFormat, locale]) - - useEffect(() => { - const fetchUser = async () => { - try { - const resUser = await api.post(`/event/${id}/people/${user.name}`, { person: { password } }) - const adjustedUser = { - ...resUser, - availability: (!!resUser.availability.length && resUser.availability[0].length === 13) - ? resUser.availability.map(date => dayjs(date, 'HHmm-DDMMYYYY').utc(true).tz(timezone).format('HHmm-DDMMYYYY')) - : resUser.availability.map(date => dayjs(date, 'HHmm').day(date.substring(5)).utc(true).tz(timezone).format('HHmm-d')), - } - setUser(adjustedUser) - } catch (e) { - console.log(e) - } - } - - if (user) { - fetchUser() - } - }, [timezone]) - - const onSubmit = async data => { - if (!data.name || data.name.length === 0) { - setFocus('name') - return setError(t('event:form.errors.name_required')) - } - - setIsLoginLoading(true) - setError(null) - - try { - const resUser = await api.post(`/event/${id}/people/${data.name}`, { - person: { - password: data.password, - }, - }) - setPassword(data.password) - const adjustedUser = { - ...resUser, - availability: (!!resUser.availability.length && resUser.availability[0].length === 13) - ? resUser.availability.map(date => dayjs(date, 'HHmm-DDMMYYYY').utc(true).tz(timezone).format('HHmm-DDMMYYYY')) - : resUser.availability.map(date => dayjs(date, 'HHmm').day(date.substring(5)).utc(true).tz(timezone).format('HHmm-d')), - } - setUser(adjustedUser) - setTab('you') - } catch (e) { - if (e.status === 401) { - setError(t('event:form.errors.password_incorrect')) - } else if (e.status === 404) { - // Create user - try { - await api.post(`/event/${id}/people`, { - person: { - name: data.name, - password: data.password, - }, - }) - setPassword(data.password) - setUser({ - name: data.name, - availability: [], - }) - setTab('you') - } catch (e) { - setError(t('event:form.errors.unknown')) - } - } - } finally { - setIsLoginLoading(false) - gtag('event', 'login', { - 'event_category': 'event', - }) - reset() - } - } - - return ( - <> - - - - {(!!event || isLoading) ? ( - <> - {event?.name} - {event?.created && t('common:created', { date: dayjs.unix(event?.created).fromNow() })} - navigator.clipboard?.writeText(`https://crab.fit/${id}`) - .then(() => { - setCopied(t('event:nav.copied')) - setTimeout(() => setCopied(null), 1000) - gtag('event', 'copy_link', { - 'event_category': 'event', - }) - }) - .catch(e => console.error('Failed to copy', e)) - } - title={navigator.clipboard ? t('event:nav.title') : ''} - >{copied ?? `https://crab.fit/${id}`} - - {!!event?.name && - Copy the link to this page, or share via gtag('event', 'send_email', { 'event_category': 'event' })} href={`mailto:?subject=${encodeURIComponent(t('event:nav.email_subject', { event_name: event?.name }))}&body=${encodeURIComponent(`${t('event:nav.email_body')} https://crab.fit/${id}`)}`}>email. - } - - - ) : ( -
- {t('event:error.title')} - {t('event:error.body')} -
- )} -
- - {(!!event || isLoading) && ( - <> - - - {user ? ( -
-

{t('event:form.signed_in', { name: user.name })}

- -
- ) : ( - <> -

{t('event:form.signed_out')}

- - - - - - - - setError(null)}>{error} - {t('event:form.info')} - - )} - - setTimezone(event.currentTarget.value)} - options={timezones} - /> - {/* eslint-disable-next-line */} - {event?.timezone && event.timezone !== timezone &&

This event was created in the timezone {{timezone: event.timezone}}. { - e.preventDefault() - setTimezone(event.timezone) - }}>Click here to use it.

} - {(( - Intl.DateTimeFormat().resolvedOptions().timeZone !== timezone - && (event?.timezone && event.timezone !== Intl.DateTimeFormat().resolvedOptions().timeZone) - ) || ( - event?.timezone === undefined - && Intl.DateTimeFormat().resolvedOptions().timeZone !== timezone - )) && ( - /* eslint-disable-next-line */ -

Your local timezone is detected to be {{timezone: Intl.DateTimeFormat().resolvedOptions().timeZone}}. { - e.preventDefault() - setTimezone(Intl.DateTimeFormat().resolvedOptions().timeZone) - }}>Click here to use it.

- )} -
-
- - - - { - e.preventDefault() - if (user) { - setTab('you') - } else { - setFocus('name') - } - }} - $selected={tab === 'you'} - disabled={!user} - title={user ? '' : t('event:tabs.you_tooltip')} - >{t('event:tabs.you')} - { - e.preventDefault() - setTab('group') - }} - $selected={tab === 'group'} - >{t('event:tabs.group')} - - - - {tab === 'group' ? ( -
- p.availability.length > 0)} - min={min} - max={max} - /> -
- ) : ( -
- { - const oldAvailability = [...user.availability] - const utcAvailability = (!!availability.length && availability[0].length === 13) - ? availability.map(date => dayjs.tz(date, 'HHmm-DDMMYYYY', timezone).utc().format('HHmm-DDMMYYYY')) - : availability.map(date => dayjs.tz(date, 'HHmm', timezone).day(date.substring(5)).utc().format('HHmm-d')) - setUser({ ...user, availability }) - try { - await api.patch(`/event/${id}/people/${user.name}`, { - person: { - password, - availability: utcAvailability, - }, - }) - } catch (e) { - console.log(e) - setUser({ ...user, oldAvailability }) - } - }} - /> -
- )} - - )} - -