f047_neu_Edit-der-Namen #28
93
src/lib/components/EditableItem.svelte
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
|
|||||||
|
import Edit from '$lib/icons/Edit.svelte';
|
||||||
|
import Trash from '$lib/icons/Trash.svelte';
|
||||||
|
import { tick } from 'svelte';
|
||||||
|
|
||||||
|
interface ListItem {
|
||||||
|
name: string;
|
||||||
|
token?: string;
|
||||||
|
// add other properties as needed
|
||||||
|
}
|
||||||
|
let {
|
||||||
|
list,
|
||||||
|
editedName = $bindable(),
|
||||||
|
currentName,
|
||||||
|
onSave = () => {},
|
||||||
|
onDelete = () => {}
|
||||||
|
} = $props();
|
||||||
|
|
||||||
|
let names = list.map((l: ListItem) => l.name);
|
||||||
|
let localName = $state(currentName);
|
||||||
|
let wasCancelled = $state(false);
|
||||||
|
|
||||||
|
let error: string = $derived(validateName(localName));
|
||||||
|
|
||||||
|
mina marked this conversation as resolved
Outdated
jared
commented
manualError wird m. E. nicht im code gesetzt. Also es wird nie ein Error definiert, oder? manualError wird m. E. nicht im code gesetzt. Also es wird nie ein Error definiert, oder?
mina
commented
Habe ich rausgenommen Habe ich rausgenommen
|
|||||||
|
let manualError = $state('');
|
||||||
|
|
||||||
|
let isEditing = $state(false);
|
||||||
|
let inputRef: HTMLInputElement;
|
||||||
|
|
||||||
|
function validateName(name: string) {
|
||||||
|
const trimmed = name.trim();
|
||||||
|
|
||||||
|
if (!trimmed) {
|
||||||
|
return 'Name darf nicht leer sein.';
|
||||||
|
}
|
||||||
|
|
||||||
|
const duplicate = list.some(
|
||||||
|
(item: ListItem) => item.name === trimmed && item.name !== currentName
|
||||||
|
);
|
||||||
|
|
||||||
|
if (duplicate) return 'Name existiert bereits.';
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function commitIfValid() {
|
||||||
|
if (!error && !wasCancelled && localName != currentName) {
|
||||||
|
jared
commented
Die Funktion commitIfValid setzt editedName = localName.trim();, aber editedName ist ein Prop und sollte nicht direkt überschrieben werden. Stattdessen sollte ein Event ausgelöst werden oder ein Callback genutzt werden. Die Funktion commitIfValid setzt editedName = localName.trim();, aber editedName ist ein Prop und sollte nicht direkt überschrieben werden. Stattdessen sollte ein Event ausgelöst werden oder ein Callback genutzt werden.
mina
commented
Ich habe es nun eine neue Variable und dann in onSave übergeben, dabei ist mir die Frage gekommen wie sieht die Abfrage mit Leerzeichen insgesamt aus, habe es als offene Frage ins Backlog geschrieben Ich habe es nun eine neue Variable und dann in onSave übergeben, dabei ist mir die Frage gekommen wie sieht die Abfrage mit Leerzeichen insgesamt aus, habe es als offene Frage ins Backlog geschrieben
|
|||||||
|
editedName = localName.trim();
|
||||||
|
onSave(editedName, currentName);
|
||||||
|
} else {
|
||||||
|
localName = currentName;
|
||||||
|
resetEdit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetEdit() {
|
||||||
|
wasCancelled = false;
|
||||||
|
manualError = '';
|
||||||
|
inputRef?.blur();
|
||||||
|
isEditing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleKeydown(event: KeyboardEvent) {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
event.preventDefault();
|
||||||
|
commitIfValid();
|
||||||
|
} else if (event.key === 'Escape') {
|
||||||
|
event.preventDefault();
|
||||||
|
localName = currentName;
|
||||||
|
resetEdit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function startEdit() {
|
||||||
|
isEditing = true;
|
||||||
|
await tick();
|
||||||
|
inputRef?.focus();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<input
|
||||||
|
bind:this={inputRef}
|
||||||
|
bind:value={localName}
|
||||||
|
onblur={commitIfValid}
|
||||||
|
onkeydown={handleKeydown}
|
||||||
|
/>
|
||||||
|
<button onclick={startEdit}><Edit /></button>
|
||||||
|
<button onclick={() => onDelete(currentName)}><Trash /></button>
|
||||||
|
{#if manualError || error}
|
||||||
|
<p style="color: red;">{manualError || error}</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
@@ -1,17 +1,28 @@
|
|||||||
import { getVorgangByToken, getCrimesListByToken } from '$lib/server/vorgangService';
|
import { getVorgangByToken, getCrimesListByToken } from '$lib/server/vorgangService';
|
||||||
import type { PageServerLoad } from './$types';
|
import type { PageServerLoad } from './$types';
|
||||||
|
|
||||||
export const load: PageServerLoad = async ({ params, url }) => {
|
export const load: PageServerLoad = async ({fetch, params, url }) => {
|
||||||
const vorgangToken = params.vorgang;
|
const vorgangToken = params.vorgang;
|
||||||
const vorgangPIN = url.searchParams.get('pin');
|
const vorgangPIN = url.searchParams.get('pin');
|
||||||
|
|
||||||
|
const adminRes = await fetch(`/api/user`)
|
||||||
|
const user = await adminRes.json()
|
||||||
|
|
||||||
const crimesList = await getCrimesListByToken(vorgangToken); // TatortList zum Vorgang
|
const crimesList = await getCrimesListByToken(vorgangToken); // TatortList zum Vorgang
|
||||||
const vorgang = getVorgangByToken(vorgangToken); //einzelner Vorgang
|
const vorgangObjekt = getVorgangByToken(vorgangToken); //einzelner Vorgang //TypeScript darf nicht undefined sein
|
||||||
|
let vorgangName:string;
|
||||||
|
if(vorgangObjekt){
|
||||||
|
vorgangName = vorgangObjekt.name;
|
||||||
|
}else{
|
||||||
|
vorgangName = '';
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
crimesList,
|
crimesList, //crimesList
|
||||||
vorgangPIN,
|
vorgangPIN, //caseToken
|
||||||
vorgang
|
vorgangName, //caseId?
|
||||||
|
vorgangObjekt,
|
||||||
|
user
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
jared
commented
Wie du beschrieben hast, unnötige Kommentare und console.logs raus Wie du beschrieben hast, unnötige Kommentare und console.logs raus
mina
commented
Sollte soweit passen, ansonsten bitte selbstständig rauslöschen Sollte soweit passen, ansonsten bitte selbstständig rauslöschen
|
|||||||
import shortenFileSize from '$lib/helper/shortenFileSize';
|
import shortenFileSize from '$lib/helper/shortenFileSize';
|
||||||
import { page } from '$app/stores';
|
|
||||||
|
|
||||||
import timeElapsed from '$lib/helper/timeElapsed';
|
import timeElapsed from '$lib/helper/timeElapsed';
|
||||||
|
|
||||||
import Alert from '$lib/components/Alert.svelte';
|
import Alert from '$lib/components/Alert.svelte';
|
||||||
@@ -11,14 +9,16 @@
|
|||||||
import ModalContent from '$lib/components/Modal/ModalContent.svelte';
|
import ModalContent from '$lib/components/Modal/ModalContent.svelte';
|
||||||
import ModalFooter from '$lib/components/Modal/ModalFooter.svelte';
|
import ModalFooter from '$lib/components/Modal/ModalFooter.svelte';
|
||||||
import Cube from '$lib/icons/Cube.svelte';
|
import Cube from '$lib/icons/Cube.svelte';
|
||||||
import Edit from '$lib/icons/Edit.svelte';
|
|
||||||
import Trash from '$lib/icons/Trash.svelte';
|
|
||||||
|
|
||||||
/** export let data; */
|
import EditableItem from '$lib/components/EditableItem.svelte';
|
||||||
/** @type {import('./$types').PageData} */
|
|
||||||
export let data;
|
|
||||||
|
|
||||||
console.log(data);
|
import { invalidate } from '$app/navigation';
|
||||||
|
import { page } from '$app/stores';
|
||||||
|
|
||||||
|
//Seite für die Tatort-Liste
|
||||||
|
let { data } = $props();
|
||||||
|
|
||||||
|
console.log('tatorte: debug ', data);
|
||||||
|
|
||||||
interface ListItem {
|
interface ListItem {
|
||||||
name: string;
|
name: string;
|
||||||
@@ -28,140 +28,207 @@
|
|||||||
// add other properties as needed
|
// add other properties as needed
|
||||||
}
|
}
|
||||||
|
|
||||||
const vorgang = data.vorgang;
|
let vorgang: string = data.vorgangName; // let vorgang = data.caseId; <!--caseId, vorgang.name aber das funktioniert nicht richtig, daher in server.ts geändert-->
|
||||||
const crimesList: ListItem[] = data.crimesList;
|
let crimesList: ListItem[] = $state(data.crimesList);
|
||||||
const vorgangPIN: string = data.vorgangPIN;
|
const vorgangPIN: string = data.vorgangPIN; //caseToken?? // const token: string | null = data.caseToken;
|
||||||
|
|
||||||
let open = false;
|
|
||||||
$: open;
|
|
||||||
let inProgress = false;
|
|
||||||
$: inProgress;
|
|
||||||
let err = false;
|
|
||||||
$: err;
|
|
||||||
|
|
||||||
let rename_input;
|
|
||||||
$: rename_input;
|
|
||||||
|
|
||||||
|
//Variablen für Modal
|
||||||
|
let open = $state(false);
|
||||||
|
let inProgress = $state(false);
|
||||||
|
mina marked this conversation as resolved
Outdated
jared
commented
In Progress wird nie gesetzt. Daher bisher keine Funktion In Progress wird nie gesetzt. Daher bisher keine Funktion
mina
commented
Da es zum Modal gehört habe ich es angepasst und nicht gelöscht. Da es zum Modal gehört habe ich es angepasst und nicht gelöscht.
|
|||||||
|
let err = $state(false);
|
||||||
function uploadSuccessful() {
|
function uploadSuccessful() {
|
||||||
open = false;
|
open = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function defocus_element(i: number) {
|
//Variabeln für EditableItem
|
||||||
let item = crimesList[i];
|
let names: string[] = $state(crimesList.map((l) => l.name));
|
||||||
let text_field_id = `label__${item.name}`;
|
let editedName: string = $state('');
|
||||||
|
let currentName: string = $state('');
|
||||||
|
|
||||||
let text_field = document.getElementById(text_field_id);
|
let editingId: number;
|
||||||
|
mina marked this conversation as resolved
Outdated
jared
commented
Funktioniert es denn jetzt??? Funktioniert es denn jetzt???
mina
commented
Ja, funktioniert. Ja, funktioniert.
|
|||||||
if (text_field) {
|
|
||||||
text_field.setAttribute('contenteditable', 'false');
|
|
||||||
text_field.textContent = item.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
// reshow button
|
// let admin = data?.user?.admin;
|
||||||
crimesList[i].show_button = true;
|
let admin = true;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleEditFieldInput(ev: KeyboardEvent, listItemIndex: number) {
|
let rename_input;
|
||||||
let item = crimesList[listItemIndex];
|
|
||||||
if (ev.key == 'Escape') {
|
|
||||||
let text_field_id = `label__${item.name}`;
|
|
||||||
|
|
||||||
let text_field = document.getElementById(text_field_id);
|
$effect(() => {
|
||||||
if (text_field) {
|
console.log('rename_input hat sich geändert:', rename_input);
|
||||||
text_field.setAttribute('contenteditable', 'false');
|
});
|
||||||
text_field.textContent = item.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
// reshow button
|
async function handleSave(newName: string, oldName: string) {
|
||||||
item.show_button = true;
|
console.log('Eltern, speichern erfolgreich', newName, oldName);
|
||||||
return;
|
try {
|
||||||
}
|
const res = await fetch(`/api/list/${vorgang}/${oldName}`, {
|
||||||
if (ev.key == 'Enter') {
|
method: 'PUT',
|
||||||
let name_field = ev.currentTarget as HTMLElement | null;
|
headers: {
|
||||||
let new_name = name_field
|
'Content-Type': 'application/json'
|
||||||
? name_field.textContent || (name_field as any).innerText || ''
|
},
|
||||||
: '';
|
body: JSON.stringify({ vorgang, oldName, newName })
|
||||||
|
});
|
||||||
|
const clone = res.clone();
|
||||||
|
const data = await res.json();
|
||||||
|
let message = data.message;
|
||||||
|
let error = !data.success;
|
||||||
|
|
||||||
if (new_name == '') {
|
console.log('Tatort Update: ', message);
|
||||||
alert('Bitte einen gültigen Namen eingeben.');
|
|
||||||
ev.preventDefault();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// actual upload
|
if (!res.ok) {
|
||||||
// -------------
|
const msg = await clone.text();
|
||||||
|
console.error('❌ Fehler beim Speichern:', msg);
|
||||||
// to prevent from item being selected
|
|
||||||
ev.preventDefault();
|
|
||||||
|
|
||||||
// construct PUT URL
|
|
||||||
const url = $page.url.pathname.split('?')[0];
|
|
||||||
|
|
||||||
let data_obj: { new_name: string; old_name: string } = { new_name: '', old_name: '' };
|
|
||||||
data_obj['new_name'] = new_name;
|
|
||||||
data_obj['old_name'] =
|
|
||||||
ev.currentTarget && (ev.currentTarget as HTMLElement).id
|
|
||||||
? (ev.currentTarget as HTMLElement).id.split('__')[1]
|
|
||||||
: '';
|
|
||||||
|
|
||||||
open = true;
|
|
||||||
inProgress = true;
|
|
||||||
|
|
||||||
const response = await fetch(url, { method: 'PUT', body: JSON.stringify(data_obj) });
|
|
||||||
|
|
||||||
inProgress = false;
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
err = true;
|
|
||||||
if (response.status == 400) {
|
|
||||||
let json_res = await response.json();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new Error(`Fehlgeschlagen: ${response.status}`);
|
|
||||||
} else {
|
} else {
|
||||||
uploadSuccessful();
|
console.log('✅ Erfolgreich gespeichert:', newName);
|
||||||
setTimeout(() => {
|
await invalidate('');
|
||||||
window.location.reload();
|
currentName = newName;
|
||||||
}, 500);
|
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
// --- upload finished ---
|
console.error('⚠️ Netzwerkfehler:', err);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function constructMailToLink() {
|
async function handleDelete(tatort: string) {
|
||||||
const subject = 'Link zum Tatvorgang';
|
let url = new URL($page.url);
|
||||||
const link = $page.url.toString().split('?')[0];
|
url.pathname += `/${tatort}`;
|
||||||
const body = `Hallo,
|
console.log('Delete tatort: ', `/api${url.pathname}`, url.pathname);
|
||||||
|
|
||||||
hier ist der Link zum Tatvorgang:
|
try {
|
||||||
${link}
|
const res = await fetch(`/api${url.pathname}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ vorgang, tatort })
|
||||||
|
});
|
||||||
|
|
||||||
Der Zugangs-PIN wird zur Sicherheit über einen zweiten Kommunikationskanal übermittelt.
|
if (!res.ok) {
|
||||||
|
const msg = await res.text();
|
||||||
Mit freundlichen Grüßen,
|
console.error('❌ Fehler beim Löschen:', msg);
|
||||||
`;
|
} else {
|
||||||
|
console.log('🗑️ Erfolgreich gelöscht:', url.pathname);
|
||||||
const mailtoLink = `mailto:?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
|
|
||||||
|
|
||||||
return mailtoLink;
|
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('⚠️ Netzwerkfehler beim Löschen:', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// function defocus_element(i: number) {
|
||||||
|
// let item = crimesList[i];
|
||||||
|
// let text_field_id = `label__${item.name}`;
|
||||||
|
|
||||||
|
// let text_field = document.getElementById(text_field_id);
|
||||||
|
// if (text_field) {
|
||||||
|
// text_field.setAttribute('contenteditable', 'false');
|
||||||
|
// text_field.textContent = item.name;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // reshow button
|
||||||
|
// crimesList[i].show_button = true;
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// async function handleEditFieldInput(ev: KeyboardEvent, listItemIndex: number) {
|
||||||
|
// let item = crimesList[listItemIndex];
|
||||||
|
// if (ev.key == 'Escape') {
|
||||||
|
// let text_field_id = `label__${item.name}`;
|
||||||
|
|
||||||
|
// let text_field = document.getElementById(text_field_id);
|
||||||
|
// if (text_field) {
|
||||||
|
// text_field.setAttribute('contenteditable', 'false');
|
||||||
|
// text_field.textContent = item.name;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // reshow button
|
||||||
|
// item.show_button = true;
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// if (ev.key == 'Enter') {
|
||||||
|
// let name_field = ev.currentTarget as HTMLElement | null;
|
||||||
|
// let new_name = name_field
|
||||||
|
// ? name_field.textContent || (name_field as any).innerText || ''
|
||||||
|
// : '';
|
||||||
|
|
||||||
|
// if (new_name == '') {
|
||||||
|
// alert('Bitte einen gültigen Namen eingeben.');
|
||||||
|
// ev.preventDefault();
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // actual upload
|
||||||
|
// // -------------
|
||||||
|
|
||||||
|
// // to prevent from item being selected
|
||||||
|
// ev.preventDefault();
|
||||||
|
|
||||||
|
// // construct PUT URL
|
||||||
|
// const url = $page.url.pathname.split('?')[0];
|
||||||
|
|
||||||
|
// let data_obj: { new_name: string; old_name: string } = { new_name: '', old_name: '' };
|
||||||
|
// data_obj['new_name'] = new_name;
|
||||||
|
// data_obj['old_name'] =
|
||||||
|
// ev.currentTarget && (ev.currentTarget as HTMLElement).id
|
||||||
|
// ? (ev.currentTarget as HTMLElement).id.split('__')[1]
|
||||||
|
// : '';
|
||||||
|
|
||||||
|
// open = true;
|
||||||
|
// inProgress = true;
|
||||||
|
|
||||||
|
// const response = await fetch(url, { method: 'PUT', body: JSON.stringify(data_obj) });
|
||||||
|
|
||||||
|
// inProgress = false;
|
||||||
|
|
||||||
|
// if (!response.ok) {
|
||||||
|
// err = true;
|
||||||
|
// if (response.status == 400) {
|
||||||
|
// let json_res = await response.json();
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// throw new Error(`Fehlgeschlagen: ${response.status}`);
|
||||||
|
// } else {
|
||||||
|
// uploadSuccessful();
|
||||||
|
// setTimeout(() => {
|
||||||
|
// window.location.reload();
|
||||||
|
// }, 500);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // --- upload finished ---
|
||||||
|
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// function constructMailToLink() {
|
||||||
|
// const subject = 'Link zum Tatvorgang';
|
||||||
|
// const link = $page.url.toString().split('?')[0];
|
||||||
|
// const body = `Hallo,
|
||||||
|
|
||||||
|
// hier ist der Link zum Tatvorgang:
|
||||||
|
// ${link}
|
||||||
|
|
||||||
|
// Der Zugangs-PIN wird zur Sicherheit über einen zweiten Kommunikationskanal übermittelt.
|
||||||
|
|
||||||
|
// Mit freundlichen Grüßen,
|
||||||
|
// `;
|
||||||
|
|
||||||
|
// const mailtoLink = `mailto:?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
|
||||||
|
|
||||||
|
// return mailtoLink;
|
||||||
|
// }
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="-z-10 bg-white">
|
{#if vorgang}
|
||||||
|
<div class="-z-10 bg-white">
|
||||||
<div class="flex flex-col items-center justify-center w-full">
|
<div class="flex flex-col items-center justify-center w-full">
|
||||||
<h1 class="text-xl">Vorgang {vorgang.name}</h1>
|
<h1 class="text-xl">Vorgang {vorgang}</h1>
|
||||||
{#if data?.user?.admin}
|
|
||||||
|
<!-- {#if data?.user?.admin}
|
||||||
Zugangs-PIN: {vorgang.pin}
|
Zugangs-PIN: {vorgang.pin}
|
||||||
<a href={constructMailToLink()}><Button>Share Link</Button></a>
|
<a href={constructMailToLink()}><Button>Share Link</Button></a>
|
||||||
{/if}
|
{/if} -->
|
||||||
</div>
|
</div>
|
||||||
<div class="mx-auto flex justify-center max-w-7xl h-full">
|
<div class="mx-auto flex justify-center max-w-7xl h-full">
|
||||||
<ul class="divide-y divide-gray-100">
|
<ul class="divide-y divide-gray-100">
|
||||||
{#each crimesList as item, crimeListItemIndex}
|
{#each crimesList as item, crimeListItemIndex}
|
||||||
<li>
|
<!-- <li>
|
||||||
<a
|
<a
|
||||||
href="/view/{$page.params.vorgang}/{item.name}?pin={vorgangPIN}"
|
href="/view/{$page.params.vorgang}/{item.name}?pin={vorgangPIN}"
|
||||||
class=" flex justify-between gap-x-6 py-5"
|
class=" flex justify-between gap-x-6 py-5"
|
||||||
@@ -231,7 +298,9 @@ Mit freundlichen Grüßen,
|
|||||||
url.pathname += `/${filename}`;
|
url.pathname += `/${filename}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api${url.pathname}`, { method: 'DELETE' });
|
const response = await fetch(`/api${url.pathname}`, {
|
||||||
|
method: 'DELETE'
|
||||||
|
});
|
||||||
if (response.status == 204) {
|
if (response.status == 204) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
@@ -269,6 +338,48 @@ Mit freundlichen Grüßen,
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
</li> -->
|
||||||
|
|
||||||
|
<li>
|
||||||
|
<div class=" flex gap-x-4">
|
||||||
|
<a
|
||||||
|
href="/view/{$page.params.vorgang}/{currentName}?pin={vorgangPIN}"
|
||||||
|
class=" flex justify-between gap-x-6 py-5"
|
||||||
|
aria-label="zum 3D-modell"
|
||||||
|
>
|
||||||
|
<Cube />
|
||||||
|
</a>
|
||||||
|
<div class="min-w-0 flex-auto">
|
||||||
|
{#if admin}
|
||||||
|
<EditableItem
|
||||||
|
list={crimesList}
|
||||||
|
bind:editedName={names[crimeListItemIndex]}
|
||||||
|
currentName={item.name}
|
||||||
|
onSave={handleSave}
|
||||||
|
onDelete={handleDelete}
|
||||||
|
></EditableItem>
|
||||||
|
{:else}
|
||||||
|
<span class="text-sm font-semibold leading-6 text-gray-900 inline-block min-w-1"
|
||||||
|
>{item.name}</span
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
|
{#if item.size}
|
||||||
|
<p class="mt-1 truncate text-xs leading-5 text-gray-500">
|
||||||
|
{shortenFileSize(item.size)}
|
||||||
|
</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="hidden sm:flex sm:flex-col sm:items-end">
|
||||||
|
<p class="text-sm leading-6 text-gray-900">3D Tatort</p>
|
||||||
|
{#if item.lastModified}
|
||||||
|
<p class="mt-1 text-xs leading-5 text-gray-500">
|
||||||
|
Zuletzt geändert <time datetime="2023-01-23T13:23Z"
|
||||||
|
>{timeElapsed(new Date(item.lastModified))}</time
|
||||||
|
>
|
||||||
|
</p>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{/each}
|
{/each}
|
||||||
</ul>
|
</ul>
|
||||||
@@ -283,9 +394,12 @@ Mit freundlichen Grüßen,
|
|||||||
<Alert class="w-full" type="error">Fehler beim Umbenennen</Alert>
|
<Alert class="w-full" type="error">Fehler beim Umbenennen</Alert>
|
||||||
{/if}
|
{/if}
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
<ModalFooter><Button disabled={inProgress} on:click={uploadSuccessful}>Ok</Button></ModalFooter>
|
<ModalFooter
|
||||||
|
><Button disabled={inProgress} on:click={uploadSuccessful}>Ok</Button></ModalFooter
|
||||||
|
>
|
||||||
</Modal>
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
ul {
|
ul {
|
||||||
|
|||||||
10
src/routes/api/user/+server.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
//Rollenabfrage ob Benutzer admin ist
|
||||||
|
|
||||||
|
import { json } from "@sveltejs/kit";
|
||||||
|
|
||||||
|
export async function GET({locals}) {
|
||||||
|
const isAdmin = locals.user?.admin === true;
|
||||||
|
const data = {admin: isAdmin}
|
||||||
|
return json(data)
|
||||||
|
|
||||||
|
}
|
||||||
Die Componente heißt EditableItem. Das suggeriert, dass damit unterschieldiche Items editierbar sind, also generisch. In meinem Verständins ist das aber eine Componente zugeschnitten für das Editieren des Namens
Habe es umbenannt in NameItemEditor, falls besserer Name bitte eigenständig umbenennen, es wird nur einmal verwendet.