Part of #145. Fourteen files whose user-facing strings are generic enough to belong in `common` — loading and empty states, the confirmation modal, the shared input modals (text/date/user/attachment viewer), the mobile nav bar, the autocomplete input, the error screen and the file-upload error paths. Extends the namespace that already exists, so `src/i18n/config.js` is untouched and this cannot collide with any other extraction PR over the `ns:` array. 28 keys added to `public/locales/en/common.json`. English only — no translations, no behaviour change. Every t() value is checked against this branch's base: the string must appear character-for-character in the code it replaces (36 call sites). One value is matched loosely and worth naming: `errorScreen.hideDetails`. The base renders `{showDetails ? 'Hide' : 'Show'} error details`, so neither full phrase exists contiguously in the source — only one branch of the ternary can. Both keys hold exactly what each branch renders. The sentence is kept whole rather than split around the ternary, because a split sentence cannot be reordered by a translator.
52 lines
1.4 KiB
JavaScript
52 lines
1.4 KiB
JavaScript
import { Avatar, Box, List, ListItem, Typography } from '@mui/joy'
|
|
import ModalActions from '../../../components/common/ModalActions'
|
|
import { useResponsiveModal } from '../../../hooks/useResponsiveModal'
|
|
import { useTranslation } from 'react-i18next'
|
|
|
|
const UserModal = ({ isOpen, performers = [], onSelect, onClose }) => {
|
|
const { t } = useTranslation('common')
|
|
const { ResponsiveModal } = useResponsiveModal()
|
|
|
|
return (
|
|
<ResponsiveModal
|
|
open={isOpen}
|
|
onClose={onClose}
|
|
size='lg'
|
|
fullWidth={true}
|
|
title='Select User'
|
|
footer={
|
|
<ModalActions secondary={{ label: t('cancel'), onClick: onClose }} />
|
|
}
|
|
>
|
|
<List sx={{ mb: 2 }}>
|
|
{performers.map(user => (
|
|
<ListItem
|
|
key={user.userId}
|
|
sx={{
|
|
cursor: 'pointer',
|
|
'&:hover': {
|
|
backgroundColor: 'rgba(0, 0, 0, 0.04)',
|
|
},
|
|
}}
|
|
onClick={() => {
|
|
onSelect(user)
|
|
onClose()
|
|
}}
|
|
>
|
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 2 }}>
|
|
<Avatar
|
|
size='lg'
|
|
src={user.image || user.avatar}
|
|
alt={user.displayName || user.name}
|
|
/>
|
|
<Typography>{user.displayName || user.name}</Typography>
|
|
</Box>
|
|
</ListItem>
|
|
))}
|
|
</List>
|
|
</ResponsiveModal>
|
|
)
|
|
}
|
|
|
|
export default UserModal
|