first commit
This commit is contained in:
146
frontend/src/components/AddLogModal.tsx
Normal file
146
frontend/src/components/AddLogModal.tsx
Normal file
@@ -0,0 +1,146 @@
|
||||
import { useState } from 'react';
|
||||
import { format } from 'date-fns';
|
||||
|
||||
interface Props {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onSave: (data: { date: string; time: string; description: string }) => Promise<unknown>;
|
||||
}
|
||||
|
||||
export function AddLogModal({ isOpen, onClose, onSave }: Props) {
|
||||
const [date, setDate] = useState(format(new Date(), 'yyyy-MM-dd'));
|
||||
const [time, setTime] = useState('8');
|
||||
const [description, setDescription] = useState('');
|
||||
const [error, setError] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
setError('');
|
||||
setIsLoading(true);
|
||||
|
||||
try {
|
||||
await onSave({ date, time, description });
|
||||
setTime('8');
|
||||
setDescription('');
|
||||
onClose();
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Ошибка');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const setQuickTime = (value: string) => {
|
||||
setTime(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<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">
|
||||
<h2 className="text-xl font-semibold mb-4">Новая запись</h2>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Дата
|
||||
</label>
|
||||
<input
|
||||
type="date"
|
||||
value={date}
|
||||
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"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Часы
|
||||
</label>
|
||||
<div className="flex gap-2 mb-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setQuickTime('8')}
|
||||
className={`px-3 py-1 rounded-md text-sm ${
|
||||
time === '8'
|
||||
? 'bg-blue-600 text-white'
|
||||
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
|
||||
}`}
|
||||
>
|
||||
8 ч
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setQuickTime('4')}
|
||||
className={`px-3 py-1 rounded-md text-sm ${
|
||||
time === '4'
|
||||
? 'bg-blue-600 text-white'
|
||||
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
|
||||
}`}
|
||||
>
|
||||
4 ч
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setQuickTime('1')}
|
||||
className={`px-3 py-1 rounded-md text-sm ${
|
||||
time === '1'
|
||||
? 'bg-blue-600 text-white'
|
||||
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
|
||||
}`}
|
||||
>
|
||||
1 ч
|
||||
</button>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
value={time}
|
||||
onChange={(e) => setTime(e.target.value)}
|
||||
placeholder="8, 8:30, 8,5"
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
required
|
||||
/>
|
||||
<p className="text-xs text-gray-500 mt-1">
|
||||
Форматы: 8, 8:30, 8,5, 8.5
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Описание
|
||||
</label>
|
||||
<textarea
|
||||
value={description}
|
||||
onChange={(e) => setDescription(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 resize-none"
|
||||
rows={3}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
{error && <p className="text-red-500 text-sm">{error}</p>}
|
||||
|
||||
<div className="flex gap-3 pt-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="flex-1 py-2 px-4 border border-gray-300 text-gray-700 rounded-md hover:bg-gray-50"
|
||||
>
|
||||
Отмена
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isLoading}
|
||||
className="flex-1 py-2 px-4 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50"
|
||||
>
|
||||
{isLoading ? 'Сохранение...' : 'Сохранить'}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user