Files
sfera/src/components/supplies/create-suppliers/blocks/SuppliersBlock.tsx
Veronika Smirnova 5fd92aebfc 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>
2025-08-13 13:19:11 +03:00

151 lines
5.8 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.

/**
* БЛОК ВЫБОРА ПОСТАВЩИКОВ
*
* Выделен из create-suppliers-supply-page.tsx
* Горизонтальный скролл поставщиков с поиском
*/
'use client'
import { Search } from 'lucide-react'
import React from 'react'
import { OrganizationAvatar } from '@/components/market/organization-avatar'
import { Input } from '@/components/ui/input'
import type { SuppliersBlockProps } from '../types/supply-creation.types'
export const SuppliersBlock = React.memo(function SuppliersBlock({
suppliers,
selectedSupplier,
searchQuery,
loading,
onSupplierSelect,
onSearchChange,
}: SuppliersBlockProps) {
if (loading) {
return (
<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>
)
}
return (
<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>
<div className="relative w-72">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-white/50" />
<Input
placeholder="Поиск по названию или ИНН..."
value={searchQuery}
onChange={(e) => onSearchChange(e.target.value)}
className="glass-input pl-10 h-9 text-sm text-white placeholder:text-white/50"
/>
</div>
</div>
{suppliers.length === 0 ? (
<div className="flex items-center justify-center flex-1">
<div className="text-center">
<div className="text-white/60 text-sm mb-2">
{searchQuery ? 'Поставщики не найдены' : 'Нет доступных поставщиков'}
</div>
{searchQuery && (
<button
onClick={() => onSearchChange('')}
className="text-purple-400 text-xs hover:text-purple-300 transition-colors"
>
Очистить поиск
</button>
)}
</div>
</div>
) : (
<div className="flex-1 overflow-hidden">
<div
className={`h-full ${
suppliers.length <= 4
? 'flex items-start gap-3 px-4'
: 'flex gap-3 overflow-x-auto px-4 pb-2 scrollbar-hide'
}`}
style={{
scrollbarWidth: 'none',
msOverflowStyle: 'none',
}}
>
{suppliers.map((supplier) => (
<div
key={supplier.id}
onClick={() => onSupplierSelect(supplier)}
className={`flex-shrink-0 p-3 rounded-lg cursor-pointer group transition-all duration-200
w-[184px] md:w-[200px] lg:w-[216px] h-[92px]
${
selectedSupplier?.id === supplier.id
? 'bg-green-500/20 border border-green-400/60 shadow-lg ring-1 ring-green-400/30'
: 'bg-white/5 border border-white/10 hover:border-white/20 hover:bg-white/10 hover:shadow-md'
}`}
>
<div className="flex items-start gap-2 h-full">
<div className="flex-shrink-0">
<OrganizationAvatar organization={supplier} size="sm" />
</div>
<div className="flex-1 min-w-0">
<h4 className="text-white font-medium text-sm truncate group-hover:text-white transition-colors">
{supplier.name || supplier.fullName}
</h4>
<p className="text-white/60 text-xs mt-1 truncate">ИНН: {supplier.inn}</p>
{/* Дополнительная информация */}
<div className="mt-2 flex items-center gap-1 flex-wrap">
{supplier.rating && <span className="text-yellow-400 text-xs"> {supplier.rating}</span>}
{supplier.market && (
<span className="text-xs px-1.5 py-0.5 rounded border text-white/70 border-white/20">
{getMarketLabel(supplier.market)}
</span>
)}
</div>
</div>
</div>
</div>
))}
</div>
</div>
)}
{/* Информация о выбранном поставщике */}
{selectedSupplier && (
<div className="mt-4 p-3 bg-green-500/10 border border-green-400/30 rounded-lg">
<div className="flex items-center gap-3">
<div className="w-2 h-2 bg-green-400 rounded-full"></div>
<span className="text-green-300 text-sm font-medium">
Выбран: {selectedSupplier.name || selectedSupplier.fullName}
</span>
{selectedSupplier.address && (
<span className="text-green-300/70 text-xs"> {selectedSupplier.address}</span>
)}
</div>
</div>
)}
</div>
)
})
// Утилитарная функция для меток рынков (временно, потом перенести в хук)
function getMarketLabel(market?: string) {
switch (market) {
case 'wildberries':
return 'WB'
case 'ozon':
return 'OZON'
case 'yandexmarket':
return 'YM'
default:
return 'Универсальный'
}
}