formatting, full migration to svelte-french-toast
This commit is contained in:
@@ -1,243 +1,232 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
|
||||
import { RunnerCardService } from "@odit/lfk-client-js";
|
||||
import Toastify from "toastify-js";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
export let bulk_modal_open;
|
||||
function focus(el) {
|
||||
el.focus();
|
||||
}
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
$: card_count = 0;
|
||||
$: is_card_count_valid = card_count > 0;
|
||||
$: processed_last_submit = true;
|
||||
$: createbtnenabled = is_card_count_valid;
|
||||
(() => {
|
||||
document.onkeydown = (e) => {
|
||||
e = e || window.event;
|
||||
if (e.key === "Escape") {
|
||||
bulk_modal_open = false;
|
||||
}
|
||||
if (e.keyCode === 13) {
|
||||
if (createbtnenabled === true) {
|
||||
createbtnenabled = false;
|
||||
submit_with_print();
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
function submit_without_print() {
|
||||
if (processed_last_submit === true) {
|
||||
processed_last_submit = false;
|
||||
const toast = Toastify({
|
||||
text: $_("creating-blanco-cards"),
|
||||
duration: -1,
|
||||
}).showToast();
|
||||
RunnerCardService.runnerCardControllerPostBlancoBulk(card_count, true)
|
||||
.then((result) => {
|
||||
bulk_modal_open = false;
|
||||
//
|
||||
Toastify({
|
||||
text: $_("created-blanco-cards"),
|
||||
duration: 500,
|
||||
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
|
||||
}).showToast();
|
||||
dispatch("created", {cards: result})
|
||||
})
|
||||
.catch((err) => {
|
||||
//
|
||||
})
|
||||
.finally(() => {
|
||||
processed_last_submit = true;
|
||||
//
|
||||
toast.hideToast();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function submit_with_print() {
|
||||
if (processed_last_submit === true) {
|
||||
processed_last_submit = false;
|
||||
const toast = Toastify({
|
||||
text: $_("creating-blanco-cards"),
|
||||
duration: -1,
|
||||
}).showToast();
|
||||
RunnerCardService.runnerCardControllerPostBlancoBulk(card_count, true)
|
||||
.then((result) => {
|
||||
bulk_modal_open = false;
|
||||
//
|
||||
Toastify({
|
||||
text: $_("created-blanco-cards"),
|
||||
duration: 500,
|
||||
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
|
||||
}).showToast();
|
||||
const toast = Toastify({
|
||||
text: $_("generating-pdf"),
|
||||
duration: -1,
|
||||
}).showToast();
|
||||
dispatch("created", {cards: result})
|
||||
fetch(
|
||||
`${config.baseurl_documentserver}/cards?&download=true&key=${config.documentserver_key}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(result),
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (response.status != "200") {
|
||||
toast.hideToast();
|
||||
Toastify({
|
||||
text: $_("pdf-generation-failed"),
|
||||
duration: 3500,
|
||||
backgroundColor:
|
||||
"linear-gradient(90deg, hsla(281, 37%, 45%, 1) 0%, hsla(1, 62%, 48%, 1) 100%)",
|
||||
}).showToast();
|
||||
} else {
|
||||
return response.blob();
|
||||
}
|
||||
})
|
||||
.then((blob) => {
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
let a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = "Bulkcards.pdf";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
toast.hideToast();
|
||||
Toastify({
|
||||
text: $_("pdf-successfully-generated"),
|
||||
duration: 3500,
|
||||
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
|
||||
}).showToast();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
//
|
||||
})
|
||||
.finally(() => {
|
||||
processed_last_submit = true;
|
||||
//
|
||||
toast.hideToast();
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if bulk_modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
bulk_modal_open = false;
|
||||
}}>
|
||||
<div
|
||||
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
|
||||
<div
|
||||
class="absolute inset-0 bg-gray-500 opacity-75"
|
||||
data-id="modal_backdrop" />
|
||||
</div>
|
||||
<span
|
||||
class="hidden sm:inline-block sm:align-middle sm:h-screen"
|
||||
aria-hidden="true">​</span>
|
||||
<div
|
||||
class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-2xl sm:w-full"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="modal-headline">
|
||||
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
|
||||
<div class="sm:flex sm:items-start">
|
||||
<div
|
||||
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w- rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10">
|
||||
<svg
|
||||
class="h-6 w-6 text-blue-600"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"><path fill="none" d="M0 0h24v24H0z" />
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M22 10v10a1 1 0 01-1 1H3a1 1 0 01-1-1V10h20zm0-2H2V4a1 1 0 011-1h18a1 1 0 011 1v4zm-7 8v2h4v-2h-4z" /></svg>
|
||||
</div>
|
||||
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||
{$_('create-bulk-blanco-cards')}
|
||||
</h3>
|
||||
<div class="mt-2 mb-6">
|
||||
<p class="text-sm text-gray-500">
|
||||
{$_('just-enter-how-many-you-want-and-the-system-will-create-them')}
|
||||
</p>
|
||||
</div>
|
||||
<div class="grid grid-cols-6 gap-6">
|
||||
<div class="col-span-6">
|
||||
<label
|
||||
for="amount"
|
||||
class="block text-sm font-medium text-gray-700">{$_('amount')}</label>
|
||||
<div class="mt-1 flex rounded-md shadow-sm">
|
||||
<input
|
||||
autocomplete="off"
|
||||
class:border-red-500={!is_card_count_valid}
|
||||
class:focus:border-red-500={!is_card_count_valid}
|
||||
class:focus:ring-red-500={!is_card_count_valid}
|
||||
bind:value={card_count}
|
||||
type="number"
|
||||
step="1"
|
||||
name="amount"
|
||||
class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 p-2"
|
||||
placeholder="400" />
|
||||
<span
|
||||
class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500 text-sm">{$_('cards')}</span>
|
||||
</div>
|
||||
{#if !is_card_count_valid}
|
||||
<span
|
||||
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1">
|
||||
{$_('you-must-create-at-least-one-card-or-cancel')}
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
|
||||
<button
|
||||
disabled={!createbtnenabled}
|
||||
class:opacity-50={!createbtnenabled}
|
||||
on:click={submit_with_print}
|
||||
type="button"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm">
|
||||
{$_('create-and-generate-pdf')}
|
||||
</button>
|
||||
<button
|
||||
disabled={!createbtnenabled}
|
||||
class:opacity-50={!createbtnenabled}
|
||||
on:click={submit_without_print}
|
||||
type="button"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-gray-400 text-base font-medium text-white hover:bg-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm">
|
||||
{$_('create-without-pdf')}
|
||||
</button>
|
||||
<button
|
||||
on:click={() => {
|
||||
bulk_modal_open = false;
|
||||
}}
|
||||
type="button"
|
||||
class="mr-auto mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm">
|
||||
{$_('cancel')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
|
||||
import { RunnerCardService } from "@odit/lfk-client-js";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import toast from "svelte-french-toast";
|
||||
export let bulk_modal_open;
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
$: card_count = 0;
|
||||
$: is_card_count_valid = card_count > 0;
|
||||
$: processed_last_submit = true;
|
||||
$: createbtnenabled = is_card_count_valid;
|
||||
(() => {
|
||||
document.onkeydown = (e) => {
|
||||
e = e || window.event;
|
||||
if (e.key === "Escape") {
|
||||
bulk_modal_open = false;
|
||||
}
|
||||
if (e.keyCode === 13) {
|
||||
if (createbtnenabled === true) {
|
||||
createbtnenabled = false;
|
||||
submit_with_print();
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
function submit_without_print() {
|
||||
if (processed_last_submit === true) {
|
||||
processed_last_submit = false;
|
||||
toast.loading($_("creating-blanco-cards"));
|
||||
RunnerCardService.runnerCardControllerPostBlancoBulk(card_count, true)
|
||||
.then((result) => {
|
||||
bulk_modal_open = false;
|
||||
//
|
||||
toast.dismiss();
|
||||
toast.success($_("created-blanco-cards"));
|
||||
dispatch("created", { cards: result });
|
||||
})
|
||||
.catch((err) => {
|
||||
//
|
||||
})
|
||||
.finally(() => {
|
||||
processed_last_submit = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function submit_with_print() {
|
||||
if (processed_last_submit === true) {
|
||||
processed_last_submit = false;
|
||||
toast.dismiss();
|
||||
toast.loading($_("creating-blanco-cards"));
|
||||
RunnerCardService.runnerCardControllerPostBlancoBulk(card_count, true)
|
||||
.then((result) => {
|
||||
bulk_modal_open = false;
|
||||
//
|
||||
toast.dismiss();
|
||||
toast.success($_("created-blanco-cards"));
|
||||
toast.loading($_("generating-pdf"));
|
||||
dispatch("created", { cards: result });
|
||||
fetch(
|
||||
`${config.baseurl_documentserver}/cards?&download=true&key=${config.documentserver_key}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(result),
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
if (response.status != "200") {
|
||||
toast.dismiss();
|
||||
toast.error($_("pdf-generation-failed"));
|
||||
} else {
|
||||
return response.blob();
|
||||
}
|
||||
})
|
||||
.then((blob) => {
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
let a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = "Bulkcards.pdf";
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
toast.dismiss();
|
||||
toast.success($_("pdf-successfully-generated"));
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error(err);
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
//
|
||||
})
|
||||
.finally(() => {
|
||||
processed_last_submit = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if bulk_modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
bulk_modal_open = false;
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"
|
||||
>
|
||||
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
|
||||
<div
|
||||
class="absolute inset-0 bg-gray-500 opacity-75"
|
||||
data-id="modal_backdrop"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
class="hidden sm:inline-block sm:align-middle sm:h-screen"
|
||||
aria-hidden="true">​</span
|
||||
>
|
||||
<div
|
||||
class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-2xl sm:w-full"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="modal-headline"
|
||||
>
|
||||
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
|
||||
<div class="sm:flex sm:items-start">
|
||||
<div
|
||||
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w- rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
|
||||
>
|
||||
<svg
|
||||
class="h-6 w-6 text-blue-600"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
><path fill="none" d="M0 0h24v24H0z" />
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M22 10v10a1 1 0 01-1 1H3a1 1 0 01-1-1V10h20zm0-2H2V4a1 1 0 011-1h18a1 1 0 011 1v4zm-7 8v2h4v-2h-4z"
|
||||
/></svg
|
||||
>
|
||||
</div>
|
||||
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||
{$_("create-bulk-blanco-cards")}
|
||||
</h3>
|
||||
<div class="mt-2 mb-6">
|
||||
<p class="text-sm text-gray-500">
|
||||
{$_(
|
||||
"just-enter-how-many-you-want-and-the-system-will-create-them"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div class="grid grid-cols-6 gap-6">
|
||||
<div class="col-span-6">
|
||||
<label
|
||||
for="amount"
|
||||
class="block text-sm font-medium text-gray-700"
|
||||
>{$_("amount")}</label
|
||||
>
|
||||
<div class="mt-1 flex rounded-md shadow-sm">
|
||||
<input
|
||||
autocomplete="off"
|
||||
class:border-red-500={!is_card_count_valid}
|
||||
class:focus:border-red-500={!is_card_count_valid}
|
||||
class:focus:ring-red-500={!is_card_count_valid}
|
||||
bind:value={card_count}
|
||||
type="number"
|
||||
step="1"
|
||||
name="amount"
|
||||
class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 p-2"
|
||||
placeholder="400"
|
||||
/>
|
||||
<span
|
||||
class="inline-flex items-center px-3 rounded-r-md border border-gray-300 bg-gray-50 text-gray-500 text-sm"
|
||||
>{$_("cards")}</span
|
||||
>
|
||||
</div>
|
||||
{#if !is_card_count_valid}
|
||||
<span
|
||||
class="flex items-center font-medium tracking-wide text-red-500 text-xs mt-1 ml-1"
|
||||
>
|
||||
{$_("you-must-create-at-least-one-card-or-cancel")}
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
|
||||
<button
|
||||
disabled={!createbtnenabled}
|
||||
class:opacity-50={!createbtnenabled}
|
||||
on:click={submit_with_print}
|
||||
type="button"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
>
|
||||
{$_("create-and-generate-pdf")}
|
||||
</button>
|
||||
<button
|
||||
disabled={!createbtnenabled}
|
||||
class:opacity-50={!createbtnenabled}
|
||||
on:click={submit_without_print}
|
||||
type="button"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-gray-400 text-base font-medium text-white hover:bg-gray-500 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
>
|
||||
{$_("create-without-pdf")}
|
||||
</button>
|
||||
<button
|
||||
on:click={() => {
|
||||
bulk_modal_open = false;
|
||||
}}
|
||||
type="button"
|
||||
class="mr-auto mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
>
|
||||
{$_("cancel")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -1,203 +1,191 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
|
||||
import {
|
||||
RunnerCardService,
|
||||
RunnerService,
|
||||
ScanService,
|
||||
} from "@odit/lfk-client-js";
|
||||
import Select from "svelte-select";
|
||||
import Toastify from "toastify-js";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
export let modal_open;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const getRunnerLabel = (option) => {
|
||||
if (option.middlename) {
|
||||
return option.firstname + " " + option.middlename + " " + option.lastname;
|
||||
}
|
||||
return option.firstname + " " + option.lastname;
|
||||
};
|
||||
|
||||
const filterRunners = (label, filterText, option) => {
|
||||
if (filterText.startsWith("#")) {
|
||||
return option.value.id == parseInt(filterText.replace("#", ""));
|
||||
}
|
||||
return (
|
||||
label.toLowerCase().includes(filterText.toLowerCase()) ||
|
||||
option.value.toString().startsWith(filterText.toLowerCase())
|
||||
);
|
||||
};
|
||||
function focus(el) {
|
||||
el.focus();
|
||||
}
|
||||
$: runner = 0;
|
||||
$: enabled = true;
|
||||
$: processed_last_submit = true;
|
||||
|
||||
let loading = true;
|
||||
let runners = [];
|
||||
RunnerService.runnerControllerGetAll().then((val) => {
|
||||
runners = val.map((r) => {
|
||||
return { label: getRunnerLabel(r), value: r };
|
||||
});
|
||||
loading = false;
|
||||
});
|
||||
$: createbtnenabled = true;
|
||||
(() => {
|
||||
document.onkeydown = (e) => {
|
||||
e = e || window.event;
|
||||
if (e.key === "Escape") {
|
||||
modal_open = false;
|
||||
}
|
||||
if (e.keyCode === 13) {
|
||||
if (createbtnenabled === true) {
|
||||
createbtnenabled = false;
|
||||
submit();
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
function submit() {
|
||||
if (processed_last_submit === true) {
|
||||
processed_last_submit = false;
|
||||
const toast = Toastify({
|
||||
text: $_("adding-card"),
|
||||
duration: -1,
|
||||
}).showToast();
|
||||
let postdata = {
|
||||
runner,
|
||||
enabled,
|
||||
};
|
||||
RunnerCardService.runnerCardControllerPost(postdata)
|
||||
.then((result) => {
|
||||
runner = 0;
|
||||
modal_open = false;
|
||||
//
|
||||
Toastify({
|
||||
text: $_("card-added"),
|
||||
duration: 500,
|
||||
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
|
||||
}).showToast();
|
||||
dispatch("created", { cards: [result] });
|
||||
})
|
||||
.catch((err) => {
|
||||
//
|
||||
})
|
||||
.finally(() => {
|
||||
processed_last_submit = true;
|
||||
//
|
||||
toast.hideToast();
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
modal_open = false;
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"
|
||||
>
|
||||
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
|
||||
<div
|
||||
class="absolute inset-0 bg-gray-500 opacity-75"
|
||||
data-id="modal_backdrop"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
class="hidden sm:inline-block sm:align-middle sm:h-screen"
|
||||
aria-hidden="true">​</span
|
||||
>
|
||||
<div
|
||||
class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="modal-headline"
|
||||
>
|
||||
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
|
||||
<div class="sm:flex sm:items-start">
|
||||
<div
|
||||
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
|
||||
>
|
||||
<svg
|
||||
class="h-6 w-6 text-blue-600"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
><path fill="none" d="M0 0h24v24H0z" />
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M22 10v10a1 1 0 01-1 1H3a1 1 0 01-1-1V10h20zm0-2H2V4a1 1 0 011-1h18a1 1 0 011 1v4zm-7 8v2h4v-2h-4z"
|
||||
/></svg
|
||||
>
|
||||
</div>
|
||||
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||
{$_("create-a-new-card")}
|
||||
</h3>
|
||||
<div class="mt-2 mb-6">
|
||||
<p class="text-sm text-gray-500">
|
||||
{$_("you-can-provide-a-runner-but-you-dont-have-to")}
|
||||
{$_(
|
||||
"if-you-want-to-create-multiple-blanco-cards-try-the-add-bulk-button"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div class="grid grid-cols-6 gap-6">
|
||||
<div class="col-span-6">
|
||||
<label
|
||||
for="donor"
|
||||
class="block text-sm font-medium text-gray-700"
|
||||
>{$_("runner")}</label
|
||||
>
|
||||
<Select
|
||||
containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2"
|
||||
itemFilter={(label, filterText, option) =>
|
||||
filterRunners(label, filterText, option)}
|
||||
items={runners}
|
||||
bind:loading
|
||||
showChevron={!loading}
|
||||
placeholder={$_("search-for-runner-by-name-or-id")}
|
||||
noOptionsMessage={$_("no-runners-found")}
|
||||
on:select={(selectedValue) =>
|
||||
(runner = selectedValue.detail.value.id)}
|
||||
on:clear={() => (runner = null)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
|
||||
<button
|
||||
disabled={!createbtnenabled}
|
||||
class:opacity-50={!createbtnenabled}
|
||||
on:click={submit}
|
||||
type="button"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
>
|
||||
{$_("create")}
|
||||
</button>
|
||||
<button
|
||||
on:click={() => {
|
||||
modal_open = false;
|
||||
}}
|
||||
type="button"
|
||||
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
>
|
||||
{$_("cancel")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
|
||||
import { RunnerCardService, RunnerService } from "@odit/lfk-client-js";
|
||||
import Select from "svelte-select";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import toast from "svelte-french-toast";
|
||||
export let modal_open;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
const getRunnerLabel = (option) => {
|
||||
if (option.middlename) {
|
||||
return option.firstname + " " + option.middlename + " " + option.lastname;
|
||||
}
|
||||
return option.firstname + " " + option.lastname;
|
||||
};
|
||||
|
||||
const filterRunners = (label, filterText, option) => {
|
||||
if (filterText.startsWith("#")) {
|
||||
return option.value.id == parseInt(filterText.replace("#", ""));
|
||||
}
|
||||
return (
|
||||
label.toLowerCase().includes(filterText.toLowerCase()) ||
|
||||
option.value.toString().startsWith(filterText.toLowerCase())
|
||||
);
|
||||
};
|
||||
function focus(el) {
|
||||
el.focus();
|
||||
}
|
||||
$: runner = 0;
|
||||
$: enabled = true;
|
||||
$: processed_last_submit = true;
|
||||
|
||||
let loading = true;
|
||||
let runners = [];
|
||||
RunnerService.runnerControllerGetAll().then((val) => {
|
||||
runners = val.map((r) => {
|
||||
return { label: getRunnerLabel(r), value: r };
|
||||
});
|
||||
loading = false;
|
||||
});
|
||||
$: createbtnenabled = true;
|
||||
(() => {
|
||||
document.onkeydown = (e) => {
|
||||
e = e || window.event;
|
||||
if (e.key === "Escape") {
|
||||
modal_open = false;
|
||||
}
|
||||
if (e.keyCode === 13) {
|
||||
if (createbtnenabled === true) {
|
||||
createbtnenabled = false;
|
||||
submit();
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
function submit() {
|
||||
if (processed_last_submit === true) {
|
||||
processed_last_submit = false;
|
||||
toast.loading($_("adding-card"));
|
||||
let postdata = {
|
||||
runner,
|
||||
enabled,
|
||||
};
|
||||
RunnerCardService.runnerCardControllerPost(postdata)
|
||||
.then((result) => {
|
||||
runner = 0;
|
||||
modal_open = false;
|
||||
//
|
||||
toast.dismiss();
|
||||
toast.success($_("card-added"));
|
||||
dispatch("created", { cards: [result] });
|
||||
})
|
||||
.catch((err) => {
|
||||
//
|
||||
})
|
||||
.finally(() => {
|
||||
processed_last_submit = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
modal_open = false;
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"
|
||||
>
|
||||
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
|
||||
<div
|
||||
class="absolute inset-0 bg-gray-500 opacity-75"
|
||||
data-id="modal_backdrop"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
class="hidden sm:inline-block sm:align-middle sm:h-screen"
|
||||
aria-hidden="true">​</span
|
||||
>
|
||||
<div
|
||||
class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="modal-headline"
|
||||
>
|
||||
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
|
||||
<div class="sm:flex sm:items-start">
|
||||
<div
|
||||
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
|
||||
>
|
||||
<svg
|
||||
class="h-6 w-6 text-blue-600"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
><path fill="none" d="M0 0h24v24H0z" />
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M22 10v10a1 1 0 01-1 1H3a1 1 0 01-1-1V10h20zm0-2H2V4a1 1 0 011-1h18a1 1 0 011 1v4zm-7 8v2h4v-2h-4z"
|
||||
/></svg
|
||||
>
|
||||
</div>
|
||||
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||
{$_("create-a-new-card")}
|
||||
</h3>
|
||||
<div class="mt-2 mb-6">
|
||||
<p class="text-sm text-gray-500">
|
||||
{$_("you-can-provide-a-runner-but-you-dont-have-to")}
|
||||
{$_(
|
||||
"if-you-want-to-create-multiple-blanco-cards-try-the-add-bulk-button"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div class="grid grid-cols-6 gap-6">
|
||||
<div class="col-span-6">
|
||||
<label
|
||||
for="donor"
|
||||
class="block text-sm font-medium text-gray-700"
|
||||
>{$_("runner")}</label
|
||||
>
|
||||
<Select
|
||||
containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2"
|
||||
itemFilter={(label, filterText, option) =>
|
||||
filterRunners(label, filterText, option)}
|
||||
items={runners}
|
||||
bind:loading
|
||||
showChevron={!loading}
|
||||
placeholder={$_("search-for-runner-by-name-or-id")}
|
||||
noOptionsMessage={$_("no-runners-found")}
|
||||
on:select={(selectedValue) =>
|
||||
(runner = selectedValue.detail.value.id)}
|
||||
on:clear={() => (runner = null)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
|
||||
<button
|
||||
disabled={!createbtnenabled}
|
||||
class:opacity-50={!createbtnenabled}
|
||||
on:click={submit}
|
||||
type="button"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
>
|
||||
{$_("create")}
|
||||
</button>
|
||||
<button
|
||||
on:click={() => {
|
||||
modal_open = false;
|
||||
}}
|
||||
type="button"
|
||||
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
>
|
||||
{$_("cancel")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -1,193 +1,200 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
|
||||
import { RunnerCardService, RunnerService } from "@odit/lfk-client-js";
|
||||
import Select from "svelte-select";
|
||||
import Toastify from "toastify-js";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
export let edit_modal_open;
|
||||
export let runner = {};
|
||||
export let editable = {};
|
||||
export let original_data = {};
|
||||
const getRunnerLabel = (option) =>
|
||||
option.firstname + " " + (option.middlename || "") + " " + option.lastname;
|
||||
const filterRunners = (label, filterText, option) => {
|
||||
if (filterText.startsWith("#")) {
|
||||
return option.value.id == parseInt(filterText.replace("#",""))
|
||||
}
|
||||
return (
|
||||
label.toLowerCase().includes(filterText.toLowerCase()) ||
|
||||
option.value.toString().startsWith(filterText.toLowerCase())
|
||||
);
|
||||
};
|
||||
|
||||
function focus(el) {
|
||||
el.focus();
|
||||
}
|
||||
$: runners = [];
|
||||
$: enabled = true;
|
||||
$: processed_last_submit = true;
|
||||
const dispatch = createEventDispatcher();
|
||||
RunnerService.runnerControllerGetAll().then((val) => {
|
||||
runners = val.map((r) => {
|
||||
return { label: getRunnerLabel(r), value: r };
|
||||
});
|
||||
});
|
||||
$: createbtnenabled = !(
|
||||
JSON.stringify(editable) === JSON.stringify(original_data)
|
||||
);
|
||||
(() => {
|
||||
document.onkeydown = (e) => {
|
||||
e = e || window.event;
|
||||
if (e.key === "Escape") {
|
||||
edit_modal_open = false;
|
||||
}
|
||||
if (e.keyCode === 13) {
|
||||
if (createbtnenabled === true) {
|
||||
createbtnenabled = false;
|
||||
submit();
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
function submit() {
|
||||
if (processed_last_submit === true) {
|
||||
processed_last_submit = false;
|
||||
const toast = Toastify({
|
||||
text: $_("updating-card"),
|
||||
duration: -1,
|
||||
}).showToast();
|
||||
RunnerCardService.runnerCardControllerPut(original_data.id, editable)
|
||||
.then((result) => {
|
||||
let id = original_data.id;
|
||||
runner = {};
|
||||
editable = {};
|
||||
original_data = {};
|
||||
edit_modal_open = false;
|
||||
//
|
||||
Toastify({
|
||||
text: $_("card-updated"),
|
||||
duration: 500,
|
||||
backgroundColor: "linear-gradient(to right, #00b09b, #96c93d)",
|
||||
}).showToast();
|
||||
dispatch('dataUpdated', {card: result});
|
||||
})
|
||||
.catch((err) => {
|
||||
//
|
||||
})
|
||||
.finally(() => {
|
||||
processed_last_submit = true;
|
||||
//
|
||||
toast.hideToast();
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if edit_modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
edit_modal_open = false;
|
||||
}}>
|
||||
<div
|
||||
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0">
|
||||
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
|
||||
<div
|
||||
class="absolute inset-0 bg-gray-500 opacity-75"
|
||||
data-id="modal_backdrop" />
|
||||
</div>
|
||||
<span
|
||||
class="hidden sm:inline-block sm:align-middle sm:h-screen"
|
||||
aria-hidden="true">​</span>
|
||||
<div
|
||||
class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="modal-headline">
|
||||
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
|
||||
<div class="sm:flex sm:items-start">
|
||||
<div
|
||||
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10">
|
||||
<svg
|
||||
class="h-6 w-6 text-blue-600"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"><path fill="none" d="M0 0h24v24H0z" />
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M22 10v10a1 1 0 01-1 1H3a1 1 0 01-1-1V10h20zm0-2H2V4a1 1 0 011-1h18a1 1 0 011 1v4zm-7 8v2h4v-2h-4z" /></svg>
|
||||
</div>
|
||||
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||
{$_('edit-a-card')}
|
||||
</h3>
|
||||
<div class="mt-2 mb-6">
|
||||
<p class="text-sm text-gray-500">
|
||||
{$_('you-can-provide-a-runner-but-you-dont-have-to')}
|
||||
</p>
|
||||
</div>
|
||||
<div class="grid grid-cols-6 gap-6">
|
||||
<div class="col-span-6">
|
||||
<label
|
||||
for="runner"
|
||||
class="block text-sm font-medium text-gray-700">{$_('runner')}</label>
|
||||
<Select
|
||||
containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2"
|
||||
itemFilter={(label, filterText, option) => filterRunners(label, filterText, option)}
|
||||
items={runners}
|
||||
showChevron={true}
|
||||
placeholder={$_('search-for-runner-by-name-or-id')}
|
||||
noOptionsMessage={$_('no-runners-found')}
|
||||
bind:selectedValue={runner}
|
||||
on:select={(selectedValue) => (editable.runner = selectedValue.detail.value.id)}
|
||||
on:clear={() => (editable.runner = null)} />
|
||||
</div>
|
||||
<div class="col-span-6">
|
||||
<p class="text-gray-500">
|
||||
<input
|
||||
id="enabled"
|
||||
on:change={() => {
|
||||
editable.enabled = !editable.enabled;
|
||||
}}
|
||||
name="enabled"
|
||||
type="checkbox"
|
||||
checked={editable.enabled}
|
||||
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded" />
|
||||
{$_('this-card-is')}
|
||||
{#if editable.enabled}
|
||||
{$_('enabled')}
|
||||
{:else}{$_('disabled')}{/if}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
|
||||
<button
|
||||
disabled={!createbtnenabled}
|
||||
class:opacity-50={!createbtnenabled}
|
||||
on:click={submit}
|
||||
type="button"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm">
|
||||
{$_('save-changes')}
|
||||
</button>
|
||||
<button
|
||||
on:click={() => {
|
||||
edit_modal_open = false;
|
||||
}}
|
||||
type="button"
|
||||
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm">
|
||||
{$_('cancel')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { clickOutside } from "../base/outsideclick";
|
||||
|
||||
import { RunnerCardService, RunnerService } from "@odit/lfk-client-js";
|
||||
import Select from "svelte-select";
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import toast from "svelte-french-toast";
|
||||
export let edit_modal_open;
|
||||
export let runner = {};
|
||||
export let editable = {};
|
||||
export let original_data = {};
|
||||
const getRunnerLabel = (option) =>
|
||||
option.firstname + " " + (option.middlename || "") + " " + option.lastname;
|
||||
const filterRunners = (label, filterText, option) => {
|
||||
if (filterText.startsWith("#")) {
|
||||
return option.value.id == parseInt(filterText.replace("#", ""));
|
||||
}
|
||||
return (
|
||||
label.toLowerCase().includes(filterText.toLowerCase()) ||
|
||||
option.value.toString().startsWith(filterText.toLowerCase())
|
||||
);
|
||||
};
|
||||
|
||||
function focus(el) {
|
||||
el.focus();
|
||||
}
|
||||
$: runners = [];
|
||||
$: enabled = true;
|
||||
$: processed_last_submit = true;
|
||||
const dispatch = createEventDispatcher();
|
||||
RunnerService.runnerControllerGetAll().then((val) => {
|
||||
runners = val.map((r) => {
|
||||
return { label: getRunnerLabel(r), value: r };
|
||||
});
|
||||
});
|
||||
$: createbtnenabled = !(
|
||||
JSON.stringify(editable) === JSON.stringify(original_data)
|
||||
);
|
||||
(() => {
|
||||
document.onkeydown = (e) => {
|
||||
e = e || window.event;
|
||||
if (e.key === "Escape") {
|
||||
edit_modal_open = false;
|
||||
}
|
||||
if (e.keyCode === 13) {
|
||||
if (createbtnenabled === true) {
|
||||
createbtnenabled = false;
|
||||
submit();
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
function submit() {
|
||||
if (processed_last_submit === true) {
|
||||
processed_last_submit = false;
|
||||
toast.loading($_("updating-card"));
|
||||
RunnerCardService.runnerCardControllerPut(original_data.id, editable)
|
||||
.then((result) => {
|
||||
runner = {};
|
||||
editable = {};
|
||||
original_data = {};
|
||||
edit_modal_open = false;
|
||||
//
|
||||
toast.dismiss();
|
||||
toast.success($_("card-updated"));
|
||||
dispatch("dataUpdated", { card: result });
|
||||
})
|
||||
.catch((err) => {
|
||||
//
|
||||
})
|
||||
.finally(() => {
|
||||
processed_last_submit = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if edit_modal_open}
|
||||
<div
|
||||
class="fixed z-10 inset-0 overflow-y-auto"
|
||||
use:clickOutside
|
||||
on:click_outside={() => {
|
||||
edit_modal_open = false;
|
||||
}}
|
||||
>
|
||||
<div
|
||||
class="flex items-end justify-center min-h-screen pt-4 px-4 pb-20 text-center sm:block sm:p-0"
|
||||
>
|
||||
<div class="fixed inset-0 transition-opacity" aria-hidden="true">
|
||||
<div
|
||||
class="absolute inset-0 bg-gray-500 opacity-75"
|
||||
data-id="modal_backdrop"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
class="hidden sm:inline-block sm:align-middle sm:h-screen"
|
||||
aria-hidden="true">​</span
|
||||
>
|
||||
<div
|
||||
class="inline-block align-bottom bg-white rounded-lg text-left shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="modal-headline"
|
||||
>
|
||||
<div class="bg-white px-4 pt-5 pb-4 sm:p-6 sm:pb-4">
|
||||
<div class="sm:flex sm:items-start">
|
||||
<div
|
||||
class="mx-auto flex-shrink-0 flex items-center justify-center h-12 w-12 rounded-full bg-blue-100 sm:mx-0 sm:h-10 sm:w-10"
|
||||
>
|
||||
<svg
|
||||
class="h-6 w-6 text-blue-600"
|
||||
fill="currentColor"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
><path fill="none" d="M0 0h24v24H0z" />
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M22 10v10a1 1 0 01-1 1H3a1 1 0 01-1-1V10h20zm0-2H2V4a1 1 0 011-1h18a1 1 0 011 1v4zm-7 8v2h4v-2h-4z"
|
||||
/></svg
|
||||
>
|
||||
</div>
|
||||
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
|
||||
<h3 class="text-lg leading-6 font-medium text-gray-900">
|
||||
{$_("edit-a-card")}
|
||||
</h3>
|
||||
<div class="mt-2 mb-6">
|
||||
<p class="text-sm text-gray-500">
|
||||
{$_("you-can-provide-a-runner-but-you-dont-have-to")}
|
||||
</p>
|
||||
</div>
|
||||
<div class="grid grid-cols-6 gap-6">
|
||||
<div class="col-span-6">
|
||||
<label
|
||||
for="runner"
|
||||
class="block text-sm font-medium text-gray-700"
|
||||
>{$_("runner")}</label
|
||||
>
|
||||
<Select
|
||||
containerClasses="rounded-l-md mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm rounded-l-md sm:text-sm border-gray-300 border bg-gray-50 text-gray-500 rounded-md p-2"
|
||||
itemFilter={(label, filterText, option) =>
|
||||
filterRunners(label, filterText, option)}
|
||||
items={runners}
|
||||
showChevron={true}
|
||||
placeholder={$_("search-for-runner-by-name-or-id")}
|
||||
noOptionsMessage={$_("no-runners-found")}
|
||||
bind:selectedValue={runner}
|
||||
on:select={(selectedValue) =>
|
||||
(editable.runner = selectedValue.detail.value.id)}
|
||||
on:clear={() => (editable.runner = null)}
|
||||
/>
|
||||
</div>
|
||||
<div class="col-span-6">
|
||||
<p class="text-gray-500">
|
||||
<input
|
||||
id="enabled"
|
||||
on:change={() => {
|
||||
editable.enabled = !editable.enabled;
|
||||
}}
|
||||
name="enabled"
|
||||
type="checkbox"
|
||||
checked={editable.enabled}
|
||||
class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
|
||||
/>
|
||||
{$_("this-card-is")}
|
||||
{#if editable.enabled}
|
||||
{$_("enabled")}
|
||||
{:else}{$_("disabled")}{/if}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-gray-50 px-4 py-3 sm:px-6 sm:flex sm:flex-row-reverse">
|
||||
<button
|
||||
disabled={!createbtnenabled}
|
||||
class:opacity-50={!createbtnenabled}
|
||||
on:click={submit}
|
||||
type="button"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
>
|
||||
{$_("save-changes")}
|
||||
</button>
|
||||
<button
|
||||
on:click={() => {
|
||||
edit_modal_open = false;
|
||||
}}
|
||||
type="button"
|
||||
class="mt-3 w-full inline-flex justify-center rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-base font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 sm:mt-0 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
>
|
||||
{$_("cancel")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
@@ -1,54 +1,53 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import store from "../../store";
|
||||
import AddCardBulkModal from "./AddCardBulkModal.svelte";
|
||||
import AddCardModal from "./AddCardModal.svelte";
|
||||
import CardsOverview from "./CardsOverview.svelte";
|
||||
$: current_cards = [];
|
||||
export let modal_open = false;
|
||||
export let bulk_modal_open = false;
|
||||
let addCards;
|
||||
</script>
|
||||
|
||||
<section class="container p-5">
|
||||
<span class="mb-1 text-3xl font-extrabold leading-tight">
|
||||
{$_("cards")}
|
||||
{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:CREATE")}
|
||||
<button
|
||||
on:click={() => {
|
||||
modal_open = true;
|
||||
}}
|
||||
type="button"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
>
|
||||
{$_("add-card")}
|
||||
</button>
|
||||
<button
|
||||
on:click={() => {
|
||||
bulk_modal_open = true;
|
||||
}}
|
||||
type="button"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
>
|
||||
{$_("create-bulk-cards")}
|
||||
</button>
|
||||
{/if}
|
||||
</span>
|
||||
<CardsOverview bind:current_cards bind:addCards />
|
||||
</section>
|
||||
|
||||
{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:CREATE")}
|
||||
<AddCardModal
|
||||
bind:modal_open
|
||||
on:created={(event) => {
|
||||
console.log(event)
|
||||
addCards(event.detail.cards);
|
||||
}}
|
||||
/>
|
||||
<AddCardBulkModal
|
||||
bind:bulk_modal_open
|
||||
on:created={(event) => {
|
||||
addCards(event.detail.cards);
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import store from "../../store";
|
||||
import AddCardBulkModal from "./AddCardBulkModal.svelte";
|
||||
import AddCardModal from "./AddCardModal.svelte";
|
||||
import CardsOverview from "./CardsOverview.svelte";
|
||||
$: current_cards = [];
|
||||
export let modal_open = false;
|
||||
export let bulk_modal_open = false;
|
||||
let addCards;
|
||||
</script>
|
||||
|
||||
<section class="container p-5">
|
||||
<span class="mb-1 text-3xl font-extrabold leading-tight">
|
||||
{$_("cards")}
|
||||
{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:CREATE")}
|
||||
<button
|
||||
on:click={() => {
|
||||
modal_open = true;
|
||||
}}
|
||||
type="button"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
>
|
||||
{$_("add-card")}
|
||||
</button>
|
||||
<button
|
||||
on:click={() => {
|
||||
bulk_modal_open = true;
|
||||
}}
|
||||
type="button"
|
||||
class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-blue-600 text-base font-medium text-white hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 sm:ml-3 sm:w-auto sm:text-sm"
|
||||
>
|
||||
{$_("create-bulk-cards")}
|
||||
</button>
|
||||
{/if}
|
||||
</span>
|
||||
<CardsOverview bind:current_cards bind:addCards />
|
||||
</section>
|
||||
|
||||
{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:CREATE")}
|
||||
<AddCardModal
|
||||
bind:modal_open
|
||||
on:created={(event) => {
|
||||
addCards(event.detail.cards);
|
||||
}}
|
||||
/>
|
||||
<AddCardBulkModal
|
||||
bind:bulk_modal_open
|
||||
on:created={(event) => {
|
||||
addCards(event.detail.cards);
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import cards_empty from "./cards.svg";
|
||||
</script>
|
||||
|
||||
<div class="text-center items-center justify-center">
|
||||
<p class="mb-16 text-lg text-gray-500">
|
||||
<img class="m-auto" style="height:15rem" src={cards_empty} alt="" />
|
||||
<span class="font-bold">{$_('there-are-no-cards-yet')}</span><br />
|
||||
<span>{$_('add-your-first-card')}</span>
|
||||
</p>
|
||||
</div>
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import cards_empty from "./cards.svg";
|
||||
</script>
|
||||
|
||||
<div class="text-center items-center justify-center">
|
||||
<p class="mb-16 text-lg text-gray-500">
|
||||
<img class="m-auto" style="height:15rem" src={cards_empty} alt="" />
|
||||
<span class="font-bold">{$_("there-are-no-cards-yet")}</span><br />
|
||||
<span>{$_("add-your-first-card")}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -1,313 +1,312 @@
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { RunnerCardService } from "@odit/lfk-client-js";
|
||||
import store from "../../store";
|
||||
import toast from "svelte-french-toast";
|
||||
import CardsEmptyState from "./CardsEmptyState.svelte";
|
||||
import CardDetailModal from "./CardDetailModal.svelte";
|
||||
import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte";
|
||||
import InputElement from "../shared/InputElement.svelte";
|
||||
import {
|
||||
createSvelteTable,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getFilteredRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
renderComponent,
|
||||
} from "@tanstack/svelte-table";
|
||||
import { writable } from "svelte/store";
|
||||
import TableBottom from "../shared/TableBottom.svelte";
|
||||
import TableActions from "../shared/TableActions.svelte";
|
||||
import TableHeader from "../shared/TableHeader.svelte";
|
||||
import CardStatus from "./CardStatus.svelte";
|
||||
import CardRunner from "./CardRunner.svelte";
|
||||
import { onMount } from "svelte";
|
||||
import { runnerFilter, statusFilter } from "../shared/tablefilters";
|
||||
import DeleteCardModal from "./DeleteCardModal.svelte";
|
||||
|
||||
export let edit_modal_open = false;
|
||||
export let runner = {};
|
||||
export let editable = {};
|
||||
export let original_data = {};
|
||||
export let current_cards = [];
|
||||
export const addCards = (cards) => {
|
||||
console.log(cards);
|
||||
current_cards = current_cards.concat(...cards);
|
||||
options.update((options) => ({
|
||||
...options,
|
||||
data: current_cards,
|
||||
}));
|
||||
};
|
||||
|
||||
$: dataLoaded = false;
|
||||
$: selected =
|
||||
$table?.getSelectedRowModel().rows.map((row) => row.index) || [];
|
||||
$: selectedCards =
|
||||
$table?.getSelectedRowModel().rows.map((row) => row.original) || [];
|
||||
$: active_delete = undefined;
|
||||
$: cards_show = generate_cards.length > 0;
|
||||
$: generate_cards = [];
|
||||
|
||||
const columns = [
|
||||
{
|
||||
accessorKey: "code",
|
||||
header: () => $_("code"),
|
||||
filterFn: `includesString`,
|
||||
},
|
||||
{
|
||||
accessorKey: "runner",
|
||||
header: () => $_("runner"),
|
||||
cell: (info) => {
|
||||
return renderComponent(CardRunner, { runner: info.getValue() });
|
||||
},
|
||||
filterFn: `runner`,
|
||||
},
|
||||
{
|
||||
accessorKey: "enabled",
|
||||
cell: (info) => {
|
||||
return renderComponent(CardStatus, { enabled: info.getValue() });
|
||||
},
|
||||
header: () => $_("status"),
|
||||
filterFn: `status`,
|
||||
},
|
||||
{
|
||||
accessorKey: "actions",
|
||||
header: () => $_("action"),
|
||||
cell: (info) => {
|
||||
return renderComponent(TableActions, {
|
||||
detailsAction: () => {
|
||||
open_edit_modal(
|
||||
current_cards[
|
||||
current_cards.findIndex((r) => r.id == info.row.original.id)
|
||||
]
|
||||
);
|
||||
},
|
||||
deleteAction: () => {
|
||||
active_delete =
|
||||
current_cards[
|
||||
current_cards.findIndex((r) => r.id == info.row.original.id)
|
||||
];
|
||||
},
|
||||
deleteEnabled:
|
||||
store.state.jwtinfo.userdetails.permissions.includes("CARD:DELETE"),
|
||||
});
|
||||
},
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
},
|
||||
];
|
||||
|
||||
const options = writable({
|
||||
data: [],
|
||||
columns: columns,
|
||||
initialState: {
|
||||
pagination: {
|
||||
pageSize: 50,
|
||||
},
|
||||
},
|
||||
filterFns: {
|
||||
runner: runnerFilter,
|
||||
status: statusFilter,
|
||||
},
|
||||
enableRowSelection: true,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
});
|
||||
|
||||
const table = createSvelteTable(options);
|
||||
|
||||
function open_edit_modal(card) {
|
||||
const getRunnerLabel = (option) =>
|
||||
option.firstname +
|
||||
" " +
|
||||
(option.middlename || "") +
|
||||
" " +
|
||||
option.lastname;
|
||||
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;
|
||||
}
|
||||
|
||||
async function deleteCard(delete_card_id) {
|
||||
await RunnerCardService.runnerCardControllerRemove(delete_card_id, true);
|
||||
current_cards = current_cards.filter((r) => r.id !== delete_card_id);
|
||||
options.update((options) => ({
|
||||
...options,
|
||||
data: current_cards,
|
||||
}));
|
||||
toast.success($_("card-deleted"));
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
toast.loading($_("loading-cards"));
|
||||
let page = 0;
|
||||
while (page >= 0) {
|
||||
const cards = await RunnerCardService.runnerCardControllerGetAll(
|
||||
page,
|
||||
500
|
||||
);
|
||||
if (cards.length == 0) {
|
||||
page = -2;
|
||||
}
|
||||
|
||||
current_cards = current_cards.concat(...cards);
|
||||
options.update((options) => ({
|
||||
...options,
|
||||
data: current_cards,
|
||||
}));
|
||||
|
||||
dataLoaded = true;
|
||||
page++;
|
||||
}
|
||||
toast.dismiss();
|
||||
toast.success($_('all-cards-loaded'));
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:UPDATE")}
|
||||
<CardDetailModal
|
||||
bind:edit_modal_open
|
||||
bind:runner
|
||||
bind:editable
|
||||
bind:original_data
|
||||
on:dataUpdated={(event) => {
|
||||
current_cards[
|
||||
current_cards.findIndex((c) => c.id === event.detail.card.id)
|
||||
] = event.detail.card;
|
||||
current_cards = current_cards;
|
||||
options.update((options) => ({
|
||||
...options,
|
||||
data: current_cards,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:GET")}
|
||||
<DeleteCardModal
|
||||
delete_card={active_delete}
|
||||
modal_open={active_delete != undefined}
|
||||
on:delete={(event) => {
|
||||
deleteCard(event.detail.id);
|
||||
}}
|
||||
/>
|
||||
{#if !dataLoaded}
|
||||
<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>
|
||||
{:else if current_cards.length === 0}
|
||||
<CardsEmptyState />
|
||||
{:else}
|
||||
<div class="h-12 mt-1">
|
||||
{#if selected.length > 0}
|
||||
<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 selectedCards) {
|
||||
prom.push(
|
||||
await RunnerCardService.runnerCardControllerRemove(
|
||||
card.id,
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
await Promise.all(prom);
|
||||
for (const card of selectedCards) {
|
||||
current_cards = current_cards.filter((r) => r.id !== card.id);
|
||||
}
|
||||
options.update((options) => ({
|
||||
...options,
|
||||
data: current_cards,
|
||||
}));
|
||||
$table.resetRowSelection();
|
||||
}}
|
||||
>
|
||||
{$_("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
|
||||
cards_show={selected.length > 0}
|
||||
bind:generate_cards={selectedCards}
|
||||
/>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
{#each $table.getHeaderGroups() as headerGroup}
|
||||
<tr class="select-none">
|
||||
<th class="inset-y-0 left-0 px-4 py-2 text-left w-px">
|
||||
<InputElement
|
||||
type="checkbox"
|
||||
checked={$table.getIsAllRowsSelected()}
|
||||
indeterminate={$table.getIsSomeRowsSelected()}
|
||||
on:change={() => $table.toggleAllRowsSelected()}
|
||||
/>
|
||||
</th>
|
||||
{#each headerGroup.headers as header}
|
||||
<TableHeader {header} />
|
||||
{/each}
|
||||
</tr>
|
||||
{/each}
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each $table.getRowModel().rows as row}
|
||||
<tr>
|
||||
<td class="inset-y-0 left-0 px-4 py-2 text-center w-px">
|
||||
<InputElement
|
||||
type="checkbox"
|
||||
checked={row.getIsSelected()}
|
||||
on:change={() => row.toggleSelected()}
|
||||
/>
|
||||
</td>
|
||||
{#each row.getVisibleCells() as cell}
|
||||
<td>
|
||||
<svelte:component
|
||||
this={flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext()
|
||||
)}
|
||||
/>
|
||||
</td>
|
||||
{/each}
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<TableBottom {table} {selected} />
|
||||
{/if}
|
||||
{/if}
|
||||
<script>
|
||||
import { _ } from "svelte-i18n";
|
||||
import { RunnerCardService } from "@odit/lfk-client-js";
|
||||
import store from "../../store";
|
||||
import toast from "svelte-french-toast";
|
||||
import CardsEmptyState from "./CardsEmptyState.svelte";
|
||||
import CardDetailModal from "./CardDetailModal.svelte";
|
||||
import GenerateRunnerCards from "../pdf_generation/GenerateRunnerCards.svelte";
|
||||
import InputElement from "../shared/InputElement.svelte";
|
||||
import {
|
||||
createSvelteTable,
|
||||
flexRender,
|
||||
getCoreRowModel,
|
||||
getFilteredRowModel,
|
||||
getPaginationRowModel,
|
||||
getSortedRowModel,
|
||||
renderComponent,
|
||||
} from "@tanstack/svelte-table";
|
||||
import { writable } from "svelte/store";
|
||||
import TableBottom from "../shared/TableBottom.svelte";
|
||||
import TableActions from "../shared/TableActions.svelte";
|
||||
import TableHeader from "../shared/TableHeader.svelte";
|
||||
import CardStatus from "./CardStatus.svelte";
|
||||
import CardRunner from "./CardRunner.svelte";
|
||||
import { onMount } from "svelte";
|
||||
import { runnerFilter, statusFilter } from "../shared/tablefilters";
|
||||
import DeleteCardModal from "./DeleteCardModal.svelte";
|
||||
|
||||
export let edit_modal_open = false;
|
||||
export let runner = {};
|
||||
export let editable = {};
|
||||
export let original_data = {};
|
||||
export let current_cards = [];
|
||||
export const addCards = (cards) => {
|
||||
current_cards = current_cards.concat(...cards);
|
||||
options.update((options) => ({
|
||||
...options,
|
||||
data: current_cards,
|
||||
}));
|
||||
};
|
||||
|
||||
$: dataLoaded = false;
|
||||
$: selected =
|
||||
$table?.getSelectedRowModel().rows.map((row) => row.index) || [];
|
||||
$: selectedCards =
|
||||
$table?.getSelectedRowModel().rows.map((row) => row.original) || [];
|
||||
$: active_delete = undefined;
|
||||
$: cards_show = generate_cards.length > 0;
|
||||
$: generate_cards = [];
|
||||
|
||||
const columns = [
|
||||
{
|
||||
accessorKey: "code",
|
||||
header: () => $_("code"),
|
||||
filterFn: `includesString`,
|
||||
},
|
||||
{
|
||||
accessorKey: "runner",
|
||||
header: () => $_("runner"),
|
||||
cell: (info) => {
|
||||
return renderComponent(CardRunner, { runner: info.getValue() });
|
||||
},
|
||||
filterFn: `runner`,
|
||||
},
|
||||
{
|
||||
accessorKey: "enabled",
|
||||
cell: (info) => {
|
||||
return renderComponent(CardStatus, { enabled: info.getValue() });
|
||||
},
|
||||
header: () => $_("status"),
|
||||
filterFn: `status`,
|
||||
},
|
||||
{
|
||||
accessorKey: "actions",
|
||||
header: () => $_("action"),
|
||||
cell: (info) => {
|
||||
return renderComponent(TableActions, {
|
||||
detailsAction: () => {
|
||||
open_edit_modal(
|
||||
current_cards[
|
||||
current_cards.findIndex((r) => r.id == info.row.original.id)
|
||||
]
|
||||
);
|
||||
},
|
||||
deleteAction: () => {
|
||||
active_delete =
|
||||
current_cards[
|
||||
current_cards.findIndex((r) => r.id == info.row.original.id)
|
||||
];
|
||||
},
|
||||
deleteEnabled:
|
||||
store.state.jwtinfo.userdetails.permissions.includes("CARD:DELETE"),
|
||||
});
|
||||
},
|
||||
enableColumnFilter: false,
|
||||
enableSorting: false,
|
||||
},
|
||||
];
|
||||
|
||||
const options = writable({
|
||||
data: [],
|
||||
columns: columns,
|
||||
initialState: {
|
||||
pagination: {
|
||||
pageSize: 50,
|
||||
},
|
||||
},
|
||||
filterFns: {
|
||||
runner: runnerFilter,
|
||||
status: statusFilter,
|
||||
},
|
||||
enableRowSelection: true,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
getFilteredRowModel: getFilteredRowModel(),
|
||||
getPaginationRowModel: getPaginationRowModel(),
|
||||
getSortedRowModel: getSortedRowModel(),
|
||||
});
|
||||
|
||||
const table = createSvelteTable(options);
|
||||
|
||||
function open_edit_modal(card) {
|
||||
const getRunnerLabel = (option) =>
|
||||
option.firstname +
|
||||
" " +
|
||||
(option.middlename || "") +
|
||||
" " +
|
||||
option.lastname;
|
||||
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;
|
||||
}
|
||||
|
||||
async function deleteCard(delete_card_id) {
|
||||
await RunnerCardService.runnerCardControllerRemove(delete_card_id, true);
|
||||
current_cards = current_cards.filter((r) => r.id !== delete_card_id);
|
||||
options.update((options) => ({
|
||||
...options,
|
||||
data: current_cards,
|
||||
}));
|
||||
toast.success($_("card-deleted"));
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
toast.loading($_("loading-cards"));
|
||||
let page = 0;
|
||||
while (page >= 0) {
|
||||
const cards = await RunnerCardService.runnerCardControllerGetAll(
|
||||
page,
|
||||
150
|
||||
);
|
||||
if (cards.length == 0) {
|
||||
page = -2;
|
||||
}
|
||||
|
||||
current_cards = current_cards.concat(...cards);
|
||||
options.update((options) => ({
|
||||
...options,
|
||||
data: current_cards,
|
||||
}));
|
||||
|
||||
dataLoaded = true;
|
||||
page++;
|
||||
}
|
||||
toast.dismiss();
|
||||
toast.success($_("all-cards-loaded"));
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:UPDATE")}
|
||||
<CardDetailModal
|
||||
bind:edit_modal_open
|
||||
bind:runner
|
||||
bind:editable
|
||||
bind:original_data
|
||||
on:dataUpdated={(event) => {
|
||||
current_cards[
|
||||
current_cards.findIndex((c) => c.id === event.detail.card.id)
|
||||
] = event.detail.card;
|
||||
current_cards = current_cards;
|
||||
options.update((options) => ({
|
||||
...options,
|
||||
data: current_cards,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
{#if store.state.jwtinfo.userdetails.permissions.includes("CARD:GET")}
|
||||
<DeleteCardModal
|
||||
delete_card={active_delete}
|
||||
modal_open={active_delete != undefined}
|
||||
on:delete={(event) => {
|
||||
deleteCard(event.detail.id);
|
||||
}}
|
||||
/>
|
||||
{#if !dataLoaded}
|
||||
<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>
|
||||
{:else if current_cards.length === 0}
|
||||
<CardsEmptyState />
|
||||
{:else}
|
||||
<div class="h-12 mt-1">
|
||||
{#if selected.length > 0}
|
||||
<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 selectedCards) {
|
||||
prom.push(
|
||||
await RunnerCardService.runnerCardControllerRemove(
|
||||
card.id,
|
||||
true
|
||||
)
|
||||
);
|
||||
}
|
||||
await Promise.all(prom);
|
||||
for (const card of selectedCards) {
|
||||
current_cards = current_cards.filter((r) => r.id !== card.id);
|
||||
}
|
||||
options.update((options) => ({
|
||||
...options,
|
||||
data: current_cards,
|
||||
}));
|
||||
$table.resetRowSelection();
|
||||
}}
|
||||
>
|
||||
{$_("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
|
||||
cards_show={selected.length > 0}
|
||||
bind:generate_cards={selectedCards}
|
||||
/>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full">
|
||||
<thead>
|
||||
{#each $table.getHeaderGroups() as headerGroup}
|
||||
<tr class="select-none">
|
||||
<th class="inset-y-0 left-0 px-4 py-2 text-left w-px">
|
||||
<InputElement
|
||||
type="checkbox"
|
||||
checked={$table.getIsAllRowsSelected()}
|
||||
indeterminate={$table.getIsSomeRowsSelected()}
|
||||
on:change={() => $table.toggleAllRowsSelected()}
|
||||
/>
|
||||
</th>
|
||||
{#each headerGroup.headers as header}
|
||||
<TableHeader {header} />
|
||||
{/each}
|
||||
</tr>
|
||||
{/each}
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each $table.getRowModel().rows as row}
|
||||
<tr>
|
||||
<td class="inset-y-0 left-0 px-4 py-2 text-center w-px">
|
||||
<InputElement
|
||||
type="checkbox"
|
||||
checked={row.getIsSelected()}
|
||||
on:change={() => row.toggleSelected()}
|
||||
/>
|
||||
</td>
|
||||
{#each row.getVisibleCells() as cell}
|
||||
<td>
|
||||
<svelte:component
|
||||
this={flexRender(
|
||||
cell.column.columnDef.cell,
|
||||
cell.getContext()
|
||||
)}
|
||||
/>
|
||||
</td>
|
||||
{/each}
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<TableBottom {table} {selected} />
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user