319 lines
9.1 KiB
Svelte
319 lines
9.1 KiB
Svelte
<div class="parent">
|
|
<div class="content">
|
|
<Card footer={false}>
|
|
<span slot="title">Forms</span>
|
|
<div slot="body" class="body-wrapper">
|
|
<div class="section">
|
|
<h2 class="section-title">Create New Form</h2>
|
|
|
|
<form on:submit|preventDefault={createForm}>
|
|
<div class="row" id="creation-row">
|
|
<Input placeholder="Form Title" col3={true} bind:value={newTitle}/>
|
|
<div id="create-button-wrapper">
|
|
<Button icon="fas fa-paper-plane" fullWidth={windowWidth <= 950}>Create</Button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
<div class="section">
|
|
<h2 class="section-title">Manage Forms</h2>
|
|
|
|
<div class="col-1" style="flex-direction: row">
|
|
<div class="col-4" style="margin-right: 12px">
|
|
<div class="multiselect-super">
|
|
<Dropdown col1={true} bind:value={activeFormId}>
|
|
<option value={null}>Select a form...</option>
|
|
{#each forms as form}
|
|
<option value="{form.form_id}">{form.title}</option>
|
|
{/each}
|
|
</Dropdown>
|
|
</div>
|
|
</div>
|
|
|
|
{#if activeFormId !== null}
|
|
<div class="col-4">
|
|
<Button danger={true} type="button"
|
|
on:click={() => deleteForm(activeFormId)}>Delete {activeFormTitle}</Button>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
|
|
<div class="manage">
|
|
{#if activeFormId !== null}
|
|
{#each forms.find(form => form.form_id === activeFormId).inputs as input, i (input)}
|
|
<div animate:flip="{{duration: 500}}">
|
|
<FormInputRow data={input} formId={activeFormId}
|
|
withSaveButton={true} withDeleteButton={true} withDirectionButtons={true}
|
|
index={i} {formLength}
|
|
on:save={(e) => editInput(activeFormId, input.id, e.detail)}
|
|
on:delete={() => deleteInput(activeFormId, input.id)}
|
|
on:move={(e) => changePosition(activeFormId, input.id, e.detail.direction)} />
|
|
</div>
|
|
{/each}
|
|
{/if}
|
|
|
|
{#if activeFormId !== null}
|
|
<FormInputRow bind:data={inputCreationData} withCreateButton={true}
|
|
on:create={(e) => createInput(e.detail)}/>
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
|
|
<svelte:window bind:innerWidth={windowWidth} />
|
|
|
|
<script>
|
|
import Card from "../components/Card.svelte";
|
|
import {notifyError, notifySuccess, withLoadingScreen} from '../js/util'
|
|
import Button from "../components/Button.svelte";
|
|
import axios from "axios";
|
|
import {API_URL} from "../js/constants";
|
|
import {setDefaultHeaders} from '../includes/Auth.svelte'
|
|
import Input from "../components/form/Input.svelte";
|
|
import Dropdown from "../components/form/Dropdown.svelte";
|
|
import FormInputRow from "../components/manage/FormInputRow.svelte";
|
|
import { flip } from "svelte/animate";
|
|
|
|
export let currentRoute;
|
|
let guildId = currentRoute.namedParams.id;
|
|
|
|
let defaultTeam = {id: 'default', name: 'Default'};
|
|
|
|
let newTitle;
|
|
let forms = [];
|
|
let activeFormId = null;
|
|
$: activeFormTitle = activeFormId !== null ? forms.find(f => f.form_id === activeFormId).title : 'Unknown';
|
|
let inputCreationData = {};
|
|
|
|
$: formLength = activeFormId !== null ? forms.find(f => f.form_id === activeFormId).inputs.length : 0;
|
|
|
|
$: windowWidth = 0;
|
|
|
|
function getForm(formId) {
|
|
return forms.find(form => form.form_id === formId);
|
|
}
|
|
|
|
async function createForm() {
|
|
let data = {
|
|
title: newTitle,
|
|
};
|
|
|
|
const res = await axios.post(`${API_URL}/api/${guildId}/forms`, data);
|
|
if (res.status !== 200) {
|
|
notifyError(res.data.error);
|
|
return;
|
|
}
|
|
|
|
notifySuccess(`Form ${newTitle} has been created`);
|
|
newTitle = '';
|
|
|
|
let form = res.data;
|
|
form.inputs = [];
|
|
|
|
activeFormId = null; // Error thrown from {#each forms.find} if we don't temporarily set this to null?
|
|
forms = [...forms, form];
|
|
activeFormId = form.form_id;
|
|
}
|
|
|
|
async function deleteForm(id) {
|
|
const res = await axios.delete(`${API_URL}/api/${guildId}/forms/${id}`);
|
|
if (res.status !== 200) {
|
|
notifyError(res.data.error);
|
|
return;
|
|
}
|
|
|
|
notifySuccess(`Form deleted successfully`);
|
|
|
|
forms = forms.filter(form => form.form_id !== id);
|
|
if (forms.length > 0) {
|
|
activeFormId = forms[0].form_id;
|
|
} else {
|
|
activeFormId = null;
|
|
}
|
|
}
|
|
|
|
async function createInput(data) {
|
|
let mapped = {...data, style: parseInt(data.style)};
|
|
|
|
const res = await axios.post(`${API_URL}/api/${guildId}/forms/${activeFormId}`, mapped);
|
|
if (res.status !== 200) {
|
|
notifyError(res.data.error);
|
|
return;
|
|
}
|
|
|
|
let form = getForm(res.data.form_id);
|
|
form.inputs = [...form.inputs, res.data];
|
|
forms = forms;
|
|
inputCreationData = {"style": "1"};
|
|
|
|
notifySuccess('Form input created successfully');
|
|
}
|
|
|
|
async function editInput(formId, inputId, data) {
|
|
let mapped = {...data, style: parseInt(data.style)};
|
|
|
|
const res = await axios.patch(`${API_URL}/api/${guildId}/forms/${formId}/${inputId}`, mapped);
|
|
if (res.status !== 200) {
|
|
notifyError(res.data.error);
|
|
return;
|
|
}
|
|
|
|
let form = getForm(formId);
|
|
form.inputs = form.inputs.filter(input => input.id !== inputId);
|
|
form.inputs = [...form.inputs, res.data];
|
|
|
|
notifySuccess('Form input updated successfully');
|
|
}
|
|
|
|
async function deleteInput(formId, inputId) {
|
|
const res = await axios.delete(`${API_URL}/api/${guildId}/forms/${formId}/${inputId}`);
|
|
if (res.status !== 200) {
|
|
notifyError(res.data.error);
|
|
return;
|
|
}
|
|
|
|
// TODO: delete keyword?
|
|
let form = getForm(formId);
|
|
form.inputs = form.inputs.filter(input => input.id !== inputId);
|
|
forms = forms;
|
|
|
|
notifySuccess('Form input deleted successfully');
|
|
}
|
|
|
|
async function changePosition(formId, inputId, direction) {
|
|
const res = await axios.patch(`${API_URL}/api/${guildId}/forms/${formId}/${inputId}/${direction}`);
|
|
if (res.status !== 200) {
|
|
notifyError(res.data.error);
|
|
return;
|
|
}
|
|
|
|
if (res.data.success) {
|
|
//let form = getForm(formId);
|
|
let form = forms.find(form => form.form_id === activeFormId);
|
|
let idx = form.inputs.findIndex((input) => input.id === inputId);
|
|
|
|
let inputs = form.inputs;
|
|
if (direction === "up") {
|
|
[inputs[idx-1], inputs[idx]] = [inputs[idx], inputs[idx-1]]
|
|
} else if (direction === "down") {
|
|
[inputs[idx+1], inputs[idx]] = [form.inputs[idx], form.inputs[idx+1]]
|
|
}
|
|
|
|
forms = forms;
|
|
}
|
|
}
|
|
|
|
async function loadForms() {
|
|
const res = await axios.get(`${API_URL}/api/${guildId}/forms`);
|
|
if (res.status !== 200) {
|
|
notifyError(res.data.error);
|
|
return;
|
|
}
|
|
|
|
forms = res.data || [];
|
|
forms.flatMap(f => f.inputs).forEach(i => {
|
|
i.optional = !i.required;
|
|
i.style = i.style.toString();
|
|
});
|
|
|
|
if (forms.length > 0) {
|
|
activeFormId = forms[0].form_id;
|
|
}
|
|
}
|
|
|
|
withLoadingScreen(async () => {
|
|
setDefaultHeaders();
|
|
await loadForms();
|
|
});
|
|
</script>
|
|
|
|
<style>
|
|
.parent {
|
|
display: flex;
|
|
justify-content: center;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.content {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
width: 96%;
|
|
height: 100%;
|
|
margin-top: 30px;
|
|
margin-bottom: 50px;
|
|
}
|
|
|
|
.body-wrapper {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
height: 100%;
|
|
padding: 1%;
|
|
}
|
|
|
|
.section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.section:not(:first-child) {
|
|
margin-top: 2%;
|
|
}
|
|
|
|
.section-title {
|
|
font-size: 36px;
|
|
font-weight: bolder !important;
|
|
}
|
|
|
|
h3 {
|
|
font-size: 28px;
|
|
margin-bottom: 4px;
|
|
}
|
|
|
|
.row {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.manage {
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: space-between;
|
|
width: 100%;
|
|
height: 100%;
|
|
margin-top: 12px;
|
|
}
|
|
|
|
#creation-row {
|
|
justify-content: flex-start !important;
|
|
}
|
|
|
|
#create-button-wrapper {
|
|
margin-left: 15px;
|
|
height: 40px;
|
|
}
|
|
|
|
@media only screen and (max-width: 950px) {
|
|
.manage {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.row {
|
|
flex-direction: column;
|
|
}
|
|
|
|
#create-button-wrapper {
|
|
margin-left: unset;
|
|
}
|
|
}
|
|
</style>
|