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

@ -0,0 +1,123 @@
import { Building2, RefreshCw, MapPin } from 'lucide-react'
import React, { memo } from 'react'
import { Button } from '@/components/ui/button'
import { Card } from '@/components/ui/card'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import type { OrganizationBlockProps } from '../types/user-settings.types'
export const OrganizationBlock = memo<OrganizationBlockProps>(
({ formData, setFormData, isEditing, onDaDataSearch }) => {
const handleInputChange = (field: keyof typeof formData, value: string) => {
setFormData({
...formData,
[field]: value,
})
}
const handleInnChange = (value: string) => {
// Удаляем все кроме цифр
const cleanInn = value.replace(/\D/g, '').slice(0, 12)
handleInputChange('inn', cleanInn)
}
const handleDaDataClick = async () => {
if (formData.inn && formData.inn.length >= 10) {
await onDaDataSearch(formData.inn)
}
}
const isDaDataAvailable = formData.inn && formData.inn.length >= 10
return (
<Card className="glass-card p-6">
<div className="flex items-center space-x-3 mb-6">
<div className="w-10 h-10 bg-green-500/20 rounded-lg flex items-center justify-center">
<Building2 className="w-5 h-5 text-green-500" />
</div>
<h3 className="text-lg font-semibold text-foreground">Данные организации</h3>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<Label htmlFor="inn" className="text-sm font-medium text-foreground">
ИНН
</Label>
<div className="flex space-x-2">
<Input
id="inn"
type="text"
placeholder="1234567890"
value={formData.inn}
onChange={(e) => handleInnChange(e.target.value)}
disabled={!isEditing}
className="flex-1"
maxLength={12}
/>
{isEditing && isDaDataAvailable && (
<Button
type="button"
variant="outline"
size="sm"
onClick={handleDaDataClick}
className="px-3"
title="Заполнить данные из ИНН"
>
<RefreshCw className="w-4 h-4" />
</Button>
)}
</div>
{isEditing && formData.inn && formData.inn.length > 0 && formData.inn.length < 10 && (
<p className="text-xs text-muted-foreground">ИНН должен содержать от 10 до 12 цифр</p>
)}
</div>
<div className="space-y-2">
<Label htmlFor="orgName" className="text-sm font-medium text-foreground">
Название организации
</Label>
<Input
id="orgName"
type="text"
placeholder="ООО Название"
value={formData.orgName}
onChange={(e) => handleInputChange('orgName', e.target.value)}
disabled={!isEditing}
className="w-full"
/>
</div>
<div className="space-y-2 md:col-span-2">
<Label htmlFor="address" className="text-sm font-medium text-foreground">
<div className="flex items-center space-x-2">
<MapPin className="w-4 h-4" />
<span>Адрес</span>
</div>
</Label>
<Input
id="address"
type="text"
placeholder="г. Москва, ул. Примерная, д. 1"
value={formData.address}
onChange={(e) => handleInputChange('address', e.target.value)}
disabled={!isEditing}
className="w-full"
/>
</div>
</div>
{isEditing && isDaDataAvailable && (
<div className="mt-4 p-3 bg-blue-500/10 border border-blue-500/20 rounded-lg">
<p className="text-xs text-blue-600 dark:text-blue-400">
💡 Нажмите кнопку обновления рядом с ИНН, чтобы автоматически заполнить данные организации
</p>
</div>
)}
</Card>
)
},
)
OrganizationBlock.displayName = 'OrganizationBlock'