UNPKG

@underpostnet/underpost

Version:
315 lines (302 loc) 12.5 kB
import { UserService } from '../../services/user/user.service.js'; import { Auth } from './Auth.js'; import { BtnIcon } from './BtnIcon.js'; import { newInstance, s4 } from './CommonJs.js'; import { renderStatus, renderWave } from './Css.js'; import { EventsUI } from './EventsUI.js'; import { fileFormDataFactory, Input } from './Input.js'; import { LogIn } from './LogIn.js'; import { Modal } from './Modal.js'; import { NotificationManager } from './NotificationManager.js'; import { Translate } from './Translate.js'; import { Validator } from './Validator.js'; import { append, htmls, s } from './VanillaJs.js'; const Account = { UpdateEvent: {}, Render: async function (options = { user: {}, bottomRender: async () => '', idModal: '' }) { // app profile page design example // CSS animated backgrounds let { user, idModal } = options; const waveAnimationId = 'account-wave'; const profileFileAccept = ['image/png', 'image/jpeg']; setTimeout(async () => { append( `.wave-animation-container-${waveAnimationId}`, html` <div class="abs center account-profile-image-container"> <img class="abs center account-profile-image" style="opacity: 1" ${LogIn.Scope.user.main.model.user.profileImage ? `src="${LogIn.Scope.user.main.model.user.profileImage.imageSrc}"` : ''} /> </div> <div class="abs center account-profile-image-loading" style="color: white"></div>`, ); const formData = [ { model: 'username', id: `account-username`, rules: [{ type: 'isEmpty' }, { type: 'isLength', options: { min: 2, max: 20 } }], }, { model: 'email', id: `account-email`, rules: [{ type: 'isEmpty' }, { type: 'isEmail' }] }, { model: 'password', defaultValue: '*******', id: `account-password`, rules: [{ type: 'isStrongPassword' }], }, ]; this.formData = formData; this.instanceModalUiEvents = async ({ user }) => { const validators = await Validator.instance(formData); for (const inputData of formData) { s(`.${inputData.id}`).value = !user[inputData.model] && inputData.defaultValue ? inputData.defaultValue : user[inputData.model]; } let lastUser; const submit = async () => { lastUser = newInstance(user); const { successKeys } = await validators(); if (successKeys.length === 0) return; const body = {}; for (const inputData of formData) { if (!s(`.${inputData.id}`).value || s(`.${inputData.id}`).value === 'undefined') continue; if ('model' in inputData && successKeys.includes(inputData.id)) { body[inputData.model] = s(`.${inputData.id}`).value; user[inputData.model] = s(`.${inputData.id}`).value; } } const result = await UserService.put({ id: user._id, body }); NotificationManager.Push({ html: result.status === 'error' && result.message ? result.message : Translate.Render(`${result.status}-update-user`), status: result.status, }); if (result.status === 'success') { user = result.data; this.triggerUpdateEvent({ user }); if (lastUser.emailConfirmed !== user.emailConfirmed) { this.renderVerifyEmailStatus(user); } lastUser = newInstance(user); } }; EventsUI.onClick(`.btn-account`, async (e) => { e.preventDefault(); await submit(); }); EventsUI.onClick(`.btn-account-update-username`, async (e) => { e.preventDefault(); await submit(); }); if (s(`.btn-confirm-email`)) EventsUI.onClick(`.btn-confirm-email`, async (e) => { e.preventDefault(); const result = await UserService.post({ id: 'mailer/verify-email', body: { email: s(`.account-email`).value }, }); NotificationManager.Push({ html: result.status === 'error' ? result.message : Translate.Render(`email send`), status: result.status, }); }); this.renderVerifyEmailStatus(user); s(`.${waveAnimationId}`).style.cursor = 'pointer'; s(`.${waveAnimationId}`).onclick = async (e) => { e.preventDefault(); s(`.account-profile-image-input`).click(); }; EventsUI.onChange( `.account-profile-image-input`, async (e) => { e.preventDefault(); s(`.account-profile-image`).style.opacity = 0; const formFile = fileFormDataFactory(e, profileFileAccept); const { status, data } = await UserService.put({ id: `profile-image/${user._id}`, body: formFile, headerId: 'file', }); if (status === 'success') { user.profileImageId = data.profileImageId; delete LogIn.Scope.user.main.model.user.profileImage; await LogIn.Trigger({ user }); s(`.account-profile-image`).src = LogIn.Scope.user.main.model.user.profileImage.imageSrc; } else { NotificationManager.Push({ html: Translate.Render('file-upload-failed'), status: 'error', }); } s(`.account-profile-image`).style.opacity = 1; }, { loadingContainer: `.account-profile-image-loading` }, ); s(`.btn-account-change-password`).onclick = (e) => { e.preventDefault(); // s(`.btn-close-modal-account`).click(); s(`.main-btn-recover`).click(); }; EventsUI.onClick( `.btn-account-delete-confirm`, async (e) => { e.preventDefault(); const confirmResult = await Modal.RenderConfirm({ html: async () => { return html` <div class="in section-mp" style="text-align: center"> ${Translate.Render('confirm-delete-account')} </div> `; }, id: 'delete-account-modal', }); if (confirmResult.status === 'cancelled') return; s(`.btn-account-delete-confirm`).classList.add('hide'); s(`.btn-account-delete`).classList.remove('hide'); s(`.btn-account-delete`).click(); }, { context: 'modal' }, ); EventsUI.onClick(`.btn-account-delete`, async (e) => { e.preventDefault(); const result = await UserService.delete({ id: user._id }); NotificationManager.Push({ html: result.status === 'error' ? result.message : Translate.Render(`success-delete-account`), status: result.status, }); s(`.btn-account-delete-confirm`).classList.remove('hide'); s(`.btn-account-delete`).classList.add('hide'); if (result.status === 'success') { Modal.onHomeRouterEvent(); await Auth.sessionOut(); } }); }; await this.instanceModalUiEvents({ user }); }); return html` <input type="file" accept="${profileFileAccept.join(', ')}" class="account-profile-image-input hide" /> ${renderWave({ id: waveAnimationId })} <form class="in"> <div class="in"> ${await Input.Render({ id: `account-username`, type: 'text', label: html`<i class="fa-solid fa-pen-to-square"></i> ${Translate.Render('username')}`, containerClass: 'inl section-mp width-mini-box input-container', placeholder: true, disabled: false, extension: async () => html`${await BtnIcon.Render({ class: `in wfa btn-input-extension btn-account-update-username`, type: 'button', style: 'text-align: left', label: html`${Translate.Render(`update`)}`, })}`, })} </div> <div class="in"> ${await Input.Render({ id: `account-email`, type: 'email', label: html`<i class="fa-solid fa-envelope"></i> ${Translate.Render('email')}`, containerClass: 'inl section-mp width-mini-box input-container', placeholder: true, autocomplete: 'email', disabled: user.emailConfirmed, extension: !(options && options.disabled && options.disabled.includes('emailConfirm')) ? async () => html`<div class="in verify-email-status"></div> ${await BtnIcon.Render({ class: `in wfa btn-input-extension btn-confirm-email`, type: 'button', style: 'text-align: left', label: html`<div class="in"> <i class="fa-solid fa-paper-plane"></i> ${Translate.Render('send')} ${Translate.Render('verify-email')} </div> `, })}` : undefined, })} </div> <div class="in"> ${await Input.Render({ id: `account-password`, type: 'password', autocomplete: 'new-password', label: html`<i class="fa-solid fa-lock"></i> ${Translate.Render('password')}`, containerClass: 'inl section-mp width-mini-box input-container', placeholder: true, disabled: true, disabledEye: true, extension: async () => html`${await BtnIcon.Render({ class: `in wfa btn-input-extension btn-account-change-password`, type: 'button', style: 'text-align: left', label: html`${Translate.Render(`change-password`)}`, })}`, })} </div> ${options?.bottomRender ? await options.bottomRender() : ``} <div class="in hide"> ${await BtnIcon.Render({ class: 'in section-mp form-button btn-account', label: Translate.Render('update'), type: 'submit', })} </div> </form> <div class="in"> ${await BtnIcon.Render({ class: 'in section-mp form-button btn-account-delete hide', label: html` ${Translate.Render(`delete-account`)}`, type: 'button', style: 'color: #5f5f5f', })} ${await BtnIcon.Render({ class: 'in section-mp form-button btn-account-delete-confirm', label: html` ${Translate.Render(`delete-account`)}`, type: 'button', style: 'color: #5f5f5f', })} </div> `; }, triggerUpdateEvent: async function (options = { user: {} }) { for (const updateEvent of Object.keys(this.UpdateEvent)) { await this.UpdateEvent[updateEvent](options); } }, renderVerifyEmailStatus: function (user) { if (s('.verify-email-status')) { if (s(`.btn-confirm-email`)) { if (user.emailConfirmed) s(`.btn-confirm-email`).classList.add('hide'); else s(`.btn-confirm-email`).classList.remove('hide'); } htmls( '.verify-email-status', html`${renderStatus(user.emailConfirmed ? 'success' : 'error', { class: 'inl' })} ${Translate.Render('email')} ${Translate.Render(user.emailConfirmed ? 'confirmed' : 'unconfirmed')}`, ); if (user.emailConfirmed === true) s(`.account-email`).setAttribute('disabled', ''); } }, instanceModalUiEvents: async (user) => null, updateForm: async function (user) { if (!s(`.modal-account`)) return; await this.instanceModalUiEvents({ user }); s(`.account-profile-image`).style.opacity = 0; for (const inputData of this.formData) if (s(`.${inputData.id}`)) s(`.${inputData.id}`).value = user[inputData.model]; if (LogIn.Scope.user.main.model.user.profileImage) { s(`.account-profile-image`).src = LogIn.Scope.user.main.model.user.profileImage.imageSrc; s(`.account-profile-image`).style.opacity = 1; } }, }; export { Account };