106 lines
3.3 KiB
TypeScript
106 lines
3.3 KiB
TypeScript
'use client';
|
|
import { FunctionComponent } from 'react';
|
|
import Stack from '@mui/material/Stack';
|
|
import Typography from '@mui/material/Typography';
|
|
import { AppButton, AccentCard } from '@/components/common';
|
|
import type { AccentTone } from '@/components/common';
|
|
import StatusChip from '@/components/StatusChip';
|
|
import type { StatusKind } from '@/components/StatusChip';
|
|
import type { BankAccountStatus } from '@/services/nurse/types';
|
|
|
|
const STATUS_KIND: Record<BankAccountStatus, StatusKind> = {
|
|
pending: 'pending',
|
|
verified: 'verified',
|
|
mismatch: 'rejected',
|
|
};
|
|
|
|
const STATUS_TONE: Record<BankAccountStatus, AccentTone> = {
|
|
pending: 'warning',
|
|
verified: 'success',
|
|
mismatch: 'error',
|
|
};
|
|
|
|
export interface BankStatusPanelProps {
|
|
status: BankAccountStatus;
|
|
/** Translated status chip / title / body for the active status. */
|
|
chipLabel: string;
|
|
title: string;
|
|
body: string;
|
|
/** Masked IBAN (last-4), shown when present. */
|
|
ibanMasked?: string;
|
|
ibanLabel?: string;
|
|
bankName?: string;
|
|
isPrimary?: boolean;
|
|
primaryLabel?: string;
|
|
/** Rendered only for the mismatch state (a friendly re-enter path). */
|
|
onReenter?: () => void;
|
|
reenterLabel?: string;
|
|
}
|
|
|
|
/**
|
|
* Renders one bank account in one of the three ownership-inquiry states — **pending**,
|
|
* **verified**, **mismatch** — each visually distinct off the semantic tokens. The IBAN is
|
|
* shown masked (last-4). Mismatch copy is passed in non-accusatory; the re-enter CTA is the
|
|
* only action offered there. All strings are translated by the caller.
|
|
* @component BankStatusPanel
|
|
*/
|
|
const BankStatusPanel: FunctionComponent<BankStatusPanelProps> = ({
|
|
status,
|
|
chipLabel,
|
|
title,
|
|
body,
|
|
ibanMasked,
|
|
ibanLabel,
|
|
bankName,
|
|
isPrimary = false,
|
|
primaryLabel,
|
|
onReenter,
|
|
reenterLabel,
|
|
}) => (
|
|
<AccentCard tone={STATUS_TONE[status]} padding="sm" data-status={status}>
|
|
<Stack sx={{ gap: 1.25 }}>
|
|
<Stack direction="row" sx={{ alignItems: 'center', gap: 1, flexWrap: 'wrap' }}>
|
|
<StatusChip status={STATUS_KIND[status]} label={chipLabel} />
|
|
{isPrimary && primaryLabel ? (
|
|
<StatusChip status="info" label={primaryLabel} />
|
|
) : null}
|
|
</Stack>
|
|
|
|
<Stack sx={{ gap: 0.25 }}>
|
|
<Typography variant="subtitle1" sx={{ fontWeight: 700 }}>
|
|
{title}
|
|
</Typography>
|
|
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
|
|
{body}
|
|
</Typography>
|
|
</Stack>
|
|
|
|
{ibanMasked ? (
|
|
<Stack direction="row" sx={{ alignItems: 'baseline', gap: 1 }}>
|
|
{ibanLabel ? (
|
|
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
|
|
{ibanLabel}
|
|
</Typography>
|
|
) : null}
|
|
<Typography sx={{ fontWeight: 500, letterSpacing: 1 }} dir="ltr">
|
|
{ibanMasked}
|
|
</Typography>
|
|
{bankName ? (
|
|
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
|
|
{bankName}
|
|
</Typography>
|
|
) : null}
|
|
</Stack>
|
|
) : null}
|
|
|
|
{status === 'mismatch' && onReenter && reenterLabel ? (
|
|
<AppButton color="primary" variant="outlined" startIcon="bank" onClick={onReenter} sx={{ alignSelf: 'flex-start' }}>
|
|
{reenterLabel}
|
|
</AppButton>
|
|
) : null}
|
|
</Stack>
|
|
</AccentCard>
|
|
);
|
|
|
|
export default BankStatusPanel;
|