561 lines
22 KiB
Cheetah
561 lines
22 KiB
Cheetah
{{define "content"}}
|
|
{{template "substitutions" .}}
|
|
{{template "paneleditmodal" .}}
|
|
{{template "multipaneleditmodal" .}}
|
|
|
|
<div class="content">
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<div class="col-md-8">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Reaction Panels</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<p class="white">Your panel quota: <b><span id="panel-count"></span> / <span id="panel-quota"></span></b></p>
|
|
<p class="white" id="premium-ad">Note: You can create unlimited panels with premium</p>
|
|
|
|
<table class="table table-hover table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Channel</th>
|
|
<th>Panel Title</th>
|
|
<th>Ticket Channel Category</th>
|
|
<th>Edit</th>
|
|
<th>Delete</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="panel-container">
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Multi-Panels</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<table class="table table-hover table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Embed Title</th>
|
|
<th>Edit</th>
|
|
<th>Delete</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="multi-panel-container">
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-8">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Create A Panel</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<form onsubmit="createPanel(); return false;">
|
|
<div class="row">
|
|
<div class="col-md-4 pr-1">
|
|
<div class="form-group">
|
|
<label class="black">Panel Title</label>
|
|
<input name="title" type="text" class="form-control" placeholder="Open a ticket!" id="title">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-8 pr-1">
|
|
<div class="form-group">
|
|
<label class="black">Panel Content</label>
|
|
<textarea name="content" type="text" class="form-control"
|
|
placeholder="By reacting to this ticket, a ticket will be opened for you." id="content"></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-3 pr-1">
|
|
<label class="black">Panel Colour</label>
|
|
<div class="input-group mb-3">
|
|
<input name="colour" type="color" class="form-control input-fill" value="#2ECC71" id="colour">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-3 pr-1">
|
|
<label class="black">Panel Channel</label>
|
|
<div class="input-group mb-3">
|
|
<div class="input-group-prepend">
|
|
<div class="input-group-text">#</div>
|
|
</div>
|
|
<select class="form-control" name="channel" id="channel-container">
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-3 pr-1">
|
|
<label class="black">Ticket Channel Category</label>
|
|
<div class="input-group mb-3">
|
|
<select class="form-control" name="categories" id="category-container">
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-3 pr-1">
|
|
<div class="form-group">
|
|
<label class="black">Reaction Emote</label>
|
|
<input name="reaction" type="text" class="form-control" placeholder="envelope_with_arrow" id="reaction">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-4 pr-1 offset-md-4">
|
|
<div class="text-center">
|
|
<button class="btn btn-primary btn-fill" type="button" data-toggle="collapse" data-target="#advanced" aria-expanded="false" aria-controls="advanced">
|
|
Expand advanced settings
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="collapse" id="advanced" style="width: 100%">
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<div class="col-md-12 pr-1">
|
|
<div class="form-group">
|
|
<label class="black">Welcome Message
|
|
<i class="fas fa-question pointer" onclick="showSubstitutionModal()"></i>
|
|
</label>
|
|
<textarea type="text" class="form-control" placeholder="If not provided, your server's default welcome message will be used" id="welcome_message"></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6 pr-1">
|
|
<div class="form-group">
|
|
<label class="black" for="mentions">Mention On Open</label>
|
|
<select class="selectpicker form-control" id="mentions" multiple data-live-search="true" data-dropup-auto="false" data-size="5" data-display="static">
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6 pr-1">
|
|
<div class="form-group">
|
|
<label class="black" for="teams">Support Teams</label>
|
|
<select class="selectpicker form-control" id="teams" multiple data-live-search="true" data-dropup-auto="false" data-size="5" data-display="static">
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-2 pr-1 offset-md-5">
|
|
<div class="form-group text-center">
|
|
<button type="submit" class="btn btn-primary btn-fill"><i class="fas fa-paper-plane"></i> Submit</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Create A Multi-Panel</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
|
|
<form onsubmit="createMultiPanel(); return false;">
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<div class="form-group">
|
|
<label class="black">Embed Title</label>
|
|
<input type="text" class="form-control" placeholder="React to open a ticket" id="multi-title">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<div class="form-group">
|
|
<label class="black">Embed Content</label>
|
|
<textarea type="text" class="form-control"
|
|
placeholder="Let users know which reaction corresponds to which panel. You are able to use emojis here." id="multi-content"></textarea>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<label class="black">Embed Colour</label>
|
|
<div class="input-group mb-3">
|
|
<input name="colour" type="color" class="form-control input-fill" value="#7289da" id="multi-colour">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-9">
|
|
<label class="black">Embed Channel</label>
|
|
<div class="input-group mb-3">
|
|
<div class="input-group-prepend">
|
|
<div class="input-group-text">#</div>
|
|
</div>
|
|
<select class="form-control" id="multi-channel-container">
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<label class="black" for="mentions">Panels</label>
|
|
<select class="selectpicker form-control" id="multi-panels" multiple data-live-search="true" data-dropup-auto="false" data-size="5" data-display="static">
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-6 pr-1 offset-md-3">
|
|
<div class="form-group text-center">
|
|
<button type="submit" class="btn btn-primary btn-fill" style="width: 100%;"><i class="fas fa-paper-plane"></i> Submit</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div aria-live="polite" aria-atomic="true" style="position: relative">
|
|
<div style="position: absolute; right: 10px" id="toast-container">
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function getValue(elementId) {
|
|
return document.getElementById(elementId).value;
|
|
}
|
|
|
|
async function getChannels() {
|
|
const res = await axios.get('/api/{{.guildId}}/channels');
|
|
return res.data;
|
|
}
|
|
|
|
function getChannelName(channels, channelId) {
|
|
const ch = channels.find(ch => ch.id === channelId);
|
|
if (ch === undefined) {
|
|
return "Unknown";
|
|
} else {
|
|
return ch.name;
|
|
}
|
|
}
|
|
|
|
async function deletePanel(panelId) {
|
|
const res = await axios.delete('/api/{{.guildId}}/panels/' + panelId);
|
|
|
|
if (res.status === 200 && res.data.success) {
|
|
notifySuccess('Panel deleted successfully');
|
|
|
|
const el = document.getElementById(panelId);
|
|
el.parentNode.removeChild(el);
|
|
} else {
|
|
notifyError(res.data.error);
|
|
}
|
|
}
|
|
|
|
async function deleteMultiPanel(panelId) {
|
|
const res = await axios.delete('/api/{{.guildId}}/multipanels/' + panelId);
|
|
|
|
if (res.status === 200 && res.data.success) {
|
|
notifySuccess('Multi-panel deleted successfully');
|
|
|
|
const el = document.getElementById(panelId);
|
|
el.parentNode.removeChild(el);
|
|
} else {
|
|
notifyError(res.data.error);
|
|
}
|
|
}
|
|
|
|
async function createPanel() {
|
|
const title = document.getElementById('title').value;
|
|
const content = document.getElementById('content').value;
|
|
const emote = document.getElementById('reaction').value.replace(':', '');
|
|
const welcomeMessage = document.getElementById('welcome_message').value;
|
|
|
|
const data = {
|
|
title: title === '' ? 'Open a ticket!' : title,
|
|
content: content === '' ? 'By reacting to this ticket, a message will be opened for you.' : content,
|
|
emote: emote === '' ? 'envelope_with_arrow' : emote,
|
|
colour: parseInt(`0x${document.getElementById('colour').value.slice(1)}`),
|
|
channel_id: document.getElementById('channel-container').options[document.getElementById('channel-container').selectedIndex].value,
|
|
category_id: document.getElementById('category-container').options[document.getElementById('category-container').selectedIndex].value,
|
|
welcome_message: welcomeMessage === '' ? null : welcomeMessage,
|
|
mentions: $('#mentions').val(),
|
|
teams: $('#teams').val()
|
|
};
|
|
|
|
const res = await axios.put('/api/{{.guildId}}/panels', data);
|
|
if (res.status === 200 && res.data.success) {
|
|
data.panel_id = res.data.panel_id;
|
|
appendPanel(data, await getChannels());
|
|
notifySuccess('Panel created successfully')
|
|
} else {
|
|
notifyError(res.data.error);
|
|
}
|
|
}
|
|
|
|
async function createMultiPanel() {
|
|
const channelContainer = document.getElementById('multi-channel-container');
|
|
|
|
const data = {
|
|
'title': getValue('multi-title'),
|
|
'content': getValue('multi-content'),
|
|
'colour': parseInt(`0x${getValue('multi-colour').slice(1)}`),
|
|
'channel_id': channelContainer.options[channelContainer.selectedIndex].value,
|
|
'panels': $('#multi-panels').val().map((id) => parseInt(id))
|
|
};
|
|
|
|
const res = await axios.post('/api/{{.guildId}}/multipanels', data);
|
|
if (res.status !== 200 || !res.data.success) {
|
|
notifyError(res.data.error);
|
|
return;
|
|
}
|
|
|
|
appendMultiPanel(res.data.data);
|
|
notify('Success', 'Multi-panel created successfully. Note: Don\'t delete the existing panels, or your they will disappear from your multi-panel.');
|
|
}
|
|
|
|
function fillChannels(elementId, channels) {
|
|
const container = document.getElementById(elementId);
|
|
|
|
channels.filter(ch => ch.type === 0).forEach(ch => {
|
|
const el = document.createElement('option');
|
|
el.value = ch.id;
|
|
el.appendChild(document.createTextNode(ch.name));
|
|
container.appendChild(el);
|
|
});
|
|
}
|
|
|
|
function fillCategories(elementId, channels) {
|
|
const container = document.getElementById(elementId);
|
|
|
|
channels.filter(ch => ch.type === 4).forEach(ch => {
|
|
const el = document.createElement('option');
|
|
el.value = ch.id;
|
|
el.appendChild(document.createTextNode(ch.name));
|
|
container.appendChild(el);
|
|
});
|
|
}
|
|
|
|
function setActiveChannel(elementId, channelId) {
|
|
const select = document.getElementById(elementId);
|
|
for (let i = 0; i < select.children.length; i++) {
|
|
const child = select.children[i];
|
|
if (child.value === channelId) {
|
|
select.selectedIndex = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: Update on append / delete
|
|
async function fillPanelQuota(panelCount) {
|
|
const res = await axios.get('/api/{{.guildId}}/premium');
|
|
|
|
const el = document.getElementById('panel-quota');
|
|
if (res.data.premium) {
|
|
el.appendChild(document.createTextNode('∞'));
|
|
} else {
|
|
el.appendChild(document.createTextNode('3'));
|
|
document.getElementById('premium-ad').style.display = 'block';
|
|
}
|
|
|
|
document.getElementById('panel-count').appendChild(document.createTextNode(panelCount));
|
|
}
|
|
|
|
function appendPanel(panel, channels) {
|
|
const container = document.getElementById('panel-container');
|
|
|
|
const tr = document.createElement('tr');
|
|
tr.id = panel.panel_id;
|
|
|
|
appendTd(tr, `#${getChannelName(channels, panel.channel_id)}`);
|
|
appendTd(tr, panel.title);
|
|
appendTd(tr, getChannelName(channels, panel.category_id));
|
|
|
|
// build edit button
|
|
const editTd = document.createElement('td');
|
|
const editButton = document.createElement('button');
|
|
editButton.type = 'button';
|
|
editButton.classList.add('btn', 'btn-primary', 'btn-fill', 'mx-auto');
|
|
editButton.appendChild(document.createTextNode('Edit'));
|
|
editButton.onclick = () => { openEditModal(panel.panel_id) };
|
|
editTd.appendChild(editButton);
|
|
tr.appendChild(editTd);
|
|
|
|
// build remove button
|
|
const deleteTd = document.createElement('td');
|
|
const deleteButton = document.createElement('button');
|
|
deleteButton.type = 'submit';
|
|
deleteButton.classList.add('btn', 'btn-primary', 'btn-fill', 'mx-auto');
|
|
deleteButton.appendChild(document.createTextNode('Delete'));
|
|
deleteButton.onclick = () => {deletePanel(panel.panel_id)};
|
|
deleteTd.appendChild(deleteButton);
|
|
tr.appendChild(deleteTd);
|
|
|
|
container.appendChild(tr);
|
|
}
|
|
|
|
function appendMultiPanel(panel) {
|
|
const container = document.getElementById('multi-panel-container');
|
|
|
|
const tr = document.createElement('tr');
|
|
tr.id = panel.id;
|
|
|
|
appendTd(tr, panel.title);
|
|
|
|
// build edit button
|
|
const editTd = document.createElement('td');
|
|
const editButton = document.createElement('button');
|
|
editButton.type = 'button';
|
|
editButton.classList.add('btn', 'btn-primary', 'btn-fill', 'mx-auto');
|
|
editButton.appendChild(document.createTextNode('Edit'));
|
|
editButton.onclick = () => { openMultiEditModal(panel.id) };
|
|
editTd.appendChild(editButton);
|
|
tr.appendChild(editTd);
|
|
|
|
// build remove button
|
|
const deleteTd = document.createElement('td');
|
|
const deleteButton = document.createElement('button');
|
|
deleteButton.type = 'submit';
|
|
deleteButton.classList.add('btn', 'btn-primary', 'btn-fill', 'mx-auto');
|
|
deleteButton.appendChild(document.createTextNode('Delete'));
|
|
deleteButton.onclick = () => {deleteMultiPanel(panel.id)};
|
|
deleteTd.appendChild(deleteButton);
|
|
tr.appendChild(deleteTd);
|
|
|
|
container.appendChild(tr);
|
|
}
|
|
|
|
async function fillPanels(channels) {
|
|
const res = await axios.get('/api/{{.guildId}}/panels');
|
|
if (res.status !== 200) {
|
|
notifyError(res.data.error);
|
|
return 0;
|
|
}
|
|
|
|
for (const panel of res.data) {
|
|
appendPanel(panel, channels);
|
|
}
|
|
|
|
appendPanelDropdownPanels('multi-panels', res.data);
|
|
appendPanelDropdownPanels('multi-edit-panels', res.data);
|
|
|
|
return res.data.length;
|
|
}
|
|
|
|
async function fillMultiPanels() {
|
|
const res = await axios.get('/api/{{.guildId}}/multipanels');
|
|
if (res.status !== 200) {
|
|
notifyError(res.data.error);
|
|
return;
|
|
}
|
|
|
|
for (const multiPanel of res.data.data) {
|
|
appendMultiPanel(multiPanel);
|
|
}
|
|
}
|
|
|
|
function appendPanelDropdownPanels(elementId, panels) {
|
|
const select = document.getElementById(elementId);
|
|
|
|
for (const panel of panels) {
|
|
const option = document.createElement('option');
|
|
option.value = panel.panel_id;
|
|
option.appendChild(document.createTextNode(panel.title));
|
|
select.appendChild(option);
|
|
}
|
|
|
|
$(`#${elementId}`).selectpicker('refresh');
|
|
}
|
|
|
|
async function fillMentions(elementId) {
|
|
const select = document.getElementById(elementId);
|
|
select.innerHTML = '';
|
|
|
|
// ticket opener
|
|
const ticketOpener = document.createElement('option');
|
|
ticketOpener.value = 'user';
|
|
ticketOpener.appendChild(document.createTextNode('Ticket Opener'));
|
|
select.appendChild(ticketOpener);
|
|
|
|
// roles
|
|
const res = await axios.get('/api/{{.guildId}}/roles');
|
|
if (res.status !== 200 || !res.data.success) {
|
|
notifyError(res.data.error);
|
|
return;
|
|
}
|
|
|
|
if (res.data.roles !== null) {
|
|
for (const role of res.data.roles) {
|
|
const option = document.createElement('option');
|
|
option.value = role.id;
|
|
option.appendChild(document.createTextNode(role.name));
|
|
select.appendChild(option);
|
|
}
|
|
}
|
|
|
|
$(`#${elementId}`).selectpicker('refresh');
|
|
}
|
|
|
|
async function fillTeams(elementId) {
|
|
const select = document.getElementById(elementId);
|
|
select.innerHTML = '';
|
|
|
|
const defaultTeam = createElement('option');
|
|
defaultTeam.value = 'default';
|
|
defaultTeam.appendChild(document.createTextNode('Default'));
|
|
select.appendChild(defaultTeam);
|
|
|
|
const res = await axios.get('/api/{{.guildId}}/team');
|
|
if (res.status !== 200) {
|
|
notifyError(res.data.error);
|
|
return;
|
|
}
|
|
|
|
if (res.data) {
|
|
for (const team of res.data) {
|
|
const option = document.createElement('option');
|
|
option.value = team.id;
|
|
option.appendChild(document.createTextNode(team.name));
|
|
select.appendChild(option);
|
|
}
|
|
}
|
|
|
|
$(`#${elementId}`).selectpicker('refresh');
|
|
}
|
|
|
|
async function loadData() {
|
|
const channels = await getChannels();
|
|
const panelCount = await fillPanels(channels);
|
|
|
|
await fillMultiPanels();
|
|
|
|
await fillPanelQuota(panelCount);
|
|
fillChannels('channel-container', channels);
|
|
fillChannels('multi-channel-container', channels);
|
|
fillCategories('category-container', channels);
|
|
await fillMentions('mentions');
|
|
|
|
await fillTeams('teams');
|
|
$(`#teams`).selectpicker('val', 'default');
|
|
}
|
|
|
|
withLoadingScreen(loadData);
|
|
</script>
|
|
</div>
|
|
{{end}} |