Migrate AvailabilityEditor

This commit is contained in:
Ben Grant 2023-05-29 01:06:57 +10:00
parent 1a6d34ac59
commit 5abba62c66
11 changed files with 277 additions and 219 deletions

View file

@ -1,23 +1,31 @@
'use client'
import { useMemo, useState } from 'react'
import { useEffect, useMemo, useState } from 'react'
import { Trans } from 'react-i18next/TransWithoutContext'
import AvailabilityEditor from '/src/components/AvailabilityEditor/AvailabilityEditor'
import AvailabilityViewer from '/src/components/AvailabilityViewer/AvailabilityViewer'
import Content from '/src/components/Content/Content'
import Login from '/src/components/Login/Login'
import Section from '/src/components/Section/Section'
import SelectField from '/src/components/SelectField/SelectField'
import { EventResponse, PersonResponse } from '/src/config/api'
import { EventResponse, getPeople, PersonResponse, updatePerson } from '/src/config/api'
import { useTranslation } from '/src/i18n/client'
import timezones from '/src/res/timezones.json'
import useRecentsStore from '/src/stores/recentsStore'
import { expandTimes, makeClass } from '/src/utils'
import styles from './page.module.scss'
const EventAvailabilities = ({ event, people }: { event: EventResponse, people: PersonResponse[] }) => {
interface EventAvailabilitiesProps {
event: EventResponse
people: PersonResponse[]
}
const EventAvailabilities = ({ event, ...data }: EventAvailabilitiesProps) => {
const { t, i18n } = useTranslation('event')
const [people, setPeople] = useState(data.people)
const expandedTimes = useMemo(() => expandTimes(event.times), [event.times])
const [user, setUser] = useState<PersonResponse>()
@ -26,12 +34,32 @@ const EventAvailabilities = ({ event, people }: { event: EventResponse, people:
const [tab, setTab] = useState<'group' | 'you'>('group')
const [timezone, setTimezone] = useState(Intl.DateTimeFormat().resolvedOptions().timeZone)
// Add this event to recents
const addRecent = useRecentsStore(state => state.addRecent)
useEffect(() => {
addRecent({
id: event.id,
name: event.name,
created_at: event.created_at,
})
}, [addRecent])
// Refetch availabilities
useEffect(() => {
if (tab === 'group') {
getPeople(event.id)
.then(setPeople)
.catch(console.warn)
}
}, [tab])
return <>
<Section id="login">
<Content>
<Login eventId={event.id} user={user} onChange={(u, p) => {
setUser(u)
setPassword(p)
setTab(u ? 'you' : 'group')
}} />
<SelectField
@ -107,10 +135,23 @@ const EventAvailabilities = ({ event, people }: { event: EventResponse, people:
</div>
</Content>
{tab === 'group' && <AvailabilityViewer
{tab === 'group' ? <AvailabilityViewer
times={expandedTimes}
people={people}
timezone={timezone}
/> : user && <AvailabilityEditor
times={expandedTimes}
timezone={timezone}
value={user.availability}
onChange={availability => {
const oldAvailability = [...user.availability]
setUser({ ...user, availability })
updatePerson(event.id, user.name, { availability }, password)
.catch(e => {
console.warn(e)
setUser({ ...user, availability: oldAvailability })
})
}}
/>}
</>
}

View file

@ -1,10 +1,22 @@
'use client'
import { useEffect } from 'react'
import Content from '/src/components/Content/Content'
import { useTranslation } from '/src/i18n/server'
import { useTranslation } from '/src/i18n/client'
import useRecentsStore from '/src/stores/recentsStore'
import styles from './page.module.scss'
const NotFound = async () => {
const { t } = await useTranslation('event')
const NotFound = () => {
const { t } = useTranslation('event')
// Remove this event from recents if it was in there
const removeRecent = useRecentsStore(state => state.removeRecent)
useEffect(() => {
// Note: Next.js doesn't expose path params to the 404 page
removeRecent(window.location.pathname.replace('/', ''))
}, [removeRecent])
return <Content>
<div style={{ marginBlock: 100 }}>

View file

@ -1,4 +1,5 @@
import { Trans } from 'react-i18next/TransWithoutContext'
import { Metadata } from 'next'
import { notFound } from 'next/navigation'
import { Temporal } from '@js-temporal/polyfill'
@ -11,7 +12,21 @@ import { makeClass, relativeTimeFormat } from '/src/utils'
import EventAvailabilities from './EventAvailabilities'
import styles from './page.module.scss'
const Page = async ({ params }: { params: { id: string } }) => {
interface PageProps {
params: { id: string }
}
export const generateMetadata = async ({ params }: PageProps): Promise<Metadata> => {
const event = await getEvent(params.id).catch(() => undefined)
const { t } = await useTranslation('event')
// TODO: More metadata
return {
title: event?.name ?? t('error.title'),
}
}
const Page = async ({ params }: PageProps) => {
const event = await getEvent(params.id).catch(() => undefined)
const people = await getPeople(params.id).catch(() => undefined)
if (!event || !people) notFound()