Add initial project setup with PocketBase integration, global state management, and UI components for gift tracking
This commit is contained in:
31
src/components/organisms/YearControls/index.tsx
Normal file
31
src/components/organisms/YearControls/index.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
'use client';
|
||||
import { FC, useState } from 'react';
|
||||
import { ActionCard } from '../../molecules/ActionCard';
|
||||
import { PersonModal } from '../../molecules/PersonModal';
|
||||
import { DB } from '@/lib/db';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
type Props = {
|
||||
year: string;
|
||||
};
|
||||
|
||||
export const YearControls: FC<Props> = ({ year }) => {
|
||||
const [modalOpen, setModalOpen] = useState<'addPerson' | null>(null);
|
||||
const router = useRouter();
|
||||
return (
|
||||
<>
|
||||
<div className='grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 my-8'>
|
||||
<ActionCard title='Dodaj nową osobę' onClick={() => setModalOpen('addPerson')} backgroundColor='bg-green-50' />
|
||||
</div>
|
||||
<PersonModal
|
||||
isOpen={modalOpen === 'addPerson'}
|
||||
year={year}
|
||||
onClose={() => setModalOpen(null)}
|
||||
onSave={async (data) => {
|
||||
await DB.createPerson(data);
|
||||
router.refresh();
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
51
src/components/organisms/YearOverview/index.tsx
Normal file
51
src/components/organisms/YearOverview/index.tsx
Normal file
@@ -0,0 +1,51 @@
|
||||
import { StatsCard } from '@/components/atoms/StatsCard';
|
||||
import { DB } from '@/lib/db';
|
||||
import { formatCurrency } from '@/helpers/formatCurrency';
|
||||
import { FC } from 'react';
|
||||
import { Heading } from '@/components/atoms/Heading';
|
||||
|
||||
type Props = {
|
||||
year?: number;
|
||||
};
|
||||
|
||||
export const YearOverview: FC<Props> = async ({ year }) => {
|
||||
const currentYear = new Date().getFullYear();
|
||||
const data = await DB.getYear(year ?? currentYear);
|
||||
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const gifts = await Promise.all(
|
||||
data.gifts.map(async (gift) => {
|
||||
return await DB.getGift(gift);
|
||||
}),
|
||||
);
|
||||
|
||||
const totalCost = gifts.reduce((acc, gift) => acc + gift.cost, 0);
|
||||
const averageCost = totalCost / gifts.length;
|
||||
|
||||
return (
|
||||
<div className='mb-6 md:mb-8'>
|
||||
<Heading size='large'>Podsumowanie roku {data.year}</Heading>
|
||||
<div className='grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4'>
|
||||
<StatsCard title='Planowane prezenty' value={gifts.length} />
|
||||
<StatsCard
|
||||
title='Łączny koszt'
|
||||
value={formatCurrency(totalCost)}
|
||||
description={`Średnio: ${formatCurrency(averageCost)}`}
|
||||
/>
|
||||
<StatsCard
|
||||
title='Status: Do kupienia'
|
||||
value={gifts.filter((gift) => gift.status === 'decided').length}
|
||||
description='Prezenty do kupienia'
|
||||
/>
|
||||
<StatsCard
|
||||
title='Status: Kupione'
|
||||
value={gifts.filter((gift) => gift.status === 'bought').length}
|
||||
description='Prezenty które zostały już kupione'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user