From b1dad2f6ba7d89a7d8ad303187604841fb36588b Mon Sep 17 00:00:00 2001 From: Dmytro Stanchiev Date: Thu, 14 Aug 2025 23:09:34 -0400 Subject: [PATCH] working idb example --- src/app/page.tsx | 53 ++++++++++++++++++++++++++++++------------ src/lib/db.ts | 60 +++++++++++++++++++++++++++++++++++++++++++----- src/lib/types.ts | 7 ++++++ 3 files changed, 99 insertions(+), 21 deletions(-) create mode 100644 src/lib/types.ts diff --git a/src/app/page.tsx b/src/app/page.tsx index 69e304b..1b72083 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,38 +1,61 @@ 'use client' -import { useState } from 'react' +import { useEffect, useState } from 'react' +import { nanoid } from 'nanoid' import { Button } from '@/components/ui/button' import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog' import { Input } from '@/components/ui/input' -import { nanoid } from 'nanoid' +import { type CalendarEvent } from '@/lib/types' -type Event = { - id: string - title: string - start: string - end?: string -} +import { addEvent, deleteEvent, getAllEvents, clearEvents } from '@/lib/db' export default function HomePage() { - const [events, setEvents] = useState([]) + const [events, setEvents] = useState([]) const [open, setOpen] = useState(false) const [title, setTitle] = useState('') const [start, setStart] = useState('') - const addEvent = () => { - setEvents([...events, { id: nanoid(), title, start }]) + // Load events only in the browser + useEffect(() => { + (async () => { + const stored = await getAllEvents() + setEvents(stored) + })() + }, []) + + const handleAdd = async () => { + const newEvent = { id: nanoid(), title, start } + await addEvent(newEvent) + setEvents(prev => [...prev, newEvent]) setTitle('') setStart('') setOpen(false) } + const handleDelete = async (id: string) => { + await deleteEvent(id) + setEvents(prev => prev.filter(e => e.id !== id)) + } + + const handleClearAll = async () => { + await clearEvents() + setEvents([]) + } + return (
- +
+ + {events.length > 0 && } +
+
    {events.map(ev => ( -
  • - {ev.title} — {ev.start} +
  • +
    + {ev.title} — {ev.start} +
    +
  • ))}
@@ -45,7 +68,7 @@ export default function HomePage() { setTitle(e.target.value)} /> setStart(e.target.value)} /> - + diff --git a/src/lib/db.ts b/src/lib/db.ts index 582d9ff..a81dc04 100644 --- a/src/lib/db.ts +++ b/src/lib/db.ts @@ -1,7 +1,55 @@ -import { openDB } from "idb"; +import { openDB, DBSchema, IDBPDatabase } from "idb"; +import { type CalendarEvent } from "./types"; -export const dbPromise = openDB("icalPWA", 1, { - upgrade(db) { - db.createObjectStore("events", { keyPath: "id" }); - }, -}); +interface ICalDB extends DBSchema { + events: { + key: string; + value: CalendarEvent; + }; +} + +let dbPromise: Promise> | null = null; + +async function initDB() { + return openDB("icalPWA", 1, { + upgrade(db) { + if (!db.objectStoreNames.contains("events")) { + db.createObjectStore("events", { keyPath: "id" }); + } + }, + }); +} + +// Get the database in a browser-safe way +export async function getDB() { + if (typeof window === "undefined") return null; + if (!dbPromise) { + dbPromise = initDB(); + } + return dbPromise; +} + +// CRUD operations — all SSR-safe +export async function getAllEvents() { + const db = await getDB(); + if (!db) return []; + return db.getAll("events"); +} + +export async function addEvent(event: ICalDB["events"]["value"]) { + const db = await getDB(); + if (!db) return; + return db.put("events", event); +} + +export async function deleteEvent(id: string) { + const db = await getDB(); + if (!db) return; + return db.delete("events", id); +} + +export async function clearEvents() { + const db = await getDB(); + if (!db) return; + return db.clear("events"); +} diff --git a/src/lib/types.ts b/src/lib/types.ts new file mode 100644 index 0000000..1449290 --- /dev/null +++ b/src/lib/types.ts @@ -0,0 +1,7 @@ +export type CalendarEvent = { + id: string; + title: string; + start: string; // ISO date string (YYYY-MM-DD) + end?: string; + description?: string; +};