feat: implement PersonModal component for adding and editing person details
This commit is contained in:
80
src/lib/components/molecules/PersonModal.svelte
Normal file
80
src/lib/components/molecules/PersonModal.svelte
Normal file
@@ -0,0 +1,80 @@
|
||||
<script lang="ts">
|
||||
import type { ComponentProps } from 'svelte';
|
||||
import type { DB } from '$lib/integrations/db';
|
||||
import Modal from '../atoms/Modal.svelte';
|
||||
import Button from '../atoms/Button.svelte';
|
||||
import { page } from '$app/state';
|
||||
|
||||
type CreatePerson = Parameters<typeof DB.createPerson>[0];
|
||||
|
||||
type Props = {
|
||||
onSave: (data: CreatePerson) => Promise<void>;
|
||||
editPerson?: Person;
|
||||
} & Omit<ComponentProps<typeof Modal>, 'children'>;
|
||||
|
||||
let { onSave, isOpen, onClose, editPerson }: Props = $props();
|
||||
|
||||
let person = $state<Person>(editPerson ?? ({} as Person));
|
||||
let isLoading = $state(false);
|
||||
|
||||
if (!person?.name) {
|
||||
person.name = '';
|
||||
person.notes = '';
|
||||
person.years = [page.params.year || new Date().getFullYear().toString()];
|
||||
}
|
||||
|
||||
const handleSubmit = async (e: Event) => {
|
||||
e.preventDefault();
|
||||
if (!person) return;
|
||||
|
||||
isLoading = true;
|
||||
try {
|
||||
await onSave(person);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
isLoading = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<Modal {isOpen} {onClose} title={person ? 'Edytuj osobę' : 'Dodaj nową osobę'}>
|
||||
<form onsubmit={handleSubmit} class="space-y-4">
|
||||
<div>
|
||||
<label for="name" class="mb-2 block text-sm font-medium text-gray-700">
|
||||
Imię i nazwisko *
|
||||
</label>
|
||||
<input
|
||||
id="name"
|
||||
type="text"
|
||||
class="w-full rounded-xl border border-gray-300 px-4 py-2 transition-all outline-none focus:border-transparent focus:ring-2 focus:ring-blue-500"
|
||||
required
|
||||
disabled={isLoading}
|
||||
bind:value={person.name}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="notes" class="mb-2 block text-sm font-medium text-gray-700"> Notatki </label>
|
||||
<textarea
|
||||
id="notes"
|
||||
rows={4}
|
||||
class="w-full resize-none rounded-xl border border-gray-300 px-4 py-2 transition-all outline-none focus:border-transparent focus:ring-2 focus:ring-blue-500"
|
||||
disabled={isLoading}
|
||||
bind:value={person.notes}
|
||||
></textarea>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{#snippet footer()}
|
||||
<div class="flex justify-end gap-3">
|
||||
<Button variant="secondary" onClick={onClose} disabled={isLoading}>Anuluj</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={handleSubmit}
|
||||
disabled={isLoading || !person?.name?.trim()}
|
||||
>
|
||||
{isLoading ? 'Zapisywanie...' : 'Zapisz'}
|
||||
</Button>
|
||||
</div>
|
||||
{/snippet}
|
||||
</Modal>
|
||||
@@ -18,7 +18,8 @@ export const DB = {
|
||||
return await pb.collection('gifts_person').getFirstListItem(`name = "${name}"`);
|
||||
},
|
||||
createPerson: async (data: Pick<DB.Person, 'name' | 'notes' | 'years'>): Promise<DB.Person> => {
|
||||
return await pb.collection('gifts_person').create({ ...data });
|
||||
const year = await pb.collection('gifts_year').getFirstListItem(`year = ${data.years[0]}`);
|
||||
return await pb.collection('gifts_person').create({ ...data, years: [year.id] });
|
||||
},
|
||||
updatePerson: async (id: string, data: Pick<DB.Person, 'name' | 'notes'>): Promise<Person> => {
|
||||
return await pb.collection('gifts_person').update(id, data);
|
||||
|
||||
Reference in New Issue
Block a user