feat: add db integration and global types

This commit is contained in:
Norbert Maciaszek
2025-11-17 18:24:49 +01:00
parent 0e45ee04fc
commit 80709b3913
7 changed files with 187 additions and 1 deletions

9
package-lock.json generated
View File

@@ -7,6 +7,9 @@
"": { "": {
"name": "gift-tracker-sv", "name": "gift-tracker-sv",
"version": "0.0.1", "version": "0.0.1",
"dependencies": {
"pocketbase": "^0.26.3"
},
"devDependencies": { "devDependencies": {
"@sveltejs/adapter-auto": "^7.0.0", "@sveltejs/adapter-auto": "^7.0.0",
"@sveltejs/kit": "^2.47.1", "@sveltejs/kit": "^2.47.1",
@@ -1821,6 +1824,12 @@
"url": "https://github.com/sponsors/jonschlinkert" "url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/pocketbase": {
"version": "0.26.3",
"resolved": "https://registry.npmjs.org/pocketbase/-/pocketbase-0.26.3.tgz",
"integrity": "sha512-5deUKRoEczpxxuHzwr6/DHVmgbggxylEVig8CKN+MjvtYxPUqX/C6puU0yaR2yhTi8zrh7J9s7Ty+qBGwVzWOQ==",
"license": "MIT"
},
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.5.6", "version": "8.5.6",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",

View File

@@ -26,5 +26,8 @@
"tailwindcss": "^4.1.14", "tailwindcss": "^4.1.14",
"typescript": "^5.9.3", "typescript": "^5.9.3",
"vite": "^7.1.10" "vite": "^7.1.10"
},
"dependencies": {
"pocketbase": "^0.26.3"
} }
} }

View File

@@ -1 +1,5 @@
@import 'tailwindcss'; @import 'tailwindcss';
body {
@apply bg-gray-50 font-sans text-gray-800 antialiased;
}

View File

@@ -3,9 +3,14 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Gift Tracker</title>
%sveltekit.head% %sveltekit.head%
</head> </head>
<body data-sveltekit-preload-data="hover"> <body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div> <div class="min-h-screen bg-gray-800 text-white">
<main class="pt-16 pb-8">
<div class="mx-auto max-w-7xl px-4 py-6 md:px-6 md:py-8">%sveltekit.body%</div>
</main>
</div>
</body> </body>
</html> </html>

View File

@@ -0,0 +1,92 @@
import PocketBase from 'pocketbase';
const pb = new PocketBase('https://db.maciaszek.ovh');
export const DB = {
getYear: async (year: number): Promise<Year> => {
return await pb.collection('gifts_year').getFirstListItem(`year = ${year}`, {
expand: 'gifts.person',
fields:
'*,expand.gifts.*,expand.gifts.expand.person.name,expand.gifts.expand.person.id,expand.gifts.expand.person.notes'
});
},
getYears: async (): Promise<DB.Year[]> => {
return await pb.collection('gifts_year').getFullList();
},
getPerson: async (name: string): Promise<DB.Person> => {
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 });
},
updatePerson: async (id: string, data: Pick<DB.Person, 'name' | 'notes'>): Promise<Person> => {
return await pb.collection('gifts_person').update(id, data);
},
deletePerson: async (id: string): Promise<void> => {
await pb.collection('gifts_person').delete(id);
},
getPersons: async (yearId: string): Promise<Person[]> => {
return await pb.collection('gifts_person').getFullList({
filter: `years ~ "${yearId}"`,
expand: 'gifts,years',
fields: '*,expand.gifts.*,expand.years.id,expand.years.year'
});
},
getGift: async (id: string): Promise<Gift> => {
return await pb.collection('gifts_items').getOne(id, {
expand: 'year,person',
fields: '*,expand.year.year,expand.person.name,expand.year.id,expand.person.id'
});
},
createGift: async (data: Omit<DB.Gift, 'id' | 'created' | 'updated'>): Promise<DB.Gift> => {
const gift = await pb.collection('gifts_items').create(data);
pb.collection('gifts_person').update(data.person, {
'gifts+': gift.id
});
pb.collection('gifts_year').update(data.year, {
'gifts+': gift.id
});
return gift as unknown as Gift;
},
updateGift: async (
id: string,
data: Omit<DB.Gift, 'id' | 'created' | 'updated'>
): Promise<DB.Gift> => {
return await pb.collection('gifts_items').update(id, data);
},
deleteGift: async (id: string): Promise<void> => {
const gift = await pb.collection('gifts_items').getOne(id);
await pb.collection('gifts_items').delete(id);
await pb.collection('gifts_person').update(gift.person, {
'gifts-': id
});
await pb.collection('gifts_year').update(gift.year, {
'gifts-': id
});
},
getGifts: async (year: number): Promise<Gift[]> => {
const yearRecord = await pb.collection('gifts_year').getFirstListItem(`year = ${year}`);
if (!yearRecord) {
return [];
}
return await pb.collection('gifts_items').getFullList({
filter: `year = "${yearRecord.id}"`,
expand: 'year,person',
fields: '*,expand.year.year,expand.person.name,expand.year.id,expand.person.id'
});
},
getRecentGifts: async (): Promise<Gift[]> => {
return await pb.collection('gifts_items').getFullList({
sort: 'created',
limit: 3,
expand: 'year,person',
fields: '*,expand.year.year,expand.person.name,expand.year.id,expand.person.id'
});
}
};

37
src/lib/integrations/db/types.d.ts vendored Normal file
View File

@@ -0,0 +1,37 @@
namespace DB {
type Year = {
id: string;
year: number;
notes: string;
budgetLimit: number;
created: Date;
updated: Date;
gifts: string[];
};
type Person = {
id: string;
name: string;
notes: string;
created: Date;
updated: Date;
years: string[];
gifts: string[];
};
type Gift = {
id: string;
title: string;
description: string;
link: string;
cost: number;
imageUrl: string;
status: 'planned' | 'decided' | 'bought' | 'ready' | 'wrapped';
created: Date;
updated: Date;
ceneo_id: string;
year: string;
person: string;
};
}

36
src/lib/types/global.d.ts vendored Normal file
View File

@@ -0,0 +1,36 @@
type Year = DB.Year & {
expand: {
gifts: Gift[] & {
expand: {
person: {
id: string;
name: string;
notes: string;
};
};
};
};
};
type Person = DB.Person & {
expand: {
gifts?: Gift[];
year: {
id: string;
year: number;
};
};
};
type Gift = DB.Gift & {
expand: {
year: {
id: string;
year: number;
};
person: {
id: string;
name: string;
};
};
};