frontend/src/lib/components/comptoir/transactionPopup.svelte

Summary

Maintainability
Test Coverage
<script lang="ts">
    import {
        ItemState,
        TransactionItemState,
        type Transaction,
        type MenuItem,
        type MenuCategory,
        type TransactionItem
    } from '$lib/api';
    import { api } from '$lib/config/config';
    import { transactionsApi } from '$lib/requests/requests';
    import { formatPrice } from '$lib/utils';
    import Error from '../error.svelte';
    import Success from '../success.svelte';

    export let transaction: Transaction;
    export let close: () => void;

    let newTransaction: Transaction = structuredClone(transaction);
    let success = '';
    let error = '';

    type MenuPopup = {
        items: MenuItem[] | undefined;
        categories: MenuCategory[] | undefined;
        pickedItems: TransactionItem[] | undefined;
    };
    let menuPopup: MenuPopup | undefined;

    async function cancelTransaction() {
        let res = await transactionsApi().patchTransactionId(
            newTransaction.account_id,
            newTransaction.id,
            'canceled',
            {
                withCredentials: true
            }
        );

        if (res.status != 200) {
            error = "Une erreur s'est produite";
            setTimeout(() => {
                error = '';
            }, 1500);
            return;
        }

        transaction = newTransaction;
        success = 'Commande annulée';
        setTimeout(() => {
            success = '';
            close();
        }, 1500);
    }

    async function putBackTransaction() {
        let res = await transactionsApi().patchTransactionId(
            newTransaction.account_id,
            newTransaction.id,
            'started',
            {
                withCredentials: true
            }
        );

        if (res.status != 200) {
            error = "Une erreur s'est produite";
            setTimeout(() => {
                error = '';
            }, 1500);
            return;
        }

        transaction = newTransaction;
        success = 'Commande remise en attente';
        setTimeout(() => {
            success = '';
            close();
        }, 1500);
    }

    async function finishTransaction() {
        let res = await transactionsApi().patchTransactionId(
            newTransaction.account_id,
            newTransaction.id,
            'finished',
            {
                withCredentials: true
            }
        );

        if (res.status != 200) {
            error = "Une erreur s'est produite";
            setTimeout(() => {
                error = '';
            }, 1500);
            return;
        }

        transaction = newTransaction;
        success = 'Commande terminée';
        setTimeout(() => {
            success = '';
            close();
        }, 1500);
    }

    async function saveTransaction() {
        for (let i = 0; i < newTransaction.items.length; i++) {
            let item = newTransaction.items[i];

            // @ts-ignore
            if (item.state == transaction.items[i].state) item.state = undefined;

            let res = await transactionsApi().patchTransactionItemId(
                newTransaction.account_id,
                newTransaction.id,
                item.item_id,
                item.state,
                item.item_amount,
                item.item_already_done,
                {
                    withCredentials: true
                }
            );

            if (res.status != 200) {
                error = "Une erreur s'est produite";
                setTimeout(() => {
                    error = '';
                }, 1500);
                return;
            }
        }

        if (!error) {
            transaction = newTransaction;
            success = 'Changements enregistrée';
            setTimeout(() => {
                success = '';
            }, 1500);
            reloadTransaction();
        }
    }

    function reloadTransaction() {
        transactionsApi()
            .getTransactionId(transaction.account_id, transaction.id, { withCredentials: true })
            .then((res) => {
                transaction = res.data;
                newTransaction = structuredClone(transaction);
            });
    }
</script>

{#if success != ''}
    <Success message={success} />
{/if}

{#if error != ''}
    <Error {error} />
{/if}

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

<div id="popup" class="absolute w-full h-full top-0 left-0 flex justify-center items-center">
    <!-- 
        We can modify the transaction here
        We can :
            - Check an item and mark it as completed
            - Check the transaction to mark it as completed
            - Cancel (item or transaction)
            - Undo a cancel (item or transaction)
            - Lower the amount of an item
            - Close the popup
    -->
    <div class="w-2/3 bg-white rounded-xl z-20 text-black">
        <h1 class="p-3 w-full text-center text-xl">Commande de : <span class="font-semibold">{transaction.account_name}</span></h1>
        <div class="p-5 h-full pr-4 w-full">
            <div class="grid grid-cols-6 gap-2">
                {#each newTransaction.items as item, i}
                    <!-- One for each item.amount -->
                    <div
                        class="flex flex-col justify-center text-center break-words rounded-xl {item.state ==
                        TransactionItemState.TransactionItemCanceled
                            ? 'bg-red-200'
                            : ''} {item.state == TransactionItemState.TransactionItemFinished
                            ? 'bg-green-200'
                            : ''}"
                    >
                        {item.item_name ? item.item_name : 'Test'}
                        {#if item.state == TransactionItemState.TransactionItemCanceled}
                            : Annulé
                        {/if}
                        {#if item.state == TransactionItemState.TransactionItemFinished}
                            : Terminé
                        {/if}
                        <!-- add tooltip if menu -->
                        {#if item.is_menu}
                            <button
                                class="flex text-white font-bold p-2 rounded justify-center"
                                on:click={() => {
                                    menuPopup = {
                                        items: item.menu_items,
                                        categories: item.menu_categories,
                                        pickedItems: item.picked_categories_items
                                    };
                                }}
                            >
                                <img
                                    src={api() + item.picture_uri}
                                    alt="ca charge"
                                    class="self-center w-10 h-10 rounded-2xl"
                                />
                            </button>
                        {:else}
                            <img
                                src={api() + item.picture_uri}
                                alt="ca charge"
                                class="self-center w-10 h-10 rounded-2xl"
                            />
                        {/if}
                        <div class="flex flex-col">
                            <div>
                                Total: {item.item_amount}
                            </div>
                            <div>
                                Restant: {item.item_amount - item.item_already_done}
                            </div>
                        </div>
                        {#if item.state == TransactionItemState.TransactionItemStarted}
                            <div class="flex flex-row justify-center">
                                <div class="grid grid-cols-3 gap-1">
                                    {#if item.item_amount > 1}
                                        <button
                                            class="bg-red-500 hover:bg-red-700 text-white font-bold p-2 rounded"
                                            on:click={() => {
                                                if (item.item_amount > 1) item.item_amount--;
                                            }}
                                        >
                                            <iconify-icon
                                                class="text-white text-lg self-center align-middle"
                                                icon="ic:baseline-minus"
                                            />
                                        </button>
                                    {/if}
                                    <button
                                        class="bg-gray-500 hover:bg-gray-700 text-white font-bold p-2 rounded col-start-2"
                                        on:click={() => {
                                            item.state = TransactionItemState.TransactionItemCanceled;
                                        }}
                                    >
                                        <iconify-icon
                                            class="text-white text-lg self-center align-middle"
                                            icon="mdi:cancel"
                                        />
                                    </button>
                                    <button
                                        class="bg-green-500 hover:bg-green-700 text-white font-bold p-2 rounded col-start-2"
                                        on:click={() => {
                                            if (item.item_already_done < item.item_amount) item.item_already_done += 1;
                                            if (item.item_already_done == item.item_amount)
                                                item.state = TransactionItemState.TransactionItemFinished;
                                        }}
                                    >
                                        <iconify-icon
                                            class="text-white text-lg self-center align-middle"
                                            icon="mdi:check"
                                        />
                                    </button>
                                    {#if item.item_amount < transaction.items[i].item_amount}
                                        <button
                                            class="bg-green-500 hover:bg-green-700 text-white font-bold p-2 rounded col-start-3"
                                            on:click={() => {
                                                if (item.item_amount < transaction.items[i].item_amount) item.item_amount++;
                                            }}
                                        >
                                            <iconify-icon
                                                class="text-white text-lg self-center align-middle"
                                                icon="ic:baseline-plus"
                                            />
                                        </button>
                                    {/if}
                                </div>
                            </div>
                        {/if}
                    </div>
                {/each}
            </div>
        </div>

        {#if menuPopup != undefined}
            <div class="w-full h-1 bg-gray-200" />

            <div class="w-full text-center text-lg font-bold">Ce menu contient:</div>

            <div class="grid grid-cols-5 max-h-64 p-5 gap-5">
                {#each menuPopup.categories ?? [] as cat}
                    <div class="flex flex-col justify-center text-center break-words rounded-xl bg-slate-200">
                        {cat.name ? cat.name : 'Test'}
                        <img
                            src={api() + cat.picture_uri}
                            alt="..."
                            class="self-center w-10 h-10 rounded-2xl"
                        />
                    </div>
                {/each}
                {#each menuPopup.items ?? [] as item}
                    <div class="flex flex-col justify-center text-center break-words rounded-xl bg-slate-200">
                        {item.name ? item.name : 'Test'}
                        <img
                            src={api() + item.picture_uri}
                            alt="..."
                            class="self-center w-10 h-10 rounded-2xl"
                        />
                    </div>
                {/each}
                {#each menuPopup.pickedItems ?? [] as pickedItem}
                    <div class="flex flex-col justify-center text-center break-words rounded-xl bg-slate-200">
                        {pickedItem.item_name ? pickedItem.item_name : 'Test'}
                        <img
                            src={api() + pickedItem.picture_uri}
                            alt="..."
                            class="self-center w-10 h-10 rounded-2xl"
                        />
                    </div>
                {/each}
            </div>

            <div class="w-full h-1 bg-gray-200" />
        {/if}

        <div class="grid grid-cols-2 gap-4 p-8">
            <!-- Save & cancel -->
            <div class="flex flex-col gap-4 p-8">
                <button
                    class="bg-green-500 rounded-xl text-white text-md font-bold p-2 h-20 w-full self-center"
                    on:click={() => {
                        saveTransaction();
                    }}
                >
                    Enregistrer les changements
                </button>
                <button
                    class="bg-red-500 rounded-xl text-white text-md font-bold p-2 h-20 w-full self-center"
                    on:click={() => {
                        close();
                    }}
                >
                    Annuler les changements
                </button>
            </div>
            <div class="flex flex-col gap-4 p-8">
                <button
                    class="bg-green-500 rounded-xl text-white text-md font-bold p-2 h-20 w-full"
                    on:click={() => {
                        finishTransaction();
                    }}
                >
                    Terminer la commande (paiement)
                </button>
                <button
                    class="bg-gray-500 rounded-xl text-white text-md font-bold p-2 h-20 w-full"
                    on:click={() => {
                        cancelTransaction();
                    }}
                >
                    Annuler la commande (remboursement)
                </button>
                <button
                    class="bg-red-500 rounded-xl text-white text-md font-bold p-2 h-20 w-full"
                    on:click={() => {
                        putBackTransaction();
                    }}
                >
                    Remettre la commande
                </button>
            </div>
        </div>

        <div class="p-5 pl-4 w-full text-lg self-center text-center">
            Prix: {formatPrice(transaction.total_cost)}
        </div>
    </div>
</div>