Files
han-app/VM1_app/figma/src/app/pages/Calendar.tsx
T

243 lines
8.4 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.
import { ArrowLeft, CheckCircle, Clock, Info, Calendar as CalendarIcon, MapPin, Briefcase, FileText, Globe, Home } from 'lucide-react';
import { useNavigate } from 'react-router';
import * as Tooltip from '@radix-ui/react-tooltip';
interface ClientData {
icon: React.ReactNode;
label: string;
value: string;
}
interface Obligation {
id: string;
title: string;
status: 'completed' | 'deadline' | 'pending' | 'info';
statusText?: string;
tooltip?: string;
}
const clientData: ClientData[] = [
{
icon: <Globe className="w-4 h-4" />,
label: 'Гражданство',
value: 'Узбекистан'
},
{
icon: <Briefcase className="w-4 h-4" />,
label: 'Цель визита',
value: 'Работа'
},
{
icon: <FileText className="w-4 h-4" />,
label: 'Основание пребывания',
value: 'Миграционная карта'
},
{
icon: <CalendarIcon className="w-4 h-4" />,
label: 'Дата въезда в РФ',
value: '15.03.2026'
},
{
icon: <MapPin className="w-4 h-4" />,
label: 'Регион РФ',
value: 'Москва'
},
];
const currentObligations: Obligation[] = [
{
id: '1',
title: 'Уведомление о прибытии',
status: 'completed',
statusText: 'Выполнено'
},
{
id: '2',
title: 'Заявление на патент',
status: 'deadline',
statusText: 'Осталось 5 дней'
},
{
id: '3',
title: 'Уведомление о работе',
status: 'pending',
statusText: 'После получения патента'
},
{
id: '4',
title: 'Оплатить НДФЛ',
status: 'deadline',
statusText: 'Осталось 3 дня'
},
];
const situationalObligations: Obligation[] = [
{
id: '1',
title: 'Смена места жительства',
status: 'info',
tooltip: 'При смене места жительства необходимо уведомить МВД в течение пяти рабочих дней'
},
];
function ObligationItem({ obligation }: { obligation: Obligation }) {
const getStatusStyles = () => {
switch (obligation.status) {
case 'completed':
return {
icon: <CheckCircle className="w-5 h-5" />,
bgColor: 'bg-green-500/10',
textColor: 'text-green-600',
badgeColor: 'bg-green-500/10 text-green-600'
};
case 'deadline':
return {
icon: <Clock className="w-5 h-5" />,
bgColor: 'bg-red-500/10',
textColor: 'text-red-600',
badgeColor: 'bg-red-500/10 text-red-600'
};
case 'pending':
return {
icon: <Clock className="w-5 h-5" />,
bgColor: 'bg-yellow-500/10',
textColor: 'text-yellow-600',
badgeColor: 'bg-yellow-500/10 text-yellow-600'
};
case 'info':
return {
icon: <Info className="w-5 h-5" />,
bgColor: 'bg-blue-500/10',
textColor: 'text-blue-600',
badgeColor: 'bg-blue-500/10 text-blue-600'
};
default:
return {
icon: <Clock className="w-5 h-5" />,
bgColor: 'bg-muted',
textColor: 'text-muted-foreground',
badgeColor: 'bg-muted text-muted-foreground'
};
}
};
const styles = getStatusStyles();
return (
<div className="p-3 flex items-center gap-3 border-b border-border last:border-b-0">
<div className={`flex items-center justify-center w-9 h-9 rounded-full flex-shrink-0 ${styles.bgColor} ${styles.textColor}`}>
{styles.icon}
</div>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium">{obligation.title}</p>
{obligation.statusText && (
<p className="text-xs text-muted-foreground mt-0.5">{obligation.statusText}</p>
)}
</div>
{obligation.tooltip ? (
<Tooltip.Provider delayDuration={200}>
<Tooltip.Root>
<Tooltip.Trigger asChild>
<button className={`flex items-center justify-center w-8 h-8 rounded-full ${styles.bgColor} ${styles.textColor}`}>
<Info className="w-4 h-4" />
</button>
</Tooltip.Trigger>
<Tooltip.Portal>
<Tooltip.Content
className="max-w-[280px] bg-popover text-popover-foreground border border-border rounded-lg px-3 py-2 text-sm shadow-lg z-50"
sideOffset={5}
>
{obligation.tooltip}
<Tooltip.Arrow className="fill-border" />
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip.Root>
</Tooltip.Provider>
) : obligation.statusText ? (
<span className={`text-xs font-medium px-2 py-1 rounded-full ${styles.badgeColor}`}>
{obligation.statusText}
</span>
) : null}
</div>
);
}
export function Calendar() {
const navigate = useNavigate();
return (
<div className="flex-1 overflow-y-auto">
<div className="px-4 py-4">
{/* Заголовок */}
<div className="flex items-center gap-3 mb-6">
<button
onClick={() => navigate('/profile')}
className="flex items-center justify-center w-9 h-9 rounded-full hover:bg-muted transition-colors"
aria-label="Назад"
>
<ArrowLeft className="w-5 h-5" />
</button>
<div>
<h1 className="text-xl font-medium">Календарь обязательств</h1>
<p className="text-sm text-muted-foreground">Важные даты и действия</p>
</div>
</div>
{/* Блок 1: Данные о клиенте */}
<div className="mb-4">
<h2 className="text-xs font-medium text-muted-foreground mb-2 px-1">Данные о пребывании</h2>
<div className="bg-muted/30 border border-border/50 rounded-lg p-3">
<div className="grid grid-cols-2 gap-2 text-xs">
{clientData.map((item, index) => (
<div key={index} className="flex items-center gap-1.5">
<div className="text-muted-foreground flex-shrink-0">
{item.icon}
</div>
<div className="flex-1 min-w-0">
<p className="text-muted-foreground truncate">{item.label}:</p>
<p className="font-medium truncate">{item.value}</p>
</div>
</div>
))}
</div>
</div>
</div>
{/* Блок 2: Текущие обязательства */}
<div className="mb-6">
<h2 className="text-sm font-medium text-muted-foreground mb-3 px-1">Текущие обязательства</h2>
<div className="bg-card border border-border rounded-lg">
{currentObligations.map((obligation) => (
<ObligationItem key={obligation.id} obligation={obligation} />
))}
</div>
</div>
{/* Блок 3: Ситуационные обязательства */}
<div className="mb-6">
<h2 className="text-sm font-medium text-muted-foreground mb-3 px-1">Ситуационные обязательства</h2>
<div className="bg-card border border-border rounded-lg">
{situationalObligations.map((obligation) => (
<ObligationItem key={obligation.id} obligation={obligation} />
))}
</div>
<p className="text-xs text-muted-foreground mt-2 px-1">
Нажмите на значок <Info className="w-3 h-3 inline" /> для получения подробной информации
</p>
</div>
{/* Информационное сообщение */}
<div className="bg-blue-500/10 border border-blue-500/20 rounded-lg p-4 flex gap-3">
<Info className="w-5 h-5 text-blue-600 flex-shrink-0 mt-0.5" />
<div className="flex-1">
<p className="text-sm font-medium text-blue-900 mb-1">Важная информация</p>
<p className="text-xs text-blue-800">
Календарь обязательств помогает следить за важными сроками. Мы автоматически напомним вам о приближающихся датах.
</p>
</div>
</div>
</div>
</div>
);
}