/** * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter. * * Puter is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ import UIWindow from './UIWindow.js' import UIAlert from './UIAlert.js' function UIWindowEmailConfirmationRequired(options){ return new Promise(async (resolve) => { options = options ?? {}; let final_code = ''; let is_checking_code = false; const submit_btn_txt = 'Confirm Email' let h = ''; h += `
×
`; h += `
`; h += ``; h += `

Confirm Your Email Address

`; h += `
`; h += `

To continue, please enter the 6-digit confirmation code sent to ${window.user.email}

`; h += `
`; h += `
`; h += ``; h += `
`; h += `
`; h += `Re-send Confirmation Code`; if(options.logout_in_footer){ h += ` • `; h += `Log Out`; } h += `
`; h += `
`; const el_window = await UIWindow({ title: null, icon: null, uid: null, is_dir: false, body_content: h, has_head: false, selectable_body: false, draggable_body: true, allow_context_menu: false, is_draggable: options.is_draggable ?? true, is_droppable: false, is_resizable: false, stay_on_top: options.stay_on_top ?? false, allow_native_ctxmenu: true, allow_user_select: true, backdrop: true, width: 390, dominant: true, onAppend: function(el_window){ $(el_window).find('.digit-input').first().focus(); }, window_class: 'window-item-properties', window_css:{ height: 'initial', }, body_css: { padding: '30px', width: 'initial', height: 'initial', 'background-color': 'rgb(247 251 255)', 'backdrop-filter': 'blur(3px)', } }) $(el_window).find('.digit-input').first().focus(); $(el_window).find('.email-confirm-btn').on('click submit', function(e){ e.preventDefault(); e.stopPropagation(); $(el_window).find('.email-confirm-btn').prop('disabled', true); $(el_window).find('.error').hide(); // Check if already checking code to prevent multiple requests if(is_checking_code) return; // Confirm button is_checking_code = true; // set animation $(el_window).find('.email-confirm-btn').html(`circle anim`); setTimeout(() => { $.ajax({ url: api_origin + "/confirm-email", type: 'POST', data: JSON.stringify({ code: final_code, }), async: true, contentType: "application/json", headers: { "Authorization": "Bearer "+auth_token }, statusCode: { 401: function () { logout(); }, }, success: function (res){ if(res.email_confirmed){ $(el_window).close(); refresh_user_data(window.auth_token) resolve(true); }else{ $(el_window).find('.error').html('Invalid confirmation code.'); $(el_window).find('.error').fadeIn(); $(el_window).find('.digit-input').val(''); $(el_window).find('.digit-input').first().focus(); $(el_window).find('.email-confirm-btn').prop('disabled', false); $(el_window).find('.email-confirm-btn').html(submit_btn_txt); } }, error: function(res){ $(el_window).find('.error').html(res.responseJSON.error); $(el_window).find('.error').fadeIn(); $(el_window).find('.digit-input').val(''); $(el_window).find('.digit-input').first().focus(); $(el_window).find('.email-confirm-btn').prop('disabled', false); $(el_window).find('.email-confirm-btn').html(submit_btn_txt); }, complete: function(){ is_checking_code = false; } }) }, 1000); }) // send email confirmation $(el_window).find('.send-conf-email').on('click', function(e){ $.ajax({ url: api_origin + "/send-confirm-email", type: 'POST', async: true, contentType: "application/json", headers: { "Authorization": "Bearer "+auth_token }, statusCode: { 401: function () { logout(); }, }, success: async function (res){ await UIAlert({ message: `A new confirmation code has been sent to ${window.user.email}.`, body_icon: window.icons['c-check.svg'], stay_on_top: true, backdrop: true, }) $(el_window).find('.digit-input').first().focus(); }, complete: function(){ } }) }) // logout $(el_window).find('.conf-email-log-out').on('click', function(e){ logout(); $(el_window).close(); }) // Elements const numberCodeForm = document.querySelector('[data-number-code-form]'); const numberCodeInputs = [...numberCodeForm.querySelectorAll('[data-number-code-input]')]; // Event listeners numberCodeForm.addEventListener('input', ({ target }) => { if(!target.value.length) { return target.value = null; } const inputLength = target.value.length; let currentIndex = Number(target.dataset.numberCodeInput); if(inputLength === 2){ const inputValues = target.value.split(''); target.value = inputValues[0]; } else if (inputLength > 1) { const inputValues = target.value.split(''); inputValues.forEach((value, valueIndex) => { const nextValueIndex = currentIndex + valueIndex; if (nextValueIndex >= numberCodeInputs.length) { return; } numberCodeInputs[nextValueIndex].value = value; }); currentIndex += inputValues.length - 2; } const nextIndex = currentIndex + 1; if (nextIndex < numberCodeInputs.length) { numberCodeInputs[nextIndex].focus(); } // Concatenate all inputs into one string to create the final code final_code = ''; for(let i=0; i< numberCodeInputs.length; i++){ final_code += numberCodeInputs[i].value; } // Automatically submit if 6 digits entered if(final_code.length === 6){ $(el_window).find('.email-confirm-btn').prop('disabled', false); $(el_window).find('.email-confirm-btn').trigger('click'); } }); numberCodeForm.addEventListener('keydown', (e) => { const { code, target } = e; const currentIndex = Number(target.dataset.numberCodeInput); const previousIndex = currentIndex - 1; const nextIndex = currentIndex + 1; const hasPreviousIndex = previousIndex >= 0; const hasNextIndex = nextIndex <= numberCodeInputs.length - 1 switch (code) { case 'ArrowLeft': case 'ArrowUp': if (hasPreviousIndex) { numberCodeInputs[previousIndex].focus(); } e.preventDefault(); break; case 'ArrowRight': case 'ArrowDown': if (hasNextIndex) { numberCodeInputs[nextIndex].focus(); } e.preventDefault(); break; case 'Backspace': if (!e.target.value.length && hasPreviousIndex) { numberCodeInputs[previousIndex].value = null; numberCodeInputs[previousIndex].focus(); } break; default: break; } }); }) } export default UIWindowEmailConfirmationRequired