rewrite website
This commit is contained in:
145
src/app/admin/settings/Settings.svelte
Normal file
145
src/app/admin/settings/Settings.svelte
Normal file
@@ -0,0 +1,145 @@
|
||||
<script lang="ts">
|
||||
import { DynamicSettings } from './dynamicSettings.ts';
|
||||
import { confirmPopupState } from '@components/popup/ConfirmPopup.ts';
|
||||
import { updateSettings } from './actions.ts';
|
||||
|
||||
// types
|
||||
interface Props {
|
||||
settings: { name: string; value: string }[];
|
||||
}
|
||||
|
||||
type SettingsInput = {
|
||||
name: string;
|
||||
entries: (
|
||||
| {
|
||||
name: string;
|
||||
type: 'checkbox';
|
||||
value: boolean;
|
||||
onChange: (value: boolean) => void;
|
||||
}
|
||||
| {
|
||||
name: string;
|
||||
type: 'text';
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
}
|
||||
| {
|
||||
name: string;
|
||||
type: 'textarea';
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
}
|
||||
)[];
|
||||
}[];
|
||||
|
||||
// inputs
|
||||
const { settings }: Props = $props();
|
||||
|
||||
const dynamicSettings = new DynamicSettings(
|
||||
settings.reduce((prev, curr) => Object.assign(prev, { [curr.name]: curr.value }), {})
|
||||
);
|
||||
|
||||
let changes = $state<{ [k: string]: string | null }>(dynamicSettings.getChanges());
|
||||
|
||||
// consts
|
||||
const settingsInput: SettingsInput = [
|
||||
{
|
||||
name: 'Anmeldung',
|
||||
entries: [
|
||||
{
|
||||
name: 'Aktiviert',
|
||||
type: 'checkbox',
|
||||
value: dynamicSettings.signupEnabled(),
|
||||
onChange: dynamicSettings.signupSetEnabled
|
||||
},
|
||||
{
|
||||
name: 'Text unter dem Anmelde Button',
|
||||
type: 'textarea',
|
||||
value: dynamicSettings.signupInfoText(),
|
||||
onChange: dynamicSettings.signupSetInfoText
|
||||
},
|
||||
{
|
||||
name: 'Text, wenn die Anmeldung deaktiviert ist',
|
||||
type: 'textarea',
|
||||
value: dynamicSettings.signupDisabledText(),
|
||||
onChange: dynamicSettings.signupSetDisabledText
|
||||
},
|
||||
{
|
||||
name: 'Subtext, wenn die Anmeldung deaktiviert ist',
|
||||
type: 'textarea',
|
||||
value: dynamicSettings.signupDisabledSubtext(),
|
||||
onChange: dynamicSettings.signupSetDisabledSubtext
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
// callbacks
|
||||
function onSaveSettingsClick() {
|
||||
$confirmPopupState = {
|
||||
title: 'Änderungen speichern?',
|
||||
message: 'Sollen die Änderungen gespeichert werden?',
|
||||
onConfirm: async () => {
|
||||
if (!(await updateSettings(changes))) return;
|
||||
dynamicSettings.setChanges();
|
||||
changes = {};
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="h-full flex flex-col items-center justify-between">
|
||||
<div class="grid grid-cols-2 w-full">
|
||||
{#each settingsInput as setting (setting.name)}
|
||||
<div class="mx-12">
|
||||
<div class="divider">{setting.name}</div>
|
||||
<div class="flex flex-col gap-5">
|
||||
{#each setting.entries as entry (entry.name)}
|
||||
<label class="flex justify-between">
|
||||
<span class="mt-[.125rem] text-sm w-1/2">{entry.name}</span>
|
||||
<div class="w-1/2">
|
||||
{#if entry.type === 'checkbox'}
|
||||
<input
|
||||
type="checkbox"
|
||||
class="toggle"
|
||||
onchange={(e) => {
|
||||
entry.onChange(e.currentTarget.checked);
|
||||
changes = dynamicSettings.getChanges();
|
||||
}}
|
||||
checked={entry.value}
|
||||
/>
|
||||
{:else if entry.type === 'text'}
|
||||
<input
|
||||
type="text"
|
||||
class="input input-bordered"
|
||||
onchange={(e) => {
|
||||
entry.onChange(e.currentTarget.value);
|
||||
changes = dynamicSettings.getChanges();
|
||||
}}
|
||||
value={entry.value}
|
||||
/>
|
||||
{:else if entry.type === 'textarea'}
|
||||
<textarea
|
||||
class="textarea"
|
||||
value={entry.value}
|
||||
onchange={(e) => {
|
||||
entry.onChange(e.currentTarget.value);
|
||||
changes = dynamicSettings.getChanges();
|
||||
}}
|
||||
></textarea>
|
||||
{/if}
|
||||
</div>
|
||||
</label>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
class="btn btn-success mt-auto mb-8"
|
||||
class:btn-disabled={Object.keys(changes).length === 0}
|
||||
onclick={onSaveSettingsClick}>Speichern</button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
19
src/app/admin/settings/actions.ts
Normal file
19
src/app/admin/settings/actions.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { actions } from 'astro:actions';
|
||||
import { actionErrorPopup } from '@util/action.ts';
|
||||
|
||||
export async function updateSettings(changes: { [k: string]: string | null }) {
|
||||
const { error } = await actions.settings.setSettings({
|
||||
settings: Object.entries(changes).reduce(
|
||||
(prev, curr) => {
|
||||
prev.push({ name: curr[0], value: curr[1] });
|
||||
return prev;
|
||||
},
|
||||
[] as { name: string; value: string | null }[]
|
||||
)
|
||||
});
|
||||
if (error) {
|
||||
actionErrorPopup(error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
48
src/app/admin/settings/dynamicSettings.ts
Normal file
48
src/app/admin/settings/dynamicSettings.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { SettingKey } from '@util/settings.ts';
|
||||
|
||||
export class DynamicSettings {
|
||||
private settings: { [k: string]: string | null };
|
||||
private changedSettings: { [k: string]: string | null } = {};
|
||||
|
||||
constructor(settings: typeof this.settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
private get<V extends string | boolean>(key: string, defaultValue: V): V {
|
||||
const setting = this.changedSettings[key] ?? this.settings[key];
|
||||
return setting != null ? JSON.parse(setting) : defaultValue;
|
||||
}
|
||||
|
||||
private set<V extends string | boolean>(key: string, value: V | null) {
|
||||
if (this.settings[key] == value) {
|
||||
delete this.changedSettings[key];
|
||||
} else {
|
||||
this.changedSettings[key] = value != null ? JSON.stringify(value) : null;
|
||||
}
|
||||
}
|
||||
|
||||
getChanges() {
|
||||
return this.changedSettings;
|
||||
}
|
||||
|
||||
setChanges() {
|
||||
this.settings = Object.assign(this.settings, this.changedSettings);
|
||||
this.changedSettings = {};
|
||||
}
|
||||
|
||||
/* signup enabled */
|
||||
signupEnabled = () => this.get(SettingKey.SignupEnabled, false);
|
||||
signupSetEnabled = (active: boolean) => this.set(SettingKey.SignupEnabled, active);
|
||||
|
||||
/* signup info text */
|
||||
signupInfoText = () => this.get(SettingKey.SignupInfoMessage, '');
|
||||
signupSetInfoText = (text: string) => this.set(SettingKey.SignupInfoMessage, text);
|
||||
|
||||
/* signup disabled text */
|
||||
signupDisabledText = () => this.get(SettingKey.SignupDisabledMessage, '');
|
||||
signupSetDisabledText = (text: string) => this.set(SettingKey.SignupDisabledMessage, text);
|
||||
|
||||
/* signup disabled subtext */
|
||||
signupDisabledSubtext = () => this.get(SettingKey.SignupDisabledSubMessage, '');
|
||||
signupSetDisabledSubtext = (text: string) => this.set(SettingKey.SignupDisabledSubMessage, text);
|
||||
}
|
||||
Reference in New Issue
Block a user