feat: update layout to fetch and provide initial movie data; enhance GlobalStoreProvider to accept initialMovies prop for improved state management

This commit is contained in:
Norbert Maciaszek 2025-08-21 17:52:17 +02:00
parent d767684c2c
commit 9051d4887c
3 changed files with 26 additions and 33 deletions

View File

@ -1,37 +1,29 @@
import "./globals.css"; import "./globals.css";
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import { Navbar } from "@/components/organisms/Navbar"; import { Navbar } from "@/components/organisms/Navbar";
import { GlobalStoreProvider } from "./store/globalStore";
import { AuroraBackground } from "@/components/effects"; import { AuroraBackground } from "@/components/effects";
import { GlobalStoreProvider } from "./store/globalStore";
const geistSans = Geist({ import { getMovies } from "@/lib/db";
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
export const metadata: Metadata = {
title: "Movie List",
description: "Personal watch list and progress tracker",
};
export default async function RootLayout({ export default async function RootLayout({
children, children,
}: Readonly<{ }: Readonly<{
children: React.ReactNode; children: React.ReactNode;
}>) { }>) {
const movies = await getMovies();
return ( return (
<html lang="pl"> <html lang="pl">
<body <head>
className={`${geistSans.variable} ${geistMono.variable} antialiased`} <title>Homepage | Movie List</title>
> <meta
<GlobalStoreProvider> name="description"
content="Personal watch list and progress tracker"
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body className={`antialiased`}>
<GlobalStoreProvider initialMovies={movies}>
<AuroraBackground /> <AuroraBackground />
<Navbar /> <Navbar />
<main className="relative">{children}</main> <main className="relative">{children}</main>

View File

@ -1,7 +1,7 @@
"use client"; "use client";
import { addMovieToDB, deleteMovieFromDB, updateMovieInDB } from "@/lib/db"; import { addMovieToDB, deleteMovieFromDB, updateMovieInDB } from "@/lib/db";
import { movies } from "@/lib/db/schema"; import { movies } from "@/lib/db/schema";
import { createContext, FC, use, useEffect, useState } from "react"; import { createContext, FC, use, useState } from "react";
type Movie = typeof movies.$inferSelect; type Movie = typeof movies.$inferSelect;
@ -21,19 +21,15 @@ const globalStore = createContext<GlobalStore>({
type Props = { type Props = {
children: React.ReactNode; children: React.ReactNode;
initialMovies?: Movie[];
}; };
export const GlobalStoreProvider: FC<Props> = ({ children }) => { export const GlobalStoreProvider: FC<Props> = ({
children,
initialMovies = [],
}) => {
// Optimistic update // Optimistic update
const [movies, setMovies] = useState<GlobalStore["movies"]>([]); const [movies, setMovies] = useState<GlobalStore["movies"]>(initialMovies);
useEffect(() => {
fetch("/api/movies")
.then((res) => res.json())
.then((data) => {
setMovies(data);
});
}, []);
const addMovie = async (movie: Movie) => { const addMovie = async (movie: Movie) => {
if (movies.find((m) => m.id === movie.id)) return; if (movies.find((m) => m.id === movie.id)) return;

View File

@ -3,6 +3,7 @@ import { drizzle } from "drizzle-orm/libsql";
import { movies } from "./schema"; import { movies } from "./schema";
import { eq } from "drizzle-orm"; import { eq } from "drizzle-orm";
import { Movie } from "@/types/global"; import { Movie } from "@/types/global";
import { revalidatePath } from "next/cache";
const db = drizzle(process.env.DB_FILE_NAME!); const db = drizzle(process.env.DB_FILE_NAME!);
@ -18,10 +19,13 @@ export const addMovieToDB = async (movie: Movie) => {
genre_ids: JSON.stringify(movie.genre_ids), genre_ids: JSON.stringify(movie.genre_ids),
}) })
.onConflictDoNothing(); .onConflictDoNothing();
revalidatePath("/", "layout");
}; };
export const deleteMovieFromDB = async (id: number) => { export const deleteMovieFromDB = async (id: number) => {
await db.delete(movies).where(eq(movies.id, id)); await db.delete(movies).where(eq(movies.id, id));
revalidatePath("/", "layout");
}; };
export const updateMovieInDB = async ( export const updateMovieInDB = async (
@ -29,4 +33,5 @@ export const updateMovieInDB = async (
movie: Partial<Movie> movie: Partial<Movie>
) => { ) => {
await db.update(movies).set(movie).where(eq(movies.id, movieId)); await db.update(movies).set(movie).where(eq(movies.id, movieId));
revalidatePath("/", "layout");
}; };