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:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user