Show/hide toast logic
This commit is contained in:
parent
0d924a1226
commit
660ad41d4e
2 changed files with 91 additions and 11 deletions
|
|
@ -1,18 +1,55 @@
|
||||||
import type { ReactElement } from 'react'
|
import { PropsWithChildren, useEffect, useState } from 'react'
|
||||||
|
import { add, format } from 'date-fns'
|
||||||
|
import { getCookie } from 'cookies-next'
|
||||||
|
|
||||||
|
import { appState } from '~utils/appState'
|
||||||
|
|
||||||
import TopHeader from '~components/Header'
|
import TopHeader from '~components/Header'
|
||||||
import Toast from '~components/Toast'
|
|
||||||
import UpdateToast from '~components/UpdateToast'
|
import UpdateToast from '~components/UpdateToast'
|
||||||
|
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
interface Props {
|
|
||||||
children: ReactElement
|
|
||||||
}
|
|
||||||
|
|
||||||
const Layout = ({ children }: Props) => {
|
interface Props {}
|
||||||
|
|
||||||
|
const Layout = ({ children }: PropsWithChildren<Props>) => {
|
||||||
|
const [updateToastOpen, setUpdateToastOpen] = useState(false)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const cookie = getToastCookie()
|
||||||
|
const now = new Date()
|
||||||
|
const updatedAt = new Date(appState.version.updated_at)
|
||||||
|
const validUntil = add(updatedAt, { days: 7 })
|
||||||
|
|
||||||
|
if (now < validUntil && !cookie.seen) setUpdateToastOpen(true)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
function getToastCookie() {
|
||||||
|
const updatedAt = new Date(appState.version.updated_at)
|
||||||
|
const cookieValues = getCookie(`update-${format(updatedAt, 'yyyy-MM-dd')}`)
|
||||||
|
return cookieValues
|
||||||
|
? (JSON.parse(cookieValues as string) as { seen: true })
|
||||||
|
: { seen: false }
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleToastActionClicked() {
|
||||||
|
setUpdateToastOpen(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleToastOpenChanged(open: boolean) {
|
||||||
|
setUpdateToastOpen(false)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TopHeader />
|
<TopHeader />
|
||||||
<UpdateToast open={true} updateType="feature" />
|
{/* TODO: Don't show toast on about pages */}
|
||||||
|
<UpdateToast
|
||||||
|
open={updateToastOpen}
|
||||||
|
updateType="feature"
|
||||||
|
onActionClicked={handleToastActionClicked}
|
||||||
|
onOpenChange={handleToastOpenChanged}
|
||||||
|
lastUpdated={appState.version.updated_at}
|
||||||
|
/>
|
||||||
<main>{children}</main>
|
<main>{children}</main>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
import { setCookie } from 'cookies-next'
|
||||||
|
import { add, format } from 'date-fns'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
|
||||||
import Button from '~components/Button'
|
import Button from '~components/Button'
|
||||||
|
|
@ -10,24 +13,64 @@ import { useTranslation } from 'next-i18next'
|
||||||
interface Props {
|
interface Props {
|
||||||
open: boolean
|
open: boolean
|
||||||
updateType: 'feature' | 'content'
|
updateType: 'feature' | 'content'
|
||||||
|
lastUpdated: string
|
||||||
|
onActionClicked: () => void
|
||||||
|
onOpenChange: (open: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const UpdateToast = (props: Props) => {
|
const UpdateToast = ({
|
||||||
|
open,
|
||||||
|
updateType,
|
||||||
|
lastUpdated,
|
||||||
|
onActionClicked,
|
||||||
|
onOpenChange,
|
||||||
|
}: Props) => {
|
||||||
const { t } = useTranslation('roadmap')
|
const { t } = useTranslation('roadmap')
|
||||||
|
|
||||||
const classes = classNames({
|
const classes = classNames({
|
||||||
Update: true,
|
Update: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function setToastCookie() {
|
||||||
|
const updatedAt = new Date(lastUpdated)
|
||||||
|
const expiresAt = add(updatedAt, { days: 7 })
|
||||||
|
setCookie(
|
||||||
|
`update-${format(updatedAt, 'yyyy-MM-dd')}`,
|
||||||
|
{ seen: true },
|
||||||
|
{ path: '/', expires: expiresAt }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleButtonClicked() {
|
||||||
|
// TODO: Set a timestamped cookie to not show
|
||||||
|
console.log('Primary button clicked')
|
||||||
|
window.open('/about', '_blank')
|
||||||
|
setToastCookie()
|
||||||
|
onActionClicked()
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleOpenChanged(open: boolean) {
|
||||||
|
if (!open) {
|
||||||
|
setToastCookie()
|
||||||
|
onOpenChange(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Toast
|
<Toast
|
||||||
className={classes}
|
className={classes}
|
||||||
title={t(`toasts.title`)}
|
title={t(`toasts.title`)}
|
||||||
content={t(`toasts.description.${props.updateType}`)}
|
content={t(`toasts.description.${updateType}`)}
|
||||||
open={true}
|
open={open}
|
||||||
type="background"
|
type="background"
|
||||||
|
onOpenChange={handleOpenChanged}
|
||||||
>
|
>
|
||||||
<Button buttonSize="small" contained={true} text={t('toasts.button')} />
|
<Button
|
||||||
|
buttonSize="small"
|
||||||
|
contained={true}
|
||||||
|
onClick={handleButtonClicked}
|
||||||
|
text={t('toasts.button')}
|
||||||
|
/>
|
||||||
</Toast>
|
</Toast>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue