mirror of
https://github.com/Djeeberjr/fw-anwesenheit.git
synced 2025-11-03 15:24:09 +00:00
enabled download of exported csv
This commit is contained in:
parent
2e75ba2908
commit
770dca5b0f
@ -3,15 +3,21 @@
|
||||
import IDTable from "./lib/IDTable.svelte";
|
||||
import LastId from "./lib/LastID.svelte";
|
||||
import AddIDModal from "./lib/AddIDModal.svelte";
|
||||
import ExportModal from "./lib/ExportModal.svelte";
|
||||
import { generateCSVFile } from "./lib/exporting";
|
||||
import { fetchMapping, type IDMap } from "./lib/IDMapping";
|
||||
import { downloadBlob } from "./lib/downloadBlob";
|
||||
|
||||
let lastID: string = $state("");
|
||||
let mapping: IDMap | null = $state(null);
|
||||
|
||||
let addModal: AddIDModal;
|
||||
let idTable: IDTable;
|
||||
let exportModal: ExportModal;
|
||||
|
||||
onMount(async () => {
|
||||
mapping = await fetchMapping();
|
||||
|
||||
onMount(() => {
|
||||
let sse = new EventSource("/api/idevent");
|
||||
|
||||
sse.onmessage = (e) => {
|
||||
lastID = e.data;
|
||||
};
|
||||
@ -25,13 +31,14 @@
|
||||
<h1 class="text-3xl sm:text-4xl font-bold text-gray-800">Anwesenheit</h1>
|
||||
</div>
|
||||
|
||||
<a
|
||||
<button
|
||||
class="px-6 py-3 text-lg font-semibold text-white bg-indigo-600 rounded-2xl shadow-md hover:bg-indigo-700 transition"
|
||||
href="/api/csv"
|
||||
download="anwesenheit.csv"
|
||||
onclick={() => {
|
||||
exportModal.open();
|
||||
}}
|
||||
>
|
||||
Download CSV
|
||||
</a>
|
||||
Export CSV
|
||||
</button>
|
||||
|
||||
<div class="pt-3 pb-2">
|
||||
<LastId
|
||||
@ -42,15 +49,32 @@
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<IDTable bind:this={idTable} onEdit={(id,firstName,lastName)=>{
|
||||
addModal.open(id,firstName,lastName);
|
||||
}}/>
|
||||
{#if mapping}
|
||||
<IDTable
|
||||
data={mapping}
|
||||
onEdit={(id, firstName, lastName) => {
|
||||
addModal.open(id, firstName, lastName);
|
||||
}}
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<AddIDModal
|
||||
bind:this={addModal}
|
||||
onSubmitted={() => {
|
||||
idTable.reloadData();
|
||||
onSubmitted={async () => {
|
||||
mapping = await fetchMapping();
|
||||
}}
|
||||
/>
|
||||
|
||||
<ExportModal
|
||||
bind:this={exportModal}
|
||||
onSubmitted={async (from, to) => {
|
||||
if (!mapping) {
|
||||
return;
|
||||
}
|
||||
let csvFile = await generateCSVFile(from, to, mapping);
|
||||
|
||||
downloadBlob("export.csv",csvFile,"text/csv");
|
||||
}}
|
||||
/>
|
||||
</main>
|
||||
|
||||
@ -1,16 +1,13 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { fetchMapping, type IDMap } from "./IDMapping";
|
||||
let data: IDMap | undefined = $state();
|
||||
import { type IDMap } from "./IDMapping";
|
||||
|
||||
let {
|
||||
onEdit,
|
||||
}: { onEdit?: (id: string, firstName: string, lastName: string) => void } =
|
||||
$props();
|
||||
|
||||
export async function reloadData() {
|
||||
data = await fetchMapping();
|
||||
}
|
||||
data,
|
||||
}: {
|
||||
onEdit?: (id: string, firstName: string, lastName: string) => void;
|
||||
data: IDMap;
|
||||
} = $props();
|
||||
|
||||
let rows = $derived(
|
||||
data
|
||||
@ -44,69 +41,61 @@
|
||||
if (sortKey !== key) return "";
|
||||
return sortDirection === "asc" ? "▲" : "▼";
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
await reloadData();
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if data == null}
|
||||
Loading...
|
||||
{:else}
|
||||
<div class="bg-indigo-500 py-2 rounded-2xl overflow-x-auto">
|
||||
<table class="px-10">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
class="text-left pr-5 pl-2 cursor-pointer select-none"
|
||||
onclick={() => {
|
||||
handleSortClick("id");
|
||||
}}
|
||||
>
|
||||
ID
|
||||
<span class="indicator">{indicator("id")}</span>
|
||||
</th>
|
||||
<th
|
||||
class="text-left pr-5 cursor-pointer select-none"
|
||||
onclick={() => {
|
||||
handleSortClick("last");
|
||||
}}
|
||||
>
|
||||
Nachname
|
||||
<span class="indicator">{indicator("last")}</span>
|
||||
</th>
|
||||
<th
|
||||
class="text-left pr-5 cursor-pointer select-none"
|
||||
onclick={() => {
|
||||
handleSortClick("first");
|
||||
}}
|
||||
>Vorname
|
||||
<div class="bg-indigo-500 py-2 rounded-2xl overflow-x-auto">
|
||||
<table class="px-10">
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
class="text-left pr-5 pl-2 cursor-pointer select-none"
|
||||
onclick={() => {
|
||||
handleSortClick("id");
|
||||
}}
|
||||
>
|
||||
ID
|
||||
<span class="indicator">{indicator("id")}</span>
|
||||
</th>
|
||||
<th
|
||||
class="text-left pr-5 cursor-pointer select-none"
|
||||
onclick={() => {
|
||||
handleSortClick("last");
|
||||
}}
|
||||
>
|
||||
Nachname
|
||||
<span class="indicator">{indicator("last")}</span>
|
||||
</th>
|
||||
<th
|
||||
class="text-left pr-5 cursor-pointer select-none"
|
||||
onclick={() => {
|
||||
handleSortClick("first");
|
||||
}}
|
||||
>Vorname
|
||||
|
||||
<span class="indicator">{indicator("first")}</span>
|
||||
</th>
|
||||
<th> </th>
|
||||
<span class="indicator">{indicator("first")}</span>
|
||||
</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each rowsSorted as row}
|
||||
<tr class="even:bg-indigo-600">
|
||||
<td class="whitespace-nowrap pr-5 pl-2 py-1">{row.id}</td>
|
||||
<td class="whitespace-nowrap pr-5">{row.last}</td>
|
||||
<td class="whitespace-nowrap pr-5">{row.first}</td>
|
||||
<td class="pr-5"
|
||||
><button
|
||||
onclick={() => {
|
||||
onEdit && onEdit(row.id, row.first, row.last);
|
||||
}}
|
||||
class="cursor-pointer">🔧</button
|
||||
></td
|
||||
>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each rowsSorted as row}
|
||||
<tr class="even:bg-indigo-600">
|
||||
<td class="whitespace-nowrap pr-5 pl-2 py-1">{row.id}</td>
|
||||
<td class="whitespace-nowrap pr-5">{row.last}</td>
|
||||
<td class="whitespace-nowrap pr-5">{row.first}</td>
|
||||
<td class="pr-5"
|
||||
><button
|
||||
onclick={() => {
|
||||
onEdit && onEdit(row.id, row.first, row.last);
|
||||
}}
|
||||
class="cursor-pointer">🔧</button
|
||||
></td
|
||||
>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{/if}
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<style lang="css" scoped>
|
||||
@reference "../app.css";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user