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,115 @@
"use client";
// ============================================================================
// Onboarding Page - First Workspace Creation
// ============================================================================
import { useState } from "react";
import { useRouter } from "next/navigation";
import { Building2, Loader2, Megaphone } from "lucide-react";
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,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { STORAGE_KEYS } from "@/lib/utils/constants";
export default function OnboardingPage() {
const router = useRouter();
const [name, setName] = useState("");
const [isCreating, setIsCreating] = useState(false);
const [error, setError] = useState<string | null>(null);
const handleCreate = async () => {
if (!name.trim()) return;
try {
setIsCreating(true);
setError(null);
const workspace = await workspacesApi.create({ name: name.trim() });
// Save as selected workspace
localStorage.setItem(STORAGE_KEYS.SELECTED_WORKSPACE, workspace.id);
// Redirect to dashboard
router.replace(`/dashboard/${workspace.id}`);
} catch (err: any) {
setError(err?.error?.message || "Не удалось создать воркспейс");
} finally {
setIsCreating(false);
}
};
return (
<div className="flex min-h-screen items-center justify-center bg-gradient-to-br from-background to-muted p-4">
<Card className="w-full max-w-md">
<CardHeader className="text-center">
<div className="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-primary/10">
<Megaphone className="h-8 w-8 text-primary" />
</div>
<CardTitle className="text-2xl">Добро пожаловать в TGEX!</CardTitle>
<CardDescription>
Создайте свой первый воркспейс для начала работы
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="space-y-2">
<Label htmlFor="workspace-name">Название воркспейса</Label>
<Input
id="workspace-name"
placeholder="Например: Моя команда"
value={name}
onChange={(e) => setName(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter") {
handleCreate();
}
}}
disabled={isCreating}
/>
<p className="text-xs text-muted-foreground">
Воркспейс это изолированное пространство для вашей команды. Вы
сможете пригласить участников и настроить права доступа.
</p>
</div>
{error && (
<div className="rounded-md bg-destructive/10 p-3 text-sm text-destructive">
{error}
</div>
)}
</CardContent>
<CardFooter>
<Button
className="w-full"
onClick={handleCreate}
disabled={!name.trim() || isCreating}
>
{isCreating ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Создание...
</>
) : (
<>
<Building2 className="mr-2 h-4 w-4" />
Создать воркспейс
</>
)}
</Button>
</CardFooter>
</Card>
</div>
);
}