TorbatYar/frontend/modules/workspace/features/assets.tsx
Mortezakoohjani a483b47369 feat(workspace): complete production workspace and content operations
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-12 11:54:17 +03:30

86 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { toast } from "sonner";
import { Button, Card, CardContent, Input, PageHeader } from "@/components/ds";
import { useCurrentHub } from "@/modules/workspace/hooks/useCurrentHub";
import { useWorkspaceCapabilities } from "@/modules/workspace/hooks/useWorkspaceCapabilities";
import { workspaceApi } from "@/modules/workspace/services/workspace-api";
import { WorkspaceEmptyState, WorkspacePageError, WorkspacePageLoader } from "@/modules/workspace/pages/shared";
export const WorkspaceAssets = function WorkspaceAssetsPage() {
const queryClient = useQueryClient();
const { tenantId, hubId, loading } = useCurrentHub();
const caps = useWorkspaceCapabilities();
const [fileRef, setFileRef] = useState("");
const [title, setTitle] = useState("");
const assets = useQuery({
queryKey: ["workspace", tenantId, "assets", hubId],
queryFn: () => workspaceApi.assets.list(tenantId!, { work_hub_id: hubId || undefined }),
enabled: !!tenantId && !!hubId,
});
const create = useMutation({
mutationFn: () =>
workspaceApi.assets.create(tenantId!, {
work_hub_id: hubId,
file_ref: fileRef,
title: title || fileRef,
}),
onSuccess: () => {
toast.success("ارجاع فایل ثبت شد");
setFileRef("");
setTitle("");
void queryClient.invalidateQueries({ queryKey: ["workspace", tenantId, "assets"] });
},
onError: (err) => toast.error(err instanceof Error ? err.message : "ثبت ارجاع ناموفق بود"),
});
if (!tenantId || loading || assets.isLoading) return <WorkspacePageLoader />;
if (!hubId) return <WorkspaceEmptyState title="مرکز کار لازم است" description="ابتدا مرکز کار را انتخاب کنید." />;
if (assets.error) return <WorkspacePageError error={assets.error} onRetry={() => assets.refetch()} />;
const storageReady = caps.data?.file_storage?.available;
return (
<div className="space-y-6">
<PageHeader title="دارایی‌ها" description="فقط ارجاع به فایل‌های سامانه ذخیره‌سازی. بارگذاری محلی جعلی وجود ندارد." />
{!storageReady ? (
<div className="rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800 dark:border-amber-900 dark:bg-amber-950/30 dark:text-amber-200">
سامانه ذخیره‌سازی فایل در دسترس نیست. می‌توانید ارجاع خارجی ثبت کنید؛ آپلود باینری در فضای کاری انجام نمی‌شود.
</div>
) : null}
<Card>
<CardContent className="grid gap-2 p-5 md:grid-cols-[1fr_1fr_auto]">
<Input value={fileRef} onChange={(event) => setFileRef(event.target.value)} placeholder="شناسه فایل خارجی" />
<Input value={title} onChange={(event) => setTitle(event.target.value)} placeholder="عنوان" />
<Button disabled={!fileRef.trim() || create.isPending} onClick={() => create.mutate()}>
ثبت ارجاع
</Button>
</CardContent>
</Card>
{(assets.data ?? []).length === 0 ? (
<WorkspaceEmptyState title="ارجاعی ثبت نشده" description="شناسه فایل را از سامانه ذخیره‌سازی وارد کنید." />
) : (
<div className="space-y-2">
{(assets.data ?? []).map((asset) => (
<Card key={String(asset.id)}>
<CardContent className="flex items-center justify-between p-4">
<div>
<p className="font-medium text-secondary">{String(asset.title || "فایل")}</p>
<p className="text-xs text-[var(--muted)]">
{asset.role ? `نقش: ${String(asset.role)} · ` : ""}
فقط ارجاع
</p>
</div>
</CardContent>
</Card>
))}
</div>
)}
</div>
);
};
export default WorkspaceAssets;