Skip to content

Commit

Permalink
feat(web): add lists to search results (#119)
Browse files Browse the repository at this point in the history
  • Loading branch information
manekenpix authored Feb 18, 2025
1 parent ce35f31 commit 5d1bf13
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 63 deletions.
1 change: 1 addition & 0 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"private": true,
"scripts": {
"dev": "vite dev",
"dev:host": "vite dev --host",
"build": "vite build",
"prepare": "cd ../ && husky install web/.husky",
"preview": "vite preview",
Expand Down
4 changes: 3 additions & 1 deletion web/src/ambient.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ export type Stats = {
};

export type SearchResult = {
db: (MovieTye & { lists: ListType })[];
db: MovieWithLists[];
tmdb: MovieType[];
};

export type MovieWithLists = MovieType & { lists: ListType[] };
2 changes: 1 addition & 1 deletion web/src/lib/Modal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
bind:this="{dialog}"
on:close="{() => (showModal = false)}"
on:click|self="{closeDialog}"
class="min-w-96 bg-background text-text rounded-xl"
class="w-11/12 sm:w-2/3 lg:w-2/4 xl:w-1/3 3xl:w-1/4 bg-background text-text rounded-xl"
>
<div class="relative" on:click|stopPropagation>
<slot />
Expand Down
11 changes: 8 additions & 3 deletions web/src/lib/Movie/MovieModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
import { FontAwesomeIcon } from '@fortawesome/svelte-fontawesome';
import { faMagnifyingGlass } from '@fortawesome/free-solid-svg-icons';
import MovieResult from './MovieResult.svelte';
import type { MovieType } from '../../ambient';
import type { MovieWithLists } from '../../ambient';
export let showMovieModal: boolean;
export let listId: string;
let search: string;
let movies: MovieType[] = [];
let movies: MovieWithLists[] = [];
const handleOnClick = async () => {
const response = await fetch(`/search?search=${search}`, {
Expand All @@ -22,11 +22,15 @@
movies = await response.json();
}
};
const handleKeyPress = async (e: KeyboardEvent) => {
e.key === 'Enter' && (await handleOnClick());
};
</script>

<Modal bind:showModal="{showMovieModal}">
<div class="p-4">
<h2 class="font-bold text-4xl underline text-center mb-4">movie</h2>
<h2 class="font-bold text-4xl underline text-center mb-4">search</h2>
<div class="flex pt-2 pb-2 mb-3 justify-center">
<label class="text-right pr-4" for="list-name">title</label>
<input
Expand All @@ -37,6 +41,7 @@
placeholder="The Godfather"
bind:value="{search}"
required
on:keypress="{handleKeyPress}"
/>
<button class="pl-4" type="button" on:click="{handleOnClick}"
><FontAwesomeIcon class="text-text text-md" icon="{faMagnifyingGlass}" /></button
Expand Down
116 changes: 61 additions & 55 deletions web/src/lib/Movie/MovieResult.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,70 +3,76 @@
import { invalidateAll } from '$app/navigation';
import { FontAwesomeIcon } from '@fortawesome/svelte-fontawesome';
import { faPlusCircle } from '@fortawesome/free-solid-svg-icons';
import type { MovieType } from '../../ambient';
import type { MovieWithLists } from '../../ambient';
import Image from '$lib/Image.svelte';
import Label from './Label.svelte';
import { getPosterUrl } from '../../utils';
import { addToast } from '../../store';
import { addedError, addedSuccess } from './messages';
import Lists from '$lib/Search/Lists.svelte';
export let movie: MovieType;
export let movie: MovieWithLists;
export let listId: string;
export let showMovieModal: boolean;
</script>

<div class="w-96 h-80 flex rounded-xl bg-background p-3 flex-shrink-0 mb-5">
<div class="relative w-2/5 mr-3 rounded-md">
<div><Image src="{getPosterUrl(movie.posterUrl)}" watched="{true}" /></div>
<p class="pt-2"><Label>rating:</Label> {movie.rating.toFixed(1)}</p>
<p>
<Label>released</Label>: {new Date(movie.releaseDate).getFullYear() ||
'unavailable'}
</p>
<form
method="POST"
action="?/updateList"
class="absolute top-0 left-0 px-1 bg-background rounded-br-md"
use:enhance="{() => {
return async ({ result }) => {
if (result.type === 'failure') {
addToast(addedError);
} else if (result.type === 'success') {
addToast(addedSuccess);
invalidateAll();
}
applyAction(result);
showMovieModal = false;
};
}}"
>
<input type="hidden" name="listId" value="{listId}" />
<input type="hidden" name="title" value="{movie.title}" />
<input type="hidden" name="description" value="{movie.description}" />
<input type="hidden" name="genre" value="{movie.genre}" />
<input type="hidden" name="releaseDate" value="{movie.releaseDate}" />
<input type="hidden" name="posterUrl" value="{movie.posterUrl}" />
<input type="hidden" name="rating" value="{movie.rating}" />
<input type="hidden" name="tmdbId" value="{movie.tmdbId}" />
<button type="submit">
<FontAwesomeIcon class="text-text" icon="{faPlusCircle}" />
</button>
</form>
</div>
<div class="w-3/5 overflow-y-auto">
<p>
<Label>title</Label>:
{movie.title}
</p>
<p class="break-normal">
<Label>genres</Label>:
{#each movie.genre as genre (genre)}
<span>{genre} </span>
{/each}
</p>
<p class="break-normal">
<Label>description</Label>:
{movie.description}
</p>
<div class="rounded-xl bg-secondary p-3 mx-auto mb-5">
<div class="h-96 flex">
<div class="relative w-2/5 mr-3 rounded-md">
<div><Image src="{getPosterUrl(movie.posterUrl)}" watched="{true}" /></div>
<p class="pt-2"><Label>rating:</Label> {movie.rating.toFixed(1)}</p>
<p>
<Label>released</Label>: {new Date(movie.releaseDate).getFullYear() ||
'unavailable'}
</p>
<form
method="POST"
action="?/updateList"
class="absolute top-0 left-0 px-1 bg-background rounded-br-md"
use:enhance="{() => {
return async ({ result }) => {
if (result.type === 'failure') {
addToast(addedError);
} else if (result.type === 'success') {
addToast(addedSuccess);
invalidateAll();
}
applyAction(result);
showMovieModal = false;
};
}}"
>
<input type="hidden" name="listId" value="{listId}" />
<input type="hidden" name="title" value="{movie.title}" />
<input type="hidden" name="description" value="{movie.description}" />
<input type="hidden" name="genre" value="{movie.genre}" />
<input type="hidden" name="releaseDate" value="{movie.releaseDate}" />
<input type="hidden" name="posterUrl" value="{movie.posterUrl}" />
<input type="hidden" name="rating" value="{movie.rating}" />
<input type="hidden" name="tmdbId" value="{movie.tmdbId}" />
<button type="submit">
<FontAwesomeIcon class="text-text" icon="{faPlusCircle}" />
</button>
</form>
</div>
<div class="w-3/5 overflow-y-auto">
<p>
<Label>title</Label>:
{movie.title}
</p>
<p class="break-normal">
<Label>genres</Label>:
{#each movie.genre as genre (genre)}
<span>{genre} </span>
{/each}
</p>
<p class="break-normal">
<Label>description</Label>:
{movie.description}
</p>
</div>
</div>
{#if movie.lists.length}
<Lists lists="{movie.lists}" />
{/if}
</div>
15 changes: 15 additions & 0 deletions web/src/lib/Search/Lists.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script lang="ts">
import type { ListType } from '../../ambient';
export let lists: ListType[] = [];
</script>

<div class="bg-background rounded-xl mt-2 p-2">
<p class="px-1 pt-2 underline">Film in list(s)</p>
{#each lists as list (list.id)}
<a
class="block bg-secondary hover:bg-secondary-hover rounded-xl p-2 mt-2"
href="{`/user/lists/${list.id}`}">{list.name}</a
>
{/each}
</div>
15 changes: 12 additions & 3 deletions web/src/routes/search/+server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { json } from '@sveltejs/kit';
import type { SearchResult } from '../../ambient.js';
import type { MovieWithLists, SearchResult } from '../../ambient.js';
import { API_HOST } from '$env/static/private';

const API = process.env.API_HOST || API_HOST || 'http://localhost:4000';
Expand All @@ -24,9 +24,18 @@ export const GET = async ({ url, locals, fetch }) => {
if (res.status !== 200) {
throw new Error();
}
const { tmdb }: SearchResult = await res.json();
const { tmdb, db }: SearchResult = await res.json();

return json(tmdb);
const moviesWithLists: MovieWithLists[] = tmdb.map(movie => {
const dbMovie = db.find(m => m.tmdbId === movie.tmdbId);

return {
...movie,
lists: dbMovie ? dbMovie.lists.filter(l => l.creatorId === locals.user?.id) : []
};
});

return json(moviesWithLists);
} catch (e) {
console.error({ error: e });
}
Expand Down
1 change: 1 addition & 0 deletions web/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default {
text: '#f7f7f7',
primary: '#999999',
secondary: '#1f1f1f',
'secondary-hover': '#2f2f2f',
accent: '#858585',
error: '#9e3641',
info: '#999999',
Expand Down
2 changes: 2 additions & 0 deletions web/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"target": "ES2022",
"useDefineForClassFields": true,
"plugins": [
{
"name": "typescript-svelte-plugin",
Expand Down

0 comments on commit 5d1bf13

Please sign in to comment.