feat: global platform v2 update

This commit is contained in:
ivannoskov
2025-12-29 10:12:13 +03:00
parent 8e6a1fa83f
commit f64cf02100
84 changed files with 11023 additions and 11486 deletions

View File

@@ -0,0 +1,204 @@
"use client";
// ============================================================================
// Workspace Settings Page
// ============================================================================
import { useState } from "react";
import { useParams, useRouter } from "next/navigation";
import { Loader2, Settings, Pencil, Trash2 } from "lucide-react";
import { DashboardHeader } from "@/components/layout/dashboard-header";
import { useWorkspace } from "@/components/providers/workspace-provider";
import { workspacesApi } from "@/lib/api";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
export default function SettingsPage() {
const params = useParams();
const router = useRouter();
const workspaceId = params?.workspaceId as string;
const { currentWorkspace, refreshWorkspaces } = useWorkspace();
const [name, setName] = useState(currentWorkspace?.name || "");
const [isUpdating, setIsUpdating] = useState(false);
const [isDeleting, setIsDeleting] = useState(false);
const handleUpdate = async () => {
if (!name.trim() || name === currentWorkspace?.name) return;
try {
setIsUpdating(true);
await workspacesApi.update(workspaceId, { name: name.trim() });
await refreshWorkspaces();
} catch (err) {
console.error("Failed to update workspace:", err);
} finally {
setIsUpdating(false);
}
};
const handleDelete = async () => {
try {
setIsDeleting(true);
await workspacesApi.delete(workspaceId);
router.replace("/");
} catch (err) {
console.error("Failed to delete workspace:", err);
} finally {
setIsDeleting(false);
}
};
if (!currentWorkspace) {
return (
<>
<DashboardHeader breadcrumbs={[{ label: "Настройки" }]} />
<div className="flex items-center justify-center py-12">
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
</div>
</>
);
}
return (
<>
<DashboardHeader
breadcrumbs={[
{ label: "Главная", href: `/dashboard/${workspaceId}` },
{ label: "Настройки" },
]}
showProjectSelector={false}
/>
<div className="flex flex-1 flex-col gap-4 p-4 pt-0 mt-4 max-w-2xl">
<div>
<h1 className="text-2xl font-bold tracking-tight">Настройки воркспейса</h1>
<p className="text-muted-foreground">
Управление настройками воркспейса
</p>
</div>
{/* General Settings */}
<Card>
<CardHeader>
<CardTitle>Основные настройки</CardTitle>
<CardDescription>
Название и основные параметры воркспейса
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<Label htmlFor="workspace-name">Название</Label>
<div className="flex gap-2">
<Input
id="workspace-name"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Название воркспейса"
/>
<Button
onClick={handleUpdate}
disabled={
!name.trim() ||
name === currentWorkspace.name ||
isUpdating
}
>
{isUpdating ? (
<Loader2 className="h-4 w-4 animate-spin" />
) : (
<Pencil className="h-4 w-4" />
)}
</Button>
</div>
</div>
</CardContent>
</Card>
{/* Team Management Links */}
<Card>
<CardHeader>
<CardTitle>Команда</CardTitle>
<CardDescription>
Управление участниками и приглашениями
</CardDescription>
</CardHeader>
<CardContent className="space-y-2">
<Button variant="outline" className="w-full justify-start" asChild>
<a href={`/dashboard/${workspaceId}/settings/members`}>
Участники воркспейса
</a>
</Button>
<Button variant="outline" className="w-full justify-start" asChild>
<a href={`/dashboard/${workspaceId}/settings/invites`}>
Приглашения
</a>
</Button>
</CardContent>
</Card>
{/* Danger Zone */}
<Card className="border-destructive">
<CardHeader>
<CardTitle className="text-destructive">Опасная зона</CardTitle>
<CardDescription>
Необратимые действия с воркспейсом
</CardDescription>
</CardHeader>
<CardContent>
<AlertDialog>
<AlertDialogTrigger asChild>
<Button variant="destructive">
<Trash2 className="h-4 w-4 mr-2" />
Удалить воркспейс
</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Удалить воркспейс?</AlertDialogTitle>
<AlertDialogDescription>
Это действие необратимо. Все данные воркспейса будут
удалены, включая проекты, креативы, размещения и аналитику.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Отмена</AlertDialogCancel>
<AlertDialogAction
onClick={handleDelete}
disabled={isDeleting}
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
>
{isDeleting ? (
<Loader2 className="h-4 w-4 animate-spin mr-2" />
) : null}
Удалить
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</CardContent>
</Card>
</div>
</>
);
}