215 lines
4.5 KiB
Svelte
215 lines
4.5 KiB
Svelte
<script lang="ts">
|
|
import { getExos, getTags } from "../../requests/exo.request";
|
|
import { writable, type Writable } from "svelte/store";
|
|
import type { Exercice, Tag } from "../../types/exo.type";
|
|
import TagViewer from "./TagViewer.svelte";
|
|
import TagSelector from "../forms/TagSelector.svelte";
|
|
import { getContext } from "svelte";
|
|
import FaTimes from "svelte-icons/fa/FaTimes.svelte";
|
|
import type { ExoSelect } from "src/types/room.type";
|
|
|
|
export let selectedExos: Writable<ExoSelect[]>;
|
|
|
|
const exos = writable<{ hasMore: Boolean; data: Exercice[]; page: number }>({
|
|
hasMore: true,
|
|
data: [],
|
|
page: 1
|
|
});
|
|
const tags = writable<Tag[]>([]);
|
|
|
|
|
|
let search = "";
|
|
let selected: Tag[] = [];
|
|
const { isAuth } = getContext<{ isAuth: Writable<boolean> }>("auth");
|
|
const { close } = getContext<{ close: () => void }>("modal");
|
|
|
|
$:filter = $isAuth ? "user" : "public";
|
|
$: {
|
|
getExos(filter, { search, size: 20, tags: [...selected.map((t) => t.id_code)] }).then((r) => {
|
|
exos.set({
|
|
hasMore: r.totalPage > 1,
|
|
data: r.items,
|
|
page: 1
|
|
});
|
|
});
|
|
}
|
|
$: getTags().then((r) => {
|
|
tags.set(r);
|
|
});
|
|
|
|
const fetchNextPage = () => {
|
|
if ($exos.hasMore) {
|
|
getExos(filter, {
|
|
search,
|
|
size: 20,
|
|
tags: [...selected.map((t) => t.id_code)],
|
|
page: $exos.page + 1
|
|
}).then((r) => {
|
|
exos.update((o) => {
|
|
return {
|
|
hasMore: r.totalPage > r.page,
|
|
data: [...o.data, ...r.items],
|
|
page: r.page
|
|
};
|
|
});
|
|
});
|
|
}
|
|
};
|
|
let more: HTMLDivElement;
|
|
let updateText: number | null = null;
|
|
</script>
|
|
|
|
<div
|
|
class="exolist"
|
|
bind:this={more}
|
|
on:scroll={() => {
|
|
if (
|
|
more != undefined &&
|
|
$exos.hasMore &&
|
|
more.offsetHeight + more.scrollTop >= more.scrollHeight
|
|
) {
|
|
fetchNextPage();
|
|
}
|
|
}}
|
|
>
|
|
<div class="close" on:click={() => {
|
|
close()
|
|
}}>
|
|
<FaTimes />
|
|
</div>
|
|
|
|
<div class="head">
|
|
<input
|
|
type="text"
|
|
name="search"
|
|
placeholder="Rechercher..."
|
|
class="input"
|
|
on:input={(e) => {
|
|
if (updateText != null) {
|
|
clearTimeout(updateText);
|
|
}
|
|
|
|
updateText = window.setTimeout(() => {
|
|
search = e.currentTarget.value;
|
|
}, 500);
|
|
}}
|
|
/>
|
|
{#if !!$isAuth}
|
|
<div class="auth-head">
|
|
<TagSelector options={$tags} bind:selected placeholder="Selectionner..." />
|
|
<select class="input" bind:value={filter}>
|
|
<option value="user">Vos exercices</option>
|
|
<option value="public">Tous les exercices</option>
|
|
</select>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
<div class="exos">
|
|
|
|
{#if $exos.data.length == 0}
|
|
<p class="empty">Aucun exercice trouvé</p>
|
|
{/if}
|
|
|
|
{#each $exos.data as e (e.id_code)}
|
|
<div
|
|
on:click={() => {
|
|
if ($selectedExos.map((s) => s.exercice_id).includes(e.id_code)) {
|
|
selectedExos.update((n) => {
|
|
return [...n.filter((s) => s.exercice_id != e.id_code)];
|
|
});
|
|
} else {
|
|
selectedExos.update((n) => {
|
|
return [...n, { quantity: 10, exercice_id: e.id_code, name: e.name }];
|
|
});
|
|
}
|
|
}}
|
|
class:selected={$selectedExos.map((s) => s.exercice_id).includes(e.id_code)}
|
|
on:keydown={() => {}}
|
|
>
|
|
<p>{e.name}</p>
|
|
<TagViewer tags={e.tags} id={e.id_code} />
|
|
</div>
|
|
{/each}
|
|
{#if $exos.hasMore}
|
|
<p class="more"><span class="spinner" /></p>
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
|
|
<style lang="scss">
|
|
@import '../../mixins';
|
|
.auth-head {
|
|
display: flex;
|
|
|
|
select {
|
|
width: max-content;
|
|
padding: 10px 5px;
|
|
gap: 5px;
|
|
}
|
|
}
|
|
|
|
.more {
|
|
display: flex;
|
|
justify-content: center;
|
|
}
|
|
|
|
.exolist {
|
|
overflow: scroll;
|
|
background-color: $background;
|
|
padding: 20px;
|
|
height: 100%;
|
|
min-width: 600px;
|
|
@include down(800){
|
|
min-width: 0;
|
|
width: 100%;
|
|
}
|
|
}
|
|
|
|
.selected {
|
|
color: grey;
|
|
}
|
|
|
|
.head {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 10px;
|
|
}
|
|
|
|
.exos {
|
|
> div {
|
|
padding: 16px 10px;
|
|
cursor: pointer;
|
|
transition: 0.3s;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 20px;
|
|
|
|
&:hover {
|
|
background-color: darken($color: $background, $amount: 3);
|
|
}
|
|
}
|
|
}
|
|
|
|
.close {
|
|
position: absolute;
|
|
top: 7px;
|
|
right: 7px;
|
|
cursor: pointer;
|
|
width: 15px;
|
|
height: 15px;
|
|
transition: .2s;
|
|
|
|
&:hover {
|
|
transform: scale(1.1);
|
|
}
|
|
}
|
|
|
|
.empty {
|
|
font-style: italic;
|
|
width: 100%;
|
|
text-align: center;
|
|
margin: 20px 0;
|
|
}
|
|
|
|
</style>
|