diff --git a/src/UI/Settings/UIWindowChangeEmail.js b/src/UI/Settings/UIWindowChangeEmail.js new file mode 100644 index 00000000..61f6a288 --- /dev/null +++ b/src/UI/Settings/UIWindowChangeEmail.js @@ -0,0 +1,129 @@ +/** + * 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' + +async function UIWindowChangeEmail(options){ + options = options ?? {}; + + const internal_id = window.uuidv4(); + let h = ''; + h += `
`; + // error msg + h += `
`; + // success msg + h += `
`; + // new email + h += `
`; + h += ``; + h += ``; + h += `
`; + + // Change Email + h += ``; + h += `
`; + + const el_window = await UIWindow({ + title: i18n('change_email'), + app: 'change-email', + single_instance: true, + icon: null, + uid: null, + is_dir: false, + body_content: h, + has_head: true, + selectable_body: false, + draggable_body: false, + allow_context_menu: false, + is_resizable: false, + is_droppable: false, + init_center: true, + allow_native_ctxmenu: false, + allow_user_select: false, + width: 350, + height: 'auto', + dominant: true, + show_in_taskbar: false, + onAppend: function(this_window){ + $(this_window).find(`.new-email`).get(0)?.focus({preventScroll:true}); + }, + window_class: 'window-publishWebsite', + body_css: { + width: 'initial', + height: '100%', + 'background-color': 'rgb(245 247 249)', + 'backdrop-filter': 'blur(3px)', + }, + ...options.window_options + }) + + $(el_window).find('.change-email-btn').on('click', function(e){ + // hide previous error/success msg + $(el_window).find('.form-success-msg, .form-success-msg').hide(); + + const new_email = $(el_window).find('.new-email').val(); + + if(!new_email){ + $(el_window).find('.form-error-msg').html(i18n('all_fields_required')); + $(el_window).find('.form-error-msg').fadeIn(); + return; + } + + $(el_window).find('.form-error-msg').hide(); + + // disable button + $(el_window).find('.change-email-btn').addClass('disabled'); + // disable input + $(el_window).find('.new-email').attr('disabled', true); + + $.ajax({ + url: api_origin + "/change_email/start", + type: 'POST', + async: true, + headers: { + "Authorization": "Bearer "+auth_token + }, + contentType: "application/json", + data: JSON.stringify({ + new_email: new_email, + }), + success: function (data){ + $(el_window).find('.form-success-msg').html(i18n('email_change_confirmation_sent')); + $(el_window).find('.form-success-msg').fadeIn(); + $(el_window).find('input').val(''); + // update email + window.user.email = new_email; + // enable button + $(el_window).find('.change-email-btn').removeClass('disabled'); + // enable input + $(el_window).find('.new-email').attr('disabled', false); + }, + error: function (err){ + $(el_window).find('.form-error-msg').html(html_encode(err.responseJSON?.message)); + $(el_window).find('.form-error-msg').fadeIn(); + // enable button + $(el_window).find('.change-email-btn').removeClass('disabled'); + // enable input + $(el_window).find('.new-email').attr('disabled', false); + } + }); + }) +} + +export default UIWindowChangeEmail \ No newline at end of file diff --git a/src/UI/Settings/UIWindowConfirmUserDeletion.js b/src/UI/Settings/UIWindowConfirmUserDeletion.js index b4b85a65..41b0f390 100644 --- a/src/UI/Settings/UIWindowConfirmUserDeletion.js +++ b/src/UI/Settings/UIWindowConfirmUserDeletion.js @@ -63,6 +63,7 @@ async function UIWindowConfirmUserDeletion(options){ backgroundColor: 'white', color: 'black', }, + ...options.window_options, }); $(el_window).find('.generic-close-window-button').on('click', function(){ diff --git a/src/UI/Settings/UIWindowSettings.js b/src/UI/Settings/UIWindowSettings.js index d7ecab01..1b2c9a23 100644 --- a/src/UI/Settings/UIWindowSettings.js +++ b/src/UI/Settings/UIWindowSettings.js @@ -19,8 +19,7 @@ import UIWindow from '../UIWindow.js' import UIWindowChangePassword from '../UIWindowChangePassword.js' -// import UIWindowChangeEmail from './UIWindowChangeEmail.js' -// import UIWindowDeleteAccount from './UIWindowDeleteAccount.js' +import UIWindowChangeEmail from './UIWindowChangeEmail.js' import UIWindowChangeUsername from '../UIWindowChangeUsername.js' import changeLanguage from "../../i18n/i18nChangeLanguage.js" import UIWindowConfirmUserDeletion from './UIWindowConfirmUserDeletion.js'; @@ -98,7 +97,7 @@ async function UIWindowSettings(options){ h += `
`; h += `
`; h += `${i18n('email')}`; - h += `${user.email}`; + h += `${user.email}`; h += `
`; h += `
`; h += ``; @@ -106,14 +105,6 @@ async function UIWindowSettings(options){ h += `
`; } - // 'Delete Account' button - h += `
`; - h += `${i18n("delete_account")}`; - h += `
`; - h += ``; - h += `
`; - h += `
`; - // session manager h += `
`; h += `${i18n('sessions')}`; @@ -122,6 +113,14 @@ async function UIWindowSettings(options){ h += `
`; h += `
`; + // 'Delete Account' button + h += `
`; + h += `${i18n("delete_account")}`; + h += `
`; + h += ``; + h += `
`; + h += `
`; + h += ``; // Personalization @@ -332,27 +331,64 @@ async function UIWindowSettings(options){ }) $(el_window).find('.change-password').on('click', function (e) { - UIWindowChangePassword(); + UIWindowChangePassword({ + window_options:{ + parent_uuid: $(el_window).attr('data-element_uuid'), + disable_parent_window: true, + parent_center: true, + } + }); }) $(el_window).find('.change-email').on('click', function (e) { - UIWindowChangeEmail(); + console.log('change email', $(el_window).attr('data-element_uuid')); + UIWindowChangeEmail({ + window_options:{ + parent_uuid: $(el_window).attr('data-element_uuid'), + disable_parent_window: true, + parent_center: true, + } + }); }) $(el_window).find('.delete-account').on('click', function (e) { - UIWindowConfirmUserDeletion(); + UIWindowConfirmUserDeletion({ + window_options:{ + parent_uuid: $(el_window).attr('data-element_uuid'), + disable_parent_window: true, + parent_center: true, + } + }); }) $(el_window).find('.change-username').on('click', function (e) { - UIWindowChangeUsername(); + UIWindowChangeUsername({ + window_options:{ + parent_uuid: $(el_window).attr('data-element_uuid'), + disable_parent_window: true, + parent_center: true, + } + }); }) $(el_window).find('.change-ui-colors').on('click', function (e) { - UIWindowThemeDialog(); + UIWindowThemeDialog({ + window_options:{ + parent_uuid: $(el_window).attr('data-element_uuid'), + disable_parent_window: true, + parent_center: true, + } + }); }) $(el_window).find('.manage-sessions').on('click', function (e) { - UIWindowManageSessions(); + UIWindowManageSessions({ + window_options:{ + parent_uuid: $(el_window).attr('data-element_uuid'), + disable_parent_window: true, + parent_center: true, + } + }); }) $(el_window).on('click', '.settings-sidebar-item', function(){ diff --git a/src/UI/UIDesktop.js b/src/UI/UIDesktop.js index 182abb76..d73f918c 100644 --- a/src/UI/UIDesktop.js +++ b/src/UI/UIDesktop.js @@ -332,6 +332,14 @@ async function UIDesktop(options){ refresh_user_data(window.auth_token); }); + socket.on('user.email_changed', (msg) => { + // don't update if this is the original client that initiated the action + if(msg.original_client_socket_id === window.socket.id) + return; + + refresh_user_data(window.auth_token); + }); + socket.on('item.renamed', async (item) => { // Notify all apps that are watching this item sendItemChangeEventToWatchingApps(item.uid, { diff --git a/src/UI/UIWindow.js b/src/UI/UIWindow.js index 0fc8a887..7274e243 100644 --- a/src/UI/UIWindow.js +++ b/src/UI/UIWindow.js @@ -520,6 +520,25 @@ async function UIWindow(options) { }); } + // ===================================== + // Center relative to parent window + // ===================================== + if(options.parent_center && options.parent_uuid){ + const $parent_window = $(`.window[data-element_uuid="${options.parent_uuid}"]`); + const parent_window_width = $parent_window.width(); + const parent_window_height = $parent_window.height(); + const parent_window_left = $parent_window.offset().left; + const parent_window_top = $parent_window.offset().top; + const window_height = $(el_window).height(); + const window_width = $(el_window).width(); + options.left = parent_window_left + parent_window_width/2 - window_width/2; + options.top = parent_window_top + parent_window_height/2 - window_height/2; + $(el_window).css({ + 'left': options.left + 'px', + 'top': options.top + 'px', + }); + } + // onAppend() - using show() is a hack to make sure window is visible AND onAppend is called when // window is actually appended and usable. // NOTE: there is another is_visible condition below diff --git a/src/UI/UIWindowChangePassword.js b/src/UI/UIWindowChangePassword.js index a04ffa58..10c33474 100644 --- a/src/UI/UIWindowChangePassword.js +++ b/src/UI/UIWindowChangePassword.js @@ -19,7 +19,9 @@ import UIWindow from './UIWindow.js' -async function UIWindowChangePassword(){ +async function UIWindowChangePassword(options){ + options = options ?? {}; + const internal_id = window.uuidv4(); let h = ''; h += `
`; @@ -77,7 +79,8 @@ async function UIWindowChangePassword(){ height: '100%', 'background-color': 'rgb(245 247 249)', 'backdrop-filter': 'blur(3px)', - } + }, + ...options.window_options, }) $(el_window).find('.change-password-btn').on('click', function(e){ diff --git a/src/UI/UIWindowChangeUsername.js b/src/UI/UIWindowChangeUsername.js index 4fa2bb7e..dadf9d01 100644 --- a/src/UI/UIWindowChangeUsername.js +++ b/src/UI/UIWindowChangeUsername.js @@ -20,7 +20,9 @@ import UIWindow from './UIWindow.js' import update_username_in_gui from '../helpers/update_username_in_gui.js' -async function UIWindowChangeUsername(){ +async function UIWindowChangeUsername(options){ + options = options ?? {}; + const internal_id = window.uuidv4(); let h = ''; h += `
`; @@ -68,7 +70,8 @@ async function UIWindowChangeUsername(){ height: '100%', 'background-color': 'rgb(245 247 249)', 'backdrop-filter': 'blur(3px)', - } + }, + ...options.window_options, }) $(el_window).find('.change-username-btn').on('click', function(e){ diff --git a/src/UI/UIWindowManageSessions.js b/src/UI/UIWindowManageSessions.js index b985f8cb..11f631bb 100644 --- a/src/UI/UIWindowManageSessions.js +++ b/src/UI/UIWindowManageSessions.js @@ -1,7 +1,9 @@ import UIAlert from "./UIAlert.js"; import UIWindow from "./UIWindow.js"; -const UIWindowManageSessions = async function UIWindowManageSessions () { +const UIWindowManageSessions = async function UIWindowManageSessions (options) { + options = options ?? {}; + const services = globalThis.services; const w = await UIWindow({ @@ -21,8 +23,7 @@ const UIWindowManageSessions = async function UIWindowManageSessions () { dominant: true, body_content: '', // width: 600, - // parent_uuid: options.parent_uuid, - // ...options.window_options, + ...options.window_options, }); const SessionWidget = ({ session }) => { diff --git a/src/UI/UIWindowSessionList.js b/src/UI/UIWindowSessionList.js index fb128452..a0d8bdb9 100644 --- a/src/UI/UIWindowSessionList.js +++ b/src/UI/UIWindowSessionList.js @@ -74,7 +74,7 @@ async function UIWindowSessionList(options){ 'display': 'flex', 'flex-direction': 'column', 'justify-content': 'center', - } + }, }) $(el_window).find('.login-c2a-session-list').on('click', async function(e){ const login = await UIWindowLogin({ diff --git a/src/UI/UIWindowThemeDialog.js b/src/UI/UIWindowThemeDialog.js index 5f507daa..3932d183 100644 --- a/src/UI/UIWindowThemeDialog.js +++ b/src/UI/UIWindowThemeDialog.js @@ -1,6 +1,7 @@ import UIWindow from "./UIWindow.js"; -const UIWindowThemeDialog = async function UIWindowThemeDialog () { +const UIWindowThemeDialog = async function UIWindowThemeDialog (options) { + options = options ?? {}; const services = globalThis.services; const svc_theme = services.get('theme'); @@ -43,7 +44,8 @@ const UIWindowThemeDialog = async function UIWindowThemeDialog () { var(--primary-alpha))`, 'backdrop-filter': 'blur(3px)', - } + }, + ...options.window_options, }); const w_body = w.querySelector('.window-body'); diff --git a/src/helpers.js b/src/helpers.js index ebbe9f1c..aa23d499 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -667,6 +667,11 @@ window.update_auth_data = (auth_token, user)=>{ if(window.user?.username !== user.username) update_username_in_gui(user.username); + // Has email changed? + if(window.user?.email !== user.email && user.email){ + $('.user-email').html(user.email); + } + // update this session's user data window.user = user; localStorage.setItem('user', JSON.stringify(window.user)); diff --git a/src/i18n/translations/en.js b/src/i18n/translations/en.js index 8e2c5c3a..f5b8eff4 100644 --- a/src/i18n/translations/en.js +++ b/src/i18n/translations/en.js @@ -83,6 +83,7 @@ const en = { download_file: 'Download File', downloading: "Downloading", email: "Email", + email_change_confirmation_sent: "A confirmation email has been sent to your new email address. Please check your inbox and follow the instructions to complete the process.", email_or_username: "Email or Username", empty_trash: 'Empty Trash', empty_trash_confirmation: `Are you sure you want to permanently delete the items in Trash?`, @@ -125,6 +126,7 @@ const en = { name_must_be_string: "Name can only be a string.", name_too_long: `Name can not be longer than %% characters.`, new: 'New', + new_email: 'New Email', new_folder: 'New folder', new_password: "New Password", new_username: "New Username", diff --git a/src/index.js b/src/index.js index 6bb56651..7e7b962c 100644 --- a/src/index.js +++ b/src/index.js @@ -46,10 +46,10 @@ window.puter_gui_enabled = true; window.gui = async function(options){ options = options ?? {}; // app_origin is deprecated, use gui_origin instead - window.gui_origin = options.gui_origin ?? options.app_origin ?? `https://puter.com`; + window.gui_origin = `https://puter.com`; window.app_domain = options.app_domain ?? new URL(window.gui_origin).hostname; window.hosting_domain = options.hosting_domain ?? 'puter.site'; - window.api_origin = options.api_origin ?? "https://api.puter.com"; + window.api_origin = "https://api.puter.com"; window.max_item_name_length = options.max_item_name_length ?? 500; window.require_email_verification_to_publish_website = options.require_email_verification_to_publish_website ?? true; diff --git a/src/initgui.js b/src/initgui.js index 5c156975..9bf42784 100644 --- a/src/initgui.js +++ b/src/initgui.js @@ -35,7 +35,6 @@ import update_title_based_on_uploads from './helpers/update_title_based_on_uploa import PuterDialog from './UI/PuterDialog.js'; import determine_active_container_parent from './helpers/determine_active_container_parent.js'; import { ThemeService } from './services/ThemeService.js'; -import UIWindowThemeDialog from './UI/UIWindowThemeDialog.js'; import { BroadcastService } from './services/BroadcastService.js'; const launch_services = async function () {