Update toast to be in the bottom middle, error for fetching game data, fixing random from collection.

This commit is contained in:
Bradley Shellnut 2022-10-29 21:03:54 -05:00
parent 226c9454c7
commit 49464d3fba
10 changed files with 174 additions and 127 deletions

View file

@ -14,6 +14,8 @@
--background-without-opacity: rgba(255, 255, 255, 0.7); --background-without-opacity: rgba(255, 255, 255, 0.7);
--column-width: 42rem; --column-width: 42rem;
--column-margin-top: 4rem; --column-margin-top: 4rem;
--z-highest: 100;
--cardBorderRadius: 12px;
} }
body { body {

View file

@ -24,11 +24,11 @@
<div class="game-info"> <div class="game-info">
<h2>{game.name}</h2> <h2>{game.name}</h2>
<a class="thumbnail" href={`/game/${game.id}`}> <a class="thumbnail" href={`/game/${game.id}`}>
<img width="140" height="140" src={game.thumb_url} alt={`Image of ${game.name}`} /> <img src={game.thumb_url} alt={`Image of ${game.name}`} />
</a> </a>
</div> </div>
{#if !minimal} {#if !minimal && game?.players && game?.playtime}
<div class="game-details"> <div class="game-details">
{#if game.year_published} {#if game.year_published}
<p>{game.year_published}</p> <p>{game.year_published}</p>
@ -36,7 +36,7 @@
<p>{game.players} {game.max_players === 1 ? 'player' : 'players'}</p> <p>{game.players} {game.max_players === 1 ? 'player' : 'players'}</p>
<p>{game.playtime} minutes</p> <p>{game.playtime} minutes</p>
<p>Minimum Age: {game.min_age}</p> <p>Minimum Age: {game.min_age}</p>
<a href={`/game/${game.id}`}>View Game</a> <!-- <a href={`/game/${game.id}`}>View Game</a> -->
{#if detailed} {#if detailed}
<div class="description">{@html game.description}</div> <div class="description">{@html game.description}</div>
{/if} {/if}
@ -68,7 +68,7 @@
<style lang="scss"> <style lang="scss">
img { img {
border-radius: 10px; max-height: 200px;
} }
button { button {
@ -84,6 +84,7 @@
.game-container { .game-container {
display: flex; display: flex;
place-content: center;
flex-wrap: wrap; flex-wrap: wrap;
@media (max-width: 650px) { @media (max-width: 650px) {
@ -101,7 +102,8 @@
.game-info { .game-info {
display: grid; display: grid;
gap: 0.5rem; place-items: center;
gap: 0.75rem;
margin: 0.2rem; margin: 0.2rem;
} }

View file

@ -1,46 +1,48 @@
<script lang="ts"> <script lang="ts">
import { boredState } from '$lib/stores/boredState'; import { boredState } from '$lib/stores/boredState';
import { gameStore } from '$lib/stores/gameSearchStore'; import { gameStore } from '$lib/stores/gameSearchStore';
import { collectionStore } from '$lib/stores/collectionStore'; import { collectionStore } from '$lib/stores/collectionStore';
import { toast } from '$lib/components/toast/toast'; import { toast } from '$lib/components/toast/toast';
import { ToastType, type SavedGameType } from '$lib/types'; import { ToastType, type SavedGameType } from '$lib/types';
import { mapSavedGameToGame } from '$root/lib/util/gameMapper';
async function getRandomCollectionGame() { async function getRandomCollectionGame() {
if ($collectionStore.length > 0) { if ($collectionStore.length > 0) {
boredState.update((n) => ({ ...n, loading: true })); boredState.update((n) => ({ ...n, loading: true }));
let randomNumber: number = Math.round(Math.random() * $collectionStore.length - 1); let randomNumber: number = Math.round(Math.random() * $collectionStore.length - 1);
if ($collectionStore.at(randomNumber)) { if ($collectionStore.at(randomNumber)) {
gameStore.removeAll(); gameStore.removeAll();
const randomGame: SavedGameType = $collectionStore.at(randomNumber)!; const randomGame: SavedGameType = $collectionStore.at(randomNumber)!;
const response = await fetch(`/api/game/${randomGame?.id}`, { // const response = await fetch(`/api/game/${randomGame?.id}`, {
method: 'GET', // method: 'GET',
headers: { accept: 'application/json' } // headers: { accept: 'application/json' }
}); // });
const responseData = await response.json(); // const responseData = await response.json();
console.log('responseData', responseData); // console.log('responseData', responseData);
gameStore.add(responseData?.game); // gameStore.add(responseData?.game);
boredState.update((n) => ({ ...n, loading: false })); const game = gameStore.add(mapSavedGameToGame(randomGame));
} else { boredState.update((n) => ({ ...n, loading: false }));
toast.send('Error!', { duration: 3000, type: ToastType.ERROR, dismissible: true }); } else {
} toast.send('Error!', { duration: 3000, type: ToastType.ERROR, dismissible: true });
boredState.update((n) => ({ ...n, loading: false })); }
} else { boredState.update((n) => ({ ...n, loading: false }));
toast.send('No items in your collection!', { } else {
duration: 3000, toast.send('No items in your collection!', {
type: ToastType.ERROR, duration: 3000,
dismissible: true type: ToastType.ERROR,
}); dismissible: true
} });
} }
}
</script> </script>
<button class="btn" type="button" on:click={() => getRandomCollectionGame()} <button class="btn" type="button" on:click={() => getRandomCollectionGame()}
>Random from collection 🎲</button >Random from collection 🎲</button
> >
<style lang="scss"> <style lang="scss">
button { button {
max-width: 450px; max-width: 450px;
padding: var(--spacing-8) var(--spacing-16); padding: var(--spacing-8) var(--spacing-16);
} }
</style> </style>

View file

@ -41,7 +41,11 @@
console.log('In success'); console.log('In success');
const resultGames = result?.data?.games; const resultGames = result?.data?.games;
if (resultGames?.length <= 0) { if (resultGames?.length <= 0) {
toast.send('No results!', { duration: 3000, type: ToastType.INFO, dismissible: true }); toast.send('No results found 😿', {
duration: 3000,
type: ToastType.INFO,
dismissible: true
});
} }
gameStore.addAll(resultGames); gameStore.addAll(resultGames);
console.log(`Frontend result: ${JSON.stringify(result)}`); console.log(`Frontend result: ${JSON.stringify(result)}`);

View file

@ -1,87 +1,94 @@
<script lang="ts"> <script lang="ts">
import { fly, fade } from 'svelte/transition'; import { fly, fade } from 'svelte/transition';
import { flip } from 'svelte/animate'; import { flip } from 'svelte/animate';
import Portal from '../../Portal.svelte'; import Portal from '../../Portal.svelte';
import ToastMessage from './ToastMessage.svelte'; import ToastMessage from './ToastMessage.svelte';
import { toast } from './toast'; import { toast } from './toast';
</script> </script>
<Portal> <Portal>
<div class="toast-wrapper"> <div class="toast-wrapper">
{#each $toast as toastData (toastData.id)} {#each $toast as toastData (toastData.id)}
<div <div
aria-label={toastData.dismissible ? 'Click to dismiss' : `${toastData.message}`} aria-label={toastData.dismissible ? 'Click to dismiss' : `${toastData.message}`}
on:click={() => toastData.dismissible && toast.remove(toastData.id)} on:click={() => toastData.dismissible && toast.remove(toastData.id)}
in:fly={{ opacity: 0, x: 100 }} on:keydown={() => toastData.dismissible && toast.remove(toastData.id)}
out:fade in:fly={{ opacity: 0, x: 100 }}
animate:flip out:fade
class={`toast ${toastData.type.toLowerCase()}`} animate:flip
> class={`toast ${toastData.type.toLowerCase()}`}
<ToastMessage {toastData} /> >
{#if toastData.dismissible && toastData.showButton} <ToastMessage {toastData} />
<button {#if toastData.dismissible && toastData.showButton}
type="button" <button
aria-label="Click to dismiss" type="button"
on:click={() => toastData.dismissible && toast.remove(toastData.id)} aria-label="Click to dismiss"
class="close" on:click={() => toastData.dismissible && toast.remove(toastData.id)}
> class="close"
<svg >
viewBox="0 0 15 15" <svg
fill="none" viewBox="0 0 15 15"
xmlns="http://www.w3.org/2000/svg" fill="none"
width="16" xmlns="http://www.w3.org/2000/svg"
height="16" width="16"
><path height="16"
d="M11.7816 4.03157C12.0062 3.80702 12.0062 3.44295 11.7816 3.2184C11.5571 2.99385 11.193 2.99385 10.9685 3.2184L7.50005 6.68682L4.03164 3.2184C3.80708 2.99385 3.44301 2.99385 3.21846 3.2184C2.99391 3.44295 2.99391 3.80702 3.21846 4.03157L6.68688 7.49999L3.21846 10.9684C2.99391 11.193 2.99391 11.557 3.21846 11.7816C3.44301 12.0061 3.80708 12.0061 4.03164 11.7816L7.50005 8.31316L10.9685 11.7816C11.193 12.0061 11.5571 12.0061 11.7816 11.7816C12.0062 11.557 12.0062 11.193 11.7816 10.9684L8.31322 7.49999L11.7816 4.03157Z" ><path
fill="currentColor" d="M11.7816 4.03157C12.0062 3.80702 12.0062 3.44295 11.7816 3.2184C11.5571 2.99385 11.193 2.99385 10.9685 3.2184L7.50005 6.68682L4.03164 3.2184C3.80708 2.99385 3.44301 2.99385 3.21846 3.2184C2.99391 3.44295 2.99391 3.80702 3.21846 4.03157L6.68688 7.49999L3.21846 10.9684C2.99391 11.193 2.99391 11.557 3.21846 11.7816C3.44301 12.0061 3.80708 12.0061 4.03164 11.7816L7.50005 8.31316L10.9685 11.7816C11.193 12.0061 11.5571 12.0061 11.7816 11.7816C12.0062 11.557 12.0062 11.193 11.7816 10.9684L8.31322 7.49999L11.7816 4.03157Z"
fill-rule="evenodd" fill="currentColor"
clip-rule="evenodd" fill-rule="evenodd"
/></svg clip-rule="evenodd"
> /></svg
</button> >
{/if} </button>
</div> {/if}
{/each} </div>
</div> {/each}
</div>
</Portal> </Portal>
<style lang="scss"> <style lang="scss">
.toast-wrapper { .toast-wrapper {
position: fixed; display: flex;
bottom: 5px; flex-flow: column;
right: 25px; align-items: center;
} justify-content: center;
position: fixed;
bottom: 5vh;
width: 100vw;
z-index: calc(var(--z-highest) + 10);
}
.toast { .toast {
display: flex; display: flex;
gap: 1rem; justify-content: center;
place-items: center; gap: 1rem;
overflow: hidden;
position: relative;
margin: 1rem 1rem 0;
min-width: 460px;
color: white;
background: var(--toast-background, #625df5);
padding: 1.5rem;
border-radius: 12px;
box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.3);
width: 30rem;
overflow: hidden; .close {
position: relative; padding: 5px;
margin-bottom: 1rem; border-radius: 5px;
color: white; opacity: 1;
background: var(--toast-background, #625df5); transition: ease 0.3s;
padding: 20px;
border-radius: 15px;
box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.3);
.close { &:hover,
padding: 5px; &:focus {
border-radius: 5px; transition: ease 0.3s;
opacity: 1; background-color: #625df5;
transition: ease 0.3s; }
}
}
&:hover, .toast.error {
&:focus { background: var(--toast-error-background, #e54b4b);
transition: ease 0.3s; color: black;
background-color: #625df5; }
}
}
}
.toast.error {
background: var(--toast-error-background, #e54b4b);
color: black;
}
</style> </style>

View file

@ -1,4 +1,14 @@
import type { GameType } from '$lib/types'; import type { GameType, SavedGameType } from '$lib/types';
export function mapSavedGameToGame(game: SavedGameType): GameType {
const { id, name, thumb_url } = game;
return {
id,
name,
thumb_url
};
}
export function mapAPIGameToBoredGame(game): GameType { export function mapAPIGameToBoredGame(game): GameType {
const { const {

View file

@ -1,10 +1,10 @@
<h1>The page you requested doesn't exist!</h1> <h1>The page you requested doesn't exist! 🤷‍♂️</h1>
<style> <style>
h1 { h1 {
margin-top: var(--spacing-64); margin-top: var(--spacing-64);
font-family: var(--font-sans); font-family: var(--font-sans);
font-size: var(--font-32); font-size: var(--font-32);
text-align: center; text-align: center;
} }
</style> </style>

View file

@ -90,7 +90,11 @@
console.log('In success'); console.log('In success');
const resultGames = result?.data?.games; const resultGames = result?.data?.games;
if (resultGames?.length <= 0) { if (resultGames?.length <= 0) {
toast.send('No results!', { duration: 3000, type: ToastType.INFO, dismissible: true }); toast.send('No results found 😿', {
duration: 3000,
type: ToastType.ERROR,
dismissible: true
});
} }
gameStore.addAll(resultGames); gameStore.addAll(resultGames);
totalItems = result?.data?.totalCount; totalItems = result?.data?.totalCount;

View file

@ -0,0 +1,12 @@
<h1>Unable to load board game info! 🤦‍♂️</h1>
<h2>Please try again later. 🙇🏼</h2>
<style>
h1,
h2 {
margin-top: var(--spacing-64);
font-family: var(--font-sans);
font-size: var(--font-32);
text-align: center;
}
</style>

View file

@ -127,6 +127,10 @@
margin-bottom: 3rem; margin-bottom: 3rem;
} }
img {
max-width: 500px;
}
button { button {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;