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 { navigate } from '../router';
// import { init } from '../router'; // Unused import
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);
}
// Removed unused modal injection methods
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;
// Modal injection methods removed - using confirmation modal instead
this.modal = document.getElementById('confirmation-modal');
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 = `
${options.title}
${options.content}
`;
// 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';
}
}