add direct invitation link
All checks were successful
deploy / build-and-deploy (push) Successful in 21s

This commit is contained in:
2025-11-02 21:31:17 +01:00
parent 593e76dcb4
commit b2c24f394f
15 changed files with 365 additions and 39 deletions

View File

@@ -0,0 +1,28 @@
<script lang="ts">
import DataTable from '@components/admin/table/DataTable.svelte';
import { confirmPopupState } from '@components/popup/ConfirmPopup.ts';
import {
deleteDirectInvitation,
type DirectInvitation,
directInvitations
} from '@app/admin/directInvitations/directInvitations.ts';
// callback
function onDirectInvitationDelete(directInvitation: DirectInvitation) {
$confirmPopupState = {
title: 'Direkte Einladung löschen?',
message: 'Soll die direkte Einladung wirklich entblockiert werden?',
onConfirm: () => deleteDirectInvitation(directInvitation)
};
}
</script>
<DataTable
data={directInvitations}
count={true}
keys={[
{ key: 'url', label: 'Link', width: 50 },
{ key: 'user.username', label: 'Registrierter Nutzer', width: 40, sortable: true }
]}
onDelete={onDirectInvitationDelete}
/>

View File

@@ -0,0 +1,32 @@
<script lang="ts">
import Icon from '@iconify/svelte';
import CrudPopup from '@components/admin/popup/CrudPopup.svelte';
import { addDirectInvitation, fetchDirectInvitations } from '@app/admin/directInvitations/directInvitations.ts';
// states
let createPopupOpen = $state(false);
// lifecycle
$effect(() => {
fetchDirectInvitations();
});
</script>
<div>
<button class="btn btn-soft w-full" onclick={() => (createPopupOpen = true)}>
<Icon icon="heroicons:plus-16-solid" />
<span>Neue direkte Einladung</span>
</button>
</div>
<CrudPopup
texts={{
title: 'Direkte Einladung erstellen',
submitButtonTitle: 'Erstellen',
confirmPopupTitle: 'Direkte Einladung erstellen',
confirmPopupMessage: 'Bist du sicher, dass die direkte Einladung erstellt werden soll?.'
}}
target={null}
onSubmit={addDirectInvitation}
bind:open={createPopupOpen}
/>

View File

@@ -0,0 +1,45 @@
import { type ActionReturnType, actions } from 'astro:actions';
import { writable } from 'svelte/store';
import { actionErrorPopup } from '@util/action.ts';
import { addToWritableArray, deleteFromWritableArray } from '@util/state.ts';
// types
export type DirectInvitations = Exclude<
ActionReturnType<typeof actions.user.directInvitations>['data'],
undefined
>['directInvitations'];
export type DirectInvitation = DirectInvitations[0];
// state
export const directInvitations = writable<DirectInvitations>([]);
// actions
export async function fetchDirectInvitations() {
const { data, error } = await actions.user.directInvitations();
if (error) {
actionErrorPopup(error);
return;
}
directInvitations.set(data.directInvitations);
}
export async function addDirectInvitation() {
const { data, error } = await actions.user.addDirectInvitation();
if (error) {
actionErrorPopup(error);
return;
}
addToWritableArray(directInvitations, data);
}
export async function deleteDirectInvitation(directInvitation: DirectInvitation) {
const { error } = await actions.user.deleteDirectInvitation(directInvitation);
if (error) {
actionErrorPopup(error);
return;
}
deleteFromWritableArray(directInvitations, (i) => i.hash === directInvitation.hash);
}