Files
no-copy-frontend/src/app/ui/violations/violations-last-combined-cases.tsx
T

242 lines
6.4 KiB
TypeScript

'use client';
import { useLastComplaints } from '@/app/hooks/react-query/useLastComplaints';
import { useLastCases } from '@/app/hooks/react-query/useLastCases';
import { formatDate, formatDateTime } from '@/app/lib/formatDate';
import { useTranslations } from 'next-intl';
import { useEffect, useState, useRef } from 'react';
import { Swiper, SwiperSlide } from 'swiper/react';
import { Navigation, Pagination } from 'swiper/modules';
import { IconEye } from '@/app/ui/icons/icons';
import Link from 'next/link';
type FilterState = {
complaints: boolean;
claims: boolean;
};
export default function ViolationsLastCombinedCases() {
const swiperRef = useRef(null);
const t = useTranslations('Global');
const [filters, setFilters] = useState<FilterState>({
complaints: true,
claims: true,
});
const { data: dataComplaint } = useLastComplaints({
page: 1,
size: 5,
sort_by: 'createdAt',
sort_direction: 'desc'
});
const { data: dataCases } = useLastCases({
page: 1,
size: 5,
sort_by: 'createdAt',
sort_direction: 'desc'
});
const getCombinedItems = () => {
const complaints = (dataComplaint?.content || []).map(item => ({
...item,
type: 'complaint' as const,
displayId: `COM-${item.id}`,
title: item.complaint_text,
status: item.status,
createdAt: item.created_at,
updatedAt: item.updated_at,
lawyer: null,
}));
const claims = (dataCases?.content || []).map(item => ({
...item,
type: 'claim' as const,
displayId: item.name,
title: item.description,
status: item.type,
createdAt: item.created_at,
updatedAt: item.updated_at,
lawyer: item.lawyer,
}));
let combined = [...complaints, ...claims];
combined.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
return combined;
};
const getFilteredItems = () => {
const allItems = getCombinedItems();
return allItems.filter(item => {
if (item.type === 'complaint') return filters.complaints;
if (item.type === 'claim') return filters.claims;
return false;
});
};
const toggleFilter = (filterType: 'complaints' | 'claims') => {
if (filters.claims && !filters.complaints && filterType === 'claims') {
return
}
if (!filters.claims && filters.complaints && filterType === 'complaints') {
return
}
setFilters(prev => ({
...prev,
[filterType]: !prev[filterType]
}));
};
const filteredItems = getFilteredItems();
const MAX_VISIBLE_ITEMS = 5;
const getSlidesPerView = () => {
if (!filteredItems || filteredItems.length === 0) return 1;
return Math.min(MAX_VISIBLE_ITEMS, filteredItems.length);
};
const slidesPerViewCount = getSlidesPerView();
const swiperSettings = {
modules: [Navigation, Pagination],
breakpoints: {
0: {
slidesPerView: Math.min(slidesPerViewCount, 1),
spaceBetween: 20,
},
768: {
slidesPerView: Math.min(slidesPerViewCount, 2),
spaceBetween: 30,
},
1024: {
slidesPerView: Math.min(slidesPerViewCount, 3),
spaceBetween: 30,
},
1792: {
slidesPerView: slidesPerViewCount,
spaceBetween: 30,
}
},
loop: filteredItems.length > 3,
pagination: {
el: '.custom-pagination-container', // Кастомный контейнер для пагинации
clickable: true,
},
onSwiper: (swiper: any) => {
swiperRef.current = swiper;
}
};
const isLoading = (!dataComplaint || !dataCases);
if (isLoading) {
return (
<div className="violations-my-cases-section">
<div className="my-cases-header">
<h3 className="my-cases-title">
{t('recent-cases')}
</h3>
<div className="my-cases-tabs">
<button className="tab-button tab-button-complaints">
{t('complaints')}
</button>
<button className="tab-button tab-button-claims">
{t('claims')}
</button>
</div>
</div>
<div className="cases-carousel-track">
<div className="loading-animation">
<div className="global-spinner"></div>
</div>
</div>
</div>
);
}
const isAllSelected = filters.complaints && filters.claims;
const isNothingSelected = !filters.complaints && !filters.claims;
return (
<div className="violations-my-cases-section">
<div className="my-cases-header">
<h3 className="my-cases-title">
{t('recent-cases')}
</h3>
<div className="my-cases-tabs">
<button
className={`tab-button tab-button-complaints ${filters.complaints ? 'active' : ''}`}
onClick={() => toggleFilter('complaints')}
>
{t('complaints')}
</button>
<button
className={`tab-button tab-button-claims ${filters.claims ? 'active' : ''}`}
onClick={() => toggleFilter('claims')}
>
{t('claims')}
</button>
</div>
</div>
<div className="cases-carousel-track">
{isNothingSelected ? (
<div className="empty-state">
{t('select-at-least-one-filter')}
</div>
) : filteredItems.length === 0 ? (
<div className="empty-state">
{t('no-claims-complaints-found')}
</div>
) : (
<Swiper {...swiperSettings}>
{filteredItems.map((item) => (
<SwiperSlide key={`${item.type}-${item.id}`}>
<div className="case-card">
<div className="case-card-header">
<div className="case-number">
{item.displayId}
</div>
<span className="case-status-badge status-submitted">
{item.status}
</span>
</div>
<div className="case-card-meta">
<div>
<strong>{t('date-of-creation')}:</strong> {item.createdAt ? `${formatDate(item.createdAt)} ${formatDateTime(item.createdAt)}` : '---'}
</div>
<div>
<strong>{t('date-of-update')}:</strong> {item.updatedAt ? `${formatDate(item.updatedAt)} ${formatDateTime(item.updatedAt)}` : '---'}
</div>
{item.type === 'claim' && (
<div>
<strong>{t('lawyer')}: </strong>
<span style={{ color: '#f59e0b' }}>{item.lawyer ? item.lawyer : t('not-assigned')}</span>
</div>
)}
</div>
<Link
href={`/pages/file/${item.file_id}?violationId=${item.violation_id}&caseType=${item.type}`}
className="mt-auto"
title={t('view')}
>
<IconEye />
</Link>
</div>
</SwiperSlide>
))}
</Swiper>
)}
</div>
{!isNothingSelected && filteredItems.length > 0 && (
<div className="custom-pagination-container text-center"></div>
)}
</div>
);
}