diff --git a/src/actions/report.ts b/src/actions/report.ts
index 52c5288..9dfc2c4 100644
--- a/src/actions/report.ts
+++ b/src/actions/report.ts
@@ -68,6 +68,39 @@ export const report = {
};
}
}),
+ addStrikeReason: defineAction({
+ input: z.object({
+ name: z.string(),
+ weight: z.number()
+ }),
+ handler: async (input, context) => {
+ Session.actionSessionFromCookies(context.cookies, Permissions.Reports);
+
+ return await db.addStrikeReason(input);
+ }
+ }),
+ editStrikeReason: defineAction({
+ input: z.object({
+ id: z.number(),
+ name: z.string(),
+ weight: z.number()
+ }),
+ handler: async (input, context) => {
+ Session.actionSessionFromCookies(context.cookies, Permissions.Reports);
+
+ await db.editStrikeReason(input);
+ }
+ }),
+ deleteStrikeReason: defineAction({
+ input: z.object({
+ id: z.number()
+ }),
+ handler: async (input, context) => {
+ Session.actionSessionFromCookies(context.cookies, Permissions.Reports);
+
+ await db.deleteStrikeReason(input);
+ }
+ }),
strikeReasons: defineAction({
handler: async (_, context) => {
Session.actionSessionFromCookies(context.cookies, Permissions.Reports);
diff --git a/src/app/admin/usersBlocked/SidebarActions.svelte b/src/app/admin/blockedUsers/SidebarActions.svelte
similarity index 97%
rename from src/app/admin/usersBlocked/SidebarActions.svelte
rename to src/app/admin/blockedUsers/SidebarActions.svelte
index ccebe61..113239e 100644
--- a/src/app/admin/usersBlocked/SidebarActions.svelte
+++ b/src/app/admin/blockedUsers/SidebarActions.svelte
@@ -1,7 +1,7 @@
+
+
+
+
+
+
diff --git a/src/app/admin/strikeReasons/StrikeReasons.svelte b/src/app/admin/strikeReasons/StrikeReasons.svelte
new file mode 100644
index 0000000..903e589
--- /dev/null
+++ b/src/app/admin/strikeReasons/StrikeReasons.svelte
@@ -0,0 +1,56 @@
+
+
+ (editPopupStrikeReason = strikeReason)}
+/>
+
+
diff --git a/src/app/admin/strikeReasons/strikeReasons.ts b/src/app/admin/strikeReasons/strikeReasons.ts
new file mode 100644
index 0000000..228e39f
--- /dev/null
+++ b/src/app/admin/strikeReasons/strikeReasons.ts
@@ -0,0 +1,55 @@
+import { type ActionReturnType, actions } from 'astro:actions';
+import { writable } from 'svelte/store';
+import { actionErrorPopup } from '@util/action.ts';
+import { addToWritableArray, deleteFromWritableArray, updateWritableArray } from '@util/state.ts';
+
+// types
+export type StrikeReasons = Exclude<
+ ActionReturnType['data'],
+ undefined
+>['strikeReasons'];
+export type StrikeReason = StrikeReasons[0];
+
+// state
+export const strikeReasons = writable([]);
+
+// actions
+export async function fetchStrikeReasons() {
+ const { data, error } = await actions.report.strikeReasons();
+ if (error) {
+ actionErrorPopup(error);
+ return;
+ }
+
+ strikeReasons.set(data.strikeReasons);
+}
+
+export async function addStrikeReason(strikeReason: StrikeReason) {
+ const { data, error } = await actions.report.addStrikeReason(strikeReason);
+ if (error) {
+ actionErrorPopup(error);
+ return;
+ }
+
+ addToWritableArray(strikeReasons, Object.assign(strikeReason, { id: data.id }));
+}
+
+export async function editStrikeReason(strikeReason: StrikeReason) {
+ const { error } = await actions.report.editStrikeReason(strikeReason);
+ if (error) {
+ actionErrorPopup(error);
+ return;
+ }
+
+ updateWritableArray(strikeReasons, strikeReason, (t) => t.id == strikeReason.id);
+}
+
+export async function deleteStrikeReason(strikeReason: StrikeReason) {
+ const { error } = await actions.report.deleteStrikeReason(strikeReason);
+ if (error) {
+ actionErrorPopup(error);
+ return;
+ }
+
+ deleteFromWritableArray(strikeReasons, (t) => t.id == strikeReason.id);
+}
diff --git a/src/components/admin/popup/CrudPopup.svelte b/src/components/admin/popup/CrudPopup.svelte
index dcf8144..79d8e40 100644
--- a/src/components/admin/popup/CrudPopup.svelte
+++ b/src/components/admin/popup/CrudPopup.svelte
@@ -42,6 +42,7 @@
| 'color'
| 'date'
| 'datetime-local'
+ | 'number'
| 'password'
| 'tel'
| 'team-search'
@@ -56,6 +57,7 @@
['color']: {};
['date']: {};
['datetime-local']: {};
+ ['number']: {};
['password']: {};
['tel']: {};
['team-search']: {};
@@ -168,7 +170,7 @@
class:grid-cols-2={key.length === 2}
>
{#each key as k (k)}
- {#if k.type === 'color' || k.type === 'date' || k.type === 'datetime-local' || k.type === 'tel' || k.type === 'text'}
+ {#if k.type === 'color' || k.type === 'date' || k.type === 'datetime-local' || k.type === 'number' || k.type === 'tel' || k.type === 'text'}
target[k.key] ?? k.default, (v) => onBindChange(k.key, v, k.options)}
diff --git a/src/components/input/Input.svelte b/src/components/input/Input.svelte
index 6c1a411..29e83ec 100644
--- a/src/components/input/Input.svelte
+++ b/src/components/input/Input.svelte
@@ -3,7 +3,7 @@
interface Props {
id?: string;
- type?: 'color' | 'date' | 'datetime-local' | 'tel' | 'text' | 'email';
+ type?: 'color' | 'date' | 'datetime-local' | 'number' | 'tel' | 'text' | 'email';
value?: string | null;
label?: string;
required?: boolean;
diff --git a/src/db/database.ts b/src/db/database.ts
index 7f01769..7c5915d 100644
--- a/src/db/database.ts
+++ b/src/db/database.ts
@@ -98,7 +98,17 @@ import {
} from './schema/feedback.ts';
import { addReport, type AddReportReq, getReports, type GetReportsReq, report } from './schema/report.ts';
import { DATABASE_URI } from 'astro:env/server';
-import { type GetStrikeReasonsReq, getStrikeReasons, strikeReason } from '@db/schema/strikeReason.ts';
+import {
+ type GetStrikeReasonsReq,
+ getStrikeReasons,
+ strikeReason,
+ type AddStrikeReasonReq,
+ addStrikeReason,
+ type EditStrikeReasonReq,
+ editStrikeReason,
+ type DeleteStrikeReasonReq,
+ deleteStrikeReason
+} from '@db/schema/strikeReason.ts';
import { getStrikesByTeamId, type GetStrikesByTeamId, strike } from '@db/schema/strike.ts';
import {
editReportStatus,
@@ -232,7 +242,12 @@ export class Database {
editReportStatus = (values: EditReportStatusReq) => editReportStatus(this.db, values);
/* strike reason */
+ addStrikeReason = (values: AddStrikeReasonReq) => addStrikeReason(this.db, values);
+ editStrikeReason = (values: EditStrikeReasonReq) => editStrikeReason(this.db, values);
+ deleteStrikeReason = (values: DeleteStrikeReasonReq) => deleteStrikeReason(this.db, values);
getStrikeReasons = (values: GetStrikeReasonsReq) => getStrikeReasons(this.db, values);
+
+ /* strikes */
getStrikesByTeamId = (values: GetStrikesByTeamId) => getStrikesByTeamId(this.db, values);
/* feedback */
diff --git a/src/db/schema/strikeReason.ts b/src/db/schema/strikeReason.ts
index 5e17444..0d10492 100644
--- a/src/db/schema/strikeReason.ts
+++ b/src/db/schema/strikeReason.ts
@@ -1,6 +1,6 @@
import { int, mysqlTable, tinyint, varchar } from 'drizzle-orm/mysql-core';
import type { MySql2Database } from 'drizzle-orm/mysql2';
-import { asc } from 'drizzle-orm';
+import { asc, eq } from 'drizzle-orm';
type Database = MySql2Database<{ strikeReason: typeof strikeReason }>;
@@ -10,8 +10,33 @@ export const strikeReason = mysqlTable('strike_reason', {
weight: tinyint('weight').notNull()
});
+export type AddStrikeReasonReq = {
+ name: string;
+ weight: number;
+};
+
+export type EditStrikeReasonReq = typeof strikeReason.$inferSelect;
+
+export type DeleteStrikeReasonReq = {
+ id: number;
+};
+
export type GetStrikeReasonsReq = {};
+export async function addStrikeReason(db: Database, values: AddStrikeReasonReq) {
+ const sr = await db.insert(strikeReason).values(values).$returningId();
+
+ return sr[0];
+}
+
+export async function editStrikeReason(db: Database, values: EditStrikeReasonReq) {
+ await db.update(strikeReason).set(values).where(eq(strikeReason.id, values.id));
+}
+
+export async function deleteStrikeReason(db: Database, values: DeleteStrikeReasonReq) {
+ await db.delete(strikeReason).where(eq(strikeReason.id, values.id));
+}
+
export async function getStrikeReasons(db: Database, _values: GetStrikeReasonsReq) {
return db.select().from(strikeReason).orderBy(asc(strikeReason.weight));
}
diff --git a/src/layouts/admin/AdminLayout.astro b/src/layouts/admin/AdminLayout.astro
index af7d3e1..eb94787 100644
--- a/src/layouts/admin/AdminLayout.astro
+++ b/src/layouts/admin/AdminLayout.astro
@@ -46,6 +46,13 @@ const adminTabs = [
href: 'admin/reports',
name: 'Reports',
icon: 'heroicons:flag',
+ subTabs: [
+ {
+ href: 'admin/reports/reasons',
+ name: 'Strikegründe',
+ icon: 'heroicons:shield-exclamation'
+ }
+ ],
enabled: session?.permissions.reports
},
{
diff --git a/src/pages/admin/reports/reasons.astro b/src/pages/admin/reports/reasons.astro
new file mode 100644
index 0000000..43d630e
--- /dev/null
+++ b/src/pages/admin/reports/reasons.astro
@@ -0,0 +1,16 @@
+---
+import { Session } from '@util/session';
+import { Permissions } from '@util/permissions';
+import { BASE_PATH } from 'astro:env/server';
+import AdminLayout from '@layouts/admin/AdminLayout.astro';
+import SidebarActions from '@app/admin/strikeReasons/SidebarActions.svelte';
+import StrikeReasons from '@app/admin/strikeReasons/StrikeReasons.svelte';
+
+const session = Session.sessionFromCookies(Astro.cookies, Permissions.Reports);
+if (!session) return Astro.redirect(`${BASE_PATH}/admin`);
+---
+
+
+
+
+