dashboard-v2/frontend/src/views/Whitelabel.svelte
2021-07-01 12:56:33 +01:00

347 lines
10 KiB
Svelte

<div class="wrapper">
<div class="content">
<div class="content-col">
<Card footer="{false}" fill="{false}">
<h4 slot="title">Bot Token</h4>
<div slot="body" class="full-width">
<form class="full-width" onsubmit="return false;">
<label class="form-label">Bot Token</label>
<input name="token" type="text" bind:value={token} class="form-input full-width"
placeholder="xxxxxxxxxxxxxxxxxxxxxxxx.xxxxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxx">
<p>Note: You will not be able to view the token after submitting it</p>
<div class="buttons">
<div class="col">
<Button icon="fas fa-paper-plane" on:click={submitToken} fullWidth="{true}">Submit</Button>
</div>
<div class="col">
<Button icon="fas fa-plus" on:click={invite} fullWidth="{true}" disabled="{bot.id === undefined}">
Generate Invite Link
</Button>
</div>
</div>
</form>
</div>
</Card>
</div>
<div class="content-col">
<Card footer="{false}" fill="{false}">
<h4 slot="title">Slash Commands</h4>
<div slot="body" class="full-width">
<form class="full-width" onsubmit="return false;">
<label class="form-label">Interactions Endpoint URL</label>
<input name="token" type="text" bind:value={interactionUrl} class="form-input full-width" readonly>
<label class="form-label">Public Key</label>
<input name="token" type="text" bind:value={publicKey} class="form-input full-width">
<div class="buttons">
<div class="col">
<Button icon="fas fa-paper-plane" on:click={updatePublicKey} fullWidth="{true}"
disabled="{bot.id === undefined}">Submit Key
</Button>
</div>
<div class="col">
<Button icon="fas fa-paper-plane" on:click={createSlashCommands} fullWidth="{true}"
disabled="{!publicKeyOk}">Create Slash Commands
</Button>
</div>
</div>
</form>
</div>
</Card>
</div>
</div>
<div class="content">
<div class="content-col">
<Card footer="{false}" fill="{false}">
<h4 slot="title">Custom Status</h4>
<div slot="body" class="full-width">
<form class="full-width" onsubmit="return false;">
<label class="form-label">Status</label>
<input name="token" type="text" bind:value={bot.status} class="form-input full-width" placeholder="/help">
<div class="buttons">
<Button icon="fas fa-paper-plane" on:click={updateStatus} fullWidth="{true}"
disabled="{bot.id === undefined}">Submit
</Button>
</div>
</form>
</div>
</Card>
</div>
<div class="content-col">
<Card footer="{false}" fill="{false}">
<h4 slot="title">Error Log</h4>
<div slot="body" class="full-width">
<table class="error-log">
<thead>
<tr style="border-bottom: 1px solid #dee2e6;">
<th class="table-col">Error</th>
<th class="table-col">Time</th>
</tr>
</thead>
<tbody id="error_body">
{#each errors as error}
<tr class="table-row table-border">
<td class="table-col">{error.message}</td>
<td class="table-col">{error.time.toLocaleString()}</td>
</tr>
{/each}
</tbody>
</table>
</div>
</Card>
</div>
</div>
</div>
<style>
.wrapper {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
align-items: center;
}
.content {
display: flex;
justify-content: space-around;
flex-direction: row;
width: 95%;
margin-top: 2%;
}
.col {
width: 48%;
height: 100%;
}
.content-col {
width: 48%;
height: 100%;
}
@media only screen and (max-width: 900px) {
.content {
flex-direction: column;
}
.content-col {
width: 100%;
margin-top: 2%;
}
}
/* TODO: Move to central stylesheet*/
:global(.form-label) {
font-size: 12px;
margin-bottom: 5px;
color: #9a9a9a;
text-transform: uppercase;
}
:global(.form-input), :global(.form-input:focus-visible) {
border-color: #2e3136 !important;
background-color: #2e3136 !important;
color: white !important;
outline: none;
border-radius: 4px;
padding: 8px 12px;
margin: 0 0 0.5em 0;
height: 40px;
}
.full-width {
width: 100%;
}
.buttons {
display: flex;
flex-direction: row;
justify-content: space-between;
margin-top: 12px;
}
.error-log {
width: 100%;
border-collapse: collapse;
}
.table-col {
width: 50%;
text-align: left;
padding: 5px 10px;
}
.table-border {
border-top: 1px solid #dee2e6;
}
</style>
<script>
import {notifyError, notifyRatelimit, notifySuccess, withLoadingScreen} from '../js/util'
import axios from "axios";
import Card from '../components/Card.svelte'
import Button from '../components/Button.svelte'
import {API_URL} from "../js/constants";
import {setDefaultHeaders} from '../includes/Auth.svelte'
setDefaultHeaders()
let token;
let publicKey;
let publicKeyOk = false;
let interactionUrl;
let bot = {};
let errors = [];
async function invite() {
const res = await axios.get(`${API_URL}/user/whitelabel/`);
if (res.status !== 200 || !res.data.success) {
notifyError(res.data.error);
return;
}
const inviteUrl = 'https://discord.com/oauth2/authorize?client_id=' + res.data.id + '&scope=bot+applications.commands&permissions=805825648';
window.open(inviteUrl, '_blank');
}
async function submitToken() {
const data = {
token: token
};
const res = await axios.post(`${API_URL}/user/whitelabel/`, data);
if (res.status !== 200 || !res.data.success) {
notifyError(res.data.error);
return;
}
$: token = '';
await loadInteractionUrl();
await loadBot();
notifySuccess(`Started tickets whitelabel on ${res.data.bot.username}#${res.data.bot.discriminator}`);
}
async function updatePublicKey() {
const data = {
public_key: publicKey,
};
const res = await axios.post(`${API_URL}/user/whitelabel/public-key`, data);
if (res.status !== 200 || !res.data.success) {
notifyError(res.data.error);
return;
}
$: publicKeyOk = true;
notifySuccess('Updated slash command settings successfully')
}
async function updateStatus() {
const data = {
status: bot.status,
};
const res = await axios.post(`${API_URL}/user/whitelabel/status`, data);
if (res.status !== 200 || !res.data.success) {
if (res.status === 429) {
notifyRatelimit()
} else {
notifyError(res.data.error)
}
return;
}
notifySuccess('Updated status successfully')
}
async function loadBot() {
const res = await axios.get(`${API_URL}/user/whitelabel/`);
if (res.status !== 200 || !res.data.success) {
if (res.status === 402) {
window.location.replace("https://ticketsbot.net/premium");
return false;
}
if (res.status !== 404) {
notifyError(res.data.error);
}
return true;
}
bot = res.data;
return true;
}
async function loadErrors() {
const res = await axios.get(`${API_URL}/user/whitelabel/errors`);
if (res.status !== 200 || !res.data.success) {
notifyError(res.data.error);
return;
}
// append errors
if (res.data.errors !== null) {
errors = res.data.errors.map(error => Object.assign({}, error, {time: new Date(error.time)}));
}
}
async function loadPublicKey() {
const res = await axios.get(`${API_URL}/user/whitelabel/public-key`);
if (res.status === 404) {
return;
}
if ((res.status !== 200 || !res.data.success)) {
notifyError(res.data.error);
return;
}
publicKey = res.data.key;
$: publicKeyOk = true;
}
async function loadInteractionUrl() {
const res = await axios.get(`${API_URL}/user/whitelabel/`);
if (res.status === 404) {
return;
}
if (res.status !== 200 || !res.data.success) {
notifyError(res.data.error);
return;
}
interactionUrl = 'https://gateway.ticketsbot.net/handle/' + res.data.id;
}
async function createSlashCommands() {
const opts = {
timeout: 20 * 1000
};
const res = await axios.post(`${API_URL}/user/whitelabel/create-interactions`, {}, opts);
if (res.status !== 200 || !res.data.success) {
notifyError(res.data.error);
return;
}
notifySuccess('Slash commands have been created. Please note, Discord may take up to an hour to show them in your client');
}
withLoadingScreen(async () => {
if (await loadBot()) {
await loadErrors();
await loadInteractionUrl();
await loadPublicKey();
}
});
</script>