All checks were successful
continuous-integration/drone/push Build is passing
ref #161
273 lines
10 KiB
Svelte
273 lines
10 KiB
Svelte
<script>
|
|
import { _ } from "svelte-i18n";
|
|
import { RunnerCardService } from "@odit/lfk-client-js";
|
|
import store from "../../store";
|
|
import Toastify from "toastify-js";
|
|
import { DataHandler, Datatable, Th, ThFilter } from "@vincjo/datatables";
|
|
import CardsEmptyState from "./CardsEmptyState.svelte";
|
|
import CardDetailModal from "./CardDetailModal.svelte";
|
|
import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte";
|
|
import ThFilterStatus from "./ThFilterStatus.svelte";
|
|
import ThFilterRunner from "./ThFilterRunner.svelte";
|
|
export let edit_modal_open = false;
|
|
export let runner = {};
|
|
export let editable = {};
|
|
export let original_data = {};
|
|
export let current_cards = [];
|
|
const handler = new DataHandler(current_cards, { rowsPerPage: 50 });
|
|
const rows = handler.getRows();
|
|
$: active_deletes = [];
|
|
$: cards_show = generate_cards.length > 0;
|
|
$: generate_cards = [];
|
|
const cards_promise = RunnerCardService.runnerCardControllerGetAll().then(
|
|
(val) => {
|
|
current_cards = val;
|
|
handler.setRows(val);
|
|
}
|
|
);
|
|
const getRunnerLabel = (option) =>
|
|
option?.firstname +
|
|
" " +
|
|
(option?.middlename || "") +
|
|
" " +
|
|
(option?.lastname || "{$_('non-blanko')}");
|
|
function open_edit_modal(card) {
|
|
if (card.runner?.id) {
|
|
runner = Object.assign(
|
|
{ runner },
|
|
{ label: getRunnerLabel(card.runner), value: card.runner }
|
|
);
|
|
card.runner = card.runner.id;
|
|
} else {
|
|
card.runner = null;
|
|
runner = null;
|
|
}
|
|
editable = Object.assign(editable, card);
|
|
original_data = Object.assign(original_data, card);
|
|
edit_modal_open = true;
|
|
}
|
|
</script>
|
|
|
|
{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:UPDATE")}
|
|
<CardDetailModal
|
|
bind:current_cards
|
|
bind:edit_modal_open
|
|
bind:runner
|
|
bind:editable
|
|
bind:original_data
|
|
on:dataUpdated={handler.setRows(current_cards)}
|
|
/>
|
|
{/if}
|
|
|
|
{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:GET")}
|
|
{#await cards_promise}
|
|
<div
|
|
class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2"
|
|
role="alert"
|
|
>
|
|
<p class="font-bold">{$_("loading-cards")}</p>
|
|
<p class="text-sm">{$_("this-might-take-a-moment")}</p>
|
|
</div>
|
|
{:then}
|
|
{#if current_cards.length === 0}
|
|
<CardsEmptyState />
|
|
{:else}
|
|
<div class="h-12 mt-1">
|
|
{#if cards_show}
|
|
<button
|
|
type="button"
|
|
class="w-full justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-red-600 text-base font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:ml-3 sm:w-auto sm:text-sm inline-flex"
|
|
id="options-menu"
|
|
on:click={async () => {
|
|
const prom = [];
|
|
for (const card of generate_cards) {
|
|
prom.push(
|
|
RunnerCardService.runnerCardControllerRemove(card.id, true)
|
|
);
|
|
}
|
|
await Promise.all(prom);
|
|
Toastify({
|
|
text: $_("cards-deleted"),
|
|
duration: 3500,
|
|
backgroundColor:
|
|
"linear-gradient(to right, #00b09b, #96c93d)",
|
|
}).showToast();
|
|
//TODO: Delete cards from table
|
|
}}
|
|
>
|
|
{$_("delete-cards")}
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke-width="1.5"
|
|
stroke="currentColor"
|
|
class="w-5 h-5"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
|
|
/>
|
|
</svg>
|
|
</button>
|
|
{/if}
|
|
<GenerateRunnerCards bind:cards_show bind:generate_cards />
|
|
</div>
|
|
<Datatable {handler}>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th style="border-bottom: 1px solid #ddd;">
|
|
<input
|
|
type="checkbox"
|
|
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
|
|
checked={generate_cards.length == current_cards.length}
|
|
on:click={() => {
|
|
if (generate_cards.length != current_cards.length) {
|
|
generate_cards = current_cards;
|
|
} else {
|
|
generate_cards = [];
|
|
}
|
|
}}
|
|
/>
|
|
</th>
|
|
<Th {handler} orderBy="code">{$_("code")}</Th>
|
|
<Th {handler} orderBy="runner">{$_("runner")}</Th>
|
|
<Th {handler} orderBy="status">{$_("status")}</Th>
|
|
<th style="border-bottom: 1px solid #ddd;">{$_("action")}</th>
|
|
</tr>
|
|
<tr>
|
|
<th style="border-bottom: 1px solid #ddd;" />
|
|
<ThFilter {handler} filterBy="code" />
|
|
<ThFilterRunner {handler} />
|
|
<ThFilterStatus {handler} />
|
|
<th style="border-bottom: 1px solid #ddd;" />
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{#each $rows as row}
|
|
<tr>
|
|
<td>
|
|
<input
|
|
type="checkbox"
|
|
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
|
|
checked={generate_cards.filter((i) => i.id == row.id)
|
|
.length > 0}
|
|
on:click={() => {
|
|
if (
|
|
generate_cards.findIndex((i) => i.id == row.id) == -1
|
|
) {
|
|
generate_cards.push(row);
|
|
generate_cards = generate_cards;
|
|
} else {
|
|
generate_cards = generate_cards.filter(
|
|
(r) => r.id != row.id
|
|
);
|
|
}
|
|
console.log(generate_cards);
|
|
}}
|
|
/>
|
|
</td>
|
|
<td>{row.code}</td>
|
|
<td>
|
|
{#if row.runner}
|
|
<a
|
|
href="../runners/{row.runner.id}"
|
|
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-gray-100 text-gray-800"
|
|
>{row.runner.firstname}
|
|
{row.runner.middlename || ""}
|
|
{row.runner.lastname}</a
|
|
>
|
|
{:else}{$_("non-blanko")}{/if}
|
|
</td>
|
|
<td>
|
|
{#if row.enabled}
|
|
<span
|
|
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800"
|
|
>{$_("enabled")}</span
|
|
>
|
|
{:else}
|
|
<span
|
|
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800"
|
|
>{$_("disabled")}</span
|
|
>
|
|
{/if}
|
|
</td>
|
|
<td>
|
|
{#if active_deletes[row.id] === true}
|
|
<button
|
|
on:click={() => {
|
|
active_deletes[row.id] = false;
|
|
}}
|
|
tabindex="0"
|
|
class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer"
|
|
>{$_("cancel-delete")}</button
|
|
>
|
|
<button
|
|
on:click={() => {
|
|
RunnerCardService.runnerCardControllerRemove(
|
|
row.id,
|
|
true
|
|
)
|
|
.then((resp) => {
|
|
current_cards = current_cards.filter(
|
|
(obj) => obj.id !== row.id
|
|
);
|
|
})
|
|
.catch((err) => {});
|
|
}}
|
|
tabindex="0"
|
|
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer"
|
|
>{$_("confirm-delete")}</button
|
|
>
|
|
{:else}
|
|
<button
|
|
on:click={() => {
|
|
open_edit_modal(row);
|
|
}}
|
|
class="text-indigo-600 hover:text-indigo-900"
|
|
>{$_("details")}</button
|
|
>
|
|
{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:DELETE")}
|
|
<button
|
|
on:click={() => {
|
|
active_deletes[row.id] = true;
|
|
}}
|
|
tabindex="0"
|
|
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer"
|
|
>{$_("delete")}</button
|
|
>
|
|
{/if}
|
|
{/if}
|
|
</td>
|
|
</tr>
|
|
{/each}
|
|
</tbody>
|
|
</table>
|
|
</Datatable>
|
|
{/if}
|
|
{:catch error}
|
|
<div class="text-white px-6 py-4 border-0 rounded relative mb-4 bg-red-500">
|
|
<span class="inline-block align-middle mr-8">
|
|
<b class="capitalize">{$_("general_promise_error")}</b>
|
|
{error}
|
|
</span>
|
|
</div>
|
|
{/await}
|
|
{/if}
|
|
|
|
<style>
|
|
table tbody {
|
|
display: block;
|
|
overflow-y: scroll;
|
|
}
|
|
|
|
table thead,
|
|
table tbody tr {
|
|
display: table;
|
|
width: 100%;
|
|
table-layout: fixed;
|
|
}
|
|
</style>
|