Files
sfera/src/components/warehouse/warehouse-dashboard.tsx

247 lines
8.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

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 React, { useState } from "react";
import { useQuery } from "@apollo/client";
import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Sidebar } from "@/components/dashboard/sidebar";
import { useSidebar } from "@/hooks/useSidebar";
import { ProductForm } from "./product-form";
import { ProductCard } from "./product-card";
import { GET_MY_PRODUCTS } from "@/graphql/queries";
import { Plus, Search, Package } from "lucide-react";
import { Input } from "@/components/ui/input";
interface Product {
id: string;
name: string;
article: string;
description: string;
price: number;
quantity: number;
type: "PRODUCT" | "CONSUMABLE";
category: { id: string; name: string } | null;
brand: string;
color: string;
size: string;
weight: number;
dimensions: string;
material: string;
images: string[];
mainImage: string;
isActive: boolean;
createdAt: string;
updatedAt: string;
}
export function WarehouseDashboard() {
const { getSidebarMargin } = useSidebar();
const [isDialogOpen, setIsDialogOpen] = useState(false);
const [editingProduct, setEditingProduct] = useState<Product | null>(null);
const [searchQuery, setSearchQuery] = useState("");
const { data, loading, error, refetch } = useQuery(GET_MY_PRODUCTS, {
errorPolicy: "all",
});
const products: Product[] = data?.myProducts || [];
// Отладочное логирование
React.useEffect(() => {
console.log("🏪 WAREHOUSE DASHBOARD DEBUG:", {
loading,
error: error?.message,
dataReceived: !!data,
productsCount: products.length,
products: products.map((p) => ({
id: p.id,
name: p.name,
article: p.article,
type: p.type,
isActive: p.isActive,
createdAt: p.createdAt,
})),
});
}, [data, loading, error, products]);
// Фильтрация товаров по поисковому запросу
const filteredProducts = products.filter(
(product) =>
product.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
product.article.toLowerCase().includes(searchQuery.toLowerCase()) ||
product.category?.name
?.toLowerCase()
.includes(searchQuery.toLowerCase()) ||
product.brand?.toLowerCase().includes(searchQuery.toLowerCase())
);
const handleCreateProduct = () => {
setEditingProduct(null);
setIsDialogOpen(true);
};
const handleEditProduct = (product: Product) => {
setEditingProduct(product);
setIsDialogOpen(true);
};
const handleProductSaved = () => {
setIsDialogOpen(false);
setEditingProduct(null);
refetch();
};
const handleProductDeleted = () => {
refetch();
};
if (error) {
return (
<div className="h-screen flex overflow-hidden">
<Sidebar />
<main className="flex-1 ml-56 px-6 py-4 overflow-hidden">
<div className="h-full w-full flex flex-col">
<Card className="flex-1 bg-white/5 backdrop-blur border-white/10 p-6">
<div className="flex items-center justify-center h-full">
<div className="text-center">
<Package className="h-16 w-16 text-white/40 mx-auto mb-4" />
<h3 className="text-lg font-medium text-white mb-2">
Ошибка загрузки
</h3>
<p className="text-white/60 text-sm mb-4">
{error.message || "Не удалось загрузить товары"}
</p>
<Button
onClick={() => refetch()}
className="bg-purple-600 hover:bg-purple-700 text-white"
>
Попробовать снова
</Button>
</div>
</div>
</Card>
</div>
</main>
</div>
);
}
return (
<div className="h-screen flex overflow-hidden">
<Sidebar />
<main
className={`flex-1 ${getSidebarMargin()} px-6 py-4 overflow-hidden transition-all duration-300`}
>
<div className="h-full w-full flex flex-col">
{/* Заголовок и поиск */}
<div className="flex items-center justify-between mb-4 flex-shrink-0">
<div>
<h1 className="text-xl font-bold text-white mb-1">Мой склад</h1>
<p className="text-white/70 text-sm">
Управление товарами и расходниками
</p>
</div>
<div className="flex gap-2">
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
<DialogTrigger asChild>
<Button
onClick={handleCreateProduct}
className="bg-gradient-to-r from-purple-600 to-pink-600 hover:from-purple-700 hover:to-pink-700 text-white border-0 shadow-lg shadow-purple-500/25 transition-all duration-300"
>
<Plus className="w-4 h-4 mr-2" />
Добавить товар/расходник
</Button>
</DialogTrigger>
<DialogContent className="glass-card max-w-4xl max-h-[90vh] overflow-y-auto">
<DialogHeader>
<DialogTitle className="text-white">
{editingProduct
? "Редактировать товар/расходник"
: "Добавить товар/расходник"}
</DialogTitle>
</DialogHeader>
<ProductForm
product={editingProduct}
onSave={handleProductSaved}
onCancel={() => setIsDialogOpen(false)}
/>
</DialogContent>
</Dialog>
</div>
</div>
{/* Поиск */}
<div className="mb-4 flex-shrink-0">
<div className="relative max-w-md">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-white/50" />
<Input
type="text"
placeholder="Поиск по названию, артикулу, категории..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="glass-input text-white placeholder:text-white/50 pl-10 h-10"
/>
</div>
</div>
{/* Основной контент */}
<Card className="flex-1 bg-white/5 backdrop-blur border-white/10 p-6 overflow-hidden">
{loading ? (
<div className="flex items-center justify-center h-full">
<div className="text-center">
<div className="animate-spin rounded-full h-16 w-16 border-4 border-white border-t-transparent mx-auto mb-4"></div>
<p className="text-white/70">Загрузка товаров...</p>
</div>
</div>
) : filteredProducts.length === 0 ? (
<div className="flex items-center justify-center h-full">
<div className="text-center">
<Package className="h-16 w-16 text-white/40 mx-auto mb-4" />
<h3 className="text-lg font-medium text-white mb-2">
{searchQuery ? "Товары не найдены" : "Склад пуст"}
</h3>
<p className="text-white/60 text-sm mb-4">
{searchQuery
? "Попробуйте изменить критерии поиска"
: "Добавьте ваш первый товар на склад"}
</p>
{!searchQuery && (
<Button
onClick={handleCreateProduct}
className="bg-purple-600 hover:bg-purple-700 text-white"
>
<Plus className="w-4 h-4 mr-2" />
Добавить товар
</Button>
)}
</div>
</div>
) : (
<div className="h-full overflow-y-auto">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
{filteredProducts.map((product) => (
<ProductCard
key={product.id}
product={product}
onEdit={handleEditProduct}
onDeleted={handleProductDeleted}
/>
))}
</div>
</div>
)}
</Card>
</div>
</main>
</div>
);
}