97 lines
4.0 KiB
Vue
97 lines
4.0 KiB
Vue
<script setup>
|
|
import { onMounted, reactive, ref } from 'vue';
|
|
|
|
import { getAdminSettings, updateAdminSettings } from '@/services/admin-settings-service.js';
|
|
|
|
const settings = reactive({
|
|
general: { publicDescription: '', publicContactEmail: '', publicContactPhone: '' },
|
|
inventory: { maxImagesPerItem: 10 },
|
|
pricing: { defaultStrategy: 'median' },
|
|
security: { sessionIdleMinutes: 60 },
|
|
});
|
|
const isLoading = ref(true);
|
|
const isSaving = ref(false);
|
|
const message = ref('');
|
|
const error = ref('');
|
|
|
|
function csrfToken() {
|
|
return document.cookie.split('; ').find((value) => value.startsWith('pokemon_inventory_csrf='))?.split('=')[1] ?? '';
|
|
}
|
|
|
|
async function load() {
|
|
try {
|
|
Object.assign(settings, await getAdminSettings());
|
|
} catch (requestError) {
|
|
error.value = requestError.message;
|
|
} finally {
|
|
isLoading.value = false;
|
|
}
|
|
}
|
|
|
|
async function save() {
|
|
isSaving.value = true;
|
|
message.value = '';
|
|
error.value = '';
|
|
try {
|
|
const payload = {
|
|
...settings,
|
|
general: {
|
|
...settings.general,
|
|
publicContactEmail: settings.general.publicContactEmail || undefined,
|
|
publicContactPhone: settings.general.publicContactPhone || undefined,
|
|
},
|
|
};
|
|
Object.assign(settings, await updateAdminSettings(payload, csrfToken()));
|
|
message.value = 'Settings saved.';
|
|
} catch (requestError) {
|
|
error.value = requestError.message;
|
|
} finally {
|
|
isSaving.value = false;
|
|
}
|
|
}
|
|
|
|
onMounted(load);
|
|
</script>
|
|
|
|
<template>
|
|
<section class="admin-page">
|
|
<p class="catalog-kicker">Configuration</p>
|
|
<h1>Settings</h1>
|
|
<p v-if="isLoading" class="state state--loading" role="status">Loading settings...</p>
|
|
<p v-if="message" class="state" role="status">{{ message }}</p>
|
|
<p v-if="error" class="state state--error" role="alert">{{ error }}</p>
|
|
<form v-if="!isLoading" class="admin-workspace-grid" @submit.prevent="save">
|
|
<fieldset class="showcase-panel">
|
|
<legend>General</legend>
|
|
<label class="fixture-label" for="settings-description">Public seller description (optional)</label>
|
|
<p id="settings-description-help">Shown on public listing and product pages. Up to 2,000 characters. Clear to remove.</p>
|
|
<textarea id="settings-description" v-model="settings.general.publicDescription" class="fixture-input" rows="5" maxlength="2000" aria-describedby="settings-description-help" />
|
|
<label class="fixture-label" for="settings-email">Public contact email</label>
|
|
<input id="settings-email" v-model="settings.general.publicContactEmail" class="fixture-input" type="email" />
|
|
<label class="fixture-label" for="settings-phone">Public contact phone</label>
|
|
<input id="settings-phone" v-model="settings.general.publicContactPhone" class="fixture-input" />
|
|
</fieldset>
|
|
<fieldset class="showcase-panel">
|
|
<legend>Inventory</legend>
|
|
<label class="fixture-label" for="settings-images">Maximum images per item</label>
|
|
<input id="settings-images" v-model.number="settings.inventory.maxImagesPerItem" class="fixture-input" type="number" min="1" max="100" />
|
|
</fieldset>
|
|
<fieldset class="showcase-panel">
|
|
<legend>Pricing</legend>
|
|
<label class="fixture-label" for="settings-strategy">Default valuation strategy</label>
|
|
<select id="settings-strategy" v-model="settings.pricing.defaultStrategy" class="fixture-input">
|
|
<option value="median">Median</option>
|
|
<option value="average">Average</option>
|
|
<option value="weighted_average">Weighted average</option>
|
|
</select>
|
|
</fieldset>
|
|
<fieldset class="showcase-panel">
|
|
<legend>Security</legend>
|
|
<label class="fixture-label" for="settings-idle">Session idle minutes</label>
|
|
<input id="settings-idle" v-model.number="settings.security.sessionIdleMinutes" class="fixture-input" type="number" min="5" max="43200" />
|
|
</fieldset>
|
|
<button class="button button--primary" type="submit" :disabled="isSaving">Save settings</button>
|
|
</form>
|
|
</section>
|
|
</template>
|