Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🔄Fix ui and data manipulations #10

Merged
merged 17 commits into from
Nov 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/lib/components/MovieCard.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
async function deleteMovie(): Promise<any> {
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: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,60 +1,68 @@
<script lang="ts">
import { movieFormInfo, store } from '$lib';
import * as Tooltip from '$lib/components/ui/tooltip';
import * as Form from '$lib/components/ui/form';
import { addSchema } from './schema';
import { toast } from 'svelte-sonner';
import { goto } from '$app/navigation';
import { scale } from 'svelte/transition';
import type { SuperValidated } from 'sveltekit-superforms';
import type { FormSchema } from './schema';
import { goto } from '$app/navigation';
import { modifySchema } from '../../routes/movie/[id]/schema';
import { addSchema } from '../../routes/movie/schema';
export let isModifying: boolean = false;
export let movie: Movie | undefined;
export let form: SuperValidated<any>;
export let errMsg: string = '';
export let form: SuperValidated<FormSchema>;
export let isValid: boolean | undefined = undefined;

$: {
if (isValid) {
toast.success(`Movie ${form.data.title} is now in the watch list`);
toast.success(isModifying ? `Movie is now updated` : `Movie added to watch list`);
goto('/');
}
if (isValid != undefined && !isValid) {
toast.error(`Failed to add movie ${errMsg}`);
toast.error(
isModifying ? `Failed to update movie: ${errMsg}` : `Failed to add movie: ${errMsg}`
);
}
}

store.subscribe((state) => {
console.log(`State changes ${JSON.stringify(state)}`);
if (state.isProcessing) {
console.log(`Showing loading`);
toast.loading(`Adding Movie ${form.data.title}`);
}
});
</script>

<div in:scale>
<div in:scale class="mt-10">
<div class="flex flex-col items-center md:items-left mb-5">
<p class="text-2xl font-bold">Add Movie</p>
<p class="text-xl font-semi-bold">Add a movie to your watch list</p>
<p class="text-2xl font-bold">{isModifying ? 'Update Movie' : 'Add Movie'}</p>
<p class="text-xl font-semi-bold">
{isModifying ? `Update Movie ${movie?.title}` : 'Add movie to watch list'}
</p>
</div>

<Form.Root class="mx-5" method="POST" {form} schema={addSchema} let:config>
<Form.Root
class="mx-5"
method="POST"
{form}
schema={isModifying ? modifySchema : addSchema}
let:config
>
<Form.Field {config} name="title">
<Form.Item>
<Form.Label class="font-bold">Title</Form.Label>
<Form.Input placeholder={movieFormInfo[0].description} />

<Form.Validation />
</Form.Item>
</Form.Field>
<Form.Field {config} name="genres">
<Form.Item>
<Form.Label>Genres</Form.Label>
<Form.Input placeholder={movieFormInfo[1].description} />

<Form.Validation />
</Form.Item>
</Form.Field>
<Form.Field {config} name="year">
<Form.Item>
<Form.Label>Year of release</Form.Label>
<Form.Input placeholder={movieFormInfo[2].description} />

<Form.Validation />
</Form.Item>
</Form.Field>
Expand All @@ -64,14 +72,32 @@
<Form.Select>
<Form.SelectTrigger placeholder={movieFormInfo[3].description} />
<Form.SelectContent class="overflow-y-auto scrollbar-hide h-40">
{#each Array.from({ length: 10 }, (_, index) => index + 1) as option (option)}
{#each Array.from({ length: 20 }, (_, index) => (index + 1) * 0.5) as option (option)}
<Form.SelectItem value={option.toString()}>{option}</Form.SelectItem>
{/each}
</Form.SelectContent>
</Form.Select>
<Form.Validation />
</Form.Item>
</Form.Field>
<Form.Button class="mt-2" formaction="?/addMovie">{`Add to watch list`}</Form.Button>
<Form.Field {config} name="watched">
<Form.Item class="flex flex-row items-center justify-between rounded-lg">
<Form.Label>Have you watched this movie?</Form.Label>
<Form.Switch />
</Form.Item>
</Form.Field>
<Tooltip.Root>
<Tooltip.Trigger asChild let:builder>
<Form.Button
builders={[builder]}
class="mt-2"
formaction={isModifying ? '?/modifyMovie' : '?/addMovie'}
>{isModifying ? `Update movie ${movie?.title}` : `Add movie`}</Form.Button
>
</Tooltip.Trigger>
<Tooltip.Content>
<p>{isModifying ? 'Update movie' : 'Add movie'}</p>
</Tooltip.Content>
</Tooltip.Root>
</Form.Root>
</div>
11 changes: 10 additions & 1 deletion src/routes/+page.server.ts
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
export const prerender = true;
import { fetchMovies } from "$lib";
import type { PageServerLoad } from "./$types";

export const load: PageServerLoad = () => {
return {
streamed: {
movies: fetchMovies()
},
};
};
26 changes: 6 additions & 20 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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;
</script>

<svelte:head>
<title>{pageTitle}</title>
<meta name="description" content={pageDescription} />
<meta name="author" content="Peter John Arao" />
<meta
name="keywords"
content="SvelteKit Movie watchlist, movie watch list"
/>
<meta name="keywords" content="SvelteKit Movie watchlist, movie watch list" />
<meta name="robots" content="index, follow" />
<link rel="canonical" href="{pageUrl}/" />
<meta http-equiv="Content-Language" content="en" />
Expand All @@ -44,16 +33,13 @@
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
<meta property="og:description" content={pageDescription} />
<meta property="og:url" content="{pageUrl}/" />
<meta
property="og:image"
content={$userPrefersMode === 'dark' ? 'thumbnail-dark.png' : 'thumbnail-light.png'}
/>
<meta property="og:image" content="thumbnail.png" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content={pageTitle} />
</svelte:head>

<div in:fade>
{#await $store.movies}
{#await data.streamed.movies}
<div class="grid place-items-center grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-5 m-4">
{#each Array.from({ length: 6 }, (_, index) => index + 1) as option (option)}
<Card.Root class="w-full">
Expand Down
12 changes: 6 additions & 6 deletions src/routes/api/movies/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down Expand Up @@ -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': '*',
Expand All @@ -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,
Expand All @@ -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': '*',
Expand All @@ -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: {
Expand Down Expand Up @@ -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: {
Expand Down
24 changes: 6 additions & 18 deletions src/routes/movie/+page.server.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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)

Expand All @@ -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
};
Expand Down
7 changes: 4 additions & 3 deletions src/routes/movie/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
<script lang="ts">
import type { PageData, ActionData } from './$types';
import AddMovieForm from './AddMovieForm.svelte';
import MovieForm from '$lib/components/MovieForm.svelte';
export let data: PageData;
export let form: ActionData;
</script>

<AddMovieForm
<MovieForm
movie={form?.movie}
form={data.form}
isValid={form?.valid}
errMsg={form?.errorMessage}
errMsg={form?.errorMessage}
/>
30 changes: 11 additions & 19 deletions src/routes/movie/[id]/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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) => {
Expand All @@ -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,
Expand Down Expand Up @@ -85,22 +86,13 @@ export const actions: Actions = {
});
const res = await response.json();

store.update((state) => ({
...state,
isProcessing: false
}));

return {
form,
result: res,
valid: response.ok,
errorMessage: res.errorMessage
};
} catch (error: any) {
store.update((state) => ({
...state,
isProcessing: false
}));
return {
form,
valid: false,
Expand Down
Loading
Loading