fuck that shit, revert
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				delpoy / build-and-deploy (push) Successful in 1m3s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	delpoy / build-and-deploy (push) Successful in 1m3s
				
			This commit is contained in:
		| @@ -6,21 +6,6 @@ | |||||||
| 	let bodyElem: HTMLTableSectionElement; | 	let bodyElem: HTMLTableSectionElement; | ||||||
| 	let intersectionElem: HTMLElement; | 	let intersectionElem: HTMLElement; | ||||||
|  |  | ||||||
| 	async function onUpdateProxy() { |  | ||||||
| 		let scrollElem: HTMLElement | null = bodyElem; |  | ||||||
| 		while (scrollElem && scrollElem.scrollHeight <= scrollElem.clientHeight) { |  | ||||||
| 			scrollElem = scrollElem.parentElement; |  | ||||||
| 		} |  | ||||||
|  |  | ||||||
| 		const scrollTop = scrollElem?.scrollTop ?? 0; |  | ||||||
|  |  | ||||||
| 		await onUpdate(); |  | ||||||
|  |  | ||||||
| 		if (scrollElem) scrollElem.scrollTop = scrollTop; |  | ||||||
|  |  | ||||||
| 		await tick(); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	async function getIntersectionElement(): Promise<HTMLElement> { | 	async function getIntersectionElement(): Promise<HTMLElement> { | ||||||
| 		if (!bodyElem.lastElementChild) { | 		if (!bodyElem.lastElementChild) { | ||||||
| 			await new Promise<void>((resolve) => { | 			await new Promise<void>((resolve) => { | ||||||
| @@ -36,7 +21,8 @@ | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	onMount(async () => { | 	onMount(async () => { | ||||||
| 		await onUpdateProxy(); | 		await onUpdate(); | ||||||
|  | 		await tick(); | ||||||
|  |  | ||||||
| 		if (!bodyElem) return; | 		if (!bodyElem) return; | ||||||
|  |  | ||||||
| @@ -47,7 +33,8 @@ | |||||||
|  |  | ||||||
| 				const rows = bodyElem.rows.length; | 				const rows = bodyElem.rows.length; | ||||||
|  |  | ||||||
| 				await onUpdateProxy(); | 				await onUpdate(); | ||||||
|  | 				await tick(); | ||||||
|  |  | ||||||
| 				if (rows === bodyElem.rows.length) return; | 				if (rows === bodyElem.rows.length) return; | ||||||
| 				observer.observe((intersectionElem = await getIntersectionElement())); | 				observer.observe((intersectionElem = await getIntersectionElement())); | ||||||
|   | |||||||
| @@ -82,7 +82,7 @@ | |||||||
|  |  | ||||||
| 	let pageTitleSuffix = $derived( | 	let pageTitleSuffix = $derived( | ||||||
| 		tabs.find((t) => $page.url.pathname === t.path)?.name ?? | 		tabs.find((t) => $page.url.pathname === t.path)?.name ?? | ||||||
| 			($page.url.pathname === `${env.PUBLIC_BASE_PATH}/admin/login` ? 'Login' : null) | 		($page.url.pathname === `${env.PUBLIC_BASE_PATH}/admin/login` ? 'Login' : null) | ||||||
| 	); | 	); | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
| @@ -133,7 +133,7 @@ | |||||||
| 	<div class="grid"> | 	<div class="grid"> | ||||||
| 		{#key $page.url.pathname} | 		{#key $page.url.pathname} | ||||||
| 			<div | 			<div | ||||||
| 				class="col-[1] row-[1] h-[calc(100vh-3rem)] w-full overflow-y-scroll overflow-x-hidden" | 				class="col-[1] row-[1] h-full w-full overflow-y-scroll overflow-x-hidden" | ||||||
| 				in:fly={{ x: transitionPrefix * window.innerWidth, duration: !transitionPrefix ? 0 : 100 }} | 				in:fly={{ x: transitionPrefix * window.innerWidth, duration: !transitionPrefix ? 0 : 100 }} | ||||||
| 				out:fly={{ | 				out:fly={{ | ||||||
| 					x: transitionPrefix * -window.innerWidth, | 					x: transitionPrefix * -window.innerWidth, | ||||||
| @@ -145,7 +145,7 @@ | |||||||
| 		{/key} | 		{/key} | ||||||
| 	</div> | 	</div> | ||||||
| {:else} | {:else} | ||||||
| 	<div class="h-[calc(100vh-3rem)] w-full"> | 	<div class="h-full w-full"> | ||||||
| 		{@render children()} | 		{@render children()} | ||||||
| 	</div> | 	</div> | ||||||
| {/if} | {/if} | ||||||
|   | |||||||
| @@ -66,67 +66,65 @@ | |||||||
| 			onUpdate={() => fetchFeedback({ from: 0 }).then((r) => (feedbacks = r))} | 			onUpdate={() => fetchFeedback({ from: 0 }).then((r) => (feedbacks = r))} | ||||||
| 		/> | 		/> | ||||||
| 		<hr class="divider my-1 mx-8 border-none" /> | 		<hr class="divider my-1 mx-8 border-none" /> | ||||||
| 		<div class="h-full overflow-scroll"> | 		<table class="table table-fixed h-fit"> | ||||||
| 			<table class="table table-fixed h-fit"> | 			<thead> | ||||||
| 				<thead> | 			<tr> | ||||||
| 					<tr> | 				<th>Event</th> | ||||||
| 						<th>Event</th> | 				<th>Titel</th> | ||||||
| 						<th>Titel</th> | 				<th>Nutzer</th> | ||||||
| 						<th>Nutzer</th> | 				<th>Datum</th> | ||||||
| 						<th>Datum</th> | 				<th>Inhalt</th> | ||||||
| 						<th>Inhalt</th> | 			</tr> | ||||||
| 					</tr> | 			</thead> | ||||||
| 				</thead> | 			<PaginationTableBody | ||||||
| 				<PaginationTableBody | 				onUpdate={async () => | ||||||
| 					onUpdate={async () => | 					await fetchFeedback().then((feedback) => (feedbacks = [...feedbacks, ...feedback]))} | ||||||
| 						await fetchFeedback().then((feedback) => (feedbacks = [...feedbacks, ...feedback]))} | 			> | ||||||
| 				> | 				{#each feedbacks as feedback} | ||||||
| 					{#each feedbacks as feedback} | 					<tr | ||||||
| 						<tr | 						class="hover [&>*]:text-sm cursor-pointer" | ||||||
| 							class="hover [&>*]:text-sm cursor-pointer" | 						class:bg-base-200={activeFeedback?.url_hash === feedback.url_hash} | ||||||
| 							class:bg-base-200={activeFeedback?.url_hash === feedback.url_hash} | 						onclick={async () => { | ||||||
| 							onclick={async () => { | 							await goto(`${window.location.href.split('#')[0]}#${feedback.url_hash}`, { | ||||||
| 								await goto(`${window.location.href.split('#')[0]}#${feedback.url_hash}`, { | 								replaceState: true | ||||||
| 									replaceState: true | 							}); | ||||||
| 								}); | 							await openHashReport(); | ||||||
| 								await openHashReport(); | 						}} | ||||||
| 							}} | 					> | ||||||
|  | 						<td title={feedback.event}>{feedback.event}</td> | ||||||
|  | 						<td class="overflow-hidden overflow-ellipsis">{feedback.title}</td> | ||||||
|  | 						<td class="flex"> | ||||||
|  | 							{feedback.user?.username || ''} | ||||||
|  | 							{#if feedback.user} | ||||||
|  | 								<button | ||||||
|  | 									class="pl-1" | ||||||
|  | 									title="Nach Ersteller filtern" | ||||||
|  | 									onclick={(e) => { | ||||||
|  | 										e.stopPropagation(); | ||||||
|  | 										feedbackFilter.username = feedback.user.username; | ||||||
|  | 										fetchFeedback({ from: 0 }).then((r) => (feedbacks = r)); | ||||||
|  | 									}} | ||||||
|  | 								> | ||||||
|  | 									<MagnifyingGlass size="14" /> | ||||||
|  | 								</button> | ||||||
|  | 							{/if} | ||||||
|  | 						</td> | ||||||
|  | 						<td | ||||||
|  | 						>{new Intl.DateTimeFormat('de-DE', { | ||||||
|  | 							year: 'numeric', | ||||||
|  | 							month: '2-digit', | ||||||
|  | 							day: '2-digit', | ||||||
|  | 							hour: '2-digit', | ||||||
|  | 							minute: '2-digit' | ||||||
|  | 						}).format(new Date(feedback.updatedAt))} Uhr</td | ||||||
| 						> | 						> | ||||||
| 							<td title={feedback.event}>{feedback.event}</td> | 						<td class="overflow-hidden overflow-ellipsis" | ||||||
| 							<td class="overflow-hidden overflow-ellipsis">{feedback.title}</td> | 						>{feedback.content}{feedback.content_stripped ? '...' : ''}</td | ||||||
| 							<td class="flex"> | 						> | ||||||
| 								{feedback.user?.username || ''} | 					</tr> | ||||||
| 								{#if feedback.user} | 				{/each} | ||||||
| 									<button | 			</PaginationTableBody> | ||||||
| 										class="pl-1" | 		</table> | ||||||
| 										title="Nach Ersteller filtern" |  | ||||||
| 										onclick={(e) => { |  | ||||||
| 											e.stopPropagation(); |  | ||||||
| 											feedbackFilter.username = feedback.user.username; |  | ||||||
| 											fetchFeedback({ from: 0 }).then((r) => (feedbacks = r)); |  | ||||||
| 										}} |  | ||||||
| 									> |  | ||||||
| 										<MagnifyingGlass size="14" /> |  | ||||||
| 									</button> |  | ||||||
| 								{/if} |  | ||||||
| 							</td> |  | ||||||
| 							<td |  | ||||||
| 								>{new Intl.DateTimeFormat('de-DE', { |  | ||||||
| 									year: 'numeric', |  | ||||||
| 									month: '2-digit', |  | ||||||
| 									day: '2-digit', |  | ||||||
| 									hour: '2-digit', |  | ||||||
| 									minute: '2-digit' |  | ||||||
| 								}).format(new Date(feedback.updatedAt))} Uhr</td |  | ||||||
| 							> |  | ||||||
| 							<td class="overflow-hidden overflow-ellipsis" |  | ||||||
| 								>{feedback.content}{feedback.content_stripped ? '...' : ''}</td |  | ||||||
| 							> |  | ||||||
| 						</tr> |  | ||||||
| 					{/each} |  | ||||||
| 				</PaginationTableBody> |  | ||||||
| 			</table> |  | ||||||
| 		</div> |  | ||||||
| 	</div> | 	</div> | ||||||
| 	{#if activeFeedback} | 	{#if activeFeedback} | ||||||
| 		<div | 		<div | ||||||
|   | |||||||
| @@ -115,97 +115,95 @@ | |||||||
| 			</div> | 			</div> | ||||||
| 		</div> | 		</div> | ||||||
| 		<hr class="divider my-1 mx-8 border-none" /> | 		<hr class="divider my-1 mx-8 border-none" /> | ||||||
| 		<div class="h-full overflow-scroll"> | 		<table class="table table-fixed h-fit"> | ||||||
| 			<table class="table table-fixed h-fit"> | 			<colgroup> | ||||||
| 				<colgroup> | 				<col style="width: 20%" /> | ||||||
| 					<col style="width: 20%" /> | 				<col style="width: 15%" /> | ||||||
| 					<col style="width: 15%" /> | 				<col style="width: 15%" /> | ||||||
| 					<col style="width: 15%" /> | 				<col style="width: 20%" /> | ||||||
| 					<col style="width: 20%" /> | 				<col style="width: 15%" /> | ||||||
| 					<col style="width: 15%" /> | 				<col style="width: 15%" /> | ||||||
| 					<col style="width: 15%" /> | 			</colgroup> | ||||||
| 				</colgroup> | 			<thead> | ||||||
| 				<thead> | 			<tr> | ||||||
| 					<tr> | 				<th>Grund</th> | ||||||
| 						<th>Grund</th> | 				<th>Ersteller</th> | ||||||
| 						<th>Ersteller</th> | 				<th>Reporteter User</th> | ||||||
| 						<th>Reporteter User</th> | 				<th>Datum</th> | ||||||
| 						<th>Datum</th> | 				<th>Bearbeitungsstatus</th> | ||||||
| 						<th>Bearbeitungsstatus</th> | 				<th>Reportstatus</th> | ||||||
| 						<th>Reportstatus</th> | 			</tr> | ||||||
| 					</tr> | 			</thead> | ||||||
| 				</thead> | 			<PaginationTableBody | ||||||
| 				<PaginationTableBody | 				onUpdate={async () => | ||||||
| 					onUpdate={async () => | 					await fetchReports().then((res) => (reports = [...reports, ...res.reports]))} | ||||||
| 						await fetchReports().then((res) => (reports = [...reports, ...res.reports]))} | 			> | ||||||
| 				> | 				{#each reports as report} | ||||||
| 					{#each reports as report} | 					<tr | ||||||
| 						<tr | 						class="hover [&>*]:text-sm cursor-pointer" | ||||||
| 							class="hover [&>*]:text-sm cursor-pointer" | 						class:bg-base-200={activeReport?.url_hash === report.url_hash} | ||||||
| 							class:bg-base-200={activeReport?.url_hash === report.url_hash} | 						onclick={() => { | ||||||
| 							onclick={() => { | 							goto(`${window.location.href.split('#')[0]}#${report.url_hash}`, { | ||||||
| 								goto(`${window.location.href.split('#')[0]}#${report.url_hash}`, { | 								replaceState: true | ||||||
| 									replaceState: true | 							}); | ||||||
| 								}); | 							activeReport = $state.snapshot(report); | ||||||
| 								activeReport = $state.snapshot(report); | 							activeReport.originalStatus = report.status; | ||||||
| 								activeReport.originalStatus = report.status; | 						}} | ||||||
| 							}} | 					> | ||||||
| 						> | 						<td title={report.subject}><div class="overflow-scroll">{report.subject}</div></td> | ||||||
| 							<td title={report.subject}><div class="overflow-scroll">{report.subject}</div></td> | 						<td class="flex"> | ||||||
| 							<td class="flex"> | 							{report.reporter.username} | ||||||
| 								{report.reporter.username} | 							<button | ||||||
|  | 								class="pl-1" | ||||||
|  | 								title="Nach Ersteller filtern" | ||||||
|  | 								onclick={(e) => { | ||||||
|  | 									e.stopPropagation(); | ||||||
|  | 									reportFilter.reporter = report.reporter.username; | ||||||
|  | 									fetchReports({ from: 0 }).then((r) => (reports = r.reports)); | ||||||
|  | 								}} | ||||||
|  | 							> | ||||||
|  | 								<MagnifyingGlass size="14" /> | ||||||
|  | 							</button> | ||||||
|  | 						</td> | ||||||
|  | 						<td> | ||||||
|  | 							{report.reported?.username || ''} | ||||||
|  | 							{#if report.reported?.id} | ||||||
| 								<button | 								<button | ||||||
| 									class="pl-1" | 									class="pl-1" | ||||||
| 									title="Nach Ersteller filtern" | 									title="Nach Reportetem Spieler filtern" | ||||||
| 									onclick={(e) => { | 									onclick={(e) => { | ||||||
| 										e.stopPropagation(); | 										e.stopPropagation(); | ||||||
| 										reportFilter.reporter = report.reporter.username; | 										reportFilter.reported = report.reported.username; | ||||||
| 										fetchReports({ from: 0 }).then((r) => (reports = r.reports)); | 										fetchReports({ from: 0 }).then((r) => (reports = r.reports)); | ||||||
| 									}} | 									}} | ||||||
| 								> | 								> | ||||||
| 									<MagnifyingGlass size="14" /> | 									<MagnifyingGlass size="14" /> | ||||||
| 								</button> | 								</button> | ||||||
| 							</td> | 							{/if} | ||||||
| 							<td> | 						</td> | ||||||
| 								{report.reported?.username || ''} | 						<td | ||||||
| 								{#if report.reported?.id} | 						>{new Intl.DateTimeFormat('de-DE', { | ||||||
| 									<button | 							year: 'numeric', | ||||||
| 										class="pl-1" | 							month: '2-digit', | ||||||
| 										title="Nach Reportetem Spieler filtern" | 							day: '2-digit', | ||||||
| 										onclick={(e) => { | 							hour: '2-digit', | ||||||
| 											e.stopPropagation(); | 							minute: '2-digit' | ||||||
| 											reportFilter.reported = report.reported.username; | 						}).format(new Date(report.createdAt))} Uhr</td | ||||||
| 											fetchReports({ from: 0 }).then((r) => (reports = r.reports)); | 						> | ||||||
| 										}} | 						<td> | ||||||
| 									> | 							{report.status === 'none' | ||||||
| 										<MagnifyingGlass size="14" /> | 								? 'Unbearbeitet' | ||||||
| 									</button> | 								: report.status === 'review' | ||||||
| 								{/if} | 									? 'In Bearbeitung' | ||||||
| 							</td> | 									: report.status === 'reviewed' | ||||||
| 							<td | 										? 'Bearbeitet' | ||||||
| 								>{new Intl.DateTimeFormat('de-DE', { | 										: ''} | ||||||
| 									year: 'numeric', | 						</td> | ||||||
| 									month: '2-digit', | 						<td>{report.draft ? 'Entwurf' : 'Erstellt'}</td> | ||||||
| 									day: '2-digit', | 					</tr> | ||||||
| 									hour: '2-digit', | 				{/each} | ||||||
| 									minute: '2-digit' | 			</PaginationTableBody> | ||||||
| 								}).format(new Date(report.createdAt))} Uhr</td | 		</table> | ||||||
| 							> |  | ||||||
| 							<td> |  | ||||||
| 								{report.status === 'none' |  | ||||||
| 									? 'Unbearbeitet' |  | ||||||
| 									: report.status === 'review' |  | ||||||
| 										? 'In Bearbeitung' |  | ||||||
| 										: report.status === 'reviewed' |  | ||||||
| 											? 'Bearbeitet' |  | ||||||
| 											: ''} |  | ||||||
| 							</td> |  | ||||||
| 							<td>{report.draft ? 'Entwurf' : 'Erstellt'}</td> |  | ||||||
| 						</tr> |  | ||||||
| 					{/each} |  | ||||||
| 				</PaginationTableBody> |  | ||||||
| 			</table> |  | ||||||
| 		</div> |  | ||||||
| 	</div> | 	</div> | ||||||
| 	{#if activeReport} | 	{#if activeReport} | ||||||
| 		<div | 		<div | ||||||
| @@ -307,7 +305,7 @@ | |||||||
| 					<option | 					<option | ||||||
| 						value="none" | 						value="none" | ||||||
| 						disabled={activeReport.auditor != null || activeReport.notice || activeReport.statement} | 						disabled={activeReport.auditor != null || activeReport.notice || activeReport.statement} | ||||||
| 						>Unbearbeitet</option | 					>Unbearbeitet</option | ||||||
| 					> | 					> | ||||||
| 					<option value="review">In Bearbeitung</option> | 					<option value="review">In Bearbeitung</option> | ||||||
| 					<option value="reviewed">Bearbeitet</option> | 					<option value="reviewed">Bearbeitet</option> | ||||||
|   | |||||||
| @@ -95,19 +95,19 @@ | |||||||
| 	<div class="h-full overflow-scroll" bind:this={userTableContainerElement}> | 	<div class="h-full overflow-scroll" bind:this={userTableContainerElement}> | ||||||
| 		<table class="table table-auto"> | 		<table class="table table-auto"> | ||||||
| 			<thead> | 			<thead> | ||||||
| 				<!-- prettier-ignore --> | 			<!-- prettier-ignore --> | ||||||
| 				<SortableTr> | 			<SortableTr class="[&>th]:bg-base-100 [&>th]:z-[1] [&>th]:sticky [&>th]:top-0"> | ||||||
| 					<th></th> | 				<th></th> | ||||||
| 					<SortableTh onSort={(e) => userFilter = {...userFilter, sort: {key: 'firstname', asc: e.asc}}}>Vorname</SortableTh> | 				<SortableTh onSort={(e) => userFilter = {...userFilter, sort: {key: 'firstname', asc: e.asc}}}>Vorname</SortableTh> | ||||||
| 					<SortableTh onSort={(e) => userFilter = {...userFilter, sort: {key: 'lastname', asc: e.asc}}}>Nachname</SortableTh> | 				<SortableTh onSort={(e) => userFilter = {...userFilter, sort: {key: 'lastname', asc: e.asc}}}>Nachname</SortableTh> | ||||||
| 					<SortableTh onSort={(e) => userFilter = {...userFilter, sort: {key: 'birthday', asc: e.asc}}}>Geburtstag</SortableTh> | 				<SortableTh onSort={(e) => userFilter = {...userFilter, sort: {key: 'birthday', asc: e.asc}}}>Geburtstag</SortableTh> | ||||||
| 					<SortableTh onSort={(e) => userFilter = {...userFilter, sort: {key: 'telephone', asc: e.asc}}}>Telefon</SortableTh> | 				<SortableTh onSort={(e) => userFilter = {...userFilter, sort: {key: 'telephone', asc: e.asc}}}>Telefon</SortableTh> | ||||||
| 					<SortableTh onSort={(e) => userFilter = {...userFilter, sort: {key: 'username', asc: e.asc}}}>Username</SortableTh> | 				<SortableTh onSort={(e) => userFilter = {...userFilter, sort: {key: 'username', asc: e.asc}}}>Username</SortableTh> | ||||||
| 					<SortableTh onSort={(e) => userFilter = {...userFilter, sort: {key: 'playertype', asc: e.asc}}}>Minecraft Edition</SortableTh> | 				<SortableTh onSort={(e) => userFilter = {...userFilter, sort: {key: 'playertype', asc: e.asc}}}>Minecraft Edition</SortableTh> | ||||||
| 					<SortableTh onSort={(e) => userFilter = {...userFilter, sort: {key: 'password', asc: e.asc}}}>Passwort</SortableTh> | 				<SortableTh onSort={(e) => userFilter = {...userFilter, sort: {key: 'password', asc: e.asc}}}>Passwort</SortableTh> | ||||||
| 					<SortableTh onSort={(e) => userFilter = {...userFilter, sort: {key: 'uuid', asc: e.asc}}}>UUID</SortableTh> | 				<SortableTh onSort={(e) => userFilter = {...userFilter, sort: {key: 'uuid', asc: e.asc}}}>UUID</SortableTh> | ||||||
| 					<th></th> | 				<th></th> | ||||||
| 				</SortableTr> | 			</SortableTr> | ||||||
| 			</thead> | 			</thead> | ||||||
| 			<PaginationTableBody | 			<PaginationTableBody | ||||||
| 				onUpdate={async () => { | 				onUpdate={async () => { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user