feat(intake): recipient picker UI (users/roles/everyone/emails)

Adds RecipientPicker (multi-select users + roles, everyone-with-inquiry-access toggle, free-text emails) and a new 'recipients' settings field type. The inquiry + residential notification-recipient settings now render the picker instead of a raw JSON textarea, persisting the structured {emails,userIds,roleIds,everyone} config the server resolver expands. tsc clean; full vitest suite (1570) green. Live browser verification of the picker pending a dev server (env currently on the prod build).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-02 17:36:24 +02:00
parent 5ea0c75fff
commit 44b004fa8f
2 changed files with 276 additions and 7 deletions

View File

@@ -20,6 +20,7 @@ import {
} from '@/components/ui/select';
import { Separator } from '@/components/ui/separator';
import { apiFetch } from '@/lib/api/client';
import { RecipientPicker } from './recipient-picker';
import { SUPPORTED_CURRENCIES, currencyLabel } from '@/lib/utils/currency';
interface Setting {
@@ -35,7 +36,7 @@ const KNOWN_SETTINGS: Array<{
key: string;
label: string;
description: string;
type: 'boolean' | 'number' | 'json' | 'string' | 'select';
type: 'boolean' | 'number' | 'json' | 'string' | 'select' | 'recipients';
defaultValue: unknown;
options?: Array<{ value: string; label: string }>;
}> = [
@@ -132,18 +133,18 @@ const KNOWN_SETTINGS: Array<{
},
{
key: 'inquiry_notification_recipients',
label: 'External Notification Recipients',
label: 'Berth & contact inquiry alerts',
description:
'Additional email addresses that receive sales notifications for new interests (JSON array)',
type: 'json',
'Who receives staff alerts for new berth + contact-form inquiries: specific users, roles, everyone with inquiry access, and/or explicit email addresses.',
type: 'recipients',
defaultValue: [],
},
{
key: 'residential_notification_recipients',
label: 'Residential Notification Recipients',
label: 'Residential inquiry alerts',
description:
'Email addresses (JSON array) that receive sales alerts for new residential inquiries. Falls back to Inquiry Contact Email when empty.',
type: 'json',
'Who receives staff alerts for new residential inquiries: users, roles, everyone with inquiry access, and/or emails. Falls back to Inquiry Contact Email when empty.',
type: 'recipients',
defaultValue: [],
},
{
@@ -451,6 +452,32 @@ export function SettingsManager() {
</Card>
)}
{/* Notification Recipients (users / roles / everyone / emails) */}
{KNOWN_SETTINGS.some((s) => s.type === 'recipients') && (
<Card>
<CardHeader>
<CardTitle>Notification Recipients</CardTitle>
<CardDescription>
Who receives staff alerts for new inquiries. Pick specific users, roles, everyone
with inquiry access, and/or extra email addresses.
</CardDescription>
</CardHeader>
<CardContent className="space-y-6">
{KNOWN_SETTINGS.filter((s) => s.type === 'recipients').map((setting) => (
<div key={setting.key} className="space-y-2">
<Label>{setting.label}</Label>
<p className="text-xs text-muted-foreground">{setting.description}</p>
<RecipientPicker
value={getEffectiveValue(setting.key, setting.defaultValue)}
saving={saving === setting.key}
onSave={(config) => saveSetting(setting.key, config)}
/>
</div>
))}
</CardContent>
</Card>
)}
{/* Numeric Settings */}
<Card>
<CardHeader>