Spaces:
Sleeping
Sleeping
File size: 6,454 Bytes
83c125e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | import { useState } from 'react'
import { useForm } from 'react-hook-form'
import { WorkspaceSettings } from '@/types/settings'
export function AdminWorkspaceSettings() {
const { register, handleSubmit, formState: { errors } } = useForm<WorkspaceSettings>({
defaultValues: {
name: 'Godspeed',
slug: 'godspeed',
description: 'Engineering knowledge base',
},
})
const [isSaving, setIsSaving] = useState(false)
const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null)
const onSubmit = async (data: WorkspaceSettings) => {
setIsSaving(true)
setMessage(null)
try {
// TODO: PATCH /api/workspace/settings
console.log('Update workspace settings:', data)
setMessage({ type: 'success', text: 'Workspace settings updated' })
} catch (err) {
setMessage({
type: 'error',
text: err instanceof Error ? err.message : 'Failed to update settings',
})
} finally {
setIsSaving(false)
}
}
return (
<form onSubmit={handleSubmit(onSubmit)} className="space-y-6 p-6">
{/* Workspace Info */}
<div>
<h3 className="mb-4 text-sm font-semibold">Workspace Settings</h3>
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-stone-700 dark:text-stone-300">
Workspace Name
</label>
<input
type="text"
{...register('name', { required: 'Name is required' })}
className="mt-1 block w-full rounded border border-stone-300 bg-white px-3 py-2 text-stone-900 shadow-sm placeholder-stone-400 focus:border-brand focus:outline-none focus:ring-1 focus:ring-brand dark:border-stone-600 dark:bg-stone-800 dark:text-white"
/>
{errors.name && <p className="mt-1 text-xs text-red-500">{errors.name.message}</p>}
</div>
<div>
<label className="block text-sm font-medium text-stone-700 dark:text-stone-300">
URL Slug
</label>
<input
type="text"
{...register('slug', { required: 'Slug is required' })}
className="mt-1 block w-full rounded border border-stone-300 bg-white px-3 py-2 font-mono text-sm text-stone-900 shadow-sm placeholder-stone-400 focus:border-brand focus:outline-none focus:ring-1 focus:ring-brand dark:border-stone-600 dark:bg-stone-800 dark:text-white"
/>
{errors.slug && <p className="mt-1 text-xs text-red-500">{errors.slug.message}</p>}
</div>
<div>
<label className="block text-sm font-medium text-stone-700 dark:text-stone-300">
Description
</label>
<textarea
{...register('description')}
rows={3}
className="mt-1 block w-full rounded border border-stone-300 bg-white px-3 py-2 text-stone-900 shadow-sm placeholder-stone-400 focus:border-brand focus:outline-none focus:ring-1 focus:ring-brand dark:border-stone-600 dark:bg-stone-800 dark:text-white"
/>
</div>
</div>
</div>
{/* Limits */}
<div className="border-t border-stone-200 pt-6 dark:border-stone-700">
<h3 className="mb-4 text-sm font-semibold">Workspace Limits</h3>
<div className="grid gap-4 sm:grid-cols-2">
<div>
<label className="block text-sm font-medium text-stone-700 dark:text-stone-300">
Max Team Members
</label>
<input
type="number"
{...register('max_team_members')}
className="mt-1 block w-full rounded border border-stone-300 bg-white px-3 py-2 text-stone-900 shadow-sm focus:border-brand focus:outline-none focus:ring-1 focus:ring-brand dark:border-stone-600 dark:bg-stone-800 dark:text-white"
/>
<p className="mt-1 text-xs text-stone-500">Leave empty for unlimited</p>
</div>
<div>
<label className="block text-sm font-medium text-stone-700 dark:text-stone-300">
Max Channels
</label>
<input
type="number"
{...register('max_channels')}
className="mt-1 block w-full rounded border border-stone-300 bg-white px-3 py-2 text-stone-900 shadow-sm focus:border-brand focus:outline-none focus:ring-1 focus:ring-brand dark:border-stone-600 dark:bg-stone-800 dark:text-white"
/>
<p className="mt-1 text-xs text-stone-500">Leave empty for unlimited</p>
</div>
</div>
</div>
{/* Message */}
{message && (
<div
className={`rounded-md p-3 text-sm ${
message.type === 'success'
? 'border border-green-200 bg-green-50 text-green-800 dark:border-green-900 dark:bg-green-950 dark:text-green-200'
: 'border border-red-200 bg-red-50 text-red-800 dark:border-red-900 dark:bg-red-950 dark:text-red-200'
}`}
>
{message.text}
</div>
)}
{/* Save Button */}
<div className="border-t border-stone-200 pt-6 dark:border-stone-700">
<button
type="submit"
disabled={isSaving}
className="rounded bg-brand px-4 py-2 text-sm font-medium text-white hover:bg-brand-dark disabled:opacity-50"
>
{isSaving ? 'Saving...' : 'Save Settings'}
</button>
</div>
{/* Danger Zone */}
<div className="border-t border-stone-200 pt-6 dark:border-stone-700">
<h3 className="mb-4 text-sm font-semibold text-red-600 dark:text-red-400">Danger Zone</h3>
<div className="space-y-3">
<div className="rounded-lg border border-red-200 bg-red-50 p-4 dark:border-red-900 dark:bg-stone-900">
<p className="text-sm font-medium text-red-900 dark:text-red-100">
Delete this workspace
</p>
<p className="mt-1 text-xs text-red-700 dark:text-red-300">
This action cannot be undone. All data will be permanently deleted.
</p>
<button
type="button"
className="mt-3 rounded bg-red-600 px-3 py-1.5 text-sm font-medium text-white hover:bg-red-700"
>
Delete Workspace
</button>
</div>
</div>
</div>
</form>
)
}
|