frontend/src/lib/components/admin/refills.svelte

Summary

Maintainability
Test Coverage
<script lang="ts">
    import { type Account, type Refill, RefillState, RefillType } from '$lib/api';
    import { refillsApi } from '$lib/requests/requests';
    import { formatDate, formatPrice } from '$lib/utils';
    import { onMount } from 'svelte';

    onMount(() => {
        reloadRefills();
    });

    let page = 0;
    let max_page = 0;
    let refills_per_page = 10;
    let refills: Refill[] = [];

    function reloadRefills() {
        refillsApi()
            .getAccountRefills(account.id, page, refills_per_page, undefined, undefined, {
                withCredentials: true
            })
            .then((res) => {
                refills = res.data.refills ?? [];
                page = res.data.page;
                max_page = res.data.max_page;
                refills_per_page = res.data.limit;
            })
            .catch((err) => {
                console.error(err);
            });
    }

    function deleteRefill(id: string) {
        refillsApi()
            .markDeleteRefill(account.id, id, { withCredentials: true })
            .then((res) => {
                reloadRefills();
            })
            .catch((err) => {
                console.error(err);
            });
    }

    export let onClose: () => void;
    export let account: Account;
</script>

<!-- Display a popup that asks for a pin -->

<button
    id="overlay"
    class="absolute w-full h-full top-0 left-0 bg-black bg-opacity-50 flex justify-center items-center z-40 hover:cursor-default"
    on:click={() => {
        onClose();
    }}
/>

<div id="popup" class="absolute w-full h-full top-0 left-0 flex justify-center items-center">
    <!-- Put a title and the numpad -->
    <div class="flex flex-col items-center bg-white rounded-lg shadow-lg p-4 z-40">
        <h1 class="text-2xl font-bold mb-4">Transactions du compte</h1>
        <div class="flex flex-col items-center">
            <!-- Table Section -->
            <div class="max-w-[95%] px-4 py-10 sm:px-6 lg:px-8 lg:py-14 mx-auto">
                <!-- Card -->
                <div class="flex flex-col">
                    <div class="-m-1.5 overflow-x-auto">
                        <div class="p-1.5 min-w-full inline-block align-middle">
                            <div
                                class="bg-white border border-gray-200 rounded-t-xl shadow-sm overflow-hidden dark:bg-slate-900 dark:border-gray-700"
                            >
                                <!-- Header -->
                                <div
                                    class="px-6 py-4 grid gap-3 md:flex md:justify-between md:items-center border-b border-gray-200 dark:border-gray-700"
                                >
                                    <div>
                                        <h2 class="text-xl font-semibold text-gray-800 dark:text-gray-200">
                                            Transactions
                                        </h2>
                                    </div>
                                </div>
                            </div>
                            <!-- End Header -->

                            <!-- Table -->
                            <table
                                class="min-w-full divide-y divide-gray-200 dark:divide-gray-700 dark:bg-slate-800"
                            >
                                <thead class="bg-gray-50 dark:bg-slate-800">
                                    <tr>
                                        <th scope="col" class="px-6 py-3 text-left">
                                            <div class="flex items-center gap-x-2">
                                                <span
                                                    class="text-xs font-semibold uppercase tracking-wide text-gray-800 dark:text-gray-200"
                                                >
                                                    Date
                                                </span>
                                            </div>
                                        </th>
                                        <th scope="col" class="px-6 py-3 text-left">
                                            <div class="flex items-center gap-x-2">
                                                <span
                                                    class="text-xs font-semibold uppercase tracking-wide text-gray-800 dark:text-gray-200"
                                                >
                                                    Emetteur
                                                </span>
                                            </div>
                                        </th>
                                        <th scope="col" class="px-6 py-3 text-left">
                                            <div class="flex items-center gap-x-2">
                                                <span
                                                    class="text-xs font-semibold uppercase tracking-wide text-gray-800 dark:text-gray-200"
                                                >
                                                    Montant
                                                </span>
                                            </div>
                                        </th>
                                        <th scope="col" class="px-6 py-3 text-left">
                                            <div class="flex items-center gap-x-2">
                                                <span
                                                    class="text-xs font-semibold uppercase tracking-wide text-gray-800 dark:text-gray-200"
                                                >
                                                    Type
                                                </span>
                                            </div>
                                        </th>
                                        <th scope="col" class="px-6 py-3 text-left">
                                            <div class="flex items-center gap-x-2">
                                                <span
                                                    class="text-xs font-semibold uppercase tracking-wide text-gray-800 dark:text-gray-200"
                                                >
                                                    Etat
                                                </span>
                                            </div>
                                        </th>
                                    </tr>
                                </thead>
                                <tbody class="divide-y divide-gray-200 dark:divide-gray-700">
                                    {#each refills as refill}
                                        <tr>
                                            <td class="h-px w-72">
                                                <div class="px-6 py-3">
                                                    <p class="text-sm dark:text-white/[.8] break-words p-2 bg-transparent">
                                                        {formatDate(refill.issued_at)}
                                                    </p>
                                                </div>
                                            </td>
                                            <td class="h-px w-72">
                                                <div class="px-6 py-3">
                                                    <p class="text-sm dark:text-white/[.8] break-words p-2 bg-transparent">
                                                        {refill.issued_by_name}
                                                    </p>
                                                </div>
                                            </td>
                                            <td class="h-px w-72">
                                                <div class="px-6 py-3">
                                                    <p class="text-sm dark:text-white/[.8] break-words p-2 bg-transparent">
                                                        {formatPrice(refill.amount)}
                                                    </p>
                                                </div>
                                            </td>
                                            <td class="h-px w-72">
                                                <div class="px-6 py-3">
                                                    <select
                                                        class="block text-sm dark:text-white/[.8] dark:bg-slate-800 break-words p-2 bg-transparent"
                                                        bind:value={refill.type}
                                                        on:change={(e) => {
                                                            // @ts-ignore
                                                            refill.type = e.target?.value;
                                                            refillsApi()
                                                                .patchRefillId(account.id, refill.id, refill.state, refill.type, {
                                                                    withCredentials: true
                                                                })
                                                                .then((res) => {
                                                                    reloadRefills();
                                                                })
                                                                .catch((err) => {
                                                                    console.error(err);
                                                                });
                                                        }}
                                                    >
                                                        <option value={RefillType.RefillOther}>Autre</option>
                                                        <option value={RefillType.RefillCash}>Liquide</option>
                                                        <option value={RefillType.RefillCard}>Carte</option>
                                                    </select>
                                                </div>
                                            </td>
                                            <td class="h-px w-72">
                                                <div class="px-6 py-3">
                                                    <select
                                                        class="block text-sm dark:text-white/[.8] dark:bg-slate-800 break-words p-2 bg-transparent"
                                                        bind:value={refill.state}
                                                        on:change={(e) => {
                                                            // @ts-ignore
                                                            refill.state = e.target?.value;
                                                            refillsApi()
                                                                .patchRefillId(account.id, refill.id, refill.state, refill.type, {
                                                                    withCredentials: true
                                                                })
                                                                .then((res) => {
                                                                    reloadRefills();
                                                                })
                                                                .catch((err) => {
                                                                    console.error(err);
                                                                });
                                                        }}
                                                    >
                                                        <option value={RefillState.Valid}>Valide</option>
                                                        <option value={RefillState.Canceled}>Annulé</option>
                                                    </select>
                                                </div>
                                            </td>
                                            <td class="h-px w-px whitespace-nowrap">
                                                <div class="px-6 py-1.5">
                                                    <button
                                                        class="inline-flex items-center gap-x-1.5 text-sm text-blue-600 decoration-2 hover:underline font-medium"
                                                        on:click={() => deleteRefill(refill.id)}
                                                    >
                                                        Supprimer
                                                    </button>
                                                </div>
                                            </td>
                                        </tr>
                                    {/each}
                                </tbody>
                            </table>
                            <!-- End Table -->

                            <!-- Footer -->
                            <div
                                class="px-6 py-4 grid gap-3 md:flex md:justify-between md:items-center border-t border-gray-200 dark:border-gray-700 dark:bg-slate-800"
                            >
                                <div>
                                    <div class="inline-flex gap-x-2">
                                        <button
                                            type="button"
                                            class="py-2 px-3 inline-flex justify-center items-center gap-2 rounded-md border font-medium bg-white text-gray-700 shadow-sm align-middle hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-white focus:ring-blue-600 transition-all text-sm dark:bg-slate-900 dark:hover:bg-slate-800 dark:border-gray-700 dark:text-gray-400 dark:hover:text-white dark:focus:ring-offset-gray-800"
                                            on:click={() => {
                                                if (page > 0) {
                                                    page--;
                                                    reloadRefills();
                                                }
                                            }}
                                        >
                                            <svg
                                                class="w-3 h-3"
                                                xmlns="http://www.w3.org/2000/svg"
                                                width="16"
                                                height="16"
                                                fill="currentColor"
                                                viewBox="0 0 16 16"
                                            >
                                                <path
                                                    fill-rule="evenodd"
                                                    d="M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z"
                                                />
                                            </svg>
                                            Précédent
                                        </button>

                                        <p class="text-sm self-center text-gray-600 dark:text-gray-400">
                                            Page {page} / {max_page + 1}
                                        </p>

                                        <button
                                            type="button"
                                            class="py-2 px-3 inline-flex justify-center items-center gap-2 rounded-md border font-medium bg-white text-gray-700 shadow-sm align-middle hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-white focus:ring-blue-600 transition-all text-sm dark:bg-slate-900 dark:hover:bg-slate-800 dark:border-gray-700 dark:text-gray-400 dark:hover:text-white dark:focus:ring-offset-gray-800"
                                            on:click={() => {
                                                if (page <= max_page) {
                                                    page++;
                                                    reloadRefills();
                                                }
                                            }}
                                        >
                                            Suivant
                                            <svg
                                                class="w-3 h-3"
                                                xmlns="http://www.w3.org/2000/svg"
                                                width="16"
                                                height="16"
                                                fill="currentColor"
                                                viewBox="0 0 16 16"
                                            >
                                                <path
                                                    fill-rule="evenodd"
                                                    d="M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z"
                                                />
                                            </svg>
                                        </button>
                                    </div>
                                </div>
                            </div>
                            <!-- End Footer -->
                        </div>
                    </div>
                </div>
            </div>
            <!-- End Card -->
        </div>
        <!-- End Table Section -->
    </div>
</div>