generateur_v3/frontend/src/components/exos/Feed.svelte

260 lines
6.5 KiB
Svelte

<script lang="ts">
import { getContext } from "svelte/internal";
import Card from "./Card.svelte";
import Head from "./Head.svelte";
import ModalCard from "./ModalCard.svelte";
import { getExo, getExos, getTags } from "../../requests/exo.request";
import { page } from "$app/stores";
import { onMount } from "svelte";
import Pagination from "./Pagination.svelte";
import { goto } from "$app/navigation";
import { type Writable, writable } from "svelte/store";
import { setContext } from "svelte";
import type { Page, Tag } from "../../types/exo.type";
import type { Store } from "../../types/api.type";
import { page as p } from "$app/stores";
const { show } = getContext<{ show: Function }>("modal");
const { navigate, insertUrl } = getContext<{ navigate: Function; insertUrl: Function }>(
"navigation"
);
const { isAuth } = getContext<{ isAuth: Writable<boolean> }>("auth");
let filter = $isAuth ? "user" : "public";
const exerciceStore = writable<Store<Page | undefined>>({
isLoading: false,
isFetching: false,
isSuccess: false,
data: undefined
});
const tagStore = writable<Store<Tag[] | undefined>>({
isLoading: false,
isFetching: false,
isSuccess: false,
data: []
});
setContext("exos", exerciceStore);
setContext("tags", tagStore);
onMount(() => {
let page = $page.url.searchParams.get("page");
if (page == null) {
page = "1";
}
if ($page.params.slug != undefined && !["user", "public"].includes($page.params.slug)) {
getExo($page.params.slug).then((r) => {
insertUrl("exercices/" + filter);
show(ModalCard, { exo: r, exos: exerciceStore, tags: tagStore }, () => navigate(-1));
});
} else if ($page.params.slug == undefined || $page.params.slug == "user") {
filter = $isAuth ? "user" : "public";
goto(`/exercices/${filter}?${new URLSearchParams({ page }).toString()}`);
} else if ($page.params.slug == "public") {
filter = "public";
goto(`/exercices/${filter}?${new URLSearchParams({ page }).toString()}`);
}
});
$: filter = ["user", "public"].includes($page.params.slug) ? $page.params.slug : filter;
/*$: if(['user', 'public'].includes($page.params.slug) && !$isAuth){
filter = "public"
//goto('/exercices/' + filter)
}*/
const size = 15;
$: activePage = parseInt($page.url.searchParams.get("page")!) || 1;
let search = "";
let selected: Tag[] = [];
$: {
if (!$isAuth) {
filter = "public";
}
exerciceStore.update((s) => {
return { ...s, isFetching: true };
});
getExos(filter as "public" | "user", {
page: activePage == 0 ? 1 : activePage,
search,
size,
tags: [...selected.map((t) => t.id_code)]
})
.then((r) => {
if (activePage > r.totalPage && r.total != 0 && r.totalPage != 0) {
activePage = r.totalPage;
//$p.url.searchParams.set('page', String(activePage));
goto(`?${new URLSearchParams({ page: activePage }).toString()}`);
return;
}
exerciceStore.update((e) => {
return { ...e, isSuccess: true, isFetching: false, data: r };
});
})
.catch(console.log);
}
$: {
if ($isAuth) {
tagStore.update((s) => {
return { ...s, isFetching: true };
});
getTags().then((r) => {
tagStore.update((e) => {
return { ...e, isSuccess: true, isFetching: false, data: r };
});
});
}
}
</script>
<div class="full" class:loading={$tagStore.isFetching || $exerciceStore.isFetching}>
{#if $tagStore.data != undefined}
<Head location={filter} bind:search bind:selected />
{/if}
<div class="feed">
<div class="title">
{#if filter == 'user'}
<h1>
Vos <span>exercices</span>
</h1>
<p>
Vous retrouverez ici tous les exercices que vous avez créé ou copié depuis les exercices
publics
</p>
{:else}
<h1>
Tous les <span>exercices</span>
</h1>
<p>Vous retrouverez ici tous les exercices créés par les autres utilisateurs</p>
{/if}
</div>
{#if $exerciceStore.data != undefined}
{#each $exerciceStore.data.items.filter((e) => e != null && selected.every((t) => e.tags
.map((s) => s.id_code)
.includes(t.id_code))) as e}
<Card bind:exo={e} />
{/each}
{#if $exerciceStore.data.items.length == 0}
<p class="empty">Aucun exercice</p>
{/if}
{:else}
{#each Array(10) as i}
<div class="skeleton"><span /></div>
{/each}
{/if}
</div>
{#if $exerciceStore.data != undefined}
<Pagination bind:page={activePage} total={$exerciceStore.data.totalPage} />
{/if}
</div>
<style lang="scss">
@import '../../variables';
@import "../../mixins.scss";
.skeleton {
//width: 330px;
max-width: 330px;
height: 250px;
opacity: .8;
span {
display: block;
height: 100%;
width: 100%;
background-color: $skeleton;
display: block;
position: relative;
border-radius: 4px;
background-color: $skeleton;
overflow: hidden;
&::after {
top: 0;
left: 0;
right: 0;
bottom: 0;
content: '';
position: absolute;
animation: waves 1.6s linear 0.5s infinite;
transform: translateX(-100%);
background: linear-gradient(
90deg,
transparent,
(lighten($color: $skeleton, $amount: 3), rgba(0, 0, 0, 0.04)),
transparent
);
}
}
}
@keyframes waves {
0% {
transform: translateX(-100%);
}
60% {
transform: translateX(100%);
}
100% {
transform: translateX(100%);
}
}
.feed {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
grid-auto-flow: dense;
grid-gap: 32px;
margin: 0 auto;
margin-top: 20px;
}
.full {
padding: 0 20px;
}
.title {
grid-column: 1/3;
display: flex;
text-align: left;
justify-content: center;
flex-direction: column;
@include down(600) {
grid-column: 1/2;
text-align: center;
}
h1 {
font-size: 3.5em;
font-weight: bolder;
margin: 0;
}
p {
font-size: 1.1em;
}
span {
color: $primary;
}
}
.empty{
display: flex;
justify-content: center;
align-items: center;
font-style: italic;
}
</style>