Files
sfera/src/components/market/organization-details-modal.tsx

431 lines
16 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 { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import { Card } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { Separator } from '@/components/ui/separator'
import {
Building2,
Phone,
Mail,
MapPin,
Calendar,
FileText,
Users,
CreditCard,
Hash,
User,
Briefcase
} from 'lucide-react'
import { OrganizationAvatar } from './organization-avatar'
interface User {
id: string
avatar?: string | null
phone: string
createdAt: string
}
interface ApiKey {
id: string
marketplace: string
isActive: boolean
createdAt: string
}
interface Organization {
id: string
inn: string
kpp?: string | null
name?: string | null
fullName?: string | null
type: 'FULFILLMENT' | 'SELLER' | 'LOGIST' | 'WHOLESALE'
address?: string | null
addressFull?: string | null
ogrn?: string | null
ogrnDate?: string | null
status?: string | null
actualityDate?: string | null
registrationDate?: string | null
liquidationDate?: string | null
managementName?: string | null
managementPost?: string | null
opfCode?: string | null
opfFull?: string | null
opfShort?: string | null
okato?: string | null
oktmo?: string | null
okpo?: string | null
okved?: string | null
employeeCount?: number | null
revenue?: string | null
taxSystem?: string | null
phones?: Array<{ value: string }> | null
emails?: Array<{ value: string }> | null
users?: User[]
apiKeys?: ApiKey[]
createdAt: string
}
interface OrganizationDetailsModalProps {
organization: Organization | null
open: boolean
onOpenChange: (open: boolean) => void
}
function formatDate(dateString?: string | null): string {
if (!dateString) return 'Не указана'
try {
let date: Date
// Проверяем, является ли строка числом (Unix timestamp)
if (/^\d+$/.test(dateString)) {
// Если это Unix timestamp в миллисекундах
const timestamp = parseInt(dateString, 10)
date = new Date(timestamp)
} else {
// Обычная строка даты
date = new Date(dateString)
}
if (isNaN(date.getTime())) {
return 'Не указана'
}
return date.toLocaleDateString('ru-RU', {
year: 'numeric',
month: 'long',
day: 'numeric'
})
} catch (error) {
return 'Не указана'
}
}
function getTypeLabel(type: string): string {
switch (type) {
case 'FULFILLMENT':
return 'Фулфилмент'
case 'SELLER':
return 'Селлер'
case 'LOGIST':
return 'Логистика'
case 'WHOLESALE':
return 'Оптовик'
default:
return type
}
}
function getTypeColor(type: string): string {
switch (type) {
case 'FULFILLMENT':
return 'bg-blue-500/20 text-blue-300 border-blue-500/30'
case 'SELLER':
return 'bg-green-500/20 text-green-300 border-green-500/30'
case 'LOGIST':
return 'bg-orange-500/20 text-orange-300 border-orange-500/30'
case 'WHOLESALE':
return 'bg-purple-500/20 text-purple-300 border-purple-500/30'
default:
return 'bg-gray-500/20 text-gray-300 border-gray-500/30'
}
}
export function OrganizationDetailsModal({ organization, open, onOpenChange }: OrganizationDetailsModalProps) {
if (!organization) return null
const displayName = organization.name || organization.fullName || 'Неизвестная организация'
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto bg-black/90 backdrop-blur-xl border border-white/20">
<DialogHeader>
<DialogTitle className="flex items-center space-x-4 text-white">
<OrganizationAvatar organization={organization} size="lg" />
<div>
<h2 className="text-xl font-semibold">{displayName}</h2>
<Badge className={getTypeColor(organization.type)}>
{getTypeLabel(organization.type)}
</Badge>
</div>
</DialogTitle>
</DialogHeader>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* Основная информация */}
<Card className="glass-card p-4">
<h3 className="text-lg font-semibold text-white mb-4 flex items-center">
<Building2 className="h-5 w-5 mr-2 text-blue-400" />
Основная информация
</h3>
<div className="space-y-3">
<div className="flex justify-between">
<span className="text-white/60">ИНН:</span>
<span className="text-white font-mono">{organization.inn}</span>
</div>
{organization.kpp && (
<div className="flex justify-between">
<span className="text-white/60">КПП:</span>
<span className="text-white font-mono">{organization.kpp}</span>
</div>
)}
{organization.ogrn && (
<div className="flex justify-between">
<span className="text-white/60">ОГРН:</span>
<span className="text-white font-mono">{organization.ogrn}</span>
</div>
)}
{organization.status && (
<div className="flex justify-between">
<span className="text-white/60">Статус:</span>
<span className="text-white">{organization.status}</span>
</div>
)}
<div className="flex justify-between">
<span className="text-white/60">Дата регистрации:</span>
<span className="text-white">{formatDate(organization.registrationDate)}</span>
</div>
</div>
</Card>
{/* Контактная информация */}
<Card className="glass-card p-4">
<h3 className="text-lg font-semibold text-white mb-4 flex items-center">
<Phone className="h-5 w-5 mr-2 text-green-400" />
Контакты
</h3>
<div className="space-y-3">
{organization.phones && organization.phones.length > 0 && (
<div>
<div className="text-white/60 text-sm mb-2">Телефоны:</div>
{organization.phones.map((phone, index) => (
<div key={index} className="flex items-center text-white">
<Phone className="h-3 w-3 mr-2 text-green-400" />
{phone.value}
</div>
))}
</div>
)}
{organization.emails && organization.emails.length > 0 && (
<div>
<div className="text-white/60 text-sm mb-2">Email:</div>
{organization.emails.map((email, index) => (
<div key={index} className="flex items-center text-white">
<Mail className="h-3 w-3 mr-2 text-blue-400" />
{email.value}
</div>
))}
</div>
)}
{organization.address && (
<div>
<div className="text-white/60 text-sm mb-2">Адрес:</div>
<div className="flex items-start text-white">
<MapPin className="h-3 w-3 mr-2 mt-1 text-orange-400 flex-shrink-0" />
<span className="text-sm">{organization.addressFull || organization.address}</span>
</div>
</div>
)}
</div>
</Card>
{/* Руководство */}
{organization.managementName && (
<Card className="glass-card p-4">
<h3 className="text-lg font-semibold text-white mb-4 flex items-center">
<User className="h-5 w-5 mr-2 text-purple-400" />
Руководство
</h3>
<div className="space-y-3">
<div className="flex justify-between">
<span className="text-white/60">Руководитель:</span>
<span className="text-white">{organization.managementName}</span>
</div>
{organization.managementPost && (
<div className="flex justify-between">
<span className="text-white/60">Должность:</span>
<span className="text-white">{organization.managementPost}</span>
</div>
)}
</div>
</Card>
)}
{/* Организационно-правовая форма */}
{organization.opfFull && (
<Card className="glass-card p-4">
<h3 className="text-lg font-semibold text-white mb-4 flex items-center">
<FileText className="h-5 w-5 mr-2 text-yellow-400" />
ОПФ
</h3>
<div className="space-y-3">
<div className="flex justify-between">
<span className="text-white/60">Полное название:</span>
<span className="text-white">{organization.opfFull}</span>
</div>
{organization.opfShort && (
<div className="flex justify-between">
<span className="text-white/60">Краткое название:</span>
<span className="text-white">{organization.opfShort}</span>
</div>
)}
{organization.opfCode && (
<div className="flex justify-between">
<span className="text-white/60">Код ОКОПФ:</span>
<span className="text-white font-mono">{organization.opfCode}</span>
</div>
)}
</div>
</Card>
)}
{/* Коды статистики */}
{(organization.okato || organization.oktmo || organization.okpo || organization.okved) && (
<Card className="glass-card p-4">
<h3 className="text-lg font-semibold text-white mb-4 flex items-center">
<Hash className="h-5 w-5 mr-2 text-cyan-400" />
Коды статистики
</h3>
<div className="space-y-3">
{organization.okato && (
<div className="flex justify-between">
<span className="text-white/60">ОКАТО:</span>
<span className="text-white font-mono">{organization.okato}</span>
</div>
)}
{organization.oktmo && (
<div className="flex justify-between">
<span className="text-white/60">ОКТМО:</span>
<span className="text-white font-mono">{organization.oktmo}</span>
</div>
)}
{organization.okpo && (
<div className="flex justify-between">
<span className="text-white/60">ОКПО:</span>
<span className="text-white font-mono">{organization.okpo}</span>
</div>
)}
{organization.okved && (
<div className="flex justify-between">
<span className="text-white/60">Основной ОКВЭД:</span>
<span className="text-white font-mono">{organization.okved}</span>
</div>
)}
</div>
</Card>
)}
{/* Финансовая информация */}
{(organization.employeeCount || organization.revenue || organization.taxSystem) && (
<Card className="glass-card p-4">
<h3 className="text-lg font-semibold text-white mb-4 flex items-center">
<CreditCard className="h-5 w-5 mr-2 text-emerald-400" />
Финансовая информация
</h3>
<div className="space-y-3">
{organization.employeeCount && (
<div className="flex justify-between">
<span className="text-white/60">Сотрудников:</span>
<span className="text-white">{organization.employeeCount}</span>
</div>
)}
{organization.revenue && (
<div className="flex justify-between">
<span className="text-white/60">Выручка:</span>
<span className="text-white">{organization.revenue}</span>
</div>
)}
{organization.taxSystem && (
<div className="flex justify-between">
<span className="text-white/60">Налоговая система:</span>
<span className="text-white">{organization.taxSystem}</span>
</div>
)}
</div>
</Card>
)}
{/* Пользователи */}
{organization.users && organization.users.length > 0 && (
<Card className="glass-card p-4">
<h3 className="text-lg font-semibold text-white mb-4 flex items-center">
<Users className="h-5 w-5 mr-2 text-indigo-400" />
Пользователи ({organization.users.length})
</h3>
<div className="space-y-3">
{organization.users.map((user, index) => (
<div key={user.id} className="flex items-center justify-between">
<div className="flex items-center space-x-3">
<OrganizationAvatar
organization={{
id: user.id,
users: [user]
}}
size="sm"
/>
<span className="text-white">{user.phone}</span>
</div>
<span className="text-white/60 text-sm">
{formatDate(user.createdAt)}
</span>
</div>
))}
</div>
</Card>
)}
{/* API ключи */}
{organization.apiKeys && organization.apiKeys.length > 0 && (
<Card className="glass-card p-4">
<h3 className="text-lg font-semibold text-white mb-4 flex items-center">
<Briefcase className="h-5 w-5 mr-2 text-pink-400" />
API ключи маркетплейсов
</h3>
<div className="space-y-3">
{organization.apiKeys.map((apiKey, index) => (
<div key={apiKey.id} className="flex items-center justify-between">
<div className="flex items-center space-x-3">
<Badge className={apiKey.isActive ? 'bg-green-500/20 text-green-300 border-green-500/30' : 'bg-red-500/20 text-red-300 border-red-500/30'}>
{apiKey.marketplace}
</Badge>
<span className="text-white/60 text-sm">
{apiKey.isActive ? 'Активен' : 'Неактивен'}
</span>
</div>
<span className="text-white/60 text-sm">
{formatDate(apiKey.createdAt)}
</span>
</div>
))}
</div>
</Card>
)}
</div>
</DialogContent>
</Dialog>
)
}