feat(donors): Load donors paginated
This commit is contained in:
parent
0708cabc75
commit
5014bf5bc5
@ -5,26 +5,155 @@
|
|||||||
import DonorsEmptyState from "./DonorsEmptyState.svelte";
|
import DonorsEmptyState from "./DonorsEmptyState.svelte";
|
||||||
import ConfirmDonorDeletion from "./ConfirmDonorDeletion.svelte";
|
import ConfirmDonorDeletion from "./ConfirmDonorDeletion.svelte";
|
||||||
import Toastify from "toastify-js";
|
import Toastify from "toastify-js";
|
||||||
|
import TableBottom from "../shared/TableBottom.svelte";
|
||||||
|
import {
|
||||||
|
createSvelteTable,
|
||||||
|
flexRender,
|
||||||
|
getCoreRowModel,
|
||||||
|
getFilteredRowModel,
|
||||||
|
getPaginationRowModel,
|
||||||
|
getSortedRowModel,
|
||||||
|
renderComponent,
|
||||||
|
} from "@tanstack/svelte-table";
|
||||||
|
import { writable } from "svelte/store";
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
import InputElement from "../shared/InputElement.svelte";
|
||||||
|
import TableHeader from "../shared/TableHeader.svelte";
|
||||||
|
import TableActions from "../shared/TableActions.svelte";
|
||||||
$: searchvalue = "";
|
$: searchvalue = "";
|
||||||
$: active_deletes = [];
|
$: active_deletes = [];
|
||||||
$: current_donations = [];
|
$: current_donations = [];
|
||||||
|
$: selectedDonors =
|
||||||
|
$table?.getSelectedRowModel().rows.map((row) => row.original) || [];
|
||||||
|
$: selected =
|
||||||
|
$table?.getSelectedRowModel().rows.map((row) => row.index) || [];
|
||||||
|
|
||||||
|
$: dataLoaded = false;
|
||||||
|
|
||||||
let modal_open = false;
|
let modal_open = false;
|
||||||
let delete_donor = {};
|
let delete_donor = {};
|
||||||
export let current_donors = [];
|
export let current_donors = [];
|
||||||
const donors_promise = DonorService.donorControllerGetAll().then((val) => {
|
|
||||||
current_donors = val;
|
//Section table
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
accessorKey: "id",
|
||||||
|
header: () => "id",
|
||||||
|
cell: (info) => {
|
||||||
|
return "TODO:";
|
||||||
|
},
|
||||||
|
filterFn: `equalsString`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "name",
|
||||||
|
header: () => $_("name"),
|
||||||
|
cell: (info) => {
|
||||||
|
return "TODO:";
|
||||||
|
},
|
||||||
|
filterFn: `includesString`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "address",
|
||||||
|
header: () => $_("contact-information"),
|
||||||
|
cell: (info) => {
|
||||||
|
return "TODO:";
|
||||||
|
},
|
||||||
|
filterFn: `includesString`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "sponsorings",
|
||||||
|
header: () => $_("sponsorings"),
|
||||||
|
cell: (info) => {
|
||||||
|
return "TODO:";
|
||||||
|
},
|
||||||
|
filterFn: `includesString`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "sponsorings",
|
||||||
|
header: () => $_("total-donation-amount"),
|
||||||
|
cell: (info) => {
|
||||||
|
return "TODO:";
|
||||||
|
},
|
||||||
|
filterFn: `group`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "sponsorings",
|
||||||
|
header: () => $_("total-paid-amount"),
|
||||||
|
cell: (info) => {
|
||||||
|
return "TODO:";
|
||||||
|
},
|
||||||
|
enableColumnFilter: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
accessorKey: "actions",
|
||||||
|
header: () => $_("action"),
|
||||||
|
cell: (info) => {
|
||||||
|
return renderComponent(TableActions, {
|
||||||
|
detailsLink: `./${info.row.original.id}`,
|
||||||
|
deleteAction: () => {
|
||||||
|
active_deletes =
|
||||||
|
current_donors[
|
||||||
|
current_donors.findIndex((r) => r.id == info.row.original.id)
|
||||||
|
];
|
||||||
|
},
|
||||||
|
deleteEnabled:
|
||||||
|
store.state.jwtinfo.userdetails.permissions.includes(
|
||||||
|
"DONOR:DELETE"
|
||||||
|
),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
enableColumnFilter: false,
|
||||||
|
enableSorting: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
const options = writable({
|
||||||
|
data: [],
|
||||||
|
columns: columns,
|
||||||
|
initialState: {
|
||||||
|
pagination: {
|
||||||
|
pageSize: 50,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
enableRowSelection: true,
|
||||||
|
getCoreRowModel: getCoreRowModel(),
|
||||||
|
getFilteredRowModel: getFilteredRowModel(),
|
||||||
|
getPaginationRowModel: getPaginationRowModel(),
|
||||||
|
getSortedRowModel: getSortedRowModel(),
|
||||||
});
|
});
|
||||||
const donation_promise = DonationService.donationControllerGetAll().then(
|
const table = createSvelteTable(options);
|
||||||
(val) => {
|
|
||||||
current_donations = val;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
function should_display_based_on_id(id) {
|
function should_display_based_on_id(id) {
|
||||||
if (searchvalue.toString().slice(-1) === "*") {
|
if (searchvalue.toString().slice(-1) === "*") {
|
||||||
return id.toString().startsWith(searchvalue.replace("*", ""));
|
return id.toString().startsWith(searchvalue.replace("*", ""));
|
||||||
}
|
}
|
||||||
return id.toString() === searchvalue;
|
return id.toString() === searchvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
let page = 0;
|
||||||
|
while (page >= 0) {
|
||||||
|
const donors = await DonorService.donorControllerGetAll(page, 500);
|
||||||
|
const donations = await DonationService.donationControllerGetAll(
|
||||||
|
page,
|
||||||
|
500
|
||||||
|
);
|
||||||
|
if (donors.length == 0 && donations.length == 0) {
|
||||||
|
page = -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_donors = current_donors.concat(...donors);
|
||||||
|
current_donations = current_donations.concat(...donors);
|
||||||
|
options.update((options) => ({
|
||||||
|
...options,
|
||||||
|
data: current_donors,
|
||||||
|
}));
|
||||||
|
|
||||||
|
dataLoaded = true;
|
||||||
|
page++;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("All donors loaded");
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ConfirmDonorDeletion
|
<ConfirmDonorDeletion
|
||||||
@ -33,186 +162,74 @@
|
|||||||
active_deletes[event.detail.id] = false;
|
active_deletes[event.detail.id] = false;
|
||||||
}}
|
}}
|
||||||
bind:modal_open
|
bind:modal_open
|
||||||
bind:delete_donor />
|
bind:delete_donor
|
||||||
{#if store.state.jwtinfo.userdetails.permissions.includes('DONOR:GET')}
|
/>
|
||||||
{#await donors_promise && donation_promise}
|
{#if store.state.jwtinfo.userdetails.permissions.includes("DONOR:GET")}
|
||||||
|
{#if !dataLoaded}
|
||||||
<div
|
<div
|
||||||
class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2"
|
class="bg-teal-lightest border-t-4 border-teal rounded-b text-teal-darkest px-4 py-3 shadow-md my-2"
|
||||||
role="alert">
|
role="alert"
|
||||||
<p class="font-bold">{$_('donors-are-being-loaded')}</p>
|
>
|
||||||
<p class="text-sm">{$_('this-might-take-a-moment')}</p>
|
<p class="font-bold">{$_("donors-are-being-loaded")}</p>
|
||||||
|
<p class="text-sm">{$_("this-might-take-a-moment")}</p>
|
||||||
</div>
|
</div>
|
||||||
{:then}
|
{:else if current_donors.length === 0}
|
||||||
{#if current_donors.length === 0}
|
<DonorsEmptyState />
|
||||||
<DonorsEmptyState />
|
{:else}
|
||||||
{:else}
|
<input
|
||||||
<input
|
type="search"
|
||||||
type="search"
|
bind:value={searchvalue}
|
||||||
bind:value={searchvalue}
|
placeholder={$_("datatable.search")}
|
||||||
placeholder={$_('datatable.search')}
|
aria-label={$_("datatable.search")}
|
||||||
aria-label={$_('datatable.search')}
|
class="mb-4"
|
||||||
class="mb-4" />
|
/>
|
||||||
<div
|
<div
|
||||||
class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll">
|
class="shadow border-b border-gray-200 sm:rounded-lg overflow-x-scroll"
|
||||||
<table class="divide-y divide-gray-200 w-full">
|
>
|
||||||
<thead class="bg-gray-50">
|
<table class="w-full">
|
||||||
<tr>
|
<thead>
|
||||||
<th
|
{#each $table.getHeaderGroups() as headerGroup}
|
||||||
scope="col"
|
<tr class="select-none">
|
||||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
<th class="inset-y-0 left-0 px-4 py-2 text-left w-px">
|
||||||
{$_('name')}
|
<InputElement
|
||||||
</th>
|
type="checkbox"
|
||||||
<th
|
checked={$table.getIsAllRowsSelected()}
|
||||||
scope="col"
|
indeterminate={$table.getIsSomeRowsSelected()}
|
||||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
on:change={() => $table.toggleAllRowsSelected()}
|
||||||
{$_('contact-information')}
|
/>
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
scope="col"
|
|
||||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
||||||
{$_('donations')}
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
scope="col"
|
|
||||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
||||||
{$_('total-donation-amount')}
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
scope="col"
|
|
||||||
class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
|
|
||||||
{$_('total-paid-amount')}
|
|
||||||
</th>
|
|
||||||
<th scope="col" class="relative px-6 py-3">
|
|
||||||
<span class="sr-only">{$_('action')}</span>
|
|
||||||
</th>
|
</th>
|
||||||
|
{#each headerGroup.headers as header}
|
||||||
|
<TableHeader {header} />
|
||||||
|
{/each}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
{/each}
|
||||||
<tbody class="divide-y divide-gray-200">
|
</thead>
|
||||||
{#each current_donors as donor}
|
<tbody>
|
||||||
{#if donor.firstname
|
{#each $table.getRowModel().rows as row}
|
||||||
.toLowerCase()
|
<tr>
|
||||||
.includes(
|
<td class="inset-y-0 left-0 px-4 py-2 text-center w-px">
|
||||||
searchvalue.toLowerCase()
|
<InputElement
|
||||||
) || donor.lastname
|
type="checkbox"
|
||||||
.toLowerCase()
|
checked={row.getIsSelected()}
|
||||||
.includes(
|
on:change={() => row.toggleSelected()}
|
||||||
searchvalue.toLowerCase()
|
/>
|
||||||
) || should_display_based_on_id(donor.id)}
|
</td>
|
||||||
<tr data-rowid="donor_{donor.id}">
|
{#each row.getVisibleCells() as cell}
|
||||||
<td class="px-6 py-4 whitespace-nowrap">
|
<td>
|
||||||
<div class="flex items-center">
|
<svelte:component
|
||||||
<div class="ml-4">
|
this={flexRender(
|
||||||
<div class="text-sm font-medium text-gray-900">
|
cell.column.columnDef.cell,
|
||||||
{donor.firstname}
|
cell.getContext()
|
||||||
{donor.middlename || ''}
|
)}
|
||||||
{donor.lastname}
|
/>
|
||||||
</div>
|
</td>
|
||||||
</div>
|
{/each}
|
||||||
</div>
|
</tr>
|
||||||
</td>
|
{/each}
|
||||||
<td class="px-6 py-4 whitespace-nowrap">
|
</tbody>
|
||||||
{#if donor.email}
|
</table>
|
||||||
<div class="text-sm text-gray-500">{donor.email}</div>
|
|
||||||
{/if}
|
|
||||||
{#if donor.phone}
|
|
||||||
<div class="text-sm text-gray-500">{donor.phone}</div>
|
|
||||||
{/if}
|
|
||||||
{#if donor.address.address1 !== null}
|
|
||||||
{donor.address.address1}<br />
|
|
||||||
<!-- {donor.address.address2 || ''}<br /> -->
|
|
||||||
{donor.address.postalcode}
|
|
||||||
{donor.address.city}
|
|
||||||
{donor.address.country}
|
|
||||||
{/if}
|
|
||||||
</td>
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap">
|
|
||||||
{#if current_donations.filter((d) => d.donor.id == donor.id).length > 0}
|
|
||||||
{#each current_donations.filter((o) => o.donor.id == donor.id) as d}
|
|
||||||
{#if d.responseType === 'DISTANCEDONATION'}
|
|
||||||
<a
|
|
||||||
href="../donations/{d.id}"
|
|
||||||
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-blue-600 text-white mr-1">{d.runner.firstname}
|
|
||||||
{d.runner.middlename || ''}
|
|
||||||
{d.runner.lastname}</a>
|
|
||||||
{:else}
|
|
||||||
<a
|
|
||||||
href="../donations/{d.id}"
|
|
||||||
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-700 text-white mr-1">{$_('fixed-donation')}:
|
|
||||||
{(d.amount / 100)
|
|
||||||
.toFixed(2)
|
|
||||||
.toLocaleString('de-DE', { valute: 'EUR' })}€</a>
|
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
{:else}{$_('donor-has-no-associated-donations')}{/if}
|
|
||||||
</td>
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap">
|
|
||||||
{(donor.donationAmount / 100)
|
|
||||||
.toFixed(2)
|
|
||||||
.toLocaleString('de-DE', { valute: 'EUR' })}€
|
|
||||||
</td>
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap">
|
|
||||||
{(donor.paidDonationAmount / 100)
|
|
||||||
.toFixed(2)
|
|
||||||
.toLocaleString('de-DE', { valute: 'EUR' })}€
|
|
||||||
</td>
|
|
||||||
{#if active_deletes[donor.id] === true}
|
|
||||||
<td
|
|
||||||
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
|
||||||
<button
|
|
||||||
on:click={() => {
|
|
||||||
active_deletes[donor.id] = false;
|
|
||||||
}}
|
|
||||||
tabindex="0"
|
|
||||||
class="ml-4 text-indigo-600 hover:text-indigo-900 cursor-pointer">{$_('cancel-delete')}</button>
|
|
||||||
<button
|
|
||||||
on:click={() => {
|
|
||||||
DonorService.donorControllerRemove(donor.id, false)
|
|
||||||
.then((resp) => {
|
|
||||||
current_donors = current_donors.filter((obj) => obj.id !== donor.id);
|
|
||||||
Toastify({
|
|
||||||
text: 'Donor deleted',
|
|
||||||
duration: 500,
|
|
||||||
backgroundColor:
|
|
||||||
'linear-gradient(to right, #00b09b, #96c93d)',
|
|
||||||
}).showToast();
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
modal_open = true;
|
|
||||||
delete_donor = donor;
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
tabindex="0"
|
|
||||||
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('confirm-delete')}</button>
|
|
||||||
</td>
|
|
||||||
{:else}
|
|
||||||
<td
|
|
||||||
class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
|
||||||
<a
|
|
||||||
href="./{donor.id}"
|
|
||||||
class="text-indigo-600 hover:text-indigo-900">{$_('details')}</a>
|
|
||||||
{#if store.state.jwtinfo.userdetails.permissions.includes('DONOR:DELETE')}
|
|
||||||
<button
|
|
||||||
on:click={() => {
|
|
||||||
active_deletes[donor.id] = true;
|
|
||||||
}}
|
|
||||||
tabindex="0"
|
|
||||||
class="ml-4 text-red-600 hover:text-red-900 cursor-pointer">{$_('delete')}</button>
|
|
||||||
{/if}
|
|
||||||
</td>
|
|
||||||
{/if}
|
|
||||||
</tr>
|
|
||||||
{/if}
|
|
||||||
{/each}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
{/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>
|
</div>
|
||||||
{/await}
|
<div class="h-2" />
|
||||||
|
<TableBottom {table} {selected} />
|
||||||
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user