mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
Updating dependencies, fixing search, fixing wishlist add and remove, fixing game page, not showing buttons on list of games, and adding helper components.
This commit is contained in:
parent
c4a141a1ff
commit
bdfc1dfd3f
28 changed files with 988 additions and 748 deletions
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
|
@ -1,3 +1,3 @@
|
||||||
{
|
{
|
||||||
"cSpell.words": ["iconify", "kickstarter", "msrp"]
|
"cSpell.words": ["iconify", "kickstarter", "lucide", "msrp"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
34
package.json
34
package.json
|
|
@ -22,18 +22,18 @@
|
||||||
"seed": "ts-node --esm prisma/seed.ts"
|
"seed": "ts-node --esm prisma/seed.ts"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@melt-ui/pp": "^0.0.7",
|
"@melt-ui/pp": "^0.1.2",
|
||||||
"@playwright/test": "^1.36.2",
|
"@playwright/test": "^1.37.0",
|
||||||
"@sveltejs/adapter-auto": "^1.0.3",
|
"@sveltejs/adapter-auto": "^1.0.3",
|
||||||
"@sveltejs/adapter-vercel": "^1.0.6",
|
"@sveltejs/adapter-vercel": "^1.0.6",
|
||||||
"@sveltejs/kit": "^1.22.4",
|
"@sveltejs/kit": "^1.22.5",
|
||||||
"@types/cookie": "^0.5.1",
|
"@types/cookie": "^0.5.1",
|
||||||
"@types/node": "^18.17.1",
|
"@types/node": "^18.17.5",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||||
"@typescript-eslint/parser": "^5.62.0",
|
"@typescript-eslint/parser": "^5.62.0",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.15",
|
||||||
"eslint": "^8.46.0",
|
"eslint": "^8.47.0",
|
||||||
"eslint-config-prettier": "^8.9.0",
|
"eslint-config-prettier": "^8.10.0",
|
||||||
"eslint-plugin-svelte": "^2.32.4",
|
"eslint-plugin-svelte": "^2.32.4",
|
||||||
"just-clone": "^6.2.0",
|
"just-clone": "^6.2.0",
|
||||||
"just-debounce-it": "^3.2.0",
|
"just-debounce-it": "^3.2.0",
|
||||||
|
|
@ -44,18 +44,18 @@
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"prettier-plugin-svelte": "^2.10.1",
|
"prettier-plugin-svelte": "^2.10.1",
|
||||||
"prisma": "^5.1.1",
|
"prisma": "^5.1.1",
|
||||||
"sass": "^1.64.2",
|
"sass": "^1.65.1",
|
||||||
"svelte": "^4.1.2",
|
"svelte": "^4.2.0",
|
||||||
"svelte-check": "^3.4.6",
|
"svelte-check": "^3.5.0",
|
||||||
"svelte-preprocess": "^5.0.4",
|
"svelte-preprocess": "^5.0.4",
|
||||||
"svelte-sequential-preprocessor": "^2.0.1",
|
"svelte-sequential-preprocessor": "^2.0.1",
|
||||||
"sveltekit-flash-message": "^2.1.0",
|
"sveltekit-flash-message": "^2.1.3",
|
||||||
"sveltekit-superforms": "^1.5.0",
|
"sveltekit-superforms": "^1.5.1",
|
||||||
"tailwindcss": "^3.3.3",
|
"tailwindcss": "^3.3.3",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
"tslib": "^2.6.1",
|
"tslib": "^2.6.1",
|
||||||
"typescript": "^5.1.6",
|
"typescript": "^5.1.6",
|
||||||
"vite": "^4.4.8",
|
"vite": "^4.4.9",
|
||||||
"vitest": "^0.25.3",
|
"vitest": "^0.25.3",
|
||||||
"zod": "^3.21.4"
|
"zod": "^3.21.4"
|
||||||
},
|
},
|
||||||
|
|
@ -70,9 +70,9 @@
|
||||||
"@iconify-icons/line-md": "^1.2.23",
|
"@iconify-icons/line-md": "^1.2.23",
|
||||||
"@iconify-icons/mdi": "^1.2.47",
|
"@iconify-icons/mdi": "^1.2.47",
|
||||||
"@lucia-auth/adapter-mysql": "^2.0.0",
|
"@lucia-auth/adapter-mysql": "^2.0.0",
|
||||||
"@lucia-auth/adapter-prisma": "^3.0.0",
|
"@lucia-auth/adapter-prisma": "^3.0.1",
|
||||||
"@lukeed/uuid": "^2.0.1",
|
"@lukeed/uuid": "^2.0.1",
|
||||||
"@melt-ui/svelte": "^0.27.3",
|
"@melt-ui/svelte": "^0.34.6",
|
||||||
"@prisma/client": "5.1.1",
|
"@prisma/client": "5.1.1",
|
||||||
"@types/feather-icons": "^4.29.1",
|
"@types/feather-icons": "^4.29.1",
|
||||||
"class-variance-authority": "^0.6.1",
|
"class-variance-authority": "^0.6.1",
|
||||||
|
|
@ -82,9 +82,9 @@
|
||||||
"iconify-icon": "^1.0.8",
|
"iconify-icon": "^1.0.8",
|
||||||
"just-kebab-case": "^4.2.0",
|
"just-kebab-case": "^4.2.0",
|
||||||
"loader": "^2.1.1",
|
"loader": "^2.1.1",
|
||||||
"lucia": "^2.0.0",
|
"lucia": "^2.3.0",
|
||||||
"lucide-svelte": "^0.256.1",
|
"lucide-svelte": "^0.256.1",
|
||||||
"open-props": "^1.5.10",
|
"open-props": "^1.5.11",
|
||||||
"radix-svelte": "^0.8.0",
|
"radix-svelte": "^0.8.0",
|
||||||
"svelte-french-toast": "^1.2.0",
|
"svelte-french-toast": "^1.2.0",
|
||||||
"svelte-lazy": "^1.2.1",
|
"svelte-lazy": "^1.2.1",
|
||||||
|
|
|
||||||
457
pnpm-lock.yaml
457
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
|
@ -46,7 +46,8 @@ model User {
|
||||||
receiveEmail Boolean @default(false)
|
receiveEmail Boolean @default(false)
|
||||||
token String? @unique
|
token String? @unique
|
||||||
collection Collection?
|
collection Collection?
|
||||||
wishlist Wishlist[]
|
wishlist Wishlist?
|
||||||
|
list List[]
|
||||||
theme String @default("system")
|
theme String @default("system")
|
||||||
created_at DateTime @default(now()) @db.Timestamp(6)
|
created_at DateTime @default(now()) @db.Timestamp(6)
|
||||||
updated_at DateTime @updatedAt @db.Timestamp(6)
|
updated_at DateTime @updatedAt @db.Timestamp(6)
|
||||||
|
|
@ -101,7 +102,6 @@ model CollectionItem {
|
||||||
|
|
||||||
model Wishlist {
|
model Wishlist {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String
|
|
||||||
user_id String @unique
|
user_id String @unique
|
||||||
user User @relation(references: [id], fields: [user_id])
|
user User @relation(references: [id], fields: [user_id])
|
||||||
items WishlistItem[]
|
items WishlistItem[]
|
||||||
|
|
@ -123,6 +123,30 @@ model WishlistItem {
|
||||||
@@map("wishlist_items")
|
@@map("wishlist_items")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model List {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
name String
|
||||||
|
user_id String @unique
|
||||||
|
user User @relation(references: [id], fields: [user_id])
|
||||||
|
items ListItem[]
|
||||||
|
|
||||||
|
@@index([user_id])
|
||||||
|
@@map("lists")
|
||||||
|
}
|
||||||
|
|
||||||
|
model ListItem {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
list_id String @unique
|
||||||
|
list List @relation(references: [id], fields: [list_id], onDelete: Cascade)
|
||||||
|
game_id String @unique
|
||||||
|
game Game @relation(references: [id], fields: [game_id])
|
||||||
|
created_at DateTime @default(now()) @db.Timestamp(6)
|
||||||
|
updated_at DateTime @updatedAt @db.Timestamp(6)
|
||||||
|
|
||||||
|
@@index([game_id, list_id])
|
||||||
|
@@map("list_items")
|
||||||
|
}
|
||||||
|
|
||||||
model Game {
|
model Game {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String
|
name String
|
||||||
|
|
@ -152,6 +176,7 @@ model Game {
|
||||||
expansions Expansion[]
|
expansions Expansion[]
|
||||||
collection_items CollectionItem[]
|
collection_items CollectionItem[]
|
||||||
wishlist_items WishlistItem[]
|
wishlist_items WishlistItem[]
|
||||||
|
list_items ListItem[]
|
||||||
external_id String @unique
|
external_id String @unique
|
||||||
created_at DateTime @default(now()) @db.Timestamp(6)
|
created_at DateTime @default(now()) @db.Timestamp(6)
|
||||||
updated_at DateTime @updatedAt @db.Timestamp(6)
|
updated_at DateTime @updatedAt @db.Timestamp(6)
|
||||||
|
|
|
||||||
0
src/lib/apis/collection.ts
Normal file
0
src/lib/apis/collection.ts
Normal file
0
src/lib/apis/wishlist.ts
Normal file
0
src/lib/apis/wishlist.ts
Normal file
138
src/lib/components/AddToList.svelte
Normal file
138
src/lib/components/AddToList.svelte
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { enhance } from "$app/forms";
|
||||||
|
import { fly } from "svelte/transition";
|
||||||
|
import { createSelect, melt } from "@melt-ui/svelte";
|
||||||
|
import { Check, ChevronDown, MinusCircle, PlusCircle } from "lucide-svelte";
|
||||||
|
import Button from "./ui/button/Button.svelte";
|
||||||
|
import type { Collection, Wishlist } from "@prisma/client";
|
||||||
|
|
||||||
|
export let game_id: string;
|
||||||
|
export let collection: Collection;
|
||||||
|
export let wishlist: Wishlist;
|
||||||
|
export let in_wishlist = false;
|
||||||
|
export let in_collection = false;
|
||||||
|
export let lists = [];
|
||||||
|
|
||||||
|
const handleChange = ({ curr, next }) => {
|
||||||
|
console.log({ curr, next });
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
elements: { trigger, menu, option, label, group, groupLabel },
|
||||||
|
states: { valueLabel, open },
|
||||||
|
helpers: { isSelected },
|
||||||
|
} = createSelect({
|
||||||
|
forceVisible: true,
|
||||||
|
onValueChange: handleChange
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log({ in_collection, in_wishlist });
|
||||||
|
|
||||||
|
let options: Record<string, string> = {};
|
||||||
|
let list_of_lists = [];
|
||||||
|
if (!in_collection) {
|
||||||
|
options[collection.id] = 'Add to collection';
|
||||||
|
}
|
||||||
|
if (!in_wishlist) {
|
||||||
|
options[wishlist.id] = 'Add to wishlist';
|
||||||
|
}
|
||||||
|
lists.forEach((list) => {
|
||||||
|
if (!list?.in_list) {
|
||||||
|
options[list.id] = list.name;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if in_wishlist}
|
||||||
|
<form method="POST" action={`/wishlist?/remove`} use:enhance>
|
||||||
|
<input type="hidden" name="id" value={game_id} />
|
||||||
|
<Button variant="destructive" type="submit">
|
||||||
|
<MinusCircle class="square-5" /> Remove from wishlist
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
{:else}
|
||||||
|
<form method="POST" action='/wishlist?/add' use:enhance>
|
||||||
|
<input type="hidden" name="id" value={game_id} />
|
||||||
|
<Button variant="destructive" type="submit">
|
||||||
|
<PlusCircle class="square-5" /> Add to wishlist
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
{#if in_collection}
|
||||||
|
<form method="POST" action='/collection?/remove' use:enhance>
|
||||||
|
<input type="hidden" name="id" value={game_id} />
|
||||||
|
<Button variant="destructive" type="submit">
|
||||||
|
<MinusCircle class="square-5" /> Remove from collection
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
{:else}
|
||||||
|
<form method="POST" action='/collection?/add' use:enhance>
|
||||||
|
<input type="hidden" name="id" value={game_id} />
|
||||||
|
<Button variant="destructive" type="submit">
|
||||||
|
<PlusCircle class="square-5" /> Add to collection
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-1">
|
||||||
|
<!-- svelte-ignore a11y-label-has-associated-control - $label contains the 'for' attribute -->
|
||||||
|
<button
|
||||||
|
class="flex h-10 min-w-[220px] items-center justify-between rounded-md bg-white px-3 py-2 text-black-500 transition-opacity hover:opacity-90"
|
||||||
|
use:melt={$trigger}
|
||||||
|
aria-label="Wishlist"
|
||||||
|
>
|
||||||
|
{$valueLabel || 'Add to...'}
|
||||||
|
<ChevronDown class="square-5" />
|
||||||
|
</button>
|
||||||
|
{#if $open}
|
||||||
|
<div
|
||||||
|
class="z-10 flex max-h-[360px] flex-col overflow-y-auto rounded-md bg-white p-1 focus:!ring-0"
|
||||||
|
use:melt={$menu}
|
||||||
|
transition:fly={{ duration: 150, y: -5 }}
|
||||||
|
>
|
||||||
|
{#each Object.entries(options) as [key, value]}
|
||||||
|
<div
|
||||||
|
class="flex relative cursor-pointer rounded-md py-1 pl-8 pr-4 text-neutral-800 focus:z-10 focus:text-purple-700 data-[highlighted]:bg-purple-50 data-[selected]:bg-purple-100 data-[highlighted]:text-purple-900 data-[selected]:text-purple-900"
|
||||||
|
use:melt={$option({ value: key, label: value })}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
{#if $isSelected(key)}
|
||||||
|
<div class="check">
|
||||||
|
<Check class="square-4" />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <CardFooter>
|
||||||
|
<div class="grid gap-2 place-items-center">
|
||||||
|
<form method="POST" action={`/collection?/${existsInCollection ? 'remove' : 'add'}`}>
|
||||||
|
<input type="hidden" name="id" value={game.id} />
|
||||||
|
<Button variant={existsInCollection ? 'destructive' : 'default'}>
|
||||||
|
{collectionText}
|
||||||
|
{#if existsInCollection}
|
||||||
|
<iconify-icon class="ml-2" icon={minusCircle} width="24" height="24" />
|
||||||
|
{:else}
|
||||||
|
<iconify-icon class="ml-2" icon={plusCircle} width="24" height="24" />
|
||||||
|
{/if}
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
<!-- Add dropdown for wishlist add -->
|
||||||
|
<!--- <form method="POST" action={`/wishlist?/${existsInWishlist ? 'remove' : 'add'}`}>
|
||||||
|
<input type="hidden" name="id" value={game.id} />
|
||||||
|
<Button variant={existsInWishlist ? 'destructive' : 'default'}>
|
||||||
|
{wishlistText}
|
||||||
|
{#if existsInWishlist}
|
||||||
|
<iconify-icon class="ml-2" icon={minusCircle} width="24" height="24" />
|
||||||
|
{:else}
|
||||||
|
<iconify-icon class="ml-2" icon={plusCircle} width="24" height="24" />
|
||||||
|
{/if}
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</CardFooter> -->
|
||||||
0
src/lib/components/WishlistButton.svelte
Normal file
0
src/lib/components/WishlistButton.svelte
Normal file
|
|
@ -1,89 +1,18 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher } from 'svelte';
|
|
||||||
import { Image } from 'svelte-lazy-loader';
|
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
import plusCircle from '@iconify-icons/line-md/plus-circle';
|
|
||||||
import minusCircle from '@iconify-icons/line-md/minus-circle';
|
|
||||||
import { superForm } from 'sveltekit-superforms/client';
|
|
||||||
// import Button from '$lib/components/button/index.svelte';
|
|
||||||
import type { GameType, SavedGameType } from '$lib/types';
|
import type { GameType, SavedGameType } from '$lib/types';
|
||||||
import { collectionStore } from '$lib/stores/collectionStore';
|
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '$components/ui/card';
|
||||||
import { wishlistStore } from '$lib/stores/wishlistStore';
|
|
||||||
import { addToCollection, removeFromCollection } from '$lib/util/manipulateCollection';
|
|
||||||
import { addToWishlist } from '$lib/util/manipulateWishlist';
|
|
||||||
import { browser } from '$app/environment';
|
|
||||||
import { binarySearchOnStore } from '$lib/util/binarySearchOnStore';
|
|
||||||
import { convertToSavedGame } from '$lib/util/gameMapper';
|
|
||||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '$components/ui/card';
|
|
||||||
import { Button } from '$components/ui/button';
|
import { Button } from '$components/ui/button';
|
||||||
import type { SuperValidated } from 'sveltekit-superforms';
|
|
||||||
import type { ListGameSchema } from '$lib/zodValidation';
|
|
||||||
import type { CollectionItem } from '@prisma/client';
|
import type { CollectionItem } from '@prisma/client';
|
||||||
|
|
||||||
// export let data: SuperValidated<ListGameSchema>;
|
// export let data: SuperValidated<ListGameSchema>;
|
||||||
export let game: GameType | CollectionItem;
|
export let game: GameType | CollectionItem;
|
||||||
export let detailed: boolean = false;
|
export let detailed: boolean = false;
|
||||||
|
|
||||||
// const { form, errors, enhance, delayed } = superForm(data);
|
|
||||||
// data={modifyListForm}
|
|
||||||
|
|
||||||
// const dispatch = createEventDispatcher();
|
|
||||||
|
|
||||||
// function removeGameFromWishlist() {
|
|
||||||
// dispatch('handleRemoveWishlist', game);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function removeGameFromCollection() {
|
|
||||||
// dispatch('handleRemoveCollection', game);
|
|
||||||
// }
|
|
||||||
|
|
||||||
function onCollectionClick() {
|
|
||||||
if (existsInCollection) {
|
|
||||||
removeGameFromCollection();
|
|
||||||
} else {
|
|
||||||
let index = binarySearchOnStore($collectionStore, convertToSavedGame(game), 'en');
|
|
||||||
addToCollection(game, index);
|
|
||||||
if (browser) {
|
|
||||||
localStorage.collection = JSON.stringify($collectionStore);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onWishlistClick() {
|
|
||||||
if (existsInWishlist) {
|
|
||||||
removeGameFromWishlist();
|
|
||||||
} else {
|
|
||||||
addToWishlist(game);
|
|
||||||
if (browser) {
|
|
||||||
localStorage.wishlist = JSON.stringify($wishlistStore);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Naive and assumes description is only on our GameType at the moment
|
// Naive and assumes description is only on our GameType at the moment
|
||||||
function isGameType(game: GameType | SavedGameType): game is GameType {
|
function isGameType(game: GameType | SavedGameType): game is GameType {
|
||||||
return (game as GameType).description !== undefined;
|
return (game as GameType).description !== undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// function lazy(img: HTMLImageElement) {
|
|
||||||
// function loaded() {
|
|
||||||
// img.classList.add('loaded');
|
|
||||||
// img.classList.remove('loading');
|
|
||||||
// }
|
|
||||||
// if (img.complete) {
|
|
||||||
// loaded();
|
|
||||||
// } else {
|
|
||||||
// img.classList.add('loading');
|
|
||||||
// img.onload = () => loaded();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// $: existsInCollection = $collectionStore.find((item: SavedGameType) => item.id === game.id);
|
|
||||||
// $: existsInWishlist = $wishlistStore.find((item: SavedGameType) => item.id === game.id);
|
|
||||||
$: existsInCollection = game.in_collection;
|
|
||||||
$: existsInWishlist = game.in_wishlist;
|
|
||||||
$: collectionText = existsInCollection ? 'Remove from collection' : 'Add to collection';
|
|
||||||
$: wishlistText = existsInWishlist ? 'Remove from wishlist' : 'Add to wishlist';
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<article class="grid grid-template-cols-2 gap-4" transition:fade|global>
|
<article class="grid grid-template-cols-2 gap-4" transition:fade|global>
|
||||||
|
|
@ -113,32 +42,6 @@
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
<CardFooter>
|
|
||||||
<div class="grid gap-2 place-items-center">
|
|
||||||
<form method="POST" action={`/collection?/${existsInCollection ? 'remove' : 'add'}`}>
|
|
||||||
<input type="hidden" name="id" value={game.id} />
|
|
||||||
<Button variant={existsInCollection ? 'destructive' : 'default'} on:click={onCollectionClick}>
|
|
||||||
{collectionText}
|
|
||||||
{#if existsInCollection}
|
|
||||||
<iconify-icon class="ml-2" icon={minusCircle} width="24" height="24" />
|
|
||||||
{:else}
|
|
||||||
<iconify-icon class="ml-2" icon={plusCircle} width="24" height="24" />
|
|
||||||
{/if}
|
|
||||||
</Button>
|
|
||||||
</form>
|
|
||||||
<form method="POST" action={`/wishlist?/${existsInWishlist ? 'remove' : 'add'}`}>
|
|
||||||
<input type="hidden" name="id" value={game.id} />
|
|
||||||
<Button variant={existsInWishlist ? 'destructive' : 'default'} on:click={onWishlistClick}>
|
|
||||||
{wishlistText}
|
|
||||||
{#if existsInWishlist}
|
|
||||||
<iconify-icon class="ml-2" icon={minusCircle} width="24" height="24" />
|
|
||||||
{:else}
|
|
||||||
<iconify-icon class="ml-2" icon={plusCircle} width="24" height="24" />
|
|
||||||
{/if}
|
|
||||||
</Button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</CardFooter>
|
|
||||||
</Card>
|
</Card>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,21 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { tick } from 'svelte';
|
import { tick } from 'svelte';
|
||||||
import { fade } from 'svelte/transition';
|
import { fade, fly } from 'svelte/transition';
|
||||||
import { applyAction, type SubmitFunction } from '$app/forms';
|
|
||||||
import { superForm } from 'sveltekit-superforms/client';
|
import { superForm } from 'sveltekit-superforms/client';
|
||||||
import SuperDebug from 'sveltekit-superforms/client/SuperDebug.svelte';
|
import SuperDebug from 'sveltekit-superforms/client/SuperDebug.svelte';
|
||||||
import type { SuperValidated } from 'sveltekit-superforms/index';
|
import type { SuperValidated } from 'sveltekit-superforms/index';
|
||||||
// import { Disclosure, DisclosureButton, DisclosurePanel } from '@rgossiaux/svelte-headlessui';
|
|
||||||
// import { ChevronRightIcon } from '@rgossiaux/svelte-heroicons/solid';
|
|
||||||
import { boredState } from '$lib/stores/boredState';
|
import { boredState } from '$lib/stores/boredState';
|
||||||
import AdvancedSearch from '$lib/components/search/advancedSearch/index.svelte';
|
import AdvancedSearch from '$lib/components/search/advancedSearch/index.svelte';
|
||||||
import { xl, md, sm } from '$lib/stores/mediaQueryStore';
|
import { xl, md, sm } from '$lib/stores/mediaQueryStore';
|
||||||
import { gameStore } from '$lib/stores/gameSearchStore';
|
import { gameStore } from '$lib/stores/gameSearchStore';
|
||||||
import { toast } from '../../toast/toast';
|
|
||||||
import Pagination from '$lib/components/pagination/index.svelte';
|
import Pagination from '$lib/components/pagination/index.svelte';
|
||||||
import Game from '$lib/components/game/index.svelte';
|
import Game from '$lib/components/game/index.svelte';
|
||||||
import { ToastType, type GameType, type SavedGameType } from '$lib/types';
|
import { type GameType, type SavedGameType } from '$lib/types';
|
||||||
// import SkeletonPlaceholder from '../../SkeletonPlaceholder.svelte';
|
import type { SearchSchema } from '$lib/zodValidation';
|
||||||
import RemoveCollectionDialog from '../../dialog/RemoveCollectionDialog.svelte';
|
|
||||||
import RemoveWishlistDialog from '../../dialog/RemoveWishlistDialog.svelte';
|
|
||||||
import type { ListGameSchema, SearchSchema } from '$lib/zodValidation';
|
|
||||||
import { Label } from '$components/ui/label';
|
import { Label } from '$components/ui/label';
|
||||||
import { Input } from '$components/ui/input';
|
import { Input } from '$components/ui/input';
|
||||||
import { Button } from '$components/ui/button';
|
import { Button } from '$components/ui/button';
|
||||||
|
|
||||||
interface RemoveGameEvent extends Event {
|
|
||||||
detail: GameType | SavedGameType;
|
|
||||||
}
|
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
console.log("text search data", data);
|
console.log("text search data", data);
|
||||||
export let showButton: boolean = false;
|
export let showButton: boolean = false;
|
||||||
|
|
@ -34,7 +23,6 @@
|
||||||
|
|
||||||
const { games, totalCount } = data?.searchData;
|
const { games, totalCount } = data?.searchData;
|
||||||
const { form, errors, enhance, constraints, message }: SuperValidated<SearchSchema> = superForm(data.form);
|
const { form, errors, enhance, constraints, message }: SuperValidated<SearchSchema> = superForm(data.form);
|
||||||
// const { form: modifyListForm, errors: listErrors, constraints: listConstraints, enhance: listEnhance, message: listMessage } : SuperValidated<ListGameSchema> = superForm(data.modifyListForm);
|
|
||||||
|
|
||||||
let gameToRemove: GameType | SavedGameType;
|
let gameToRemove: GameType | SavedGameType;
|
||||||
let numberOfGameSkeleton = 1;
|
let numberOfGameSkeleton = 1;
|
||||||
|
|
@ -47,7 +35,6 @@
|
||||||
let name = form?.name || '';
|
let name = form?.name || '';
|
||||||
let disclosureOpen = $errors.length > 0 || false;
|
let disclosureOpen = $errors.length > 0 || false;
|
||||||
|
|
||||||
// $: skip = (page - 1) * pageSize;
|
|
||||||
$: showPagination = totalCount > pageSize;
|
$: showPagination = totalCount > pageSize;
|
||||||
|
|
||||||
if ($xl) {
|
if ($xl) {
|
||||||
|
|
@ -60,12 +47,6 @@
|
||||||
numberOfGameSkeleton = 1;
|
numberOfGameSkeleton = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// let placeholderList = [...Array(numberOfGameSkeleton).keys()];
|
|
||||||
|
|
||||||
// if (form?.error) {
|
|
||||||
// disclosureOpen = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
async function handleNextPageEvent(event: CustomEvent) {
|
async function handleNextPageEvent(event: CustomEvent) {
|
||||||
if (+event?.detail?.page === page + 1) {
|
if (+event?.detail?.page === page + 1) {
|
||||||
page += 1;
|
page += 1;
|
||||||
|
|
@ -89,54 +70,6 @@
|
||||||
submitButton.click();
|
submitButton.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
// function handleRemoveCollection(event: RemoveGameEvent) {
|
|
||||||
// gameToRemove = event?.detail;
|
|
||||||
// boredState.update((n) => ({
|
|
||||||
// ...n,
|
|
||||||
// dialog: { isOpen: true, content: RemoveCollectionDialog, additionalData: gameToRemove }
|
|
||||||
// }));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function handleRemoveWishlist(event: RemoveGameEvent) {
|
|
||||||
// gameToRemove = event?.detail;
|
|
||||||
// boredState.update((n) => ({
|
|
||||||
// ...n,
|
|
||||||
// dialog: { isOpen: true, content: RemoveWishlistDialog, additionalData: gameToRemove }
|
|
||||||
// }));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const submitSearch: SubmitFunction = ({ form, data, action, cancel }) => {
|
|
||||||
// const { name } = Object.fromEntries(data);
|
|
||||||
// if (!disclosureOpen && name?.length === 0) {
|
|
||||||
// toast.send('Please enter a search term', {
|
|
||||||
// duration: 3000,
|
|
||||||
// type: ToastType.ERROR,
|
|
||||||
// dismissible: true
|
|
||||||
// });
|
|
||||||
// cancel();
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// gameStore.removeAll();
|
|
||||||
// boredState.update((n) => ({ ...n, loading: true }));
|
|
||||||
// return async ({ result }) => {
|
|
||||||
// boredState.update((n) => ({ ...n, loading: false }));
|
|
||||||
// // `result` is an `ActionResult` object
|
|
||||||
// if (result.type === 'error') {
|
|
||||||
// toast.send('Error!', { duration: 3000, type: ToastType.ERROR, dismissible: true });
|
|
||||||
// await applyAction(result);
|
|
||||||
// } else if (result.type === 'success') {
|
|
||||||
// gameStore.removeAll();
|
|
||||||
// gameStore.addAll(result?.data?.searchData?.games);
|
|
||||||
// totalItems = result?.data?.searchData?.totalCount;
|
|
||||||
// // toast.send('Success!', { duration: 3000, type: ToastType.INFO, dismissible: true });
|
|
||||||
// await applyAction(result);
|
|
||||||
// } else {
|
|
||||||
// await applyAction(result);
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// };
|
|
||||||
|
|
||||||
const dev = process.env.NODE_ENV !== 'production';
|
const dev = process.env.NODE_ENV !== 'production';
|
||||||
|
|
||||||
// TODO: Keep all Pagination Values on back and forth browser
|
// TODO: Keep all Pagination Values on back and forth browser
|
||||||
|
|
@ -147,7 +80,7 @@
|
||||||
<SuperDebug data={$form} />
|
<SuperDebug data={$form} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<form id="search-form" action="/search" method="GET">
|
<form id="search-form" action="/search" method="GET" use:enhance>
|
||||||
<div class="search">
|
<div class="search">
|
||||||
<fieldset class="text-search" aria-busy={submitting} disabled={submitting}>
|
<fieldset class="text-search" aria-busy={submitting} disabled={submitting}>
|
||||||
<Label for="label">Search</Label>
|
<Label for="label">Search</Label>
|
||||||
|
|
|
||||||
|
|
@ -265,6 +265,11 @@ const searchResultSchema = z.object({
|
||||||
count: z.number()
|
count: z.number()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const WishlistSchema = z.object({
|
||||||
|
name: z.string(),
|
||||||
|
id: z.string()
|
||||||
|
});
|
||||||
|
|
||||||
// export const game_raw_schema_json = zodToJsonSchema(game_schema, {
|
// export const game_raw_schema_json = zodToJsonSchema(game_schema, {
|
||||||
// $refStrategy: 'none',
|
// $refStrategy: 'none',
|
||||||
// });
|
// });
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { fail, redirect } from '@sveltejs/kit';
|
import { fail, redirect } from '@sveltejs/kit';
|
||||||
import { setError, superValidate } from 'sveltekit-superforms/server';
|
import { setError, superValidate } from 'sveltekit-superforms/server';
|
||||||
import type { PageServerLoad } from '../$types.js';
|
import type { PageServerLoad } from '../../$types.js';
|
||||||
import prisma from '$lib/prisma.js';
|
import prisma from '$lib/prisma.js';
|
||||||
import { modifyListGameSchema, type ListGame } from '$lib/config/zod-schemas.js';
|
import { modifyListGameSchema, type ListGame } from '$lib/config/zod-schemas.js';
|
||||||
import type { CollectionItemWithGame } from '$lib/types.js';
|
import type { CollectionItemWithGame } from '$lib/types.js';
|
||||||
|
|
@ -127,7 +127,7 @@ export const actions = {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game) {
|
if (game) {
|
||||||
const wishlist = await prisma.wishlist.create({
|
const wishlist = await prisma.collectionItem.create({
|
||||||
data: {
|
data: {
|
||||||
user_id: session.userId,
|
user_id: session.userId,
|
||||||
name: form.name
|
name: form.name
|
||||||
|
|
|
||||||
35
src/routes/(protected)/list/+layout.server.ts
Normal file
35
src/routes/(protected)/list/+layout.server.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
import prisma from '$lib/prisma.js';
|
||||||
|
import { redirect } from '@sveltejs/kit';
|
||||||
|
|
||||||
|
export async function load({ params, locals }) {
|
||||||
|
const session = await locals.auth.validate();
|
||||||
|
if (!session) {
|
||||||
|
throw redirect(302, '/auth/signin');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let wishlists = await prisma.wishlist.findMany({
|
||||||
|
where: {
|
||||||
|
user_id: session.userId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (wishlists.length === 0) {
|
||||||
|
const wishlist = await prisma.wishlist.create({
|
||||||
|
data: {
|
||||||
|
user_id: session.userId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
wishlists.push(wishlist);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
wishlists
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
wishlists: []
|
||||||
|
};
|
||||||
|
}
|
||||||
41
src/routes/(protected)/list/+layout.svelte
Normal file
41
src/routes/(protected)/list/+layout.svelte
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import Transition from '$lib/components/transition/index.svelte';
|
||||||
|
|
||||||
|
export let data;
|
||||||
|
const wishlists = data.wishlists || [];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<aside class="wishlists">
|
||||||
|
<h2>Your Wishlists</h2>
|
||||||
|
<div class="separator"></div>
|
||||||
|
{#each wishlists as wishlist}
|
||||||
|
<h2 class="wishlist"><a href={`/wishlist/${wishlist.id}`}>{wishlist.name}</a></h2>
|
||||||
|
{/each}
|
||||||
|
</aside>
|
||||||
|
<div class="content">
|
||||||
|
<Transition url={data.url} transition={{ type: 'page' }}>
|
||||||
|
<slot />
|
||||||
|
</Transition>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<style lang="postcss">
|
||||||
|
.wishlists {
|
||||||
|
position: fixed;
|
||||||
|
left: 0;
|
||||||
|
padding-left: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
margin: 5px 0;
|
||||||
|
height: 1px;
|
||||||
|
--tw-bg-opacity: 1;
|
||||||
|
background-color: rgba(0, 0, 0, 1);
|
||||||
|
background-color: rgba(0, 0, 0, var(--tw-bg-opacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
.wishlist {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
126
src/routes/(protected)/list/[id]/+page.server.ts
Normal file
126
src/routes/(protected)/list/[id]/+page.server.ts
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
import { fail, redirect } from '@sveltejs/kit';
|
||||||
|
import { superValidate } from 'sveltekit-superforms/server';
|
||||||
|
import prisma from '$lib/prisma.js';
|
||||||
|
import { list_game_request_schema } from '$lib/zodValidation';
|
||||||
|
|
||||||
|
export async function load({ params, locals }) {
|
||||||
|
const session = await locals.auth.validate();
|
||||||
|
if (!session) {
|
||||||
|
throw redirect(302, '/auth/signin');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let wishlist = await prisma.wishlist.findUnique({
|
||||||
|
where: {
|
||||||
|
id: params.id,
|
||||||
|
AND: {
|
||||||
|
user_id: session.userId
|
||||||
|
}
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
items: {
|
||||||
|
include: {
|
||||||
|
game: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
thumb_url: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
wishlist
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const actions = {
|
||||||
|
// Add game to a wishlist
|
||||||
|
add: async (event) => {
|
||||||
|
const { params, locals, request } = event;
|
||||||
|
const form = await superValidate(event, modifyListGameSchema);
|
||||||
|
|
||||||
|
const session = await locals.auth.validate();
|
||||||
|
if (!session) {
|
||||||
|
throw redirect(302, '/auth/signin');
|
||||||
|
}
|
||||||
|
|
||||||
|
let game = await prisma.game.findUnique({
|
||||||
|
where: {
|
||||||
|
id: form.id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!game) {
|
||||||
|
// game = await prisma.game.create({
|
||||||
|
// data: {
|
||||||
|
// name: form.name
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
return fail(400, {
|
||||||
|
message: 'Game not found'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const wishlist = await prisma.wishlist.findUnique({
|
||||||
|
where: {
|
||||||
|
id: params.id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (wishlist?.user_id !== session.userId) {
|
||||||
|
return fail(401, {
|
||||||
|
message: 'Unauthorized'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wishlist) {
|
||||||
|
throw redirect(302, '/404');
|
||||||
|
}
|
||||||
|
|
||||||
|
const wishlistItem = await prisma.wishlistItem.create({
|
||||||
|
data: {
|
||||||
|
game_id: game.id,
|
||||||
|
wishlist_id: wishlist.id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!wishlistItem) {
|
||||||
|
return fail(500, {
|
||||||
|
message: 'Something went wrong'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
form
|
||||||
|
};
|
||||||
|
},
|
||||||
|
// Create new wishlist
|
||||||
|
create: async ({ params, locals, request }) => {
|
||||||
|
const session = await locals.auth.validate();
|
||||||
|
if (!session) {
|
||||||
|
throw redirect(302, '/auth/signin');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Delete a wishlist
|
||||||
|
delete: async ({ params, locals, request }) => {
|
||||||
|
const session = await locals.auth.validate();
|
||||||
|
if (!session) {
|
||||||
|
throw redirect(302, '/auth/signin');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Remove game from a wishlist
|
||||||
|
remove: async ({ params, locals, request }) => {
|
||||||
|
const session = await locals.auth.validate();
|
||||||
|
if (!session) {
|
||||||
|
throw redirect(302, '/auth/signin');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
24
src/routes/(protected)/list/[id]/+page.svelte
Normal file
24
src/routes/(protected)/list/[id]/+page.svelte
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import Game from '$lib/components/game/index.svelte';
|
||||||
|
|
||||||
|
export let data;
|
||||||
|
console.log('data', data);
|
||||||
|
const wishlist = data.wishlist;
|
||||||
|
const gamesItems = wishlist?.items;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>{`Wishlist ${wishlist.name} | Bored Game`}</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<h1>{wishlist.name}</h1>
|
||||||
|
<h2>Games on your wishlist:</h2>
|
||||||
|
<div class="games-list">
|
||||||
|
{#if gamesItems.length > 0}
|
||||||
|
{#each gamesItems as game (game.id)}
|
||||||
|
<Game {game} />
|
||||||
|
{/each}
|
||||||
|
{:else}
|
||||||
|
<h2>Sorry no games found!</h2>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import { redirect } from '@sveltejs/kit';
|
import { error, redirect } from '@sveltejs/kit';
|
||||||
import { superValidate } from 'sveltekit-superforms/server';
|
import { superValidate } from 'sveltekit-superforms/server';
|
||||||
import prisma from '$lib/prisma.js';
|
import prisma from '$lib/prisma.js';
|
||||||
import { list_game_request_schema } from '$lib/zodValidation';
|
import { list_game_request_schema } from '$lib/zodValidation';
|
||||||
|
import { modifyListGameSchema } from '$lib/config/zod-schemas.js';
|
||||||
|
|
||||||
export async function load({ params, locals }) {
|
export async function load({ params, locals }) {
|
||||||
const session = await locals.auth.validate();
|
const session = await locals.auth.validate();
|
||||||
|
|
@ -9,72 +10,98 @@ export async function load({ params, locals }) {
|
||||||
throw redirect(302, '/auth/signin');
|
throw redirect(302, '/auth/signin');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('Wishlist load User id', session.user);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let wishlists = await prisma.wishlist.findMany({
|
let wishlist = await prisma.wishlist.findUnique({
|
||||||
where: {
|
where: {
|
||||||
user_id: session.userId
|
user_id: session?.user?.userId
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
items: true
|
items: {
|
||||||
|
include: {
|
||||||
|
game: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
thumb_url: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (wishlists.length === 0) {
|
if (!wishlist) {
|
||||||
const wishlist = await prisma.wishlist.create({
|
throw redirect(302, '/404');
|
||||||
data: {
|
|
||||||
user_id: session.userId,
|
|
||||||
name: 'My Wishlist'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
wishlists.push(wishlist);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('wishlist', wishlist);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
wishlists
|
games: wishlist?.items
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
redirect(302, '/404');
|
||||||
}
|
}
|
||||||
|
|
||||||
export const actions = {
|
export const actions = {
|
||||||
// Add game to a wishlist
|
// Add game to a wishlist
|
||||||
add: async (event) => {
|
add: async (event) => {
|
||||||
const { params, locals, request } = event;
|
const { params, locals, request } = event;
|
||||||
const form = await superValidate(event, list_game_request_schema);
|
const form = await superValidate(event, modifyListGameSchema);
|
||||||
|
|
||||||
const session = await locals.auth.validate();
|
try {
|
||||||
if (!session) {
|
const session = await locals.auth.validate();
|
||||||
throw redirect(302, '/auth/signin');
|
if (!session) {
|
||||||
}
|
throw redirect(302, '/auth/signin');
|
||||||
|
|
||||||
let game = await prisma.game.findUnique({
|
|
||||||
where: {
|
|
||||||
id: form.id
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
if (!game) {
|
let game = await prisma.game.findUnique({
|
||||||
game = await prisma.game.create({
|
where: {
|
||||||
data: {
|
id: form.data.id
|
||||||
name: form.name
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
throw redirect(302, '/404');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (game) {
|
if (!game) {
|
||||||
const wishlist = await prisma.wishlist.create({
|
// game = await prisma.game.create({
|
||||||
data: {
|
// data: {
|
||||||
user_id: session.userId,
|
// name: form.name
|
||||||
name: form.name
|
// }
|
||||||
|
// });
|
||||||
|
console.log('game not found');
|
||||||
|
throw redirect(302, '/404');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (game) {
|
||||||
|
const wishlist = await prisma.wishlist.findUnique({
|
||||||
|
where: {
|
||||||
|
user_id: session.user.userId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!wishlist) {
|
||||||
|
console.log('Wishlist not found');
|
||||||
|
return error(404, 'Wishlist not found');
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
await prisma.wishlistItem.create({
|
||||||
form
|
data: {
|
||||||
};
|
game_id: game.id,
|
||||||
|
wishlist_id: wishlist.id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
form
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return error(500, 'Something went wrong');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
// Create new wishlist
|
// Create new wishlist
|
||||||
create: async ({ params, locals, request }) => {
|
create: async ({ params, locals, request }) => {
|
||||||
|
|
@ -91,10 +118,58 @@ export const actions = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Remove game from a wishlist
|
// Remove game from a wishlist
|
||||||
remove: async ({ params, locals, request }) => {
|
remove: async (event) => {
|
||||||
const session = await locals.auth.validate();
|
const { params, locals, request } = event;
|
||||||
if (!session) {
|
const form = await superValidate(event, modifyListGameSchema);
|
||||||
throw redirect(302, '/auth/signin');
|
|
||||||
|
try {
|
||||||
|
const session = await locals.auth.validate();
|
||||||
|
if (!session) {
|
||||||
|
throw redirect(302, '/auth/signin');
|
||||||
|
}
|
||||||
|
|
||||||
|
let game = await prisma.game.findUnique({
|
||||||
|
where: {
|
||||||
|
id: form.data.id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!game) {
|
||||||
|
// game = await prisma.game.create({
|
||||||
|
// data: {
|
||||||
|
// name: form.name
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
console.log('game not found');
|
||||||
|
throw redirect(302, '/404');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (game) {
|
||||||
|
const wishlist = await prisma.wishlist.findUnique({
|
||||||
|
where: {
|
||||||
|
user_id: session.user.userId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!wishlist) {
|
||||||
|
console.log('Wishlist not found');
|
||||||
|
return error(404, 'Wishlist not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
await prisma.wishlistItem.delete({
|
||||||
|
where: {
|
||||||
|
wishlist_id: wishlist.id,
|
||||||
|
game_id: game.id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
form
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return error(500, 'Something went wrong');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,134 +1,22 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
// import { tick, onDestroy } from 'svelte';
|
import Game from '$lib/components/game/index.svelte';
|
||||||
// import Game from '$lib/components/game/index.svelte';
|
|
||||||
// import { wishlistStore } from '$lib/stores/wishlistStore';
|
|
||||||
// import type { GameType, SavedGameType } from '$lib/types';
|
|
||||||
// import { boredState } from '$lib/stores/boredState';
|
|
||||||
// import Pagination from '$lib/components/pagination/index.svelte';
|
|
||||||
// import RemoveWishlistDialog from '$lib/components/dialog/RemoveWishlistDialog.svelte';
|
|
||||||
// import RemoveCollectionDialog from '$lib/components/dialog/RemoveCollectionDialog.svelte';
|
|
||||||
// import { createSearchStore, searchHandler } from '$lib/stores/search';
|
|
||||||
|
|
||||||
// let gameToRemove: GameType | SavedGameType;
|
|
||||||
// let pageSize = 10;
|
|
||||||
// let page = 1;
|
|
||||||
|
|
||||||
// const searchStore = createSearchStore($wishlistStore);
|
|
||||||
// console.log('searchStore', $searchStore);
|
|
||||||
|
|
||||||
// const unsubscribe = searchStore.subscribe((model) => searchHandler(model));
|
|
||||||
|
|
||||||
// onDestroy(() => {
|
|
||||||
// unsubscribe();
|
|
||||||
// });
|
|
||||||
|
|
||||||
// $: skip = (page - 1) * pageSize;
|
|
||||||
// $: gamesShown = $searchStore.filtered.slice(skip, skip + pageSize);
|
|
||||||
// $: totalItems = $searchStore.search === '' ? $wishlistStore.length : $searchStore.filtered.length;
|
|
||||||
|
|
||||||
// interface RemoveGameEvent extends Event {
|
|
||||||
// detail: GameType | SavedGameType;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function handleRemoveCollection(event: RemoveGameEvent) {
|
|
||||||
// gameToRemove = event?.detail;
|
|
||||||
// boredState.update((n) => ({
|
|
||||||
// ...n,
|
|
||||||
// dialog: { isOpen: true, content: RemoveCollectionDialog, additionalData: gameToRemove }
|
|
||||||
// }));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// function handleRemoveWishlist(event: RemoveGameEvent) {
|
|
||||||
// gameToRemove = event?.detail;
|
|
||||||
// boredState.update((n) => ({
|
|
||||||
// ...n,
|
|
||||||
// dialog: { isOpen: true, content: RemoveWishlistDialog, additionalData: gameToRemove }
|
|
||||||
// }));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async function handleNextPageEvent(event: CustomEvent) {
|
|
||||||
// if (+event?.detail?.page === page + 1) {
|
|
||||||
// page += 1;
|
|
||||||
// }
|
|
||||||
// await tick();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async function handlePreviousPageEvent(event: CustomEvent) {
|
|
||||||
// if (+event?.detail?.page === page - 1) {
|
|
||||||
// page -= 1;
|
|
||||||
// }
|
|
||||||
// await tick();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// async function handlePerPageEvent(event: CustomEvent) {
|
|
||||||
// page = 1;
|
|
||||||
// pageSize = event.detail.pageSize;
|
|
||||||
// await tick();
|
|
||||||
// }
|
|
||||||
export let data;
|
export let data;
|
||||||
const wishlists = data.wishlists || [];
|
console.log('data', data);
|
||||||
|
const games = data.games;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
<title>Your Wishlist | Bored Game</title>
|
<title>{`Your Wishlist | Bored Game`}</title>
|
||||||
</svelte:head>
|
</svelte:head>
|
||||||
|
|
||||||
<h1>Your Wishlist</h1>
|
<h2>Games on your wishlist:</h2>
|
||||||
{#each wishlists as wishlist}
|
<div class="games-list">
|
||||||
<h2>{wishlist.name}</h2>
|
{#if games.length > 0}
|
||||||
{/each}
|
{#each games as game (game.id)}
|
||||||
<!-- <input type="text" id="search" name="search" placeholder="Search Your Wishlist" bind:value={$searchStore.search} />
|
<Game {game} />
|
||||||
|
{/each}
|
||||||
<div class="games">
|
{:else}
|
||||||
<div class="games-list">
|
<h2>Sorry no games found!</h2>
|
||||||
{#if $wishlistStore.length === 0}
|
|
||||||
<h2>No games in your wishlist</h2>
|
|
||||||
{:else}
|
|
||||||
{#each gamesShown as game}
|
|
||||||
<Game
|
|
||||||
on:handleRemoveWishlist={handleRemoveWishlist}
|
|
||||||
on:handleRemoveCollection={handleRemoveCollection}
|
|
||||||
{game}
|
|
||||||
/>
|
|
||||||
{/each}
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{#if $wishlistStore.length !== 0}
|
|
||||||
<Pagination
|
|
||||||
{pageSize}
|
|
||||||
{page}
|
|
||||||
{totalItems}
|
|
||||||
forwardText="Next"
|
|
||||||
backwardText="Prev"
|
|
||||||
pageSizes={[10, 25, 50, 100]}
|
|
||||||
on:nextPageEvent={handleNextPageEvent}
|
|
||||||
on:previousPageEvent={handlePreviousPageEvent}
|
|
||||||
on:perPageEvent={handlePerPageEvent}
|
|
||||||
/>
|
|
||||||
{/if}
|
{/if}
|
||||||
</div> -->
|
</div>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
h1 {
|
|
||||||
margin: 1.5rem 0rem;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.games {
|
|
||||||
margin: 2rem 0rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.games-list {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(3, minmax(200px, 1fr));
|
|
||||||
gap: 2rem;
|
|
||||||
|
|
||||||
@media (max-width: 800px) {
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 550px) {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -11,7 +11,6 @@
|
||||||
import Header from '$lib/components/header/index.svelte';
|
import Header from '$lib/components/header/index.svelte';
|
||||||
import Footer from '$lib/components/footer.svelte';
|
import Footer from '$lib/components/footer.svelte';
|
||||||
import Loading from '$lib/components/loading.svelte';
|
import Loading from '$lib/components/loading.svelte';
|
||||||
import Transition from '$lib/components/transition/index.svelte';
|
|
||||||
import Portal from '$lib/Portal.svelte';
|
import Portal from '$lib/Portal.svelte';
|
||||||
import { boredState } from '$lib/stores/boredState';
|
import { boredState } from '$lib/stores/boredState';
|
||||||
import { collectionStore } from '$lib/stores/collectionStore';
|
import { collectionStore } from '$lib/stores/collectionStore';
|
||||||
|
|
@ -123,9 +122,9 @@
|
||||||
<Header user={data.user} />
|
<Header user={data.user} />
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<Transition url={data.url} transition={{ type: 'page' }}>
|
<!-- <Transition url={data.url} transition={{ type: 'page' }}> -->
|
||||||
<slot />
|
<slot />
|
||||||
</Transition>
|
<!-- </Transition> -->
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|
|
||||||
33
src/routes/api/wishlist/+server.ts
Normal file
33
src/routes/api/wishlist/+server.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { error } from '@sveltejs/kit';
|
||||||
|
|
||||||
|
// Fetch collection for user
|
||||||
|
// export function GET({ url, locals }) {
|
||||||
|
// if (!locals.user) {
|
||||||
|
// throw error(401, {});
|
||||||
|
// }
|
||||||
|
// const
|
||||||
|
// const searchParams = Object.fromEntries(url.searchParams);
|
||||||
|
// const q = searchParams?.q;
|
||||||
|
// const limit = parseInt(searchParams?.limit) || 10;
|
||||||
|
// const skip = parseInt(searchParams?.skip) || 0;
|
||||||
|
|
||||||
|
// return new Response();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Create a new collection for user
|
||||||
|
// export function POST({ url }) {
|
||||||
|
// const searchParams = Object.fromEntries(url.searchParams);
|
||||||
|
// const q = searchParams?.q;
|
||||||
|
// const limit = parseInt(searchParams?.limit) || 10;
|
||||||
|
// const skip = parseInt(searchParams?.skip) || 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Update or Create a collection
|
||||||
|
// export function PUT({ url }) {
|
||||||
|
// const searchParams = Object.fromEntries(url.searchParams);
|
||||||
|
// const q = searchParams?.q;
|
||||||
|
// const limit = parseInt(searchParams?.limit) || 10;
|
||||||
|
// const skip = parseInt(searchParams?.skip) || 0;
|
||||||
|
// }
|
||||||
|
|
||||||
|
//
|
||||||
0
src/routes/api/wishlist/[id]/items/+server.ts
Normal file
0
src/routes/api/wishlist/[id]/items/+server.ts
Normal file
74
src/routes/api/wishlist/[id]/search/+server.ts
Normal file
74
src/routes/api/wishlist/[id]/search/+server.ts
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
import { error, json } from '@sveltejs/kit';
|
||||||
|
import prisma from '$lib/prisma.js';
|
||||||
|
import type { CollectionItemWithGame } from '$lib/types.js';
|
||||||
|
|
||||||
|
// Search a user's collection
|
||||||
|
export async function GET({ url, locals, params }) {
|
||||||
|
const searchParams = Object.fromEntries(url.searchParams);
|
||||||
|
const q = searchParams?.q || '';
|
||||||
|
const limit = parseInt(searchParams?.limit) || 10;
|
||||||
|
const skip = parseInt(searchParams?.skip) || 0;
|
||||||
|
const order = searchParams?.order || 'asc';
|
||||||
|
const sort = searchParams?.sort || 'name';
|
||||||
|
const collection_id = params.id;
|
||||||
|
const session = await locals.auth.validate();
|
||||||
|
console.log('url', url);
|
||||||
|
console.log('username', locals?.user?.id);
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
|
throw error(401, { message: 'Unauthorized' });
|
||||||
|
}
|
||||||
|
|
||||||
|
let collection = await prisma.collection.findUnique({
|
||||||
|
where: {
|
||||||
|
user_id: locals.user.userId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
console.log('collection', collection);
|
||||||
|
|
||||||
|
if (!collection) {
|
||||||
|
console.log('Collection was not found');
|
||||||
|
throw error(404, { message: 'Collection was not found' });
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const orderBy = { [sort]: order };
|
||||||
|
let collection_items: CollectionItemWithGame[] = await prisma.collectionItem.findMany({
|
||||||
|
where: {
|
||||||
|
collection_id,
|
||||||
|
AND: [
|
||||||
|
{
|
||||||
|
game: {
|
||||||
|
name: {
|
||||||
|
contains: q
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
orderBy: [
|
||||||
|
{
|
||||||
|
game: {
|
||||||
|
...orderBy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
include: {
|
||||||
|
game: {
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
thumb_url: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
skip,
|
||||||
|
take: limit
|
||||||
|
});
|
||||||
|
|
||||||
|
return json(collection_items);
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
throw error(500, { message: 'Something went wrong' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -71,12 +71,10 @@ export const actions = {
|
||||||
user_id: user.id
|
user_id: user.id
|
||||||
},
|
},
|
||||||
create: {
|
create: {
|
||||||
user_id: user.id,
|
user_id: user.id
|
||||||
name: 'My Wishlist'
|
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
user_id: user.id,
|
user_id: user.id
|
||||||
name: 'My Wishlist'
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -89,8 +89,7 @@ export const actions = {
|
||||||
});
|
});
|
||||||
await prisma.wishlist.create({
|
await prisma.wishlist.create({
|
||||||
data: {
|
data: {
|
||||||
user_id: user.userId,
|
user_id: user.userId
|
||||||
name: 'My Wishlist'
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,44 @@ export const load = async ({ params, setHeaders, locals }) => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log('found game', game);
|
console.log('found game', game);
|
||||||
|
|
||||||
|
if (!game) {
|
||||||
|
throw error(404, 'not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
const wishlist = await prisma.wishlist.findUnique({
|
||||||
|
where: {
|
||||||
|
user_id: user.userId
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
items: {
|
||||||
|
where: {
|
||||||
|
game_id: game.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const collection = await prisma.collection.findUnique({
|
||||||
|
where: {
|
||||||
|
user_id: user.userId
|
||||||
|
},
|
||||||
|
include: {
|
||||||
|
items: {
|
||||||
|
where: {
|
||||||
|
game_id: game.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
game,
|
game,
|
||||||
user
|
user,
|
||||||
|
in_wishlist: wishlist?.items?.length !== 0 || false,
|
||||||
|
in_collection: collection?.items?.length !== 0 || false,
|
||||||
|
wishlist,
|
||||||
|
collection
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
|
|
||||||
|
|
@ -3,20 +3,14 @@
|
||||||
import { Image } from 'svelte-lazy-loader';
|
import { Image } from 'svelte-lazy-loader';
|
||||||
import minusCircle from '@iconify-icons/line-md/minus-circle';
|
import minusCircle from '@iconify-icons/line-md/minus-circle';
|
||||||
import plusCircle from '@iconify-icons/line-md/plus-circle';
|
import plusCircle from '@iconify-icons/line-md/plus-circle';
|
||||||
import type { GameType, SavedGameType } from '$lib/types';
|
import type { SavedGameType } from '$lib/types';
|
||||||
import { collectionStore } from '$lib/stores/collectionStore';
|
import { collectionStore } from '$lib/stores/collectionStore';
|
||||||
import { wishlistStore } from '$lib/stores/wishlistStore';
|
import { wishlistStore } from '$lib/stores/wishlistStore';
|
||||||
import RemoveCollectionDialog from '$lib/components/dialog/RemoveCollectionDialog.svelte';
|
|
||||||
import { addToCollection } from '$lib/util/manipulateCollection';
|
|
||||||
import type { PageData } from './$types';
|
import type { PageData } from './$types';
|
||||||
import { boredState } from '$lib/stores/boredState';
|
|
||||||
import { browser } from '$app/environment';
|
|
||||||
import LinkWithIcon from '$lib/components/LinkWithIcon.svelte';
|
import LinkWithIcon from '$lib/components/LinkWithIcon.svelte';
|
||||||
import { addToWishlist } from '$lib/util/manipulateWishlist';
|
|
||||||
import RemoveWishlistDialog from '$lib/components/dialog/RemoveWishlistDialog.svelte';
|
|
||||||
import { binarySearchOnStore } from '$lib/util/binarySearchOnStore';
|
|
||||||
import { convertToSavedGame } from '$lib/util/gameMapper';
|
|
||||||
import { Button } from '$components/ui/button';
|
import { Button } from '$components/ui/button';
|
||||||
|
import AddToList from '$components/AddToList.svelte';
|
||||||
|
import { Dices } from 'lucide-svelte';
|
||||||
|
|
||||||
$: existsInCollection = $collectionStore.find((item: SavedGameType) => item.id === game.id);
|
$: existsInCollection = $collectionStore.find((item: SavedGameType) => item.id === game.id);
|
||||||
$: existsInWishlist = $wishlistStore.find((item: SavedGameType) => item.id === game.id);
|
$: existsInWishlist = $wishlistStore.find((item: SavedGameType) => item.id === game.id);
|
||||||
|
|
@ -25,56 +19,11 @@
|
||||||
|
|
||||||
export let data: PageData;
|
export let data: PageData;
|
||||||
console.log('data', data);
|
console.log('data', data);
|
||||||
// let game: GameType;
|
|
||||||
$: ({ game, user } = data);
|
$: ({ game, user, wishlist, collection, in_collection, in_wishlist } = data);
|
||||||
// let game = data?.game;
|
|
||||||
// export let game: GameType = data?.game;
|
|
||||||
let seeMore: boolean = false;
|
let seeMore: boolean = false;
|
||||||
console.log('game', game);
|
console.log('game', game);
|
||||||
// let firstParagraphEnd = 0;
|
|
||||||
// if (game?.description?.indexOf('</p>') > 0) {
|
|
||||||
// firstParagraphEnd = game?.description?.indexOf('</p>') + 4;
|
|
||||||
// } else if (game?.description?.indexOf('</ p>') > 0) {
|
|
||||||
// firstParagraphEnd = game?.description?.indexOf('</ p>') + 5;
|
|
||||||
// }
|
|
||||||
|
|
||||||
function onCollectionClick() {
|
|
||||||
if (existsInCollection) {
|
|
||||||
removeFromCollection();
|
|
||||||
} else {
|
|
||||||
let index = binarySearchOnStore($collectionStore, convertToSavedGame(game), 'en');
|
|
||||||
console.log(`Binary index: ${index}`)
|
|
||||||
addToCollection(game, index);
|
|
||||||
if (browser) {
|
|
||||||
localStorage.collection = JSON.stringify($collectionStore);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onWishlistClick() {
|
|
||||||
if (existsInWishlist) {
|
|
||||||
removeFromWishList();
|
|
||||||
} else {
|
|
||||||
addToWishlist(game);
|
|
||||||
if (browser) {
|
|
||||||
localStorage.wishlist = JSON.stringify($wishlistStore);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeFromCollection() {
|
|
||||||
boredState.update((n) => ({
|
|
||||||
...n,
|
|
||||||
dialog: { isOpen: true, content: RemoveCollectionDialog, additionalData: game }
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeFromWishList() {
|
|
||||||
boredState.update((n) => ({
|
|
||||||
...n,
|
|
||||||
dialog: { isOpen: true, content: RemoveWishlistDialog, additionalData: game }
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
|
|
@ -86,7 +35,11 @@
|
||||||
<section class="game">
|
<section class="game">
|
||||||
<div>
|
<div>
|
||||||
<a class="thumbnail" href={game.url}>
|
<a class="thumbnail" href={game.url}>
|
||||||
<Image src={game.thumb_url} alt={`Image of ${game.name}`} />
|
{#if game?.thumb_url}
|
||||||
|
<Image src={game.thumb_url} alt={`Image of ${game.name}`} />
|
||||||
|
{:else}
|
||||||
|
<Dices />
|
||||||
|
{/if}
|
||||||
<!-- <img src={game.image_url} alt={`Image of ${game.name}`} /> -->
|
<!-- <img src={game.image_url} alt={`Image of ${game.name}`} /> -->
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -110,24 +63,7 @@
|
||||||
</LinkWithIcon>
|
</LinkWithIcon>
|
||||||
</div>
|
</div>
|
||||||
{#if user?.username}
|
{#if user?.username}
|
||||||
<div style="display: grid; gap: 1.5rem; place-content: center;">
|
<AddToList {in_collection} {in_wishlist} game_id={game.id} {wishlist} {collection} />
|
||||||
<Button size="md" kind={existsInCollection ? 'danger' : 'primary'} icon on:click={onCollectionClick}>
|
|
||||||
{collectionText}
|
|
||||||
{#if existsInCollection}
|
|
||||||
<iconify-icon icon={minusCircle} width="24" height="24" />
|
|
||||||
{:else}
|
|
||||||
<iconify-icon icon={plusCircle} width="24" height="24" />
|
|
||||||
{/if}
|
|
||||||
</Button>
|
|
||||||
<Button kind={existsInWishlist ? 'danger' : 'primary'} icon on:click={onWishlistClick}>
|
|
||||||
{wishlistText}
|
|
||||||
{#if existsInWishlist}
|
|
||||||
<iconify-icon icon={minusCircle} width="24" height="24" />
|
|
||||||
{:else}
|
|
||||||
<iconify-icon icon={plusCircle} width="24" height="24" />
|
|
||||||
{/if}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
{:else}
|
{:else}
|
||||||
<span>
|
<span>
|
||||||
<Button href="/auth/signup">Sign Up</Button> or <Button href="/auth/signin">Sign In</Button> to add to a list.
|
<Button href="/auth/signup">Sign Up</Button> or <Button href="/auth/signin">Sign In</Button> to add to a list.
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import type { PageServerLoad } from '../$types.js';
|
||||||
* an array of all the games fetched. If any error occurred during the operation, it returns an object with totalCount as 0 and games as empty array.
|
* an array of all the games fetched. If any error occurred during the operation, it returns an object with totalCount as 0 and games as empty array.
|
||||||
* @throws will throw an error if the response received from fetching games operation is not OK (200).
|
* @throws will throw an error if the response received from fetching games operation is not OK (200).
|
||||||
*/
|
*/
|
||||||
async function searchForGames(urlQueryParams: SearchQuery, locals, eventFetch) {
|
async function searchForGames(urlQueryParams: SearchQuery, eventFetch) {
|
||||||
try {
|
try {
|
||||||
console.log('urlQueryParams search games', urlQueryParams);
|
console.log('urlQueryParams search games', urlQueryParams);
|
||||||
// let games = await prisma.game.findMany({
|
// let games = await prisma.game.findMany({
|
||||||
|
|
@ -104,8 +104,8 @@ async function searchForGames(urlQueryParams: SearchQuery, locals, eventFetch) {
|
||||||
console.log('totalCount', totalCount);
|
console.log('totalCount', totalCount);
|
||||||
gameList.forEach((game) => {
|
gameList.forEach((game) => {
|
||||||
if (game?.min_players && game?.max_players) {
|
if (game?.min_players && game?.max_players) {
|
||||||
game.players = `${game.min_players}-${game.max_players}`;
|
game.players = `${game.min_players} - ${game.max_players}`;
|
||||||
game.playtime = `${game.min_playtime}-${game.max_playtime}`;
|
game.playtime = `${game.min_playtime} - ${game.max_playtime}`;
|
||||||
}
|
}
|
||||||
const boredGame = mapAPIGameToBoredGame(game);
|
const boredGame = mapAPIGameToBoredGame(game);
|
||||||
createOrUpdateGame(boredGame);
|
createOrUpdateGame(boredGame);
|
||||||
|
|
@ -114,51 +114,6 @@ async function searchForGames(urlQueryParams: SearchQuery, locals, eventFetch) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (locals?.user) {
|
|
||||||
const game_ids = games.map((game) => game.id);
|
|
||||||
console.log('game_ids', game_ids);
|
|
||||||
const collections = await prisma.collection.findMany({
|
|
||||||
where: {
|
|
||||||
user_id: locals.user.id
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
items: {
|
|
||||||
where: {
|
|
||||||
game_id: {
|
|
||||||
in: game_ids
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
console.log('collections', collections);
|
|
||||||
const wishlists = await prisma.wishlist.findMany({
|
|
||||||
where: {
|
|
||||||
user_id: locals.user.id
|
|
||||||
},
|
|
||||||
include: {
|
|
||||||
items: {
|
|
||||||
where: {
|
|
||||||
id: {
|
|
||||||
in: game_ids
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// console.log('wishlist_items', wishlist_items);
|
|
||||||
for (const game of games) {
|
|
||||||
console.log(
|
|
||||||
'Checking collection',
|
|
||||||
collections.findIndex((item) => item.items.some((i) => i.game_id === game.id))
|
|
||||||
);
|
|
||||||
game.in_collection =
|
|
||||||
collections.findIndex((item) => item.items.some((i) => i.game_id === game.id)) === 0;
|
|
||||||
game.in_wishlist =
|
|
||||||
wishlists.findIndex((item) => item.items.some((i) => i.game_id === game.id)) === 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
totalCount,
|
totalCount,
|
||||||
games
|
games
|
||||||
|
|
@ -290,42 +245,54 @@ export const load: PageServerLoad = async ({ params, locals, request, fetch, url
|
||||||
};
|
};
|
||||||
|
|
||||||
// fields: ('id,name,min_age,min_players,max_players,thumb_url,min_playtime,max_playtime,min_age,description');
|
// fields: ('id,name,min_age,min_players,max_players,thumb_url,min_playtime,max_playtime,min_age,description');
|
||||||
|
try {
|
||||||
if (form.data?.minAge) {
|
if (form.data?.minAge) {
|
||||||
if (form.data?.exactMinAge) {
|
if (form.data?.exactMinAge) {
|
||||||
queryParams.min_age = form.data?.minAge;
|
queryParams.min_age = form.data?.minAge;
|
||||||
} else {
|
} else {
|
||||||
queryParams.gt_min_age = form.data?.minAge === 1 ? 0 : form.data?.minAge - 1;
|
queryParams.gt_min_age = form.data?.minAge === 1 ? 0 : form.data?.minAge - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (form.data?.minPlayers) {
|
if (form.data?.minPlayers) {
|
||||||
if (form.data?.exactMinPlayers) {
|
if (form.data?.exactMinPlayers) {
|
||||||
queryParams.min_players = form.data?.minPlayers;
|
queryParams.min_players = form.data?.minPlayers;
|
||||||
} else {
|
} else {
|
||||||
queryParams.gt_min_players = form.data?.minPlayers === 1 ? 0 : form.data?.minPlayers - 1;
|
queryParams.gt_min_players = form.data?.minPlayers === 1 ? 0 : form.data?.minPlayers - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if (form.data?.maxPlayers) {
|
||||||
if (form.data?.maxPlayers) {
|
if (form.data?.exactMaxPlayers) {
|
||||||
if (form.data?.exactMaxPlayers) {
|
queryParams.max_players = form.data?.maxPlayers;
|
||||||
queryParams.max_players = form.data?.maxPlayers;
|
} else {
|
||||||
} else {
|
queryParams.lt_max_players = form.data?.maxPlayers + 1;
|
||||||
queryParams.lt_max_players = form.data?.maxPlayers + 1;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const newQueryParams: Record<string, string> = {};
|
||||||
|
for (const key in queryParams) {
|
||||||
|
newQueryParams[key] = `${queryParams[key as keyof SearchQuery]}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const urlQueryParams = new URLSearchParams(newQueryParams);
|
||||||
|
const searchData = await searchForGames(urlQueryParams, fetch);
|
||||||
|
// console.log('searchData', searchData);
|
||||||
|
|
||||||
|
return {
|
||||||
|
form,
|
||||||
|
// modifyListForm,
|
||||||
|
searchData
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
console.log(`Error searching board games ${e}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const newQueryParams: Record<string, string> = {};
|
|
||||||
for (const key in queryParams) {
|
|
||||||
newQueryParams[key] = `${queryParams[key as keyof SearchQuery]}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const urlQueryParams = new URLSearchParams(newQueryParams);
|
|
||||||
const searchData = await searchForGames(urlQueryParams, locals, fetch);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
form,
|
form,
|
||||||
// modifyListForm,
|
searchData: {
|
||||||
searchData
|
totalCount: 0,
|
||||||
|
games: []
|
||||||
|
},
|
||||||
|
wishlists: []
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,4 +28,5 @@ const config = {
|
||||||
componentPath: './src/lib/components/ui'
|
componentPath: './src/lib/components/ui'
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue