docs: обновление архитектурной документации и модульного рефакторинга

- Обновлен CLAUDE.md с новыми правилами системы
- Дополнен workflow-catalog.md с процессами
- Обновлены interaction-integrity-rules.md
- Завершен модульный рефакторинг create-suppliers компонента
- Добавлен модульный user-settings с блочной архитектурой
- Система готова к следующему этапу архитектурных улучшений

🚀 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Veronika Smirnova
2025-08-13 13:19:11 +03:00
parent 7da70f96e1
commit 5fd92aebfc
24 changed files with 3585 additions and 69 deletions

View File

@ -31,7 +31,8 @@ export const CartBlock = React.memo(function CartBlock({
}: CartBlockProps) {
return (
<div className="w-72 flex-shrink-0">
<div className="bg-white/10 backdrop-blur border-white/20 p-3 sticky top-0 rounded-2xl">
{/* ОТКАТ: было w-96, вернули w-72 */}
<div className="bg-white/10 backdrop-blur border-white/20 p-3 rounded-2xl h-full flex flex-col">
<h3 className="text-white font-semibold mb-3 flex items-center text-sm">
<ShoppingCart className="h-4 w-4 mr-2" />
Корзина ({selectedGoods.length} шт)
@ -47,31 +48,33 @@ export const CartBlock = React.memo(function CartBlock({
</div>
) : (
<>
{/* Список товаров в корзине */}
<div className="space-y-2 mb-4">
{selectedGoods.map((item) => {
const priceWithRecipe = item.price // Здесь будет расчет с рецептурой
{/* Список товаров в корзине - скроллируемая область */}
<div className="flex-1 overflow-y-auto mb-4">
<div className="space-y-2">
{selectedGoods.map((item) => {
const priceWithRecipe = item.price // Здесь будет расчет с рецептурой
return (
<div key={item.id} className="flex items-center justify-between bg-white/5 rounded-lg p-2">
<div className="flex-1 min-w-0">
<h4 className="text-white text-sm font-medium truncate">{item.name}</h4>
<p className="text-white/60 text-xs">
{priceWithRecipe.toLocaleString('ru-RU')} × {item.selectedQuantity}
</p>
return (
<div key={item.id} className="flex items-center justify-between bg-white/5 rounded-lg p-2">
<div className="flex-1 min-w-0">
<h4 className="text-white text-sm font-medium truncate">{item.name}</h4>
<p className="text-white/60 text-xs">
{priceWithRecipe.toLocaleString('ru-RU')} × {item.selectedQuantity}
</p>
</div>
<button
onClick={() => onItemRemove(item.id)}
className="text-white/40 hover:text-red-400 ml-2 transition-colors"
>
<X className="h-3 w-3" />
</button>
</div>
<button
onClick={() => onItemRemove(item.id)}
className="text-white/40 hover:text-red-400 ml-2 transition-colors"
>
<X className="h-3 w-3" />
</button>
</div>
)
})}
)
})}
</div>
</div>
{/* Настройки поставки */}
{/* Настройки поставки - фиксированная область */}
<div className="space-y-3 mb-4">
<div>
<p className="text-white/60 text-xs mb-1">Дата поставки:</p>

View File

@ -43,7 +43,7 @@ export const DetailedCatalogBlock = React.memo(function DetailedCatalogBlock({
const fulfillmentCenters = allCounterparties?.filter((partner) => partner.type === 'FULFILLMENT') || []
return (
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl">
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl h-full flex flex-col">
{/* Панель управления */}
<div className="p-6 border-b border-white/10">
<h3 className="text-white font-semibold text-lg mb-4 flex items-center">
@ -89,7 +89,7 @@ export const DetailedCatalogBlock = React.memo(function DetailedCatalogBlock({
</div>
{/* Каталог товаров с рецептурой */}
<div className="p-6">
<div className="flex-1 overflow-y-auto p-6">
<h4 className="text-white font-semibold text-md mb-4">Товары в поставке ({allSelectedProducts.length})</h4>
{allSelectedProducts.length === 0 ? (

View File

@ -22,7 +22,8 @@ export const ProductCardsBlock = React.memo(function ProductCardsBlock({
}: ProductCardsBlockProps) {
if (!selectedSupplier) {
return (
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl p-6">
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl p-6 h-full flex flex-col">
{/* ОТКАТ: вернули h-full flex flex-col */}
<div className="text-center py-8">
<div className="bg-gradient-to-br from-blue-500/20 to-purple-500/20 rounded-full p-4 w-fit mx-auto mb-3">
<Package className="h-8 w-8 text-blue-300" />
@ -36,7 +37,8 @@ export const ProductCardsBlock = React.memo(function ProductCardsBlock({
if (products.length === 0) {
return (
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl p-6">
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl p-6 h-full flex flex-col">
{/* ОТКАТ: вернули h-full flex flex-col */}
<h3 className="text-white font-semibold text-lg mb-4">2. Товары поставщика (0)</h3>
<div className="text-center py-8">
<div className="bg-gradient-to-br from-orange-500/20 to-red-500/20 rounded-full p-4 w-fit mx-auto mb-3">
@ -50,10 +52,12 @@ export const ProductCardsBlock = React.memo(function ProductCardsBlock({
}
return (
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl p-6">
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl p-6 h-full flex flex-col">
{/* ОТКАТ: вернули h-full flex flex-col */}
<h3 className="text-white font-semibold text-lg mb-4">2. Товары поставщика ({products.length})</h3>
<div className="overflow-x-auto">
<div className="flex-1 overflow-x-auto overflow-y-hidden">
{/* ОТКАТ: вернули flex-1 overflow-x-auto overflow-y-hidden */}
<div className="flex gap-3 pb-2" style={{ width: 'max-content' }}>
{products.slice(0, 10).map(
(

View File

@ -25,8 +25,8 @@ export const SuppliersBlock = React.memo(function SuppliersBlock({
}: SuppliersBlockProps) {
if (loading) {
return (
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl p-6">
<div className="flex items-center justify-center h-44">
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl p-6 h-full flex flex-col">
<div className="flex items-center justify-center flex-1">
<div className="text-white/60 text-sm">Загрузка поставщиков...</div>
</div>
</div>
@ -34,7 +34,7 @@ export const SuppliersBlock = React.memo(function SuppliersBlock({
}
return (
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl p-6">
<div className="bg-white/10 backdrop-blur-xl border border-white/20 rounded-2xl p-6 h-full flex flex-col">
{/* Заголовок и поиск */}
<div className="flex items-center justify-between mb-4">
<h3 className="text-white font-semibold text-lg">1. Выберите поставщика ({suppliers.length})</h3>
@ -50,7 +50,7 @@ export const SuppliersBlock = React.memo(function SuppliersBlock({
</div>
{suppliers.length === 0 ? (
<div className="flex items-center justify-center h-44">
<div className="flex items-center justify-center flex-1">
<div className="text-center">
<div className="text-white/60 text-sm mb-2">
{searchQuery ? 'Поставщики не найдены' : 'Нет доступных поставщиков'}
@ -66,7 +66,7 @@ export const SuppliersBlock = React.memo(function SuppliersBlock({
</div>
</div>
) : (
<div className="h-44 overflow-hidden">
<div className="flex-1 overflow-hidden">
<div
className={`h-full ${
suppliers.length <= 4

View File

@ -7,7 +7,7 @@
import { useMutation } from '@apollo/client'
import { useRouter } from 'next/navigation'
import { useState, useMemo } from 'react'
import { useState, useMemo, useCallback } from 'react'
import { toast } from 'sonner'
import { CREATE_SUPPLY_ORDER } from '@/graphql/mutations'

View File

@ -191,24 +191,30 @@ export function CreateSuppliersSupplyPage() {
<div className="flex-1 flex gap-2 min-h-0">
{/* ЛЕВАЯ КОЛОНКА - 3 блока */}
<div className="flex-1 flex flex-col gap-2 min-h-0">
{/* БЛОК 1: ВЫБОР ПОСТАВЩИКОВ */}
<SuppliersBlock
suppliers={suppliers}
selectedSupplier={selectedSupplier}
searchQuery={searchQuery}
loading={suppliersLoading}
onSupplierSelect={handleSupplierSelect}
onSearchChange={setSearchQuery}
/>
{/* БЛОК 1: ВЫБОР ПОСТАВЩИКОВ - Фиксированная высота */}
<div className="h-48">
{/* ОТКАТ: было h-44, вернули h-48 */}
<SuppliersBlock
suppliers={suppliers}
selectedSupplier={selectedSupplier}
searchQuery={searchQuery}
loading={suppliersLoading}
onSupplierSelect={handleSupplierSelect}
onSearchChange={setSearchQuery}
/>
</div>
{/* БЛОК 2: КАРТОЧКИ ТОВАРОВ (МИНИ-ПРЕВЬЮ) */}
<ProductCardsBlock
products={products}
selectedSupplier={selectedSupplier}
onProductAdd={handleProductAdd}
/>
{/* БЛОК 2: КАРТОЧКИ ТОВАРОВ (МИНИ-ПРЕВЬЮ) - Фиксированная высота */}
<div className="h-72">
{/* ОТКАТ: было flex-shrink-0, вернули h-72 */}
<ProductCardsBlock
products={products}
selectedSupplier={selectedSupplier}
onProductAdd={handleProductAdd}
/>
</div>
{/* БЛОК 3: ДЕТАЛЬНЫЙ КАТАЛОГ С РЕЦЕПТУРОЙ */}
{/* БЛОК 3: ДЕТАЛЬНЫЙ КАТАЛОГ С РЕЦЕПТУРОЙ - Оставшееся место */}
<div className="flex-1 min-h-0">
<DetailedCatalogBlock
allSelectedProducts={allSelectedProducts}