feat: add policy update notice and handling

- Introduced a new policy update modal to inform users of changes to the Privacy Policy and Terms of Service.
- Implemented a service to manage the state of policy updates, including versioning and acknowledgment tracking.
- Added a prompt component that surfaces the policy update modal based on user profile and acknowledgment status.
- Updated Privacy Policy and Terms of Service documents with new effective dates and content.
- Enhanced developer settings to allow manual triggering of the policy update notice for testing purposes.
This commit is contained in:
Mo Tarbin
2026-08-13 22:31:21 -04:00
parent 97a7b12d87
commit e2b41c85f6
9 changed files with 625 additions and 289 deletions

View File

@@ -0,0 +1,81 @@
import { ChevronRight, Gavel, PrivacyTip } from '@mui/icons-material'
import { Button, Stack } from '@mui/joy'
import { useTranslation } from 'react-i18next'
import { useNavigate } from 'react-router-dom'
import ModalActions from '../../components/common/ModalActions.jsx'
import { useResponsiveModal } from '../../hooks/useResponsiveModal.js'
/**
* One-time notice that the Privacy Policy and Terms changed. The frame is
* generic and always points at the documents, so a future revision only needs
* POLICY_VERSION bumped.
*/
const PolicyUpdateModal = ({ onAcknowledge, onClose, open }) => {
const { t } = useTranslation()
const { ResponsiveModal } = useResponsiveModal()
const navigate = useNavigate()
const handleClose = () => {
onAcknowledge?.()
onClose()
}
const openDocument = path => {
handleClose()
navigate(path)
}
const documentButtonSx = {
justifyContent: 'flex-start',
fontWeight: 500,
'--Button-gap': '12px',
'& .MuiButton-endDecorator': { ml: 'auto' },
}
return (
<ResponsiveModal
open={open}
onClose={handleClose}
size='sm'
title={t('policyUpdate.title')}
description={t('policyUpdate.subtitle')}
footer={
<ModalActions
primary={{
label: t('policyUpdate.acknowledge'),
onClick: handleClose,
sx: { width: { xs: '100%', sm: 'auto' } },
}}
/>
}
>
<Stack spacing={1}>
<Button
variant='outlined'
color='neutral'
fullWidth
startDecorator={<PrivacyTip />}
endDecorator={<ChevronRight />}
onClick={() => openDocument('/privacy')}
sx={documentButtonSx}
>
{t('policyUpdate.readPrivacy')}
</Button>
<Button
variant='outlined'
color='neutral'
fullWidth
startDecorator={<Gavel />}
endDecorator={<ChevronRight />}
onClick={() => openDocument('/terms')}
sx={documentButtonSx}
>
{t('policyUpdate.readTerms')}
</Button>
</Stack>
</ResponsiveModal>
)
}
export default PolicyUpdateModal