ihm_client/src/services/modal.service.ts
2024-11-26 21:20:23 +01:00

163 lines
5.6 KiB
TypeScript
Executable File

import modalHtml from '../components/login-modal/login-modal.html?raw';
import modalScript from '../components/login-modal/login-modal.js?raw';
import Services from './service';
import { U32_MAX } from './service';
import { navigate } from '../router';
import { addressToEmoji } from '../utils/sp-address.utils';
import { RoleDefinition } from 'dist/pkg/sdk_client';
export default class ModalService {
private static instance: ModalService;
private currentPcdCommitment: string | null = null;
private currentOutpoint: string | null = null;
private constructor() {}
private paired_addresses: string[] = [];
// Method to access the singleton instance of Services
public static async getInstance(): Promise<ModalService> {
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('.page-container');
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);
}
}
// this is kind of too specific for pairing though
public async openConfirmationModal(pcd: any, commitmentTx: string, merkleRoot: string) {
let map: Record<string, RoleDefinition>;
if (pcd['roles']) {
const roles = pcd['roles'];
try {
map = JSON.parse(roles);
} catch (e) {
throw new Error(`Failed to parse roles: ${e}`);
}
} else {
throw new Error('Pcd doesn\'t have a \"roles\" field');
}
// pairing specifics
let members;
if (map['owner']) {
const owner = map['owner'];
members = owner.members;
} else {
throw new Error('No \"owner\" role');
}
// pairing specifics
if (members.length != 1) {
throw new Error('Must have exactly 1 member');
}
// We take all the addresses except our own
const service = await Services.getInstance();
const localAddress = await service.getDeviceAddress();
console.log('🚀 ~ Routing ~ openConfirmationModal ~ pcd:', pcd);
for (const member of members) {
for (const address of member['sp_addresses']) {
if (address !== localAddress) {
this.paired_addresses.push(address);
}
}
}
this.currentOutpoint = commitmentTx;
this.currentPcdCommitment = merkleRoot;
await this.injectModal(members);
const modal = document.getElementById('modal');
if (modal) modal.style.display = 'flex';
// const newScript = document.createElement('script');
// newScript.setAttribute('type', 'module');
// newScript.textContent = confirmationModalScript;
// document.head.appendChild(newScript).parentNode?.removeChild(newScript);
// Add correct text
// Close modal when clicking outside of it
window.onclick = (event) => {
const modal = document.getElementById('modal');
if (event.target === modal) {
this.closeConfirmationModal();
}
};
}
confirmLogin() {
console.log('=============> Confirm Login');
}
async closeLoginModal() {
const modal = document.getElementById('login-modal');
if (modal) modal.style.display = 'none';
}
async confirmPairing() {
const service = await Services.getInstance();
const modal = document.getElementById('modal');
if (modal) modal.style.display = 'none';
// We send the prd update
if (this.currentPcdCommitment) {
try {
const createPrdUpdateReturn = await service.createPrdUpdate(this.currentPcdCommitment);
await service.handleApiReturn(createPrdUpdateReturn);
} catch (e) {
throw e
}
} else {
throw new Error('No currentPcdCommitment');
}
// We send confirmation that we validate the change
try {
const approveChangeReturn = await service.approveChange(this.currentPcdCommitment!);
await service.handleApiReturn(approveChangeReturn);
} catch (e) {
throw e
}
service.pairDevice(this.paired_addresses);
this.paired_addresses = [];
this.currentOutpoint = null;
this.currentPcdCommitment = null;
const newDevice = service.dumpDevice();
await service.saveDevice(newDevice);
navigate('process');
}
async closeConfirmationModal() {
const service = await Services.getInstance();
await service.unpairDevice();
const modal = document.getElementById('modal');
if (modal) modal.style.display = 'none';
}
}