Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | 2x 8x 8x 8x 8x 8x 8x 8x 2x 2x 1x 1x 8x | /**
* UnsuppressDialog — Confirmation dialog for unsuppressing a bounced subscriber
*
* Story 10.29 AC8: Admin visibility — bounce status in subscriber list
*/
import React from 'react';
import {
Alert,
Box,
Button,
CircularProgress,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
IconButton,
Typography,
} from '@mui/material';
import { Close, WarningAmber } from '@mui/icons-material';
import { useTranslation } from 'react-i18next';
import type { components } from '@/types/generated/event-newsletter-api.types';
import { useBreakpoints } from '@/hooks/useBreakpoints';
import { useUnsuppressSubscriber } from '@/hooks/useNewsletterSubscribers';
type SubscriberResponse = components['schemas']['SubscriberResponse'];
interface UnsuppressDialogProps {
open: boolean;
subscriber: SubscriberResponse | null;
onClose: () => void;
onSuccess: () => void;
}
const UnsuppressDialog: React.FC<UnsuppressDialogProps> = ({
open,
subscriber,
onClose,
onSuccess,
}) => {
const { t } = useTranslation('newsletterSubscribers');
const { t: tCommon } = useTranslation('common');
const { isMobile } = useBreakpoints();
const mutation = useUnsuppressSubscriber();
React.useEffect(() => {
if (open) mutation.reset();
}, [open, mutation]);
const handleConfirm = () => {
Iif (!subscriber?.id) return;
mutation.mutate(subscriber.id, {
onSuccess: () => {
onSuccess();
onClose();
},
});
};
return (
<Dialog open={open} onClose={onClose} maxWidth="sm" fullWidth fullScreen={isMobile}>
<DialogTitle>
<Box display="flex" justifyContent="space-between" alignItems="center">
<Box display="flex" alignItems="center" gap={1}>
<WarningAmber color="warning" />
<Typography variant="h6">{t('dialogs.unsuppress.title')}</Typography>
</Box>
<IconButton onClick={onClose} aria-label={tCommon('actions.close')}>
<Close />
</IconButton>
</Box>
</DialogTitle>
<DialogContent dividers>
<Typography>{t('dialogs.unsuppress.message', { email: subscriber?.email })}</Typography>
<Typography variant="body2" color="text.secondary" sx={{ mt: 1 }}>
{t('dialogs.unsuppress.detail', {
bounceType: subscriber?.bounceType ?? '—',
bounceCount: subscriber?.bounceCount ?? 0,
})}
</Typography>
{mutation.isError && (
<Alert severity="error" sx={{ mt: 2 }}>
{tCommon('errors.unexpected')}
</Alert>
)}
</DialogContent>
<DialogActions>
<Button onClick={onClose} variant="outlined">
{tCommon('actions.cancel')}
</Button>
<Button
onClick={handleConfirm}
variant="contained"
color="warning"
disabled={mutation.isPending}
data-testid="confirm-unsuppress"
>
{mutation.isPending ? <CircularProgress size={20} /> : t('actions.unsuppress')}
</Button>
</DialogActions>
</Dialog>
);
};
export default UnsuppressDialog;
|