refactor: migrate session, script-builder, account to Design System v4
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -36,27 +36,27 @@ export function DeleteAccountModal({ onClose }: Props) {
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4">
|
||||
<div className="glass-card-static w-full max-w-md p-6">
|
||||
<div className="card-flat w-full max-w-md p-6">
|
||||
<div className="flex items-center gap-2 text-rose-500 mb-4">
|
||||
<AlertTriangle className="h-5 w-5" />
|
||||
<h2 className="text-lg font-semibold font-heading text-foreground">Delete Account</h2>
|
||||
<h2 className="text-lg font-semibold font-heading text-[#e2e5eb]">Delete Account</h2>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground mb-4">
|
||||
<p className="text-sm text-[#848b9b] mb-4">
|
||||
This action is <strong className="text-rose-400">permanent</strong>. Your account, data,
|
||||
and all associated flows will be permanently deleted.
|
||||
</p>
|
||||
|
||||
<form onSubmit={handleDelete} className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-foreground">Confirm Password</label>
|
||||
<label className="block text-sm font-medium text-[#e2e5eb]">Confirm Password</label>
|
||||
<input
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
required
|
||||
className={cn(
|
||||
'mt-1 block w-full rounded-[10px] border border-border bg-card px-3 py-2',
|
||||
'text-foreground focus:border-primary focus:outline-hidden'
|
||||
'mt-1 block w-full rounded-lg border border-[#1e2130] bg-[#14161d] px-3 py-2',
|
||||
'text-[#e2e5eb] focus:border-primary focus:outline-hidden'
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
@@ -68,8 +68,8 @@ export function DeleteAccountModal({ onClose }: Props) {
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className={cn(
|
||||
'rounded-[10px] px-4 py-2 text-sm font-medium',
|
||||
'bg-white/[0.04] border border-brand-border text-foreground'
|
||||
'rounded-lg px-4 py-2 text-sm font-medium',
|
||||
'bg-white/[0.04] border border-brand-border text-[#e2e5eb]'
|
||||
)}
|
||||
>
|
||||
Cancel
|
||||
@@ -78,7 +78,7 @@ export function DeleteAccountModal({ onClose }: Props) {
|
||||
type="submit"
|
||||
disabled={isSubmitting || !password}
|
||||
className={cn(
|
||||
'rounded-[10px] px-4 py-2 text-sm font-semibold',
|
||||
'rounded-lg px-4 py-2 text-sm font-semibold',
|
||||
'bg-rose-500 text-white hover:bg-rose-400 disabled:opacity-50'
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -31,21 +31,21 @@ export function LeaveAccountModal({ accountName, onClose }: Props) {
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4">
|
||||
<div className="glass-card-static w-full max-w-md p-6">
|
||||
<div className="card-flat w-full max-w-md p-6">
|
||||
<div className="flex items-center gap-2 text-amber-400 mb-4">
|
||||
<AlertTriangle className="h-5 w-5" />
|
||||
<h2 className="text-lg font-semibold font-heading text-foreground">Leave Account</h2>
|
||||
<h2 className="text-lg font-semibold font-heading text-[#e2e5eb]">Leave Account</h2>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground mb-4">
|
||||
Are you sure you want to leave <strong className="text-foreground">{accountName}</strong>?
|
||||
<p className="text-sm text-[#848b9b] mb-4">
|
||||
Are you sure you want to leave <strong className="text-[#e2e5eb]">{accountName}</strong>?
|
||||
A new personal account will be created for you.
|
||||
</p>
|
||||
<div className="flex justify-end gap-3">
|
||||
<button
|
||||
onClick={onClose}
|
||||
className={cn(
|
||||
'rounded-[10px] px-4 py-2 text-sm font-medium',
|
||||
'bg-white/[0.04] border border-brand-border text-foreground'
|
||||
'rounded-lg px-4 py-2 text-sm font-medium',
|
||||
'bg-white/[0.04] border border-brand-border text-[#e2e5eb]'
|
||||
)}
|
||||
>
|
||||
Cancel
|
||||
@@ -54,7 +54,7 @@ export function LeaveAccountModal({ accountName, onClose }: Props) {
|
||||
onClick={handleLeave}
|
||||
disabled={isSubmitting}
|
||||
className={cn(
|
||||
'rounded-[10px] px-4 py-2 text-sm font-semibold',
|
||||
'rounded-lg px-4 py-2 text-sm font-semibold',
|
||||
'bg-rose-500 text-white hover:bg-rose-400 disabled:opacity-50'
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -173,16 +173,16 @@ export function NotificationSettings() {
|
||||
{/* Section header */}
|
||||
<div className="mb-6 flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<Bell className="h-6 w-6 text-muted-foreground" />
|
||||
<h2 className="text-xl font-semibold font-heading text-foreground">Notifications</h2>
|
||||
<Bell className="h-6 w-6 text-[#848b9b]" />
|
||||
<h2 className="text-xl font-semibold font-heading text-[#e2e5eb]">Notifications</h2>
|
||||
</div>
|
||||
|
||||
<div className="relative" ref={dropdownRef}>
|
||||
<button
|
||||
onClick={() => setShowDropdown(!showDropdown)}
|
||||
className={cn(
|
||||
'inline-flex items-center gap-2 rounded-[10px] px-4 py-2 text-sm font-medium',
|
||||
'bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-foreground',
|
||||
'inline-flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium',
|
||||
'bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-[#e2e5eb]',
|
||||
'hover:border-[rgba(255,255,255,0.12)] transition-all'
|
||||
)}
|
||||
>
|
||||
@@ -192,16 +192,16 @@ export function NotificationSettings() {
|
||||
</button>
|
||||
|
||||
{showDropdown && (
|
||||
<div className="absolute right-0 mt-1 z-20 w-48 rounded-xl border border-border bg-card shadow-xl">
|
||||
<div className="absolute right-0 mt-1 z-20 w-48 rounded-xl border border-[#1e2130] bg-[#14161d] shadow-xl">
|
||||
{(Object.entries(CHANNEL_LABELS) as [ChannelType, string][]).map(([key, label]) => {
|
||||
const Icon = CHANNEL_ICONS[key]
|
||||
return (
|
||||
<button
|
||||
key={key}
|
||||
onClick={() => handleAddChannel(key)}
|
||||
className="flex w-full items-center gap-2.5 px-4 py-2.5 text-sm text-foreground hover:bg-[rgba(255,255,255,0.04)] first:rounded-t-xl last:rounded-b-xl transition-colors"
|
||||
className="flex w-full items-center gap-2.5 px-4 py-2.5 text-sm text-[#e2e5eb] hover:bg-[rgba(255,255,255,0.04)] first:rounded-t-xl last:rounded-b-xl transition-colors"
|
||||
>
|
||||
<Icon className="h-4 w-4 text-muted-foreground" />
|
||||
<Icon className="h-4 w-4 text-[#848b9b]" />
|
||||
{label}
|
||||
</button>
|
||||
)
|
||||
@@ -214,15 +214,15 @@ export function NotificationSettings() {
|
||||
{/* Loading */}
|
||||
{loading && (
|
||||
<div className="flex justify-center py-8">
|
||||
<Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
|
||||
<Loader2 className="h-6 w-6 animate-spin text-[#848b9b]" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Empty state */}
|
||||
{!loading && configs.length === 0 && !addingChannel && (
|
||||
<div className="glass-card-static p-6 text-center">
|
||||
<Bell className="mx-auto h-8 w-8 text-muted-foreground/50 mb-3" />
|
||||
<p className="text-sm text-muted-foreground">
|
||||
<div className="card-flat p-6 text-center">
|
||||
<Bell className="mx-auto h-8 w-8 text-[#848b9b]/50 mb-3" />
|
||||
<p className="text-sm text-[#848b9b]">
|
||||
No notification channels configured. Add a channel to receive alerts for session events.
|
||||
</p>
|
||||
</div>
|
||||
@@ -234,11 +234,11 @@ export function NotificationSettings() {
|
||||
{configs.map(config => {
|
||||
const Icon = CHANNEL_ICONS[config.channel]
|
||||
return (
|
||||
<div key={config.id} className="glass-card-static p-5">
|
||||
<div key={config.id} className="card-flat p-5">
|
||||
{/* Header row */}
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<Icon className="h-5 w-5 text-muted-foreground" />
|
||||
<span className="text-sm font-medium text-foreground">
|
||||
<Icon className="h-5 w-5 text-[#848b9b]" />
|
||||
<span className="text-sm font-medium text-[#e2e5eb]">
|
||||
{CHANNEL_LABELS[config.channel]}
|
||||
</span>
|
||||
<span
|
||||
@@ -248,8 +248,8 @@ export function NotificationSettings() {
|
||||
)}
|
||||
/>
|
||||
<span className={cn(
|
||||
'text-xs font-label',
|
||||
config.is_active ? 'text-emerald-400' : 'text-muted-foreground'
|
||||
'text-xs font-sans text-xs',
|
||||
config.is_active ? 'text-emerald-400' : 'text-[#848b9b]'
|
||||
)}>
|
||||
{config.is_active ? 'Active' : 'Inactive'}
|
||||
</span>
|
||||
@@ -259,20 +259,20 @@ export function NotificationSettings() {
|
||||
<div className="mb-4">
|
||||
{config.webhook_url && (
|
||||
<div>
|
||||
<span className="font-label text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground">
|
||||
<span className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-[#848b9b]">
|
||||
Webhook URL
|
||||
</span>
|
||||
<p className="mt-0.5 text-sm text-foreground font-mono">
|
||||
<p className="mt-0.5 text-sm text-[#e2e5eb] font-mono">
|
||||
{maskWebhookUrl(config.webhook_url)}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
{config.email_addresses && config.email_addresses.length > 0 && (
|
||||
<div>
|
||||
<span className="font-label text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground">
|
||||
<span className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-[#848b9b]">
|
||||
Email Addresses
|
||||
</span>
|
||||
<p className="mt-0.5 text-sm text-foreground">
|
||||
<p className="mt-0.5 text-sm text-[#e2e5eb]">
|
||||
{config.email_addresses.join(', ')}
|
||||
</p>
|
||||
</div>
|
||||
@@ -281,7 +281,7 @@ export function NotificationSettings() {
|
||||
|
||||
{/* Event toggles */}
|
||||
<div className="mb-4">
|
||||
<span className="font-label text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground">
|
||||
<span className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-[#848b9b]">
|
||||
Events
|
||||
</span>
|
||||
<div className="mt-2 grid gap-2 sm:grid-cols-2">
|
||||
@@ -294,28 +294,28 @@ export function NotificationSettings() {
|
||||
type="checkbox"
|
||||
checked={config.events_enabled[eventKey] ?? false}
|
||||
onChange={() => handleToggleEvent(config, eventKey)}
|
||||
className="h-3.5 w-3.5 rounded border-border bg-card text-primary focus:ring-primary/30 focus:ring-offset-0 cursor-pointer accent-[#06b6d4]"
|
||||
className="h-3.5 w-3.5 rounded border-[#1e2130] bg-[#14161d] text-primary focus:ring-primary/30 focus:ring-offset-0 cursor-pointer accent-[#06b6d4]"
|
||||
/>
|
||||
<span className="text-sm text-foreground">{eventLabel}</span>
|
||||
<span className="text-sm text-[#e2e5eb]">{eventLabel}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Action buttons */}
|
||||
<div className="flex items-center gap-3 pt-2 border-t border-border">
|
||||
<div className="flex items-center gap-3 pt-2 border-t border-[#1e2130]">
|
||||
<button
|
||||
onClick={() => handleToggleActive(config)}
|
||||
className={cn(
|
||||
'inline-flex items-center gap-1.5 rounded-[10px] px-3 py-1.5 text-sm font-medium',
|
||||
'bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-foreground',
|
||||
'inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm font-medium',
|
||||
'bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-[#e2e5eb]',
|
||||
'hover:border-[rgba(255,255,255,0.12)] transition-all'
|
||||
)}
|
||||
>
|
||||
{config.is_active ? (
|
||||
<ToggleRight className="h-4 w-4 text-emerald-400" />
|
||||
) : (
|
||||
<ToggleLeft className="h-4 w-4 text-muted-foreground" />
|
||||
<ToggleLeft className="h-4 w-4 text-[#848b9b]" />
|
||||
)}
|
||||
{config.is_active ? 'Disable' : 'Enable'}
|
||||
</button>
|
||||
@@ -324,8 +324,8 @@ export function NotificationSettings() {
|
||||
onClick={() => handleTest(config.id)}
|
||||
disabled={testingId === config.id}
|
||||
className={cn(
|
||||
'inline-flex items-center gap-1.5 rounded-[10px] px-3 py-1.5 text-sm font-medium',
|
||||
'bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-foreground',
|
||||
'inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-sm font-medium',
|
||||
'bg-[rgba(255,255,255,0.04)] border border-[rgba(255,255,255,0.06)] text-[#e2e5eb]',
|
||||
'hover:border-[rgba(255,255,255,0.12)] transition-all',
|
||||
'disabled:opacity-50 disabled:cursor-not-allowed'
|
||||
)}
|
||||
@@ -349,7 +349,7 @@ export function NotificationSettings() {
|
||||
) : (
|
||||
<button
|
||||
onClick={() => setConfirmDeleteId(config.id)}
|
||||
className="ml-auto inline-flex items-center gap-1.5 text-sm text-muted-foreground hover:text-red-400 transition-colors"
|
||||
className="ml-auto inline-flex items-center gap-1.5 text-sm text-[#848b9b] hover:text-red-400 transition-colors"
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
Remove
|
||||
@@ -362,20 +362,20 @@ export function NotificationSettings() {
|
||||
|
||||
{/* Inline add form */}
|
||||
{addingChannel && (
|
||||
<div className="glass-card-static p-5">
|
||||
<div className="card-flat p-5">
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
{(() => {
|
||||
const Icon = CHANNEL_ICONS[addingChannel]
|
||||
return <Icon className="h-5 w-5 text-muted-foreground" />
|
||||
return <Icon className="h-5 w-5 text-[#848b9b]" />
|
||||
})()}
|
||||
<span className="text-sm font-medium text-foreground">
|
||||
<span className="text-sm font-medium text-[#e2e5eb]">
|
||||
Add {CHANNEL_LABELS[addingChannel]}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{addingChannel === 'email' ? (
|
||||
<div>
|
||||
<label className="font-label text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground">
|
||||
<label className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-[#848b9b]">
|
||||
Email Addresses
|
||||
</label>
|
||||
<Input
|
||||
@@ -385,13 +385,13 @@ export function NotificationSettings() {
|
||||
placeholder="user@example.com, team@example.com"
|
||||
className="mt-1"
|
||||
/>
|
||||
<p className="mt-1 text-xs text-muted-foreground">
|
||||
<p className="mt-1 text-xs text-[#848b9b]">
|
||||
Separate multiple addresses with commas
|
||||
</p>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<label className="font-label text-[0.625rem] uppercase tracking-[0.1em] text-muted-foreground">
|
||||
<label className="font-sans text-xs text-[0.625rem] uppercase tracking-[0.1em] text-[#848b9b]">
|
||||
Webhook URL
|
||||
</label>
|
||||
<Input
|
||||
@@ -413,9 +413,9 @@ export function NotificationSettings() {
|
||||
onClick={handleSaveNew}
|
||||
disabled={isSaving}
|
||||
className={cn(
|
||||
'inline-flex items-center gap-2 rounded-[10px] px-5 py-2.5 text-sm font-semibold',
|
||||
'bg-gradient-brand text-[#101114] shadow-lg shadow-primary/20',
|
||||
'hover:opacity-90 active:scale-[0.97] transition-all',
|
||||
'inline-flex items-center gap-2 rounded-lg px-5 py-2.5 text-sm font-semibold',
|
||||
'bg-[#22d3ee] text-white',
|
||||
'hover:brightness-110 active:scale-[0.98] transition-all',
|
||||
'disabled:opacity-50 disabled:cursor-not-allowed'
|
||||
)}
|
||||
>
|
||||
@@ -424,7 +424,7 @@ export function NotificationSettings() {
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setAddingChannel(null)}
|
||||
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
|
||||
className="text-sm text-[#848b9b] hover:text-[#e2e5eb] transition-colors"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
@@ -40,27 +40,27 @@ export function TransferOwnershipModal({ members, onClose, onTransferred }: Prop
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4">
|
||||
<div className="glass-card-static w-full max-w-md p-6">
|
||||
<div className="card-flat w-full max-w-md p-6">
|
||||
<div className="flex items-center gap-2 text-amber-400 mb-4">
|
||||
<AlertTriangle className="h-5 w-5" />
|
||||
<h2 className="text-lg font-semibold font-heading text-foreground">Transfer Ownership</h2>
|
||||
<h2 className="text-lg font-semibold font-heading text-[#e2e5eb]">Transfer Ownership</h2>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground mb-4">
|
||||
<p className="text-sm text-[#848b9b] mb-4">
|
||||
This will make the selected member the new account owner. You will become an engineer.
|
||||
</p>
|
||||
|
||||
{nonOwnerMembers.length === 0 ? (
|
||||
<p className="text-sm text-muted-foreground">No other members to transfer to.</p>
|
||||
<p className="text-sm text-[#848b9b]">No other members to transfer to.</p>
|
||||
) : (
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-foreground">New Owner</label>
|
||||
<label className="block text-sm font-medium text-[#e2e5eb]">New Owner</label>
|
||||
<select
|
||||
value={targetUserId}
|
||||
onChange={(e) => setTargetUserId(e.target.value)}
|
||||
className={cn(
|
||||
'mt-1 block w-full rounded-[10px] border border-border bg-card px-3 py-2',
|
||||
'text-foreground focus:border-primary focus:outline-hidden'
|
||||
'mt-1 block w-full rounded-lg border border-[#1e2130] bg-[#14161d] px-3 py-2',
|
||||
'text-[#e2e5eb] focus:border-primary focus:outline-hidden'
|
||||
)}
|
||||
>
|
||||
{nonOwnerMembers.map((m) => (
|
||||
@@ -69,15 +69,15 @@ export function TransferOwnershipModal({ members, onClose, onTransferred }: Prop
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-foreground">Your Password</label>
|
||||
<label className="block text-sm font-medium text-[#e2e5eb]">Your Password</label>
|
||||
<input
|
||||
type="password"
|
||||
value={password}
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
required
|
||||
className={cn(
|
||||
'mt-1 block w-full rounded-[10px] border border-border bg-card px-3 py-2',
|
||||
'text-foreground focus:border-primary focus:outline-hidden'
|
||||
'mt-1 block w-full rounded-lg border border-[#1e2130] bg-[#14161d] px-3 py-2',
|
||||
'text-[#e2e5eb] focus:border-primary focus:outline-hidden'
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
@@ -89,8 +89,8 @@ export function TransferOwnershipModal({ members, onClose, onTransferred }: Prop
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className={cn(
|
||||
'rounded-[10px] px-4 py-2 text-sm font-medium',
|
||||
'bg-white/[0.04] border border-brand-border text-foreground'
|
||||
'rounded-lg px-4 py-2 text-sm font-medium',
|
||||
'bg-white/[0.04] border border-brand-border text-[#e2e5eb]'
|
||||
)}
|
||||
>
|
||||
Cancel
|
||||
@@ -99,7 +99,7 @@ export function TransferOwnershipModal({ members, onClose, onTransferred }: Prop
|
||||
type="submit"
|
||||
disabled={isSubmitting || !password}
|
||||
className={cn(
|
||||
'rounded-[10px] px-4 py-2 text-sm font-semibold',
|
||||
'rounded-lg px-4 py-2 text-sm font-semibold',
|
||||
'bg-amber-500 text-brand-dark hover:bg-amber-400',
|
||||
'disabled:opacity-50'
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user