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);
--column-width: 42rem;
--column-margin-top: 4rem;
--z-highest: 100;
--cardBorderRadius: 12px;
}
body {

View file

@ -24,11 +24,11 @@
<div class="game-info">
<h2>{game.name}</h2>
<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>
</div>
{#if !minimal}
{#if !minimal && game?.players && game?.playtime}
<div class="game-details">
{#if game.year_published}
<p>{game.year_published}</p>
@ -36,7 +36,7 @@
<p>{game.players} {game.max_players === 1 ? 'player' : 'players'}</p>
<p>{game.playtime} minutes</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}
<div class="description">{@html game.description}</div>
{/if}
@ -68,7 +68,7 @@
<style lang="scss">
img {
border-radius: 10px;
max-height: 200px;
}
button {
@ -84,6 +84,7 @@
.game-container {
display: flex;
place-content: center;
flex-wrap: wrap;
@media (max-width: 650px) {
@ -101,7 +102,8 @@
.game-info {
display: grid;
gap: 0.5rem;
place-items: center;
gap: 0.75rem;
margin: 0.2rem;
}

View file

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

View file

@ -41,7 +41,11 @@
console.log('In success');
const resultGames = result?.data?.games;
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);
console.log(`Frontend result: ${JSON.stringify(result)}`);

View file

@ -1,87 +1,94 @@
<script lang="ts">
import { fly, fade } from 'svelte/transition';
import { flip } from 'svelte/animate';
import Portal from '../../Portal.svelte';
import ToastMessage from './ToastMessage.svelte';
import { toast } from './toast';
import { fly, fade } from 'svelte/transition';
import { flip } from 'svelte/animate';
import Portal from '../../Portal.svelte';
import ToastMessage from './ToastMessage.svelte';
import { toast } from './toast';
</script>
<Portal>
<div class="toast-wrapper">
{#each $toast as toastData (toastData.id)}
<div
aria-label={toastData.dismissible ? 'Click to dismiss' : `${toastData.message}`}
on:click={() => toastData.dismissible && toast.remove(toastData.id)}
in:fly={{ opacity: 0, x: 100 }}
out:fade
animate:flip
class={`toast ${toastData.type.toLowerCase()}`}
>
<ToastMessage {toastData} />
{#if toastData.dismissible && toastData.showButton}
<button
type="button"
aria-label="Click to dismiss"
on:click={() => toastData.dismissible && toast.remove(toastData.id)}
class="close"
>
<svg
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
><path
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="currentColor"
fill-rule="evenodd"
clip-rule="evenodd"
/></svg
>
</button>
{/if}
</div>
{/each}
</div>
<div class="toast-wrapper">
{#each $toast as toastData (toastData.id)}
<div
aria-label={toastData.dismissible ? 'Click to dismiss' : `${toastData.message}`}
on:click={() => toastData.dismissible && toast.remove(toastData.id)}
on:keydown={() => toastData.dismissible && toast.remove(toastData.id)}
in:fly={{ opacity: 0, x: 100 }}
out:fade
animate:flip
class={`toast ${toastData.type.toLowerCase()}`}
>
<ToastMessage {toastData} />
{#if toastData.dismissible && toastData.showButton}
<button
type="button"
aria-label="Click to dismiss"
on:click={() => toastData.dismissible && toast.remove(toastData.id)}
class="close"
>
<svg
viewBox="0 0 15 15"
fill="none"
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
><path
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="currentColor"
fill-rule="evenodd"
clip-rule="evenodd"
/></svg
>
</button>
{/if}
</div>
{/each}
</div>
</Portal>
<style lang="scss">
.toast-wrapper {
position: fixed;
bottom: 5px;
right: 25px;
}
.toast-wrapper {
display: flex;
flex-flow: column;
align-items: center;
justify-content: center;
position: fixed;
bottom: 5vh;
width: 100vw;
z-index: calc(var(--z-highest) + 10);
}
.toast {
display: flex;
gap: 1rem;
place-items: center;
.toast {
display: flex;
justify-content: 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;
position: relative;
margin-bottom: 1rem;
color: white;
background: var(--toast-background, #625df5);
padding: 20px;
border-radius: 15px;
box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.3);
.close {
padding: 5px;
border-radius: 5px;
opacity: 1;
transition: ease 0.3s;
.close {
padding: 5px;
border-radius: 5px;
opacity: 1;
transition: ease 0.3s;
&:hover,
&:focus {
transition: ease 0.3s;
background-color: #625df5;
}
}
}
&:hover,
&:focus {
transition: ease 0.3s;
background-color: #625df5;
}
}
}
.toast.error {
background: var(--toast-error-background, #e54b4b);
color: black;
}
.toast.error {
background: var(--toast-error-background, #e54b4b);
color: black;
}
</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 {
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>
h1 {
margin-top: var(--spacing-64);
font-family: var(--font-sans);
font-size: var(--font-32);
text-align: center;
}
h1 {
margin-top: var(--spacing-64);
font-family: var(--font-sans);
font-size: var(--font-32);
text-align: center;
}
</style>

View file

@ -90,7 +90,11 @@
console.log('In success');
const resultGames = result?.data?.games;
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);
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;
}
img {
max-width: 500px;
}
button {
display: flex;
justify-content: space-between;