Files
gift-tracker/src/components/molecules/GiftModal/index.tsx

185 lines
6.3 KiB
TypeScript

'use client';
import { FC, useState, useEffect } from 'react';
import { Modal } from '@/components/atoms/Modal';
import { Button } from '@/components/atoms/Button';
import { formatStatus } from '@/helpers/formatStatus';
type Props = {
isOpen: boolean;
onClose: () => void;
gift?: Gift;
yearId: string;
personId?: string;
onSave: (data: {
title: string;
description: string;
link: string;
cost: number;
imageUrl: string;
status: 'planned' | 'decided' | 'bought' | 'wrapped';
year: string;
person: string;
}) => Promise<void>;
};
export const GiftModal: FC<Props> = ({ isOpen, onClose, gift, yearId, personId, onSave }) => {
const [title, setTitle] = useState(gift?.title || '');
const [description, setDescription] = useState(gift?.description || '');
const [link, setLink] = useState(gift?.link || '');
const [cost, setCost] = useState(gift?.cost || 0);
const [imageUrl, setImageUrl] = useState(gift?.imageUrl || '');
const [status, setStatus] = useState<Gift['status']>(gift?.status || 'planned');
const [selectedPersonId, setSelectedPersonId] = useState(personId || '');
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
if (gift) {
setTitle(gift.title);
setDescription(gift.description || '');
setLink(gift.link || '');
setCost(gift.cost);
setImageUrl(gift.imageUrl || '');
setStatus(gift.status);
setSelectedPersonId(gift.person);
} else {
setTitle('');
setDescription('');
setLink('');
setCost(0);
setImageUrl('');
setStatus('planned');
setSelectedPersonId(personId || '');
}
}, [gift, personId, isOpen]);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setIsLoading(true);
try {
await onSave({
title,
description,
link,
cost,
imageUrl,
status,
year: yearId,
person: selectedPersonId,
});
onClose();
} catch (error) {
console.error('Error saving gift:', error);
} finally {
setIsLoading(false);
}
};
return (
<Modal
isOpen={isOpen}
onClose={onClose}
title={gift ? 'Edytuj prezent' : 'Dodaj nowy prezent'}
footer={
<div className='flex justify-end gap-3'>
<Button variant='secondary' onClick={onClose} disabled={isLoading}>
Anuluj
</Button>
<Button variant='primary' onClick={handleSubmit} disabled={isLoading || !title.trim() || !selectedPersonId}>
{isLoading ? 'Zapisywanie...' : 'Zapisz'}
</Button>
</div>
}>
<form onSubmit={handleSubmit} className='space-y-4'>
<div>
<label htmlFor='title' className='block text-sm font-medium text-gray-700 mb-2'>
Tytuł *
</label>
<input
id='title'
type='text'
value={title}
onChange={(e) => setTitle(e.target.value)}
className='w-full px-4 py-2 border border-gray-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all'
required
disabled={isLoading}
/>
</div>
<div>
<label htmlFor='description' className='block text-sm font-medium text-gray-700 mb-2'>
Opis
</label>
<textarea
id='description'
value={description}
onChange={(e) => setDescription(e.target.value)}
rows={3}
className='w-full px-4 py-2 border border-gray-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all resize-none'
disabled={isLoading}
/>
</div>
<div className='grid grid-cols-1 md:grid-cols-2 gap-4'>
<div>
<label htmlFor='cost' className='block text-sm font-medium text-gray-700 mb-2'>
Koszt (PLN) *
</label>
<input
id='cost'
type='number'
step='0.01'
min='0'
value={cost}
onChange={(e) => setCost(parseFloat(e.target.value) || 0)}
className='w-full px-4 py-2 border border-gray-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all'
required
disabled={isLoading}
/>
</div>
<div>
<label htmlFor='status' className='block text-sm font-medium text-gray-700 mb-2'>
Status *
</label>
<select
id='status'
value={status}
onChange={(e) => setStatus(e.target.value as typeof status)}
className='w-full px-4 py-2 border border-gray-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all'
required
disabled={isLoading}>
<option value='planned'>{formatStatus('planned')} </option>
<option value='decided'>{formatStatus('decided')}</option>
<option value='bought'>{formatStatus('bought')}</option>
<option value='wrapped'>{formatStatus('wrapped')}</option>
</select>
</div>
</div>
<div>
<label htmlFor='link' className='block text-sm font-medium text-gray-700 mb-2'>
Link
</label>
<input
id='link'
type='url'
value={link}
onChange={(e) => setLink(e.target.value)}
className='w-full px-4 py-2 border border-gray-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all'
disabled={isLoading}
/>
</div>
<div>
<label htmlFor='imageUrl' className='block text-sm font-medium text-gray-700 mb-2'>
URL obrazu
</label>
<input
id='imageUrl'
type='url'
value={imageUrl}
onChange={(e) => setImageUrl(e.target.value)}
className='w-full px-4 py-2 border border-gray-300 rounded-xl focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all'
disabled={isLoading}
/>
</div>
</form>
</Modal>
);
};