feat(ux): convert all hand-rolled modals to accessible Radix Dialog

S3 (final Tier 1 item). ops (4 modals), members/tasks/projects/
payments/contacts add-edit modals, settings integration-credentials
modal, and the payments link-member modal now use components/ui/dialog
(focus trap, ESC, aria, scroll lock for free). Forms, fields, handlers,
validation and close/reset behavior preserved verbatim; onOpenChange
mirrors the old Cancel/X reset. Removed now-unused X imports; replaced
a stray em-dash with a middot in the link-member subtitle.
This commit is contained in:
Moheeb Zara
2026-05-16 14:02:32 -07:00
parent 97cb4d756a
commit 108c2a54cb
7 changed files with 170 additions and 199 deletions
+17 -17
View File
@@ -1,13 +1,14 @@
'use client'
import { useState } from 'react'
import { X, Check, Copy, Eye, EyeOff, RotateCcw } from 'lucide-react'
import { Check, Copy, Eye, EyeOff, RotateCcw } from 'lucide-react'
import { updateSpaceSettings, saveIntegration, disconnectIntegration, rotateWebhookSecret, updateSpaceVisibility, createArea, updateArea, deleteArea, createTier, updateTier, deleteTier, createInvite, updateInvite, deleteInvite, createOnboardingStep, updateOnboardingStep, deleteOnboardingStep } from '@/lib/actions'
import { toast } from 'sonner'
import { financialVisibilities, directoryVisibilities } from '@/lib/validations'
import type { Tables } from '@/types/database'
import { PageTitle } from '@/components/ui/page-title'
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'
type Space = Tables<'spaces'>
type Integration = Tables<'integrations'>
@@ -567,20 +568,18 @@ export default function SettingsClient({ space, isAdmin, integrations, currentRo
</div>
{/* Integration Config Modal */}
{editingIntegration && (
<div className="fixed inset-0 bg-black/60 flex items-center justify-center z-50 p-4">
<div className="bg-card border border-border rounded-lg w-full max-w-md">
<div className="flex items-center justify-between px-6 py-4 border-b border-border">
<div className="flex items-center gap-2">
<div className="w-6 h-6 flex items-center justify-center">{editingIntegration.icon}</div>
<h2 className="font-sans text-base font-semibold text-foreground">{editingIntegration.name}</h2>
</div>
<button onClick={() => setEditingIntegration(null)} className="text-muted-foreground hover:text-foreground">
<X className="w-4 h-4" />
</button>
</div>
<Dialog open={!!editingIntegration} onOpenChange={(o) => { if (!o) setEditingIntegration(null) }}>
<DialogContent className="sm:max-w-md">
{editingIntegration && (
<>
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<div className="w-6 h-6 flex items-center justify-center">{editingIntegration.icon}</div>
{editingIntegration.name}
</DialogTitle>
</DialogHeader>
<form onSubmit={handleSaveIntegration} className="p-6 space-y-4">
<form onSubmit={handleSaveIntegration} className="space-y-4">
{editingIntegration.fields.map(field => (
<div key={field.key}>
<label className="font-mono text-[10px] tracking-widest text-muted-foreground uppercase block mb-1">{field.label}</label>
@@ -656,9 +655,10 @@ export default function SettingsClient({ space, isAdmin, integrations, currentRo
</button>
</div>
</form>
</div>
</div>
)}
</>
)}
</DialogContent>
</Dialog>
</div>
)
}