feat: introduce PersonCard component for displaying and managing person details and gifts
This commit is contained in:
89
src/lib/components/molecules/PersonCard.svelte
Normal file
89
src/lib/components/molecules/PersonCard.svelte
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { refreshAll } from '$app/navigation';
|
||||||
|
import { formatCurrency } from '$lib/helpers/formatCurrency';
|
||||||
|
import { DB } from '$lib/integrations/db';
|
||||||
|
import Button from '../atoms/Button.svelte';
|
||||||
|
import Heading from '../atoms/Heading.svelte';
|
||||||
|
import GiftCard from './GiftCard.svelte';
|
||||||
|
import GiftModal from './GiftModal.svelte';
|
||||||
|
import PersonModal from './PersonModal.svelte';
|
||||||
|
|
||||||
|
let person: Person = $props();
|
||||||
|
const gifts = $derived(person.expand.gifts);
|
||||||
|
const totalCost = $derived(gifts?.reduce((acc, gift) => acc + gift.cost, 0) || 0);
|
||||||
|
|
||||||
|
let editPersonModal = $state(false);
|
||||||
|
let addGiftModal = $state(false);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="mt-6 rounded-2xl bg-gray-300 p-4 text-gray-700 shadow-sm transition-all duration-200 ease-in-out hover:shadow-md md:p-6"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="mb-6 flex flex-col items-center gap-4 border-b border-gray-700 pb-4 sm:justify-between"
|
||||||
|
>
|
||||||
|
<Heading size="large" spacing="none">
|
||||||
|
<span class="text-gray-700">
|
||||||
|
{person.name}
|
||||||
|
</span>
|
||||||
|
</Heading>
|
||||||
|
|
||||||
|
<div class="flex flex-row items-center justify-center gap-2">
|
||||||
|
<Button variant="primary" onClick={() => (editPersonModal = true)}>Edytuj</Button>
|
||||||
|
<Button
|
||||||
|
variant="danger"
|
||||||
|
onClick={() => {
|
||||||
|
DB.deletePerson(person.id).finally(() => {
|
||||||
|
refreshAll();
|
||||||
|
});
|
||||||
|
}}>Usuń</Button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<PersonModal
|
||||||
|
isOpen={editPersonModal}
|
||||||
|
onClose={() => (editPersonModal = false)}
|
||||||
|
editPerson={person}
|
||||||
|
title="Edytuj osobę"
|
||||||
|
onSave={async (data) => {
|
||||||
|
await DB.updatePerson(person.id, data);
|
||||||
|
refreshAll();
|
||||||
|
editPersonModal = false;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{#if person.notes}
|
||||||
|
<p class="text-gray-600">{person.notes}</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-wrap items-center gap-4 text-sm text-gray-500">
|
||||||
|
<span>Ilość prezentów: {gifts?.length || 0}</span>
|
||||||
|
<span>•</span>
|
||||||
|
<span>Koszt: {formatCurrency(totalCost)}</span>
|
||||||
|
</div>
|
||||||
|
<div class="mt-8 mb-4 flex items-start justify-between gap-4">
|
||||||
|
<Heading size="medium" spacing="none">
|
||||||
|
<span class="text-gray-700">
|
||||||
|
Prezenty <br />
|
||||||
|
</span>
|
||||||
|
</Heading>
|
||||||
|
|
||||||
|
<Button variant="secondary" onClick={() => (addGiftModal = true)}>+</Button>
|
||||||
|
|
||||||
|
<!-- <GiftCardAdd person={person} /> -->
|
||||||
|
<GiftModal
|
||||||
|
title="Dodaj nowy prezent"
|
||||||
|
isOpen={addGiftModal}
|
||||||
|
onClose={() => (addGiftModal = false)}
|
||||||
|
onSave={async (data) => {
|
||||||
|
await DB.createGift(data);
|
||||||
|
refreshAll();
|
||||||
|
addGiftModal = false;
|
||||||
|
}}
|
||||||
|
personId={person.id}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{#each gifts as gift (gift.id)}
|
||||||
|
<GiftCard {...gift} editable />
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
let { onSave, isOpen, onClose, editPerson }: Props = $props();
|
let { onSave, isOpen, onClose, editPerson }: Props = $props();
|
||||||
|
|
||||||
let person = $state<Person>(editPerson ?? ({} as Person));
|
let person = $state<Person>(editPerson ? { ...editPerson } : ({} as Person));
|
||||||
let isLoading = $state(false);
|
let isLoading = $state(false);
|
||||||
|
|
||||||
if (!person?.name) {
|
if (!person?.name) {
|
||||||
|
|||||||
Reference in New Issue
Block a user