import modalHtml from '../components/login-modal/login-modal.html?raw'; import modalScript from '../components/login-modal/login-modal.js?raw'; import validationModalStyle from '../components/validation-modal/validation-modal.css?raw'; import Services from './service'; import { init, navigate } from '../router'; import { addressToEmoji } from '../utils/sp-address.utils'; import { RoleDefinition } from 'pkg/sdk_client'; import { initValidationModal } from '~/components/validation-modal/validation-modal'; import { interpolate } from '~/utils/html.utils'; interface ConfirmationModalOptions { title: string; content: string; confirmText?: string; cancelText?: string; } export default class ModalService { private static instance: ModalService; private stateId: string | null = null; private processId: string | null = null; private constructor() {} private paired_addresses: string[] = []; private modal: HTMLElement | null = null; // Method to access the singleton instance of Services public static async getInstance(): Promise { if (!ModalService.instance) { ModalService.instance = new ModalService(); } return ModalService.instance; } public openLoginModal(myAddress: string, receiverAddress: string) { const container = document.querySelector('.page-container'); let html = modalHtml; html = html.replace('{{device1}}', myAddress); html = html.replace('{{device2}}', receiverAddress); if (container) container.innerHTML += html; const modal = document.getElementById('login-modal'); if (modal) modal.style.display = 'flex'; const newScript = document.createElement('script'); newScript.setAttribute('type', 'module'); newScript.textContent = modalScript; document.head.appendChild(newScript).parentNode?.removeChild(newScript); } async injectModal(members: any[]) { const container = document.querySelector('#containerId'); if (container) { let html = await fetch('/src/components/modal/confirmation-modal.html').then((res) => res.text()); html = html.replace('{{device1}}', await addressToEmoji(members[0]['sp_addresses'][0])); html = html.replace('{{device2}}', await addressToEmoji(members[0]['sp_addresses'][1])); container.innerHTML += html; // Dynamically load the header JS const script = document.createElement('script'); script.src = '/src/components/modal/confirmation-modal.ts'; script.type = 'module'; document.head.appendChild(script); } } async injectCreationModal(members: any[]) { const container = document.querySelector('#containerId'); if (container) { let html = await fetch('/src/components/modal/creation-modal.html').then((res) => res.text()); html = html.replace('{{device1}}', await addressToEmoji(members[0]['sp_addresses'][0])); container.innerHTML += html; // Dynamically load the header JS const script = document.createElement('script'); script.src = '/src/components/modal/confirmation-modal.ts'; script.type = 'module'; document.head.appendChild(script); } } // Device 1 wait Device 2 async injectWaitingModal() { const container = document.querySelector('#containerId'); if (container) { let html = await fetch('/src/components/modal/waiting-modal.html').then((res) => res.text()); container.innerHTML += html; } } async injectValidationModal(processDiff: any) { const container = document.querySelector('#containerId'); if (container) { let html = await fetch('/src/components/validation-modal/validation-modal.html').then((res) => res.text()); html = interpolate(html, {processId: processDiff.processId}) container.innerHTML += html; // Dynamically load the header JS const script = document.createElement('script'); script.id = 'validation-modal-script'; script.src = '/src/components/validation-modal/validation-modal.ts'; script.type = 'module'; document.head.appendChild(script); const css = document.createElement('style'); css.id = 'validation-modal-css'; css.innerText = validationModalStyle; document.head.appendChild(css); initValidationModal(processDiff) } } async closeValidationModal() { const script = document.querySelector('#validation-modal-script'); const css = document.querySelector('#validation-modal-css'); const component = document.querySelector('#validation-modal'); script?.remove(); css?.remove(); component?.remove(); } public async openPairingConfirmationModal(roleDefinition: Record, processId: string, stateId: string) { let members; if (roleDefinition['pairing']) { const owner = roleDefinition['pairing']; members = owner.members; } else { throw new Error('No "pairing" role'); } if (members.length != 1) { throw new Error('Must have exactly 1 member'); } console.log("MEMBERS:", members); // We take all the addresses except our own const service = await Services.getInstance(); const localAddress = service.getDeviceAddress(); for (const member of members) { if (member.sp_addresses) { for (const address of member.sp_addresses) { if (address !== localAddress) { this.paired_addresses.push(address); } } } } this.processId = processId; this.stateId = stateId; if (members[0].sp_addresses.length === 1) { await this.injectCreationModal(members); this.modal = document.getElementById('creation-modal'); console.log("LENGTH:", members[0].sp_addresses.length); } else { await this.injectModal(members); this.modal = document.getElementById('modal'); console.log("LENGTH:", members[0].sp_addresses.length); } if (this.modal) this.modal.style.display = 'flex'; // Close modal when clicking outside of it window.onclick = (event) => { if (event.target === this.modal) { this.closeConfirmationModal(); } }; } confirmLogin() { console.log('=============> Confirm Login'); } async closeLoginModal() { if (this.modal) this.modal.style.display = 'none'; } async showConfirmationModal(options: ConfirmationModalOptions, fullscreen: boolean = false): Promise { // Create modal element const modalElement = document.createElement('div'); modalElement.id = 'confirmation-modal'; modalElement.innerHTML = ` `; // Add modal to document document.body.appendChild(modalElement); // Return promise that resolves with user choice return new Promise((resolve) => { const confirmButton = modalElement.querySelector('#confirm-button'); const cancelButton = modalElement.querySelector('#cancel-button'); const modalOverlay = modalElement.querySelector('.modal-overlay'); const cleanup = () => { modalElement.remove(); }; confirmButton?.addEventListener('click', () => { cleanup(); resolve(true); }); cancelButton?.addEventListener('click', () => { cleanup(); resolve(false); }); modalOverlay?.addEventListener('click', (e) => { if (e.target === modalOverlay) { cleanup(); resolve(false); } }); }); } async closeConfirmationModal() { const service = await Services.getInstance(); await service.unpairDevice(); if (this.modal) this.modal.style.display = 'none'; } }