ppt-tool/frontend/app/admin/components/CreateClientDialog.tsx
Vadym Samoilenko cf21ba4516 Phase 1-2: Foundation + Admin Panel & Client Management
Phase 1 (Foundation):
- Project restructure (presenton-main → backend/ + frontend/)
- Database schema (8 new models, Alembic config, seed script)
- Auth (Azure AD SSO + dev bypass, JWT sessions, AuthMiddleware)
- RBAC (access_service, rbac_middleware, admin routers)
- Audit logging (fire-and-forget, AuditMiddleware, admin router)
- i18n (react-i18next with 5 namespace files)

Phase 2 (Admin Panel & Client Management):
- Admin panel shell (sidebar layout, role guard, 12 pages)
- Redux admin slice with 18 async thunks
- User management (role changes, deactivation)
- Client management (CRUD, brand config, team management)
- Brand config editor (colors, fonts, logos, voice rules)
- Master deck upload & parser (PPTX → HTML → React pipeline)
- Audit log viewer with filters and CSV/JSON export

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 15:37:17 +00:00

77 lines
2.3 KiB
TypeScript

'use client';
import { useState } from 'react';
import { useDispatch } from 'react-redux';
import { AppDispatch } from '@/store/store';
import { createClient } from '@/store/slices/adminSlice';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogFooter,
} from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Button } from '@/components/ui/button';
import { toast } from 'sonner';
interface CreateClientDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
}
export default function CreateClientDialog({ open, onOpenChange }: CreateClientDialogProps) {
const dispatch = useDispatch<AppDispatch>();
const [name, setName] = useState('');
const [loading, setLoading] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!name.trim()) return;
setLoading(true);
try {
await dispatch(createClient({ name: name.trim() })).unwrap();
toast.success('Client created successfully');
setName('');
onOpenChange(false);
} catch (err) {
toast.error(typeof err === 'string' ? err : 'Failed to create client');
} finally {
setLoading(false);
}
};
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent>
<DialogHeader>
<DialogTitle>Create New Client</DialogTitle>
</DialogHeader>
<form onSubmit={handleSubmit}>
<div className="space-y-4 py-4">
<div className="space-y-2">
<Label htmlFor="client-name">Client Name</Label>
<Input
id="client-name"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="e.g. Nike, Adidas"
required
/>
</div>
</div>
<DialogFooter>
<Button type="button" variant="outline" onClick={() => onOpenChange(false)}>
Cancel
</Button>
<Button type="submit" disabled={loading || !name.trim()}>
{loading ? 'Creating...' : 'Create Client'}
</Button>
</DialogFooter>
</form>
</DialogContent>
</Dialog>
);
}