Files
Timetable-V2/src/views/settings/AdminSettings.vue
minie4 f11fe89835 🐛 Fix timetable card in admin settings
- Now displays timetable class and ID again
2023-08-27 14:14:22 +02:00

287 lines
7.0 KiB
Vue

<script setup>
import ExpandSection from "@/components/settings/expand-section.vue";
import KeyCard from "@/components/settings/key-card.vue";
import RadioCard from "@/components/settings/radio-card.vue";
import { baseUrl } from "@/store";
import {
PlusIcon,
SaveIcon,
XIcon,
RefreshCwIcon,
Edit2Icon,
TrashIcon,
} from "lucide-vue-next";
import { ref } from "vue";
function confirm(message) {
return window.confirm(message);
}
/* General */
async function fetchObjects(type) {
const response = await fetch(baseUrl + "/admin/" + type);
if (response.status != 200) return;
return await response.json();
}
async function deleteObject(type, id) {
const response = await fetch(
baseUrl + `/admin/${type}?id=${encodeURIComponent(id)}`,
{ method: "delete" },
);
if (response.status != 200) alert("Delete failed!");
updateData();
}
async function createObject(type, data) {
const response = await fetch(baseUrl + "/admin/" + type, {
method: "post",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
if (response.status != 201) alert("Post failed!");
updateData();
}
async function updateObject(type, id, data) {
const response = await fetch(
baseUrl + `/admin/${type}?id=${encodeURIComponent(id)}`,
{
method: "put",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(data),
},
);
if (response.status != 201) alert("Post failed!");
updateData();
}
/* Timetable */
const timetables = ref([]);
const timetableEditId = ref(-1);
const timetableName = ref();
const timetableClass = ref();
const timetableSource = ref();
const timetableTrusted = ref(true);
async function createTimetable() {
return await createObject("timetable", {
title: timetableName.value,
class: timetableClass.value,
source: timetableSource.value,
trusted: timetableTrusted.value,
data: [],
});
}
async function updateTimetable() {
return await updateObject("timetable", timetableEditId.value, {
title: timetableName.value,
class: timetableClass.value,
source: timetableSource.value,
trusted: timetableTrusted.value,
});
}
/* Key */
const keys = ref([]);
const keyEditId = ref(-1);
const keyId = ref();
const keyPermissions = ref();
const keyNotes = ref();
async function createKey() {
return await createObject("key", {
key: keyId.value,
permissions: keyPermissions.value.split(","),
notes: keyNotes.value,
});
}
async function updateKey() {
return await updateObject("key", keyEditId.value, {
key: keyId.value,
permissions: keyPermissions.value.split(","),
notes: keyNotes.value,
});
}
function regenerateId() {
keyId.value = Math.random().toString(36).slice(-8);
}
async function updateData() {
timetables.value = await fetchObjects("timetable");
keys.value = await fetchObjects("key");
}
updateData();
</script>
<template>
<h1>Admin Settings</h1>
<ExpandSection title="Timetables">
<div class="list">
<div class="create_options">
<input type="text" placeholder="Name" v-model="timetableName" />
<input type="text" placeholder="Class" v-model="timetableClass" />
<input type="text" placeholder="Source" v-model="timetableSource" />
<div>
<input type="checkbox" v-model="timetableTrusted" />
<span>Trusted</span>
</div>
<div
class="button"
v-if="timetableEditId == -1"
@click="createTimetable()"
>
<PlusIcon />
<span>Create Timetable</span>
</div>
<div
class="button"
v-if="timetableEditId != -1"
@click="updateTimetable()"
>
<SaveIcon />
<span>Save Timetable</span>
</div>
<div
class="button"
v-if="timetableEditId != -1"
@click="timetableEditId = -1"
>
<XIcon />
<span>Cancel edit</span>
</div>
</div>
<RadioCard
v-for="timetable in timetables"
:key="timetable"
:title="timetable.title"
:subtitle="`${$t('settings.source')}: ${timetable.source}, Class: ${
timetable.class
}, ID: ${timetable.id}`"
:selected="timetable.id == timetableEditId"
>
<Edit2Icon
@click="
() => {
timetableEditId = timetable.id;
timetableName = timetable.title;
timetableClass = timetable.class;
timetableSource = timetable.source;
timetableTrusted = timetable.trusted;
}
"
/>
<TrashIcon
@click="
if (confirm('Delete this timetable?'))
deleteObject('timetable', timetable.id);
"
/>
</RadioCard>
</div>
</ExpandSection>
<ExpandSection title="Keys">
<div class="list">
<div class="create_options">
<div class="inline">
<input type="text" placeholder="Key" v-model="keyId" />
<RefreshCwIcon
:size="24"
class="button inline"
@click="regenerateId()"
/>
</div>
<input
type="text"
placeholder="Permissions (eg. perm1,perm2)"
v-model="keyPermissions"
/>
<input type="text" placeholder="Notes" v-model="keyNotes" />
<div class="button" v-if="keyEditId == -1" @click="createKey()">
<PlusIcon />
<span>Create Key</span>
</div>
<div class="button" v-if="keyEditId != -1" @click="updateKey()">
<SaveIcon />
<span>Save Key</span>
</div>
<div class="button" v-if="keyEditId != -1" @click="keyEditId = -1">
<XIcon />
<span>Cancel edit</span>
</div>
</div>
<KeyCard
:edit="true"
:keyData="key"
v-for="key in keys"
:key="key"
@delete="
() => {
if (
key.permissions.includes('admin') &&
!confirm('Are you sure you want to delete an admin key?')
) {
return;
}
deleteObject('key', key.key);
}
"
@edit="
() => {
keyEditId = key.key;
keyId = key.key;
keyPermissions = key.permissions.join(',');
keyNotes = key.notes;
}
"
/>
</div>
</ExpandSection>
</template>
<style scoped>
h1 {
margin: 0px 0px 10px;
}
.list {
display: flex;
flex-direction: column;
gap: 5px;
}
.button {
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
background-color: var(--element-color);
padding: 5px 10px;
border-radius: 5px;
}
.create_options {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
justify-content: center;
align-items: center;
gap: 10px;
padding: 10px;
cursor: pointer;
}
.inline {
display: grid;
grid-template-columns: 1fr auto;
box-sizing: border-box;
gap: 5px;
width: 100%;
}
.inline .button {
padding: 5px;
}
</style>