513 lines
22 KiB
Cheetah
513 lines
22 KiB
Cheetah
{{define "content"}}
|
|
<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">Settings</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<form onsubmit="updateSettings(); return false;">
|
|
<div class="row">
|
|
<div class="col-md-2 pr-1">
|
|
<div class="form-group">
|
|
<label>Prefix (Max len. 8)</label>
|
|
<input name="prefix" type="text" class="form-control" placeholder="t!" id="prefix">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-1 px-1">
|
|
<div class="form-group">
|
|
<label>Ticket Limit</label>
|
|
<select class="custom-select mr-sm-2" id="ticket_limit" name="ticketlimit">
|
|
<option value="1">1</option>
|
|
<option value="2">2</option>
|
|
<option value="3">3</option>
|
|
<option value="4">4</option>
|
|
<option value="5">5</option>
|
|
<option value="6">6</option>
|
|
<option value="7">7</option>
|
|
<option value="8">8</option>
|
|
<option value="9">9</option>
|
|
<option value="10">10</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-3 px-1">
|
|
<div class="form-group">
|
|
<label>Ping @everyone on ticket open</label>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="pingeveryone" value="on" id="ping_everyone" style="width:30px;height:30px;">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-2 px-1">
|
|
<div class="form-group">
|
|
<label>Allow users to close tickets</label>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="userscanclose" value="on"
|
|
id="users_can_close" style="width:30px;height:30px;">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-2 px-1">
|
|
<div class="form-group">
|
|
<label>Ticket close confirmation</label>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" value="on"
|
|
id="close_confirmation" style="width:30px;height:30px;">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-2 px-1">
|
|
<div class="form-group">
|
|
<label>Enable modmail</label>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" value="on"
|
|
id="enable_modmail" style="width:30px;height:30px;">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-12">
|
|
<label>Welcome Message (Max len. 1000)
|
|
<i class="fas fa-question pointer" data-toggle="modal" data-target="#modal-substitutions"></i>
|
|
</label>
|
|
<textarea name="welcomeMessage" class="form-control" rows="3" id="welcome_message"></textarea>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-4 pr-1">
|
|
<label>Archive 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="archive_channel" id="archive_channel">
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-4 px-1">
|
|
<div class="form-group">
|
|
<label>Channel Category</label>
|
|
<select class="form-control" name="category" id="category">
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<label>Ticket Naming Scheme</label>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="namingscheme" id="naming-by-id" value="id">
|
|
<label class="form-check-label white" for="naming-by-id">
|
|
Ticket ID (#ticket-1)
|
|
</label>
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="namingscheme" id="naming-by-username"
|
|
value="username">
|
|
<label class="form-check-label white" for="naming-by-username">
|
|
Username (#ryan-1)
|
|
</label>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-md-2 pr-1">
|
|
<div class="form-group">
|
|
<button class="btn btn-primary btn-fill" type="submit"><i class="fas fa-paper-plane"></i>
|
|
Submit
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Claim settings -->
|
|
<div class="col-md-4">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Claim Settings</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<form onsubmit="updateClaimSettings(); return false;">
|
|
<div class="row">
|
|
<div class="col-md-6 pr-1">
|
|
<div class="form-group">
|
|
<label>Support Reps Can View Claimed Tickets</label>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="can_view" value="on" id="can_view" style="width:30px;height:30px;" onclick="canViewChanged();">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6 pr-1">
|
|
<div class="form-group">
|
|
<label>Support Reps Can Type In Claimed Tickets</label>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="can_type" value="on" id="can_type" style="width:30px;height:30px;">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row" style="padding-top: 20px">
|
|
<div class="col-md-12 pr-1">
|
|
<div class="form-group">
|
|
<button class="btn btn-primary btn-fill" type="submit"><i class="fas fa-paper-plane"></i>
|
|
Submit
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</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>
|
|
|
|
<div class="row">
|
|
<!-- Autoclose settings -->
|
|
<div class="col-md-8">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h4 class="card-title">Auto-Close</h4>
|
|
</div>
|
|
<div class="card-body">
|
|
<form onsubmit="updateAutoCloseSettings(); return false;">
|
|
<div class="row">
|
|
<div class="col-md-1 pr-1">
|
|
<div class="form-group">
|
|
<label>Enabled</label>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="enabled" value="on" id="autoclose_enabled" style="width:30px;height:30px;">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2 pr-1">
|
|
<div class="form-group">
|
|
<label>Close on user leave</label>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" name="enabled" value="on" id="autoclose_on_user_leave" style="width:30px;height:30px;">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-group">
|
|
<label>Time since open with no message</label>
|
|
<div class="row">
|
|
<div class="input-group col-md-4">
|
|
<input type="text" class="form-control" id="sinceopen_days">
|
|
<div class="input-group-append">
|
|
<div class="input-group-text">d</div>
|
|
</div>
|
|
</div>
|
|
<div class="input-group col-md-4">
|
|
<input type="text" class="form-control" id="sinceopen_hours">
|
|
<div class="input-group-append">
|
|
<div class="input-group-text">h</div>
|
|
</div>
|
|
</div>
|
|
<div class="input-group col-md-4">
|
|
<input type="text" class="form-control" id="sinceopen_minutes">
|
|
<div class="input-group-append">
|
|
<div class="input-group-text">m</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-4">
|
|
<div class="form-group">
|
|
<label>Time since last message</label>
|
|
<div class="row">
|
|
<div class="input-group col-md-4">
|
|
<input type="text" class="form-control" id="sincelast_days">
|
|
<div class="input-group-append">
|
|
<div class="input-group-text">d</div>
|
|
</div>
|
|
</div>
|
|
<div class="input-group col-md-4">
|
|
<input type="text" class="form-control" id="sincelast_hours">
|
|
<div class="input-group-append">
|
|
<div class="input-group-text">h</div>
|
|
</div>
|
|
</div>
|
|
<div class="input-group col-md-4">
|
|
<input type="text" class="form-control" id="sincelast_minutes">
|
|
<div class="input-group-append">
|
|
<div class="input-group-text">m</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row" style="padding-top: 20px">
|
|
<div class="col-md-2 pr-1">
|
|
<div class="form-group">
|
|
<button class="btn btn-primary btn-fill" type="submit"><i class="fas fa-paper-plane"></i>
|
|
Submit
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
async function getSettings() {
|
|
const res = await axios.get('/api/{{.guildId}}/settings');
|
|
return res.data;
|
|
}
|
|
|
|
async function getChannels() {
|
|
const res = await axios.get('/api/{{.guildId}}/channels');
|
|
return res.data;
|
|
}
|
|
|
|
async function fillArchiveChannels(channels, archiveChannelId) {
|
|
const container = document.getElementById('archive_channel');
|
|
channels.filter((ch) => ch.type === 0).forEach((ch) => {
|
|
const node = document.createElement("option");
|
|
const text = document.createTextNode(ch.name);
|
|
node.appendChild(text);
|
|
|
|
node.value = ch.id;
|
|
if (archiveChannelId === ch.id) {
|
|
node.selected = true;
|
|
}
|
|
|
|
|
|
container.appendChild(node);
|
|
});
|
|
}
|
|
|
|
async function fillCategories(channels, categoryId) {
|
|
const container = document.getElementById('category');
|
|
channels.filter((ch) => ch.type === 4).forEach((ch) => {
|
|
const node = document.createElement("option");
|
|
const text = document.createTextNode(ch.name);
|
|
node.appendChild(text);
|
|
|
|
node.value = ch.id;
|
|
if (categoryId === ch.id) {
|
|
node.selected = true;
|
|
}
|
|
|
|
container.appendChild(node);
|
|
});
|
|
}
|
|
|
|
async function loadData() {
|
|
const settings = await getSettings();
|
|
if (settings.ticket_limit < 1) {
|
|
settings.ticket_limit = 5;
|
|
}
|
|
|
|
document.getElementById("prefix").value = settings.prefix;
|
|
document.getElementById("welcome_message").value = settings.welcome_message;
|
|
document.getElementById("ticket_limit").selectedIndex = settings.ticket_limit - 1;
|
|
document.getElementById("ping_everyone").checked = settings.ping_everyone;
|
|
document.getElementById("users_can_close").checked = settings.users_can_close;
|
|
document.getElementById("close_confirmation").checked = settings.close_confirmation;
|
|
document.getElementById("enable_modmail").checked = settings.modmail_enabled;
|
|
|
|
if (settings.naming_scheme === "username") {
|
|
document.getElementById("naming-by-username").checked = true;
|
|
} else {
|
|
document.getElementById("naming-by-id").checked = true;
|
|
}
|
|
|
|
const channels = await getChannels();
|
|
await fillArchiveChannels(channels, settings.archive_channel);
|
|
await fillCategories(channels, settings.category);
|
|
}
|
|
|
|
loadData();
|
|
</script>
|
|
|
|
<script>
|
|
async function getClaimSettings() {
|
|
const res = await axios.get('/api/{{.guildId}}/claimsettings');
|
|
return res.data;
|
|
}
|
|
|
|
async function loadClaimSettings() {
|
|
const settings = await getClaimSettings();
|
|
document.getElementById('can_view').checked = settings.support_can_view;
|
|
document.getElementById('can_type').checked = settings.support_can_type;
|
|
}
|
|
|
|
loadClaimSettings();
|
|
|
|
async function updateClaimSettings() {
|
|
const data = {
|
|
support_can_view: document.getElementById('can_view').checked,
|
|
support_can_type: document.getElementById('can_type').checked
|
|
};
|
|
|
|
const res = await axios.post('/api/{{.guildId}}/claimsettings', data);
|
|
if (res.status === 200 && res.data.success) {
|
|
showToast("Success", "Your settings have been saved.");
|
|
} else {
|
|
showToast("Error", res.data.error);
|
|
}
|
|
}
|
|
|
|
function canViewChanged() {
|
|
const isChecked = document.getElementById('can_view').checked;
|
|
if (isChecked) {
|
|
document.getElementById('can_type').disabled = false;
|
|
} else {
|
|
document.getElementById('can_type').disabled = true;
|
|
document.getElementById('can_type').checked = false;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<script>
|
|
const minuteNanos = 60 * 1000 * 1000 * 1000;
|
|
const hourNanos = 60 * minuteNanos;
|
|
const dayNanos = 24 * hourNanos;
|
|
|
|
function fromNanoSeconds(nanoseconds) {
|
|
const days = Math.floor(nanoseconds / dayNanos);
|
|
nanoseconds -= (days * dayNanos);
|
|
|
|
const hours = Math.floor(nanoseconds / hourNanos);
|
|
nanoseconds -= (hours * hourNanos);
|
|
|
|
const minutes = Math.floor(nanoseconds / minuteNanos);
|
|
|
|
return [days, hours, minutes];
|
|
}
|
|
|
|
async function loadAutoCloseSettings() {
|
|
const res = await axios.get('/api/{{.guildId}}/autoclose');
|
|
const settings = res.data;
|
|
|
|
document.getElementById('autoclose_enabled').checked = settings.enabled;
|
|
document.getElementById('autoclose_on_user_leave').checked = settings.on_user_leave;
|
|
|
|
const sinceOpen = fromNanoSeconds(settings.since_open_with_no_response);
|
|
document.getElementById('sinceopen_days').value = sinceOpen[0];
|
|
document.getElementById('sinceopen_hours').value = sinceOpen[1];
|
|
document.getElementById('sinceopen_minutes').value = sinceOpen[2];
|
|
|
|
const sinceLast = fromNanoSeconds(settings.since_last_message);
|
|
document.getElementById('sincelast_days').value = sinceLast[0];
|
|
document.getElementById('sincelast_hours').value = sinceLast[1];
|
|
document.getElementById('sincelast_minutes').value = sinceLast[2];
|
|
}
|
|
|
|
function toNanoSeconds(days, hours, minutes) {
|
|
return days * dayNanos + hours * hourNanos + minutes * minuteNanos;
|
|
}
|
|
|
|
async function updateAutoCloseSettings() {
|
|
const data = {
|
|
enabled: document.getElementById('autoclose_enabled').checked,
|
|
on_user_leave: document.getElementById('autoclose_on_user_leave').checked,
|
|
since_open_with_no_response: toNanoSeconds(document.getElementById('sinceopen_days').value, document.getElementById('sinceopen_hours').value, document.getElementById('sinceopen_minutes').value),
|
|
since_last_message: toNanoSeconds(document.getElementById('sincelast_days').value, document.getElementById('sincelast_hours').value, document.getElementById('sincelast_minutes').value),
|
|
};
|
|
|
|
const res = await axios.post('/api/{{.guildId}}/autoclose', data);
|
|
if (res.status !== 200 || !res.data.success) {
|
|
showToast('Error', res.data.error);
|
|
return;
|
|
}
|
|
|
|
showToast('Success', 'Auto close settings updated');
|
|
}
|
|
|
|
loadAutoCloseSettings();
|
|
</script>
|
|
|
|
<script>
|
|
async function updateSettings() {
|
|
const data = {
|
|
'prefix': document.getElementById('prefix').value,
|
|
'welcome_message': document.getElementById("welcome_message").value,
|
|
'ticket_limit': parseInt(document.getElementById('ticket_limit').options[document.getElementById('ticket_limit').selectedIndex].value),
|
|
'ping_everyone': document.getElementById("ping_everyone").checked,
|
|
'users_can_close': document.getElementById("users_can_close").checked,
|
|
'close_confirmation': document.getElementById("close_confirmation").checked,
|
|
'naming_scheme': document.querySelector('input[name="namingscheme"]:checked').value,
|
|
'archive_channel': document.getElementById('archive_channel').options[document.getElementById('archive_channel').selectedIndex].value,
|
|
'category': document.getElementById('category').options[document.getElementById('category').selectedIndex].value,
|
|
'modmail_enabled': document.getElementById('enable_modmail').checked
|
|
};
|
|
|
|
const res = await axios.post('/api/{{.guildId}}/settings', data);
|
|
if (res.status === 200) {
|
|
const success = showValidations(res.data);
|
|
if (success) {
|
|
showToast("Success", "Your settings have been saved.");
|
|
}
|
|
} else {
|
|
showToast("Error", "A severe error occurred. Please check your console for more information.");
|
|
console.log(res);
|
|
}
|
|
}
|
|
|
|
function showValidations(data) {
|
|
let success = true;
|
|
|
|
if (!data.prefix) {
|
|
success = false;
|
|
showToast("Warning", "Your prefix has not been saved.<br />Prefixes must be between 1 - 8 characters in length.")
|
|
}
|
|
|
|
if (!data.welcome_message) {
|
|
success = false;
|
|
showToast("Warning", "Your welcome message has not been saved.<br />Welcome messages must be between 1 - 1000 characters in length.")
|
|
}
|
|
|
|
if (!data.ticket_limit) {
|
|
success = false;
|
|
showToast("Warning", "Your ticket limit has not been saved.<br />Ticket limits must be in the range 1 - 10.")
|
|
}
|
|
|
|
if (!data.archive_channel) {
|
|
success = false;
|
|
showToast("Warning", "Your archive channel has not been saved.")
|
|
}
|
|
|
|
if (!data.category) {
|
|
success = false;
|
|
showToast("Warning", "Your channel category has not been saved.")
|
|
}
|
|
|
|
if (!data.naming_scheme) {
|
|
success = false;
|
|
showToast("Warning", "Your archive channel has not been saved.")
|
|
}
|
|
|
|
return success;
|
|
}
|
|
</script>
|
|
</div>
|
|
{{end}}
|