feat: improve date handling in UI
- Change date format to DD/MM/YYYY in log list - Add prev/next day buttons in add log modal - Remember last selected date between modal opens
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect, useRef } from 'react';
|
||||||
import { format, parseISO } from 'date-fns';
|
import { format, parseISO, addDays, subDays } from 'date-fns';
|
||||||
import type { TimeLog } from '../hooks/useLogs';
|
import type { TimeLog } from '../hooks/useLogs';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -16,12 +16,16 @@ function formatTimeForInput(hours: number, mins: number): string {
|
|||||||
return `${hours}:${String(mins).padStart(2, '0')}`;
|
return `${hours}:${String(mins).padStart(2, '0')}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store last used date outside component to persist between modal opens
|
||||||
|
let lastUsedDate: string | null = null;
|
||||||
|
|
||||||
export function AddLogModal({ isOpen, onClose, onSave, editingLog }: Props) {
|
export function AddLogModal({ isOpen, onClose, onSave, editingLog }: Props) {
|
||||||
const [date, setDate] = useState(format(new Date(), 'yyyy-MM-dd'));
|
const [date, setDate] = useState(format(new Date(), 'yyyy-MM-dd'));
|
||||||
const [time, setTime] = useState('8');
|
const [time, setTime] = useState('8');
|
||||||
const [description, setDescription] = useState('');
|
const [description, setDescription] = useState('');
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const initializedRef = useRef(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
@@ -30,14 +34,25 @@ export function AddLogModal({ isOpen, onClose, onSave, editingLog }: Props) {
|
|||||||
setTime(formatTimeForInput(editingLog.hours, editingLog.mins));
|
setTime(formatTimeForInput(editingLog.hours, editingLog.mins));
|
||||||
setDescription(editingLog.description);
|
setDescription(editingLog.description);
|
||||||
} else {
|
} else {
|
||||||
setDate(format(new Date(), 'yyyy-MM-dd'));
|
// Use last used date or today
|
||||||
|
setDate(lastUsedDate || format(new Date(), 'yyyy-MM-dd'));
|
||||||
setTime('8');
|
setTime('8');
|
||||||
setDescription('');
|
setDescription('');
|
||||||
}
|
}
|
||||||
setError('');
|
setError('');
|
||||||
|
initializedRef.current = true;
|
||||||
|
} else {
|
||||||
|
initializedRef.current = false;
|
||||||
}
|
}
|
||||||
}, [isOpen, editingLog]);
|
}, [isOpen, editingLog]);
|
||||||
|
|
||||||
|
// Save date when it changes (but not on initial load)
|
||||||
|
useEffect(() => {
|
||||||
|
if (initializedRef.current && !editingLog) {
|
||||||
|
lastUsedDate = date;
|
||||||
|
}
|
||||||
|
}, [date, editingLog]);
|
||||||
|
|
||||||
if (!isOpen) return null;
|
if (!isOpen) return null;
|
||||||
|
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
@@ -59,6 +74,18 @@ export function AddLogModal({ isOpen, onClose, onSave, editingLog }: Props) {
|
|||||||
setTime(value);
|
setTime(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handlePrevDay = () => {
|
||||||
|
const currentDate = parseISO(date);
|
||||||
|
setDate(format(subDays(currentDate, 1), 'yyyy-MM-dd'));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNextDay = () => {
|
||||||
|
const currentDate = parseISO(date);
|
||||||
|
setDate(format(addDays(currentDate, 1), 'yyyy-MM-dd'));
|
||||||
|
};
|
||||||
|
|
||||||
|
const displayDate = format(parseISO(date), 'dd/MM/yyyy');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||||
<div className="bg-white rounded-lg p-6 w-full max-w-md mx-4">
|
<div className="bg-white rounded-lg p-6 w-full max-w-md mx-4">
|
||||||
@@ -71,13 +98,40 @@ export function AddLogModal({ isOpen, onClose, onSave, editingLog }: Props) {
|
|||||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||||
Дата
|
Дата
|
||||||
</label>
|
</label>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={handlePrevDay}
|
||||||
|
className="p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded-md transition-colors"
|
||||||
|
title="Предыдущий день"
|
||||||
|
>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path fillRule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clipRule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div className="flex-1 relative">
|
||||||
<input
|
<input
|
||||||
type="date"
|
type="date"
|
||||||
value={date}
|
value={date}
|
||||||
onChange={(e) => setDate(e.target.value)}
|
onChange={(e) => setDate(e.target.value)}
|
||||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 opacity-0 absolute inset-0 cursor-pointer"
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
|
<div className="w-full px-3 py-2 border border-gray-300 rounded-md bg-white text-center font-medium cursor-pointer hover:bg-gray-50">
|
||||||
|
{displayDate}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={handleNextDay}
|
||||||
|
className="p-2 text-gray-500 hover:text-gray-700 hover:bg-gray-100 rounded-md transition-colors"
|
||||||
|
title="Следующий день"
|
||||||
|
>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
|
||||||
|
<path fillRule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clipRule="evenodd" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useState, useRef, useEffect } from 'react';
|
import { useState, useRef, useEffect } from 'react';
|
||||||
import { format, parseISO } from 'date-fns';
|
import { format, parseISO } from 'date-fns';
|
||||||
import { ru } from 'date-fns/locale';
|
|
||||||
import type { TimeLog } from '../hooks/useLogs';
|
import type { TimeLog } from '../hooks/useLogs';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -143,7 +142,7 @@ export function LogList({ logs, onDelete, onEdit, onUpdateTime, isLoading }: Pro
|
|||||||
<div key={dateKey} className="bg-white rounded-lg shadow-sm border">
|
<div key={dateKey} className="bg-white rounded-lg shadow-sm border">
|
||||||
<div className="px-4 py-3 bg-gray-50 border-b flex justify-between items-center rounded-t-lg">
|
<div className="px-4 py-3 bg-gray-50 border-b flex justify-between items-center rounded-t-lg">
|
||||||
<span className="font-medium text-gray-700">
|
<span className="font-medium text-gray-700">
|
||||||
{format(parseISO(dateKey), 'd MMMM yyyy', { locale: ru })}
|
{format(parseISO(dateKey), 'dd/MM/yyyy')}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-sm text-gray-500">
|
<span className="text-sm text-gray-500">
|
||||||
Всего: {formatTime(totalHours, totalMins)}
|
Всего: {formatTime(totalHours, totalMins)}
|
||||||
|
|||||||
Reference in New Issue
Block a user