let colorPicker = new iro.ColorPicker('#colorpicker'); let $discordFrame; const $loader = document.querySelector('#loader'); const $colorPickerModal = document.querySelector('div#pickColorModal'); const $colorPickerInput = $colorPickerModal.querySelector('input'); let timezone = luxon.DateTime.now().zone.name; const browserTimezone = luxon.DateTime.now().zone.name; let botTimezone = 'UTC'; let channels; let roles; function colorToInt(r, g, b) { return (r << 16) + (g << 8) + (b); } function resize_textareas() { document.querySelectorAll('textarea.autoresize').forEach((element) => { element.style.height = ""; element.style.height = element.scrollHeight + 3 + "px"; element.addEventListener('input', () => { element.style.height = ""; element.style.height = element.scrollHeight + 3 + "px"; }); }); } function switch_pane(selector) { document.querySelectorAll('aside a').forEach((el) => { el.classList.remove('is-active'); }); document.querySelectorAll('div.is-main-content > section').forEach((el) => { el.classList.add('is-hidden'); }); document.getElementById(selector).classList.remove('is-hidden'); resize_textareas(); } function update_select(sel) { if (sel.selectedOptions[0].dataset['webhookAvatar']) { sel .closest('div.reminderContent') .querySelector('img.discord-avatar') .src = sel.selectedOptions[0].dataset['webhookAvatar']; } else { sel .closest('div.reminderContent') .querySelector('img.discord-avatar') .src = ''; } if (sel.selectedOptions[0].dataset['webhookName']) { sel .closest('div.reminderContent') .querySelector('input.discord-username') .value = sel.selectedOptions[0].dataset['webhookName']; } else { sel .closest('div.reminderContent') .querySelector('input.discord-username') .value = ''; } } function reset_guild_pane() { document.querySelectorAll('select.channel-selector option').forEach((opt) => opt.remove()); } function fetch_roles(guild_id) { fetch(`/dashboard/api/guild/${guild_id}/roles`) .then(response => response.json()) .then(data => { if (data.error) { show_error(data.error); } else { roles = data; } }) } async function fetch_reminders(guild_id) { // fetch dm reminders instead if (guild_id === undefined) { const $reminderBox = document.querySelector('div#personalReminders'); // reset div contents $reminderBox.innerHTML = ''; // fetch reminders await fetch('dashboard/api/user/reminders') .then(response => response.json()) .then(data => { if (data.error) { show_error(data.error); } else { const $template = document.querySelector('template#personalReminder'); for (let reminder of data) { let newFrame = $template.content.cloneNode(true); for (let prop in reminder) { if (reminder.hasOwnProperty(prop) && reminder[prop] !== null) { let $input = newFrame.querySelector(`*[name="${prop}"]`); let $image = newFrame.querySelector(`img.${prop}`); if ($input !== null) { $input.value = reminder[prop]; } else if ($image !== null) { $image.src = reminder[prop]; } } } $reminderBox.append(newFrame); } } }); } else { const $reminderBox = document.querySelector('div#guildReminders'); // reset div contents $reminderBox.innerHTML = ''; // fetch reminders await fetch(`dashboard/api/guild/${guild_id}/reminders`) .then(response => response.json()) .then(data => { if (data.error) { show_error(data.error); } else { console.log(data); const $template = document.querySelector('template#guildReminder'); for (let reminder of data) { let newFrame = $template.content.cloneNode(true); // populate channels set_channels(newFrame.querySelector('select.channel-selector')) // populate majority of items for (let prop in reminder) { if (reminder.hasOwnProperty(prop) && reminder[prop] !== null) { let $input = newFrame.querySelector(`*[name="${prop}"]`); let $image = newFrame.querySelector(`img.${prop}`); if ($input !== null) { $input.value = reminder[prop]; } else if ($image !== null) { $image.src = reminder[prop]; } } } let timeInput = newFrame.querySelector('input[name="time"]'); let localTime = luxon.DateTime.fromISO(reminder["utc_time"]).setZone(timezone); timeInput.value = localTime.toFormat("yyyy-LL-dd'T'HH:mm:ss"); $reminderBox.appendChild(newFrame); } } }); } register_interval_hide(); } function show_error(error) { document.getElementById('errors').querySelector('span.error-message').textContent = error; document.getElementById('errors').classList.add('is-active'); window.setTimeout(() => { document.getElementById('errors').classList.remove('is-active'); }, 5000); } function update_times() { document.querySelectorAll('span.set-timezone').forEach((element) => { element.textContent = timezone; }); document.querySelectorAll('span.set-time').forEach((element) => { element.textContent = luxon.DateTime.now().setZone(timezone).toFormat('HH:mm'); }); document.querySelectorAll('span.browser-timezone').forEach((element) => { element.textContent = browserTimezone; }); document.querySelectorAll('span.browser-time').forEach((element) => { element.textContent = luxon.DateTime.now().toFormat('HH:mm'); }); document.querySelectorAll('span.bot-timezone').forEach((element) => { element.textContent = botTimezone; }); document.querySelectorAll('span.bot-time').forEach((element) => { element.textContent = luxon.DateTime.now().setZone(botTimezone).toFormat('HH:mm'); }); } window.setInterval(() => { update_times(); }, 30000) document.getElementById('set-bot-timezone').addEventListener('click', () => { timezone = botTimezone; update_times(); }); document.getElementById('set-browser-timezone').addEventListener('click', () => { timezone = browserTimezone; update_times(); }); document.getElementById('update-bot-timezone').addEventListener('click', () => { timezone = browserTimezone; fetch('/dashboard/api/user', { method: 'PATCH', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify({timezone: timezone}) }) .then(response => response.json()) .then(data => { if (data.error) { show_error(data.error) } else { botTimezone = browserTimezone; update_times(); } }); }); $colorPickerInput.value = colorPicker.color.hexString; $colorPickerInput.addEventListener('input', () => { if (/^#[0-9a-fA-F]{6}$/.test($colorPickerInput.value) === true) { colorPicker.color.hexString = $colorPickerInput.value; } }); colorPicker.on('color:change', function (color) { $colorPickerInput.value = color.hexString; }); document.querySelectorAll('.discord-embed').forEach((element) => { element.addEventListener('click', (e) => { if (e.offsetX < parseInt(window.getComputedStyle(element).borderLeftWidth)) { $discordFrame = element; $colorPickerModal.classList.toggle('is-active'); colorPicker.color.rgbString = window.getComputedStyle($discordFrame).borderLeftColor; } }) }); document.querySelectorAll('.set-color').forEach((element) => { element.addEventListener('click', (e) => { e.preventDefault(); $discordFrame = element.closest('div.reminderContent').querySelector('div.discord-embed'); $colorPickerModal.classList.toggle('is-active'); colorPicker.color.rgbString = window.getComputedStyle($discordFrame).borderLeftColor; }) }); $colorPickerModal.querySelector('button.is-success').addEventListener('click', () => { $discordFrame.style.borderLeftColor = colorPicker.color.rgbString; $colorPickerModal.classList.remove('is-active') }); document.querySelectorAll('a.show-modal').forEach((element) => { element.addEventListener('click', (e) => { e.preventDefault(); document.getElementById(element.dataset['modal']).classList.toggle('is-active'); }) }) document.addEventListener('DOMContentLoaded', () => { $loader.classList.remove('is-hidden'); document.querySelectorAll('.navbar-burger').forEach(el => { el.addEventListener('click', () => { const target = el.dataset.target; const $target = document.getElementById(target); el.classList.toggle('is-active'); $target.classList.toggle('is-active'); }); }); fetch('/dashboard/api/user') .then(response => response.json()) .then(data => { if (data.error) { show_error(data.error); } else { document.querySelectorAll('a.switch-pane').forEach((element) => { element.innerHTML = element.innerHTML.replace('%username%', data.name); element.addEventListener('click', (e) => { e.preventDefault(); switch_pane(element.dataset['pane']); element.classList.add('is-active'); document.querySelectorAll('p.pageTitle').forEach((el) => { el.textContent = 'Your Reminders'; }); }); }); if (data.timezone !== null) { botTimezone = data.timezone; } update_times(); } }); fetch('/dashboard/api/user/guilds') .then(response => response.json()) .then(data => { if (data.error) { show_error(data.error); } else { const $template = document.getElementById('guildListEntry'); for (let guild of data) { document.querySelectorAll('.guildList').forEach((element) => { const $clone = $template.content.cloneNode(true); const $anchor = $clone.querySelector('a'); $anchor.innerHTML = $clone.querySelector('a').innerHTML.replace('%guildname%', guild.name); $anchor.dataset['guild'] = guild.id; $anchor.dataset['name'] = guild.name; $anchor.addEventListener('click', async (e) => { e.preventDefault(); $loader.classList.remove('is-hidden'); switch_pane($anchor.dataset['pane']); reset_guild_pane(); fetch_roles($anchor.dataset['guild']); await fetch(`/dashboard/api/guild/${$anchor.dataset['guild']}/channels`) .then(response => response.json()) .then(data => { if (data.error) { if (data.error === "Bot not in guild") { switch_pane('guild-error'); } else { show_error(data.error); } } else { channels = data; document.querySelectorAll('select.channel-selector').forEach(set_channels); } }); fetch_reminders($anchor.dataset['guild']); document.querySelectorAll('p.pageTitle').forEach((el) => { el.textContent = $anchor.dataset['name'] + ' Reminders'; }); document.querySelectorAll('select.channel-selector').forEach((el) => { el.addEventListener('change', (e) => { update_select(e.target); }) }); $anchor.classList.add('is-active'); resize_textareas(); $loader.classList.add('is-hidden'); }); element.append($clone); }); } } }); $loader.classList.add('is-hidden'); }); function set_channels(element) { for (let channel of channels) { let newOption = document.createElement('option'); newOption.value = channel.id; newOption.textContent = channel.name; if (channel.webhook_avatar !== null) { newOption.dataset['webhookAvatar'] = channel.webhook_avatar; } if (channel.webhook_name !== null) { newOption.dataset['webhookName'] = channel.webhook_name; } element.appendChild(newOption); } update_select(element); } let $createReminder = document.querySelector('#reminderCreator'); $createReminder.querySelector('button#createReminder').addEventListener('click', () => { // create reminder object let seconds = parseInt($createReminder.querySelector('input[name="interval_seconds"]').value) || null; let months = parseInt($createReminder.querySelector('input[name="interval_months"]').value) || null; let rgb_color = window.getComputedStyle($createReminder.querySelector('div.discord-embed')).borderLeftColor; let rgb = rgb_color.match(/\d+/g); let color = colorToInt(parseInt(rgb[0]), parseInt(rgb[1]), parseInt(rgb[2])); let utc_time = luxon.DateTime.fromISO($createReminder.querySelector('input[name="time"]').value).setZone('UTC'); let reminder = { avatar: $createReminder.querySelector('img.discord-avatar').src, channel: $createReminder.querySelector('select.channel-selector').value, content: $createReminder.querySelector('textarea#messageContent').value, embed_author_url: $createReminder.querySelector('img.embed_author_url').src, embed_author: $createReminder.querySelector('textarea#embedAuthor').value, embed_color: color, embed_description: $createReminder.querySelector('textarea#embedDescription').value, embed_footer: $createReminder.querySelector('textarea#embedFooter').value, embed_footer_url: $createReminder.querySelector('img.embed_footer_url').src, embed_image_url: $createReminder.querySelector('img.embed_image_url').src, embed_thumbnail_url: $createReminder.querySelector('img.embed_thumbnail_url').src, embed_title: $createReminder.querySelector('textarea#embedTitle').value, enabled: true, expires: null, interval_seconds: seconds, interval_months: months, name: $createReminder.querySelector('input[name="name"]').value, pin: $createReminder.querySelector('input[name="pin"]').checked, restartable: false, tts: $createReminder.querySelector('input[name="tts"]').checked, username: $createReminder.querySelector('input#reminderUsername').value, utc_time: utc_time.toFormat("yyyy-LL-dd'T'HH:mm:ss") } // send to server let guild = document.querySelector('.guildList a.is-active').dataset['guild']; fetch(`/dashboard/api/guild/${guild}/reminders`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(reminder) }).then(response => response.json()).then(data => console.log(data)) // process response // reset inputs }); document.querySelectorAll('textarea.autoresize').forEach((element) => { element.addEventListener('input', () => { element.style.height = ""; element.style.height = element.scrollHeight + 3 + "px"; }); }); let $img; const $urlModal = document.querySelector('div#addImageModal'); const $urlInput = $urlModal.querySelector('input'); $urlModal.querySelector('button.is-success').addEventListener('click', () => { $img.src = $urlInput.value; $urlInput.value = ''; $urlModal.classList.remove('is-active') }); document.querySelectorAll('button.close-modal').forEach((element) => { element.addEventListener('click', () => { let $modal = element.closest('div.modal'); $urlInput.value = ''; $modal.classList.remove('is-active') }); }); document.querySelectorAll('.customizable').forEach((element) => { element.querySelector('a').addEventListener('click', (e) => { e.preventDefault(); $img = element.querySelector('img'); $urlModal.classList.toggle('is-active') }); }); document.querySelectorAll('a.icon-toggle').forEach((element) => { element.addEventListener('click', (e) => { e.preventDefault(); element.classList.toggle('is-active'); }) }); let $showButton = document.querySelector('button#showReminderCreator'); $showButton.addEventListener('click', () => { $showButton.querySelector('span.icon i').classList.toggle('fa-chevron-right'); $showButton.querySelector('span.icon i').classList.toggle('fa-chevron-down'); document.querySelector('div#reminderCreator').classList.toggle('is-hidden'); }); function register_interval_hide() { let $showInterval = document.querySelectorAll('a.intervalLabel'); $showInterval.forEach((element) => { element.addEventListener('click', () => { element.querySelector('i').classList.toggle('fa-chevron-right'); element.querySelector('i').classList.toggle('fa-chevron-down'); element.nextElementSibling.classList.toggle('is-hidden'); }); }); } const fileInput = document.querySelectorAll('input[type=file]'); fileInput.forEach((element) => { element.addEventListener('change', () => { if (element.files.length > 0) { const fileName = element.parentElement.querySelector('.file-label'); fileName.textContent = element.files[0].name; } }) }); function check_embed_fields() { document.querySelectorAll('.discord-field-title').forEach((element) => { const $template = document.querySelector('template#embedFieldTemplate'); const $complement = element.parentElement.querySelector('.discord-field-value'); // when the user clicks out of the field title and if the field title/value are empty, remove the field element.addEventListener('blur', () => { if (element.value === '' && $complement.value === '' && element.parentElement.nextElementSibling !== null) { element.parentElement.remove(); } }); $complement.addEventListener('blur', () => { if (element.value === '' && $complement.value === '' && element.parentElement.nextElementSibling !== null) { element.parentElement.remove(); } }); // when the user inputs into the end field, create a new field after it element.addEventListener('input', () => { if (element.value !== '' && $complement.value !== '' && element.parentElement.nextElementSibling === null) { const $clone = $template.content.cloneNode(true); element.parentElement.parentElement.append($clone); } }); $complement.addEventListener('input', () => { if (element.value !== '' && $complement.value !== '' && element.parentElement.nextElementSibling === null) { const $clone = $template.content.cloneNode(true); element.parentElement.parentElement.append($clone); } }); }); } document.addEventListener('DOMNodeInserted', () => { document.querySelectorAll('div.mobile-sidebar a').forEach((element) => { element.addEventListener('click', (e) => { document.getElementById('mobileSidebar').classList.remove('is-active'); document.querySelectorAll('.navbar-burger').forEach((el) => { el.classList.remove('is-active'); }); }); }); check_embed_fields(); resize_textareas(); });