diff --git a/src/lib/components/MovieCard.svelte b/src/lib/components/MovieCard.svelte index a5aa29b..0d6db83 100644 --- a/src/lib/components/MovieCard.svelte +++ b/src/lib/components/MovieCard.svelte @@ -11,6 +11,7 @@ async function deleteMovie(): Promise { return new Promise(async (resolve, reject) => { try { + console.log(`Deleting movie with title: ${movie.title}`) const response: Response = await fetch(`${host}/api/movies`, { method: 'DELETE', headers: { diff --git a/src/routes/movie/AddMovieForm.svelte b/src/lib/components/MovieForm.svelte similarity index 51% rename from src/routes/movie/AddMovieForm.svelte rename to src/lib/components/MovieForm.svelte index c474faa..e28cc51 100644 --- a/src/routes/movie/AddMovieForm.svelte +++ b/src/lib/components/MovieForm.svelte @@ -1,46 +1,52 @@ -
+
-

Add Movie

-

Add a movie to your watch list

+

{isModifying ? 'Update Movie' : 'Add Movie'}

+

+ {isModifying ? `Update Movie ${movie?.title}` : 'Add movie to watch list'} +

- + Title + @@ -48,6 +54,7 @@ Genres + @@ -55,6 +62,7 @@ Year of release + @@ -64,7 +72,7 @@ - {#each Array.from({ length: 10 }, (_, index) => index + 1) as option (option)} + {#each Array.from({ length: 20 }, (_, index) => (index + 1) * 0.5) as option (option)} {option} {/each} @@ -72,6 +80,24 @@ - {`Add to watch list`} + + + Have you watched this movie? + + + + + + {isModifying ? `Update movie ${movie?.title}` : `Add movie`} + + +

{isModifying ? 'Update movie' : 'Add movie'}

+
+
diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts index c8cacf0..751009a 100644 --- a/src/routes/+page.server.ts +++ b/src/routes/+page.server.ts @@ -1 +1,10 @@ -export const prerender = true; \ No newline at end of file +import { fetchMovies } from "$lib"; +import type { PageServerLoad } from "./$types"; + +export const load: PageServerLoad = () => { + return { + streamed: { + movies: fetchMovies() + }, + }; +}; \ No newline at end of file diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 8fea7fc..6122b18 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -10,32 +10,21 @@ import { onMount } from 'svelte'; import { page } from '$app/stores'; import { fetchMovies, host, store } from '$lib'; - import { userPrefersMode } from 'mode-watcher'; + import type { PageData } from './$types'; export let pageTitle = 'SvelteKit x MongoDB x shadcn-svelte Movie Watch List'; export let pageDescription = 'SvelteKit-powered Movie Watchlist: Easily track, rate, and organize your movie choices with this user-friendly app. '; export let pageUrl = host; - onMount(() => { - try { - return store.update((state) => ({ - ...state, - movies: fetchMovies() - })); - } catch (err) { - throw error(500, `${JSON.stringify(err)}`); - } - }); + + export let data: PageData; {pageTitle} - + @@ -44,16 +33,13 @@ - +
- {#await $store.movies} + {#await data.streamed.movies}
{#each Array.from({ length: 6 }, (_, index) => index + 1) as option (option)} diff --git a/src/routes/api/movies/+server.ts b/src/routes/api/movies/+server.ts index 56a461e..41f6d80 100644 --- a/src/routes/api/movies/+server.ts +++ b/src/routes/api/movies/+server.ts @@ -212,7 +212,7 @@ export const DELETE: RequestHandler = async ({ request }) => { .then((fetchedMovie: Document) => { if (!fetchedMovie) { return new Response( - JSON.stringify({ errorMesage: `Movie with id ${id} is not a movie document!` }), + JSON.stringify({ errorMessage: `Movie with id ${id} is not a movie document!` }), { status: 400, headers: { @@ -268,7 +268,7 @@ export const DELETE: RequestHandler = async ({ request }) => { ); }) .catch((error: MongoServerError) => { - return new Response(JSON.stringify({ errorMesage: error.message }), { + return new Response(JSON.stringify({ errorMessage: error.message }), { status: 500, headers: { 'Access-Control-Allow-Origin': '*', @@ -281,7 +281,7 @@ export const DELETE: RequestHandler = async ({ request }) => { () => new Response( JSON.stringify({ - errorMesage: `Cannot delete movie, movie with id ${id} does not exist` + errorMessage: `Cannot delete movie, movie with id ${id} does not exist` }), { status: 404, @@ -293,7 +293,7 @@ export const DELETE: RequestHandler = async ({ request }) => { ) ); } catch { - return new Response(JSON.stringify({ errorMesage: 'Cannot delete movie, invalid body' }), { + return new Response(JSON.stringify({ errorMessage: 'Cannot delete movie, invalid body' }), { status: 404, headers: { 'Access-Control-Allow-Origin': '*', @@ -308,7 +308,7 @@ export const PATCH: RequestHandler = async (event) => { if (requestOrigin && !allowedOrigins.includes(requestOrigin)) { return new Response( - JSON.stringify({ errorMesage: `Origin ${requestOrigin} is not authorized` }), + JSON.stringify({ errorMessage: `Origin ${requestOrigin} is not authorized` }), { status: 401, headers: { @@ -388,7 +388,7 @@ export const PATCH: RequestHandler = async (event) => { }) .catch((error: MongoServerError) => { return new Response( - JSON.stringify({ errorMesage: `Failed to update movie ${data.title}: ${error.message}` }), + JSON.stringify({ errorMessage: `Failed to update movie ${data.title}: ${error.message}` }), { status: 400, headers: { diff --git a/src/routes/movie/+page.server.ts b/src/routes/movie/+page.server.ts index 29e9205..d0f1c65 100644 --- a/src/routes/movie/+page.server.ts +++ b/src/routes/movie/+page.server.ts @@ -1,8 +1,8 @@ import type { PageServerLoad } from './$types'; import { superValidate } from 'sveltekit-superforms/server'; import { addSchema } from './schema'; -import { fail, type Actions, type RequestEvent } from '@sveltejs/kit'; -import { host, store } from '$lib'; +import { fail, type Actions } from '@sveltejs/kit'; +import { host } from '$lib'; export const load = (() => { return { @@ -21,16 +21,11 @@ export const actions: Actions = { if (!form.valid) { return fail(400, { - form + form, + movie: undefined }); } - store.update((state) => ({ - ...state, - movie: form.data.title, - isProcessing: true - })); - const genres: string[] = form.data.genres.split(' ') .map((genre) => genre) @@ -54,25 +49,18 @@ export const actions: Actions = { }); const res = await response.json(); - store.update((state) => ({ - ...state, - isProcessing: false - })); - return { form, result: res, + movie: undefined, valid: response.ok, errorMessage: res.errorMessage }; } catch (error: any) { - store.update((state) => ({ - ...state, - isProcessing: false - })); return { form, + movie: undefined, valid: false, errorMessage: error.message }; diff --git a/src/routes/movie/+page.svelte b/src/routes/movie/+page.svelte index e018731..315cc6a 100644 --- a/src/routes/movie/+page.svelte +++ b/src/routes/movie/+page.svelte @@ -1,12 +1,13 @@ - diff --git a/src/routes/movie/[id]/+page.server.ts b/src/routes/movie/[id]/+page.server.ts index 79128f1..ac2a669 100644 --- a/src/routes/movie/[id]/+page.server.ts +++ b/src/routes/movie/[id]/+page.server.ts @@ -2,7 +2,7 @@ import type { PageServerLoad } from './$types'; import { superValidate } from 'sveltekit-superforms/server'; import { fail, type Actions, type RequestEvent, error } from '@sveltejs/kit'; import { genres, getDocumentById, movies } from '$db/collections'; -import { fetchMovies, host, mapFetchedGenreToType, mapFetchedMovieToType, store } from '$lib'; +import { fetchMovies, host, mapFetchedGenreToType, mapFetchedMovieToType } from '$lib'; import type { Document, MongoServerError } from 'mongodb'; import { modifySchema } from './schema'; @@ -32,11 +32,18 @@ export const load = (async (event: RequestEvent) => { : { ...movie, _id: movie._id.toString() }; console.log(`Movie with appropriate genres: ${JSON.stringify(updatedMovie)}`); + let form = await superValidate(modifySchema, { + id: 'modifySchema' + }); + + form.data.title = updatedMovie.title; + form.data.genres = updatedMovie.genres.join(' '); + form.data.year = updatedMovie.year.toString(); + form.data.rating = updatedMovie.rating.toString(); + form.data.watched = updatedMovie.watched; return { movie: updatedMovie, - form: await superValidate(modifySchema, { - id: 'modifySchema' - }) + form: form }; }) .catch((e: MongoServerError) => { @@ -50,12 +57,6 @@ export const actions: Actions = { id: 'modifySchema' }); - store.update((state) => ({ - ...state, - movie: form.data.title, - isProcessing: true - })); - if (!form.valid) { return fail(400, { form, @@ -85,11 +86,6 @@ export const actions: Actions = { }); const res = await response.json(); - store.update((state) => ({ - ...state, - isProcessing: false - })); - return { form, result: res, @@ -97,10 +93,6 @@ export const actions: Actions = { errorMessage: res.errorMessage }; } catch (error: any) { - store.update((state) => ({ - ...state, - isProcessing: false - })); return { form, valid: false, diff --git a/src/routes/movie/[id]/+page.svelte b/src/routes/movie/[id]/+page.svelte index 0b49844..a76fed6 100644 --- a/src/routes/movie/[id]/+page.svelte +++ b/src/routes/movie/[id]/+page.svelte @@ -1,13 +1,14 @@ - + isModifying={true} +/> \ No newline at end of file diff --git a/src/routes/movie/[id]/UpdateMovieForm.svelte b/src/routes/movie/[id]/UpdateMovieForm.svelte deleted file mode 100644 index 65e214c..0000000 --- a/src/routes/movie/[id]/UpdateMovieForm.svelte +++ /dev/null @@ -1,87 +0,0 @@ - - -
-
-

Update Movie

-

{`Update Movie ${movie.title}`}

-
- - - - - Title - - - - - - - - Genres - - - - - - - - Year of release - - - - - - - - Rating - - - - {#each Array.from({ length: 10 }, (_, index) => index + 1) as option (option)} - {option} - {/each} - - - - - - - - {`Update movie ${movie.title}`} - - -

Update movie

-
-
-
-
diff --git a/src/routes/movie/[id]/schema.ts b/src/routes/movie/[id]/schema.ts index ab7ac9a..b5d2420 100644 --- a/src/routes/movie/[id]/schema.ts +++ b/src/routes/movie/[id]/schema.ts @@ -6,9 +6,7 @@ export const modifySchema = z.object({ .string() .min(2, { message: 'Title must be at least 2 characters long' }) .max(50, { message: 'Title cannot exceed 50 characters' }), - genres: z - .string() - .min(3, { message: 'Genre must be at least 3 characters long' }), + genres: z.string().min(3, { message: 'Genre must be at least 3 characters long' }), year: z .string() .min(4, { message: 'Year must be at least 4 characters long' }) @@ -17,15 +15,16 @@ export const modifySchema = z.object({ if (isNaN(Number(value))) { throw error(400, 'Year must be a number'); } - return Number(value) >= 1900 && Number(value) <= new Date().getFullYear(); + return Number(value) >= 1888 && Number(value) <= new Date().getFullYear(); }, - { message: 'Year must be between 1900 and current year' } + { message: 'Year must be between 1888 and current year' } ), rating: z .string() .min(1, { message: 'Rating must be at least 1 characters long' }) .max(10, { message: 'Rating cannot exceed 10 characters' }), - movieId: z.string() + movieId: z.string(), + watched: z.boolean() }); export type FormSchema = typeof modifySchema; diff --git a/src/routes/movie/schema.ts b/src/routes/movie/schema.ts index 9305d22..d734691 100644 --- a/src/routes/movie/schema.ts +++ b/src/routes/movie/schema.ts @@ -17,14 +17,15 @@ export const addSchema = z.object({ if (isNaN(Number(value))) { throw error(400, 'Year must be a number'); } - return Number(value) >= 1900 && Number(value) <= new Date().getFullYear(); + return Number(value) >= 1888 && Number(value) <= new Date().getFullYear(); }, - { message: 'Year must be between 1900 and current year' } + { message: 'Year must be between 1888 and current year' } ), rating: z .string() .min(1, { message: 'Rating must be at least 1 characters long' }) - .max(10, { message: 'Rating cannot exceed 10 characters' }) + .max(10, { message: 'Rating cannot exceed 10 characters' }), + watched: z.boolean() }); export type FormSchema = typeof addSchema; diff --git a/static/thumbnail-dark.png b/static/thumbnail-dark.png deleted file mode 100644 index c551d07..0000000 Binary files a/static/thumbnail-dark.png and /dev/null differ diff --git a/static/thumbnail-light.png b/static/thumbnail-light.png deleted file mode 100644 index 25b9283..0000000 Binary files a/static/thumbnail-light.png and /dev/null differ diff --git a/static/thumbnail.png b/static/thumbnail.png new file mode 100644 index 0000000..ef06aa8 Binary files /dev/null and b/static/thumbnail.png differ diff --git a/svelte.config.js b/svelte.config.js index cb537ad..43c3da0 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -3,14 +3,9 @@ import { vitePreprocess } from '@sveltejs/kit/vite'; /** @type {import('@sveltejs/kit').Config} */ const config = { - // Consult https://kit.svelte.dev/docs/integrations#preprocessors - // for more information about preprocessors preprocess: [vitePreprocess({})], runtime: 'edge', kit: { - // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. - // If your environment is not supported or you settled on a specific environment, switch out the adapter. - // See https://kit.svelte.dev/docs/adapters for more information about adapters. adapter: adapter(), alias: { $lib: './src/lib',