From 9b5f89ea39ed7db649b94fcc517415397b204a90 Mon Sep 17 00:00:00 2001 From: AnisHADJARAB Date: Wed, 23 Oct 2024 07:53:08 +0000 Subject: [PATCH] add a routing and page system --- src/index.html => index.html | 3 +- src/html/home.js | 102 -- src/index.ts | 61 +- src/{html => pages/home}/home.html | 0 src/pages/home/home.ts | 114 ++ src/{html => pages/process}/process.html | 0 .../process.js => pages/process/process.ts} | 280 ++-- src/router.ts | 104 ++ src/services/routing.service.ts | 4 +- src/services/service.ts | 1389 ++++++++--------- tsconfig.json | 2 +- 11 files changed, 1065 insertions(+), 994 deletions(-) rename src/index.html => index.html (82%) delete mode 100644 src/html/home.js rename src/{html => pages/home}/home.html (100%) create mode 100644 src/pages/home/home.ts rename src/{html => pages/process}/process.html (100%) rename src/{html/process.js => pages/process/process.ts} (53%) create mode 100644 src/router.ts diff --git a/src/index.html b/index.html similarity index 82% rename from src/index.html rename to index.html index 2e696aa..e528215 100644 --- a/src/index.html +++ b/index.html @@ -14,6 +14,7 @@
- + + \ No newline at end of file diff --git a/src/html/home.js b/src/html/home.js deleted file mode 100644 index 7aab0ae..0000000 --- a/src/html/home.js +++ /dev/null @@ -1,102 +0,0 @@ -import Routing from "/src/services/routing.service.ts"; -import Services from "/src/services/service.ts"; - -document.querySelectorAll('.tab').forEach(tab => { - tab.addEventListener('click', () => { - document.querySelectorAll('.tab').forEach(t => t.classList.remove('active')); - tab.classList.add('active'); - - document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active')); - document.getElementById(tab.getAttribute('data-tab')).classList.add('active'); - }); - }); - - document.getElementById('notification-bell').addEventListener('click', openCloseNotifications); - - - export function toggleMenu() { - var menu = document.getElementById('menu'); - if (menu.style.display === 'block') { - menu.style.display = 'none'; - } else { - menu.style.display = 'block'; - } - } - - - //// Modal - export async function openModal(myAddress, receiverAddress) { - const router = await Routing.getInstance(); - router.openLoginModal(myAddress, receiverAddress) - } - - - function openCloseNotifications() { - const notifications = document.querySelector('.notification-board') - notifications.style.display = notifications?.style.display === 'none' ? 'block' : 'none' - } - -// const service = await Services.getInstance() -// service.setNotification() - -window.toggleMenu = toggleMenu; -window.openModal = openModal; - -/// Scan QR Code -function docReady(fn) { - // see if DOM is already available - if (document.readyState === "complete" - || document.readyState === "interactive") { - // call on next available tick - setTimeout(fn, 1); - } else { - document.addEventListener("DOMContentLoaded", fn); - } -} - -docReady(function () { - scanDevice(); - var resultContainer = document.getElementById('qr-reader-results'); - var lastResult, countResults = 0; - async function onScanSuccess(decodedText, decodedResult) { - if (lastResult === decodedText) { return; } - lastResult = decodedText; - ++countResults; - // Handle on success condition with the decoded message. - console.log(`Scan result ${decodedText}`, decodedResult); - try { - // Attempt to parse the decoded text as a URL - const scannedUrl = new URL(decodedText); - - // Extract the 'sp_address' parameter - const spAddress = scannedUrl.searchParams.get('sp_address'); - - if (spAddress) { - html5QrcodeScanner.clear(); - const service = await Services.getInstance() - // Call the sendPairingTx function with the extracted sp_address - await service.sendPairingTx(spAddress); - } else { - console.error('The scanned URL does not contain the sp_address parameter.'); - alert('Invalid QR code: sp_address parameter missing.'); - } - } catch (error) { - // Handle cases where decodedText is not a valid URL - console.error('Scanned text is not a valid URL:', error); - alert('Invalid QR code: Unable to parse URL.'); - } - } - - var html5QrcodeScanner = new Html5QrcodeScanner( - "qr-reader", { fps: 10, qrbox: 250 }); - html5QrcodeScanner.render(onScanSuccess); -}); - -function scanDevice() { - const scannerImg = document.querySelector('#scanner') - if(scannerImg) scannerImg.style.display = 'none' - const scannerQrCode = document.querySelector('.qr-code-scanner') - if(scannerQrCode) scannerQrCode.style.display = 'block' -} - -window.scanDevice = scanDevice \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 3ab6f7c..60d65b4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,33 +1,40 @@ -import Services from './services/service'; +// import Services from './services/service'; -document.addEventListener('DOMContentLoaded', async () => { - try { +// document.addEventListener('DOMContentLoaded', async () => { +// try { - const services = await Services.getInstance(); - setTimeout( async () => { - let device = await services.getDevice() +// const services = await Services.getInstance(); +// setTimeout( async () => { +// let device = await services.getDevice() +// console.log("πŸš€ ~ setTimeout ~ device:", device) - if(!device) { - device = await services.createNewDevice(); - } else { - await services.restoreDevice(device) - } - await services.restoreProcesses(); - await services.restoreMessages(); +// if(!device) { +// device = await services.createNewDevice(); +// } else { +// await services.restoreDevice(device) +// } +// await services.restoreProcesses(); +// await services.restoreMessages(); - if (services.isPaired()) { await services.injectProcessListPage() } - else { - const queryString = window.location.search; - const urlParams = new URLSearchParams(queryString) - const pairingAddress = urlParams.get('sp_address') +// const amount = await services.getAmount(); - if(pairingAddress) { - setTimeout(async () => await services.sendPairingTx(pairingAddress), 1000) - } - } - }, 500); - } catch (error) { - console.error(error); - } -}); +// if (amount === 0n) { +// const faucetMsg = await services.createFaucetMessage(); +// await services.sendFaucetMessage(faucetMsg); +// } +// if (services.isPaired()) { await services.injectProcessListPage() } +// else { +// const queryString = window.location.search; +// const urlParams = new URLSearchParams(queryString) +// const pairingAddress = urlParams.get('sp_address') + +// if(pairingAddress) { +// setTimeout(async () => await services.sendPairingTx(pairingAddress), 2000) +// } +// } +// }, 500); +// } catch (error) { +// console.error(error); +// } +// }); diff --git a/src/html/home.html b/src/pages/home/home.html similarity index 100% rename from src/html/home.html rename to src/pages/home/home.html diff --git a/src/pages/home/home.ts b/src/pages/home/home.ts new file mode 100644 index 0000000..f8c9bfd --- /dev/null +++ b/src/pages/home/home.ts @@ -0,0 +1,114 @@ +import { Html5QrcodeScanner } from "html5-qrcode"; +import Routing from "../../services/routing.service"; +import Services from "../../services/service"; + +let resultContainer = document.getElementById('qr-reader-results'); +let lastResult: any, countResults = 0; + +export function initHomePage(): void { + console.log('INIT') + document.querySelectorAll('.tab').forEach(tab => { + + tab.addEventListener('click', () => { + document.querySelectorAll('.tab').forEach(t => t.classList.remove('active')); + tab.classList.add('active'); + + document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active')); + document.getElementById(tab.getAttribute('data-tab') as string)?.classList.add('active'); + + }); + }); + +document.getElementById('notification-bell')?.addEventListener('click', openCloseNotifications); + +var html5QrcodeScanner = new Html5QrcodeScanner( + "qr-reader", { fps: 10, qrbox: 250 }, undefined); +html5QrcodeScanner.render(onScanSuccess, undefined); + +docReady(() => { + scanDevice(); + + +}); +} + + +async function onScanSuccess(decodedText: any, decodedResult: any) { + if (lastResult === decodedText) { return; } + lastResult = decodedText; + ++countResults; + // Handle on success condition with the decoded message. + console.log(`Scan result ${decodedText}`, decodedResult); + try { + // Attempt to parse the decoded text as a URL + const scannedUrl = new URL(decodedText); + + // Extract the 'sp_address' parameter + const spAddress = scannedUrl.searchParams.get('sp_address'); + + if (spAddress) { + html5QrcodeScanner.clear(); + const service = await Services.getInstance() + // Call the sendPairingTx function with the extracted sp_address + await service.sendPairingTx(spAddress); + } else { + console.error('The scanned URL does not contain the sp_address parameter.'); + alert('Invalid QR code: sp_address parameter missing.'); + } + } catch (error) { + // Handle cases where decodedText is not a valid URL + console.error('Scanned text is not a valid URL:', error); + alert('Invalid QR code: Unable to parse URL.'); + } +} +export function toggleMenu() { + let menu = document.getElementById('menu'); + if(menu) { + if (menu.style.display === 'block') { + menu.style.display = 'none'; + } else { + menu.style.display = 'block'; + } + } +} + + //// Modal + export async function openModal(myAddress: string, receiverAddress: string) { + const router = await Routing.getInstance(); + router.openLoginModal(myAddress, receiverAddress) + } + + + function openCloseNotifications() { + const notifications = document.querySelector('.notification-board') as HTMLDivElement + notifications.style.display = notifications?.style.display === 'none' ? 'block' : 'none' + } + +// const service = await Services.getInstance() +// service.setNotification() + +(window as any).toggleMenu = toggleMenu; +(window as any).openModal = openModal; + +/// Scan QR Code +function docReady(fn: any) { + // see if DOM is already available + if (document.readyState === "complete" + || document.readyState === "interactive") { + // call on next available tick + setTimeout(fn, 1); + } else { + document.addEventListener("DOMContentLoaded", fn); + } +} + + + +function scanDevice() { + const scannerImg = document.querySelector('#scanner') as HTMLElement + if(scannerImg) scannerImg.style.display = 'none' + const scannerQrCode = document.querySelector('.qr-code-scanner') as HTMLElement + if(scannerQrCode) scannerQrCode.style.display = 'block' +} + +(window as any).scanDevice = scanDevice \ No newline at end of file diff --git a/src/html/process.html b/src/pages/process/process.html similarity index 100% rename from src/html/process.html rename to src/pages/process/process.html diff --git a/src/html/process.js b/src/pages/process/process.ts similarity index 53% rename from src/html/process.js rename to src/pages/process/process.ts index 3141982..ca4abae 100644 --- a/src/html/process.js +++ b/src/pages/process/process.ts @@ -1,7 +1,7 @@ -import Services from "/src/services/service.ts"; - +import Services from "../../services/service"; +import {IProcess } from "~/models/process.model"; function toggleMenu() { - const menu = document.getElementById("menu"); + const menu = document.getElementById("menu") as HTMLDivElement; if (menu.style.display === "block") { menu.style.display = "none"; } else { @@ -11,7 +11,7 @@ function toggleMenu() { // Initialize function, create initial tokens with itens that are already selected by the user -function init(element) { +function init(element: HTMLElement) { // Create div that wroaps all the elements inside (select, elements selected, search div) to put select inside const wrapper = document.createElement("div"); wrapper.addEventListener("click", clickOnWrapper); @@ -30,7 +30,6 @@ function init(element) { input.addEventListener("click", openOptions); const dropdown_icon = document.createElement("a"); - dropdown_icon.setAttribute("href", "#"); dropdown_icon.classList.add("dropdown-icon"); dropdown_icon.addEventListener("click", clickDropdown); @@ -41,7 +40,7 @@ function init(element) { search_div.appendChild(dropdown_icon); // set the wrapper as child (instead of the element) - element.parentNode.replaceChild(wrapper, element); + element.parentNode?.replaceChild(wrapper, element); // set element as child of wrapper wrapper.appendChild(element); wrapper.appendChild(search_div); @@ -58,64 +57,65 @@ function init(element) { // } } -function removePlaceholder(wrapper) { +function removePlaceholder(wrapper: HTMLElement) { const input_search = wrapper.querySelector(".selected-input"); - input_search.removeAttribute("placeholder"); + input_search?.removeAttribute("placeholder"); } -function addPlaceholder(wrapper) { +function addPlaceholder(wrapper: HTMLElement) { const input_search = wrapper.querySelector(".selected-input"); const tokens = wrapper.querySelectorAll(".selected-wrapper"); if (!tokens.length && !(document.activeElement === input_search)) - input_search.setAttribute("placeholder", "---------"); + input_search?.setAttribute("placeholder", "---------"); } // Listener of user search -function inputChange(e) { - const wrapper = e.target.parentNode.parentNode; - const select = wrapper.querySelector("select"); - const dropdown = wrapper.querySelector(".dropdown-icon"); +function inputChange(e: Event) { + const target = e.target as HTMLInputElement + const wrapper = target?.parentNode?.parentNode; + const select = wrapper?.querySelector("select") as HTMLSelectElement; + const dropdown = wrapper?.querySelector(".dropdown-icon"); - const input_val = e.target.value; + const input_val = target?.value; if (input_val) { - dropdown.classList.add("active"); + dropdown?.classList.add("active"); populateAutocompleteList(select, input_val.trim()); } else { - dropdown.classList.remove("active"); + dropdown?.classList.remove("active"); const event = new Event("click"); - dropdown.dispatchEvent(event); + dropdown?.dispatchEvent(event); } } // Listen for clicks on the wrapper, if click happens focus on the input -function clickOnWrapper(e) { - const wrapper = e.target; +function clickOnWrapper(e: Event) { + const wrapper = e.target as HTMLElement; if (wrapper.tagName == "DIV") { const input_search = wrapper.querySelector(".selected-input"); const dropdown = wrapper.querySelector(".dropdown-icon"); - if (!dropdown.classList.contains("active")) { + if (!dropdown?.classList.contains("active")) { const event = new Event("click"); - dropdown.dispatchEvent(event); + dropdown?.dispatchEvent(event); } - input_search.focus(); + (input_search as HTMLInputElement)?.focus(); removePlaceholder(wrapper); } } -function openOptions(e) { - const input_search = e.target; - const wrapper = input_search.parentElement.parentElement; - const dropdown = wrapper.querySelector(".dropdown-icon"); - if (!dropdown.classList.contains("active")) { +function openOptions(e: Event) { + const input_search = e.target as HTMLElement; + const wrapper = input_search?.parentElement?.parentElement; + const dropdown = wrapper?.querySelector(".dropdown-icon"); + if (!dropdown?.classList.contains("active")) { const event = new Event("click"); - dropdown.dispatchEvent(event); + dropdown?.dispatchEvent(event); } e.stopPropagation(); } // Function that create a token inside of a wrapper with the given value -function createToken(wrapper, value) { +function createToken(wrapper: HTMLElement, value: any) { const search = wrapper.querySelector(".search-container"); const inputInderline = document.querySelector(".selected-processes"); // Create token wrapper @@ -128,48 +128,48 @@ function createToken(wrapper, value) { close.classList.add("selected-close"); close.setAttribute("tabindex", "-1"); close.setAttribute("data-option", value); - close.setAttribute("data-hits", 0); + close.setAttribute("data-hits", '0'); close.setAttribute("href", "#"); close.innerText = "x"; close.addEventListener("click", removeToken); token.appendChild(token_span); token.appendChild(close); - inputInderline.appendChild(token); + inputInderline?.appendChild(token); } // Listen for clicks in the dropdown option -function clickDropdown(e) { - const dropdown = e.target; - const wrapper = dropdown.parentNode.parentNode; - const input_search = wrapper.querySelector(".selected-input"); - const select = wrapper.querySelector("select"); +function clickDropdown(e: Event) { + const dropdown = e.target as HTMLElement; + const wrapper = dropdown?.parentNode?.parentNode; + const input_search = wrapper?.querySelector(".selected-input") as HTMLInputElement; + const select = wrapper?.querySelector("select") as HTMLSelectElement; dropdown.classList.toggle("active"); if (dropdown.classList.contains("active")) { - removePlaceholder(wrapper); - input_search.focus(); + removePlaceholder(wrapper as HTMLElement); + input_search?.focus(); - if (!input_search.value) { + if (!input_search?.value) { populateAutocompleteList(select, "", true); } else { populateAutocompleteList(select, input_search.value); } } else { clearAutocompleteList(select); - addPlaceholder(wrapper); + addPlaceholder(wrapper as HTMLElement); } } // Clears the results of the autocomplete list -function clearAutocompleteList(select) { +function clearAutocompleteList(select: HTMLSelectElement) { const wrapper = select.parentNode; - const autocomplete_list = wrapper.querySelector(".autocomplete-list"); - autocomplete_list.innerHTML = ""; + const autocomplete_list = wrapper?.querySelector(".autocomplete-list"); + if(autocomplete_list) autocomplete_list.innerHTML = ""; } // Populate the autocomplete list following a given query from the user -function populateAutocompleteList(select, query, dropdown = false) { +function populateAutocompleteList(select: HTMLSelectElement, query: string, dropdown = false) { const { autocomplete_options } = getOptions(select); let options_to_show; @@ -178,9 +178,9 @@ function populateAutocompleteList(select, query, dropdown = false) { else options_to_show = autocomplete(query, autocomplete_options); const wrapper = select.parentNode; - const input_search = wrapper.querySelector(".search-container"); - const autocomplete_list = wrapper.querySelector(".autocomplete-list"); - autocomplete_list.innerHTML = ""; + const input_search = wrapper?.querySelector(".search-container"); + const autocomplete_list = wrapper?.querySelector(".autocomplete-list"); + if(autocomplete_list) autocomplete_list.innerHTML = ""; const result_size = options_to_show.length; if (result_size == 1) { @@ -188,7 +188,7 @@ function populateAutocompleteList(select, query, dropdown = false) { li.innerText = options_to_show[0]; li.setAttribute("data-value", options_to_show[0]); li.addEventListener("click", selectOption); - autocomplete_list.appendChild(li); + autocomplete_list?.appendChild(li); if (query.length == options_to_show[0].length) { const event = new Event("click"); li.dispatchEvent(event); @@ -199,18 +199,18 @@ function populateAutocompleteList(select, query, dropdown = false) { li.innerText = options_to_show[i]; li.setAttribute("data-value", options_to_show[i]); li.addEventListener("click", selectOption); - autocomplete_list.appendChild(li); + autocomplete_list?.appendChild(li); } } else { const li = document.createElement("li"); li.classList.add("not-cursor"); li.innerText = "No options found"; - autocomplete_list.appendChild(li); + autocomplete_list?.appendChild(li); } } // Listener to autocomplete results when clicked set the selected property in the select option -function selectOption(e) { +function selectOption(e: any) { const wrapper = e.target.parentNode.parentNode.parentNode; const input_search = wrapper.querySelector(".selected-input"); const option = wrapper.querySelector( @@ -243,7 +243,7 @@ function selectOption(e) { } // function that returns a list with the autcomplete list of matches -function autocomplete(query, options) { +function autocomplete(query: string, options: any) { // No query passed, just return entire list if (!query) { return options; @@ -261,7 +261,7 @@ function autocomplete(query, options) { } // Returns the options that are selected by the user and the ones that are not -function getOptions(select) { +function getOptions(select: HTMLSelectElement) { // Select all the options available const all_options = Array.from(select.querySelectorAll("option")).map( (el) => el.value @@ -270,10 +270,10 @@ function getOptions(select) { // Get the options that are selected from the user const options_selected = Array.from( select.querySelectorAll("option:checked") - ).map((el) => el.value); + ).map((el: any) => el.value); // Create an autocomplete options array with the options that are not selected by the user - const autocomplete_options = []; + const autocomplete_options: any[] = []; all_options.forEach((option) => { if (!options_selected.includes(option)) { autocomplete_options.push(option); @@ -289,62 +289,63 @@ function getOptions(select) { } // Listener for when the user wants to remove a given token. -function removeToken(e) { +function removeToken(e: Event) { // Get the value to remove - const value_to_remove = e.target.dataset.option; - const wrapper = e.target.parentNode.parentNode.parentNode; - const input_search = wrapper.querySelector(".selected-input"); - const dropdown = wrapper.querySelector(".dropdown-icon"); + const target = e.target as HTMLSelectElement + const value_to_remove = target.dataset.option; + const wrapper = target.parentNode?.parentNode?.parentNode; + const input_search = wrapper?.querySelector(".selected-input"); + const dropdown = wrapper?.querySelector(".dropdown-icon"); // Get the options in the select to be unselected - const option_to_unselect = wrapper.querySelector( + const option_to_unselect = wrapper?.querySelector( `select option[value="${value_to_remove}"]` ); - option_to_unselect.removeAttribute("selected"); + option_to_unselect?.removeAttribute("selected"); // Remove token attribute - e.target.parentNode.remove(); - dropdown.classList.remove("active"); - const process = document.querySelector("#" + e.target.dataset.option); - process.remove(); + (target.parentNode as any)?.remove(); + dropdown?.classList.remove("active"); + const process = document.querySelector("#" + target.dataset.option); + process?.remove(); } // Listen for 2 sequence of hits on the delete key, if this happens delete the last token if exist -function deletePressed(e) { - const wrapper = e.target.parentNode.parentNode; - const input_search = e.target; +function deletePressed(e: KeyboardEvent) { + const input_search = e.target as HTMLInputElement; + const wrapper = input_search?.parentNode?.parentNode; const key = e.keyCode || e.charCode; - const tokens = wrapper.querySelectorAll(".selected-wrapper"); + const tokens = wrapper?.querySelectorAll(".selected-wrapper"); - if (tokens.length) { + if (tokens?.length) { const last_token_x = tokens[tokens.length - 1].querySelector("a"); - let hits = +last_token_x.dataset.hits; + let hits = +(last_token_x?.dataset?.hits || 0); if (key == 8 || key == 46) { if (!input_search.value) { if (hits > 1) { // Trigger delete event const event = new Event("click"); - last_token_x.dispatchEvent(event); + last_token_x?.dispatchEvent(event); } else { - last_token_x.dataset.hits = 2; + if(last_token_x?.dataset.hits) last_token_x.dataset.hits = '2'; } } } else { - last_token_x.dataset.hits = 0; + if(last_token_x?.dataset.hits) last_token_x.dataset.hits = '0'; } } return true; } -function addOption(target, val, text) { - const select = document.querySelector(target); - let opt = document.createElement("option"); - opt.value = val; - opt.innerHTML = text; - select.appendChild(opt); -} +// function addOption(target, val, text) { +// const select = document.querySelector(target); +// let opt = document.createElement("option"); +// opt.value = val; +// opt.innerHTML = text; +// select.appendChild(opt); +// } // get select that has the options available -const select = document.querySelectorAll("[data-multi-select-plugin]"); +const select = document.querySelectorAll("[data-multi-select-plugin]") as NodeListOf; select.forEach((select) => { console.log(select); init(select); @@ -356,18 +357,18 @@ document.addEventListener("click", () => { const select = document.querySelectorAll("[data-multi-select-plugin]"); for (let i = 0; i < select.length; i++) { if (event) { - var isClickInside = select[i].parentElement.parentElement.contains( - event.target + var isClickInside = select[i].parentElement?.parentElement?.contains( + event.target as Node ); if (!isClickInside) { - const wrapper = select[i].parentElement.parentElement; - const dropdown = wrapper.querySelector(".dropdown-icon"); - const autocomplete_list = wrapper.querySelector(".autocomplete-list"); + const wrapper = select[i].parentElement?.parentElement; + const dropdown = wrapper?.querySelector(".dropdown-icon"); + const autocomplete_list = wrapper?.querySelector(".autocomplete-list"); //the click was outside the specifiedElement, do something - dropdown.classList.remove("active"); - autocomplete_list.innerHTML = ""; - addPlaceholder(wrapper); + dropdown?.classList.remove("active"); + if(autocomplete_list) autocomplete_list.innerHTML = ""; + addPlaceholder(wrapper as HTMLElement); } } } @@ -379,4 +380,97 @@ export async function unpair() { await service.unpairDevice() } -window.unpair = unpair; \ No newline at end of file +(window as any).unpair = unpair; + + +async function showSelectedProcess(event: MouseEvent) { + const elem = event.target; + if(elem) { + + const cardContent = document.querySelector(".card-content"); + + const processes = await getProcesses(); + console.log("πŸš€ ~ Services ~ showSelectedProcess ~ processes:", processes) + const process = processes.find((process: any) => process.name === (elem as any).dataset.value); + if (process) { + const processDiv = document.createElement("div"); + processDiv.className = "process"; + processDiv.id = process.name; + const titleDiv = document.createElement("div"); + titleDiv.className = "process-title"; + titleDiv.innerHTML = `${process.name} : ${process.description}`; + processDiv.appendChild(titleDiv); + for (const zone of process.zoneList) { + const zoneElement = document.createElement("div"); + zoneElement.className = "process-element"; + zoneElement.setAttribute('zone-id', zone.id.toString()) + zoneElement.innerHTML = `Zone ${zone.id} : ${zone.name}`; + const service = await Services.getInstance() + service.addSubscription(zoneElement, 'click', 'goToProcessPage') + processDiv.appendChild(zoneElement); + } + if(cardContent) cardContent.appendChild(processDiv); + } + } +} + +function goToProcessPage(event: MouseEvent) { + const target = event.target as HTMLDivElement; + const zoneId = target?.getAttribute('zone-id'); + const processList = document.querySelectorAll('.process-element'); + if(processList) { + for(const process of processList) { + process.classList.remove('selected') + } + } + target.classList.add('selected') + + console.log('=======================> going to process page', zoneId) +} + +async function getProcesses(): Promise { + const service = await Services.getInstance() + // const processes = service.getProcesses() + // console.log("πŸš€ ~ Services ~ getProcesses ~ processes:", processes) + return [ + { + id: 1, + name: "Messaging", + description: "Encrypted messages", + zoneList: [ + { + id: 1, + name: "General", + path: '/test' + }, + ], + }, + { + id: 2, + name: "Storage", + description: "Distributed storage", + zoneList: [ + { + id: 1, + name: "Paris", + path: '/test' + }, + { + id: 2, + name: "Normandy", + path: '/test' + }, + { + id: 3, + name: "New York", + path: '/test' + }, + { + id: 4, + name: "Moscow", + path: '/test' + }, + ], + }, + ]; +} \ No newline at end of file diff --git a/src/router.ts b/src/router.ts new file mode 100644 index 0000000..a8169ac --- /dev/null +++ b/src/router.ts @@ -0,0 +1,104 @@ +import '../public/style/4nk.css'; +import { initHomePage } from './pages/home/home'; +import Services from './services/service'; + +const routes: { [key: string]: string } = { + 'home': '/src/pages/home/home.html', + 'process': '/src/pages/process/process.html', +}; + +export async function navigate(path: string) { + path = path.replace(/^\//, ''); + if (!routes[path]) { + path = 'home'; + } else { + } + + await handleLocation(path); +} + +async function handleLocation(path: string) { + const isPaired = await init() + console.log("πŸš€ ~ handleLocation ~ isPaired:", isPaired) + // if(!isPaired) path = 'home' + const routeHtml = routes[path] || routes['home']; + + const content = document.getElementById('containerId'); + if (content) { + const html = await fetch(routeHtml).then(data => data.text()); + content.innerHTML = html; + + await new Promise(requestAnimationFrame); + + if(path === "home") { + const { initHomePage } = await import('./pages/home/home'); + initHomePage() + } + else if (path === "process") { + await import('./pages/process/process'); + } + } +} + +window.onpopstate = () => handleLocation('home'); +window.onclick = (event: MouseEvent) => { + const target = event.target as HTMLElement; + if (target.tagName === 'A') { + event.preventDefault(); + const path = target.getAttribute('href'); + if (path) { + navigate(path); + } + } +}; + + +async function init(): Promise { + let isPaired = false; + try { + + const services = await Services.getInstance(); + setTimeout( async () => { + let device = await services.getDevice() + console.log("πŸš€ ~ setTimeout ~ device:", device) + + if(!device) { + device = await services.createNewDevice(); + } else { + await services.restoreDevice(device) + } + await services.restoreProcesses(); + await services.restoreMessages(); + + const amount = await services.getAmount(); + + if (amount === 0n) { + const faucetMsg = await services.createFaucetMessage(); + await services.sendFaucetMessage(faucetMsg); + } + if (services.isPaired()) { + isPaired = true; + await navigate('process'); + } + else { + const queryString = window.location.search; + const urlParams = new URLSearchParams(queryString) + const pairingAddress = urlParams.get('sp_address') + if(pairingAddress) { + setTimeout(async () => await services.sendPairingTx(pairingAddress), 2000) + } + } + return isPaired + + }, 200); +} catch (error) { + console.error(error); + return isPaired +} +return isPaired + +} + +(async () => { + await navigate('home'); +})(); diff --git a/src/services/routing.service.ts b/src/services/routing.service.ts index 6973357..91e7ed3 100644 --- a/src/services/routing.service.ts +++ b/src/services/routing.service.ts @@ -4,6 +4,7 @@ import modalScript from '../html/login-modal.js?raw'; import confirmationModalScript from '../html/confirmation-modal.js?raw'; import Services from './service'; import { U32_MAX } from './service'; +import { navigate } from '../router'; export default class Routing { @@ -83,7 +84,6 @@ export default class Routing { confirmLogin() { console.log('=============> Confirm Login') const loginTx = this.sdkClient.create_login_transaction(1) - console.log("πŸš€ ~ Routing ~ confirmLogin ~ loginTx:", loginTx) this.sdkClient.login('LOGIN', loginTx) } async closeLoginModal() { @@ -105,7 +105,7 @@ export default class Routing { this.paired_addresses = [] const newDevice = await service.dumpDevice(); await service.saveDevice(newDevice); - service.injectProcessListPage(); + navigate('process'); } async closeConfirmationModal() { diff --git a/src/services/service.ts b/src/services/service.ts index 4b5fed1..7b5ff1a 100644 --- a/src/services/service.ts +++ b/src/services/service.ts @@ -1,214 +1,195 @@ // import { WebSocketClient } from '../websockets'; import { INotification } from '~/models/notification.model'; -import homePage from '../html/home.html?raw'; -import homeScript from '../html/home.js?raw'; -import processPage from '../html/process.html?raw'; -import processScript from '../html/process.js?raw'; +import homePage from '../pages/home/home.html?raw'; +import homeScript from '../pages/home/home.ts?raw'; +import processPage from '../pages/process/process.html?raw'; +import processScript from '../pages/process/process.js?raw'; import { IProcess } from '~/models/process.model'; // import Database from './database'; import { WebSocketClient } from '../websockets'; import QRCode from 'qrcode' -import { servicesVersion } from 'typescript'; -import { ApiReturn, CachedMessage, Member } from '../../dist/pkg/sdk_client'; +import { ApiReturn } from '../../dist/pkg/sdk_client'; import Routing from './routing.service'; type ProcessesCache = { - [key: string]: any; + [key: string]: any; }; export const U32_MAX = 4294967295; const wsurl = `https://demo.4nkweb.com/ws/`; export default class Services { - private static initializing: Promise | null = null; - private static instance: Services; - private current_process: string | null = null; - private sdkClient: any; - private websocketConnection: WebSocketClient | null = null; - private processes: IProcess[] | null = null; - private notifications: INotification[] | null = null; - private subscriptions: { element: Element; event: string; eventHandler: string; }[] = []; - private database: any - // Private constructor to prevent direct instantiation from outside - private constructor() { } + private static initializing: Promise | null = null; + private static instance: Services; + private current_process: string | null = null; + private sdkClient: any; + private websocketConnection: WebSocketClient | null = null; + private processes: IProcess[] | null = null; + private notifications: INotification[] | null = null; + private subscriptions: {element: Element; event: string; eventHandler: string;}[] = [] ; + private database: any + // Private constructor to prevent direct instantiation from outside + private constructor() {} - // Method to access the singleton instance of Services - public static async getInstance(): Promise { - if (Services.instance) { - return Services.instance; + // Method to access the singleton instance of Services + public static async getInstance(): Promise { + if (Services.instance) { + return Services.instance; + } + + if (!Services.initializing) { + Services.initializing = (async () => { + const instance = new Services(); + await instance.init(); + return instance; + })(); + } + + console.log('initializing services'); + Services.instance = await Services.initializing; + Services.initializing = null; // Reset for potential future use + return Services.instance; } - if (!Services.initializing) { - Services.initializing = (async () => { - const instance = new Services(); - await instance.init(); - return instance; - })(); + public async init(): Promise { + this.notifications = this.getNotifications(); + this.sdkClient = await import("../../dist/pkg/sdk_client"); + this.sdkClient.setup(); + await this.addWebsocketConnection(wsurl); } - console.log('initializing services'); - Services.instance = await Services.initializing; - Services.initializing = null; // Reset for potential future use - return Services.instance; - } - - public async init(): Promise { - this.notifications = this.getNotifications(); - this.sdkClient = await import("../../dist/pkg/sdk_client"); - this.sdkClient.setup(); - await this.addWebsocketConnection(wsurl); - await this.recoverInjectHtml(); - } - - public async addWebsocketConnection(url: string): Promise { - // const services = await Services.getInstance(); - if (!this.websocketConnection) { - console.log('Opening new websocket connection'); - const newClient = new WebSocketClient(url, this); - this.websocketConnection = newClient; - } - } - - public async recoverInjectHtml(): Promise { - const container = document.getElementById('containerId'); - - if (!container) { - console.error("No html container"); - return; + public async addWebsocketConnection(url: string): Promise { + // const services = await Services.getInstance(); + if (!this.websocketConnection) { + console.log('Opening new websocket connection'); + const newClient = new WebSocketClient(url, this); + this.websocketConnection = newClient; + } } - container.innerHTML = homePage; - - const newScript = document.createElement('script') - newScript.setAttribute('type', 'module') - newScript.textContent = homeScript; - document.head.appendChild(newScript).parentNode?.removeChild(newScript); - } - - private generateQRCode = async (text: string) => { - console.log("πŸš€ ~ Services ~ generateQRCode= ~ text:", text) - try { - const container = document.getElementById('containerId'); - const currentUrl = window.location.href; - const url = await QRCode.toDataURL(currentUrl + "?sp_address=" + text); - const qrCode = container?.querySelector('.qr-code img'); - qrCode?.setAttribute('src', url) - - //Generate Address CopyBtn - const address = container?.querySelector('.sp-address-btn') - if (address) { - address.textContent = "Copy address"; - } - const copyBtn = document.getElementById('copyBtn'); - if (copyBtn) { - copyBtn.addEventListener('click', () => this.copyToClipboard(currentUrl + "?sp_address=" + text)); - } - } catch (err) { - console.error(err); - } - } - - //Copy Address - public async copyToClipboard(fullAddress: string) { - try { - await navigator.clipboard.writeText(fullAddress); - alert("Adresse copiΓ©e dans le presse-papiers !"); - } catch (err) { - console.error("Failed to copy the address: ", err); - } - } - - //Generate emojis list - public generateEmojiList(): string[] { - const emojiRanges = [ - [0x1F600, 0x1F64F], - [0x1F300, 0x1F5FF], - [0x1F680, 0x1F6FF], - [0x1F700, 0x1F77F] - ]; - - const emojiList: string[] = []; - for (const range of emojiRanges) { - const [start, end] = range; - for (let i = start; i <= end && emojiList.length < 256; i++) { - emojiList.push(String.fromCodePoint(i)); - } - if (emojiList.length >= 256) { - break; + private generateQRCode = async (text: string) => { + try { + const container = document.getElementById('containerId'); + const currentUrl = 'https://' + window.location.host; + const url = await QRCode.toDataURL(currentUrl + "?sp_address=" + text); + const qrCode = container?.querySelector('.qr-code img'); + qrCode?.setAttribute('src', url) + + //Generate Address CopyBtn + const address = container?.querySelector('.sp-address-btn') + if (address) { + address.textContent = "Copy address"; + } + const copyBtn = document.getElementById('copyBtn'); + if (copyBtn) { + copyBtn.addEventListener('click', () => this.copyToClipboard(currentUrl + "?sp_address=" + text)); + } + } catch (err) { + console.error(err); } } - return emojiList.slice(0, 256); - } - - //Adress to emojis - public addressToEmoji = async (text: string): Promise => { - //Adress to Hash - const encoder = new TextEncoder(); - const data = encoder.encode(text); - const hashBuffer = await crypto.subtle.digest('SHA-256', data); - - const hash = new Uint8Array(hashBuffer); - const bytes = hash.slice(-4); - - //Hash slice to emojis - const emojiList = this.generateEmojiList(); - const emojis = Array.from(bytes).map(byte => emojiList[byte]).join(''); - return emojis; - } - - //Get emojis from other device - public async emojisPairingRequest() { - try { - const container = document.getElementById('containerId'); - - const urlParams: URLSearchParams = new URLSearchParams(window.location.search); - const sp_adress: string | null = urlParams.get('sp_address'); - - if (!sp_adress) { - // console.error("No 'sp_adress' parameter found in the URL."); - return; + //Copy Address + public async copyToClipboard(fullAddress: string) { + try { + await navigator.clipboard.writeText(fullAddress); + alert("Adresse copiΓ©e dans le presse-papiers !"); + } catch (err) { + console.error("Failed to copy the address: ", err); } - - const emojis = await this.addressToEmoji(sp_adress); - const emojiDisplay = container?.querySelector('.pairing-request'); - - if (emojiDisplay) { - emojiDisplay.textContent = "(Request from: " + emojis + ")"; - } - } catch (err) { - console.error(err); } - } - // Display address emojis and other device emojis - private displayEmojis = async (text: string) => { - console.log("πŸš€ ~ Services ~ adressToEmoji") - try { - const container = document.getElementById('containerId'); - const emojis = await this.addressToEmoji(text); - const emojiDisplay = container?.querySelector('.emoji-display'); - - if (emojiDisplay) { - emojiDisplay.textContent = emojis; + //Generate emojis list + public generateEmojiList(): string[] { + const emojiRanges = [ + [0x1F600, 0x1F64F], + [0x1F300, 0x1F5FF], + [0x1F680, 0x1F6FF], + [0x1F700, 0x1F77F] + ]; + + const emojiList: string[] = []; + for (const range of emojiRanges) { + const [start, end] = range; + for (let i = start; i <= end && emojiList.length < 256; i++) { + emojiList.push(String.fromCodePoint(i)); + } + if (emojiList.length >= 256) { + break; + } } - - this.emojisPairingRequest(); - - this.initAddressInput(); - - } catch (err) { - console.error(err); + + return emojiList.slice(0, 256); } - } - // Verify Other address - public initAddressInput() { - const addressInput = document.getElementById('addressInput') as HTMLInputElement; - const emojiDisplay = document.getElementById('emoji-display-2'); - const okButton = document.getElementById('okButton'); + //Adress to emojis + public addressToEmoji = async (text: string): Promise => { + //Adress to Hash + const encoder = new TextEncoder(); + const data = encoder.encode(text); + const hashBuffer = await crypto.subtle.digest('SHA-256', data); - addressInput.addEventListener('input', async () => { + const hash = new Uint8Array(hashBuffer); + const bytes = hash.slice(-4); + + //Hash slice to emojis + const emojiList = this.generateEmojiList(); + const emojis = Array.from(bytes).map(byte => emojiList[byte]).join(''); + return emojis; + } + + //Get emojis from other device + public async emojisPairingRequest () { + try { + const container = document.getElementById('containerId'); + + const urlParams: URLSearchParams = new URLSearchParams(window.location.search); + const sp_adress: string | null = urlParams.get('sp_address'); + + if (!sp_adress) { + // console.error("No 'sp_adress' parameter found in the URL."); + return; + } + + const emojis = await this.addressToEmoji(sp_adress); + const emojiDisplay = container?.querySelector('.pairing-request'); + + if (emojiDisplay) { + emojiDisplay.textContent = "(Request from: " +emojis+")"; + } + } catch (err) { + console.error(err); + } + } + + // Display address emojis and other device emojis + private displayEmojis = async (text: string) => { + console.log("πŸš€ ~ Services ~ adressToEmoji") + try { + const container = document.getElementById('containerId'); + const emojis = await this.addressToEmoji(text); + const emojiDisplay = container?.querySelector('.emoji-display'); + + if (emojiDisplay) { + emojiDisplay.textContent = emojis; + } + + this.emojisPairingRequest(); + + this.initAddressInput(); + + } catch (err) { + console.error(err); + } + } + + // Verify Other address + public initAddressInput() { + const addressInput = document.getElementById('addressInput') as HTMLInputElement; + const emojiDisplay = document.getElementById('emoji-display-2'); + const okButton = document.getElementById('okButton'); + + addressInput.addEventListener('input', async () => { let address = addressInput.value; // VΓ©rifie si l'adresse est une URL @@ -226,661 +207,533 @@ export default class Services { // Si ce n'est pas une URL valide, on garde l'adresse originale console.log("Ce n'est pas une URL valide, on garde l'adresse originale."); } - - if (address) { - const emojis = await this.addressToEmoji(address); - if (emojiDisplay) { - emojiDisplay.innerHTML = emojis; - } - if (okButton) { + if (address) { + const emojis = await this.addressToEmoji(address); + if (emojiDisplay) { + emojiDisplay.innerHTML = emojis; + } + if (okButton) { okButton.style.display = 'inline-block'; - } - } else { - if (emojiDisplay) { - emojiDisplay.innerHTML = ''; - } - if (okButton) { + } + } else { + if (emojiDisplay) { + emojiDisplay.innerHTML = ''; + } + if (okButton) { okButton.style.display = 'none'; - } - } - }); + } + } + }); - if (okButton) { + if (okButton) { okButton.addEventListener('click', () => { this.onOkButtonClick(); }); - } -} - - private async onOkButtonClick() { - const addressInput = (document.getElementById('addressInput') as HTMLInputElement).value; - await this.sendPairingTx(addressInput); - } - - - public isPaired(): boolean | undefined { - try { - return this.sdkClient.is_linking(); - } catch (e) { - console.error("isPaired ~ Error:", e); - } - } - - public async unpairDevice(): Promise { - const service = await Services.getInstance() - await service.sdkClient.unpair_device() - const newDevice = await this.dumpDevice(); - await this.saveDevice(newDevice); - } - - private prepareProcessTx(myAddress: string, recipientAddress: string) { - const initial_session_privkey = new Uint8Array(32); - const initial_session_pubkey = new Uint8Array(32); - const pairingTemplate = { - "description": "AliceBob", - "roles": { - "owner": { - "members": - [{ sp_addresses: [myAddress, recipientAddress] }], - "validation_rules": - [ - { - "quorum": 1.0, - "fields": [ - "description", - "roles", - "session_privkey", - "session_pubkey", - "key_parity" - ], - "min_sig_member": 1.0 - } - ] - } - }, - "session_privkey": initial_session_privkey, - "session_pubkey": initial_session_pubkey, - "key_parity": true, + } } - - const apiReturn = this.sdkClient.create_update_transaction(undefined, JSON.stringify(pairingTemplate), 1) - return apiReturn - } - - public async sendPairingTx(spAddress: string): Promise { - const amount = this.sdkClient.get_available_amount(); - - if (amount === 0n) { - const faucetMsg = this.sdkClient.create_faucet_msg(); - await this.sendFaucetMessage(faucetMsg); + private async onOkButtonClick() { + const addressInput = (document.getElementById('addressInput') as HTMLInputElement).value; + await this.sendPairingTx(addressInput); + } + + public isPaired(): boolean | undefined { + try { + return this.sdkClient.is_linking(); + } catch (e) { + console.error("isPaired ~ Error:", e); + } } - const localAddress = this.sdkClient.get_address(); - const emptyTxid = '0'.repeat(64) + public async unpairDevice(): Promise { + const service = await Services.getInstance() + await service.sdkClient.unpair_device() + const newDevice = await this.dumpDevice(); + await this.saveDevice(newDevice); + } + + private prepareProcessTx(myAddress: string, recipientAddress: string) { + const initial_session_privkey = new Uint8Array(32); + const initial_session_pubkey = new Uint8Array(32); + const pairingTemplate = { + "description": "AliceBob", + "roles": { + "owner": { + "members": + [{sp_addresses: [myAddress, recipientAddress]}], + "validation_rules": + [ + { + "quorum": 1.0, + "fields": [ + "description", + "roles", + "session_privkey", + "session_pubkey", + "key_parity" + ], + "min_sig_member": 1.0 + } + ] + } + }, + "session_privkey": initial_session_privkey, + "session_pubkey": initial_session_pubkey, + "key_parity": true, + } + + + const apiReturn = this.sdkClient.create_update_transaction(undefined, JSON.stringify(pairingTemplate), 1) + return apiReturn + } + + public async sendPairingTx(spAddress: string): Promise { + + const localAddress = this.sdkClient.get_address(); + const emptyTxid = '0'.repeat(64) + + try { + let commitmentOutpoint = `${emptyTxid}:${U32_MAX}`; + this.sdkClient.pair_device(commitmentOutpoint, [spAddress]) + } catch (e) { + console.error("Services ~ Error:", e); + return + } + + setTimeout( async () => { + const apiReturn = this.prepareProcessTx(localAddress, spAddress) + await this.handleApiReturn(apiReturn); + }, 1500) - try { - let commitmentOutpoint = `${emptyTxid}:${U32_MAX}`; - this.sdkClient.pair_device(commitmentOutpoint, [spAddress]) - } catch (e) { - console.error("Services ~ Error:", e); return } - setTimeout(async () => { - const apiReturn = this.prepareProcessTx(localAddress, spAddress) - await this.handleApiReturn(apiReturn); - }, 100) - - return - } - - async resetDevice() { - await this.sdkClient.reset_device() - } - - async sendNewTxMessage(message: string) { - if (!this.websocketConnection) { - throw new Error('No websocket connection'); + async resetDevice() { + await this.sdkClient.reset_device() } - // console.log("πŸš€ ~ WebSocketClient ~ this.ws.onopen= ~ newTxMessage:", message) - await this.websocketConnection.sendMessage('NewTx', message) - } - async sendCommitMessage(message: string) { - // console.log("πŸš€ ~ WebSocketClient ~ this.ws.onopen= ~ CommitMessage:", message) - await this.websocketConnection?.sendMessage('Commit', message) - } - - async sendCipherMessages(ciphers: string[]) { - for (let i = 0; i < ciphers.length; i++) { - const cipher = ciphers[i]; - await this.websocketConnection?.sendMessage('Cipher', cipher); - } - } - - async sendFaucetMessage(message: string): Promise { - // console.log("πŸš€ ~ WebSocketClient ~ this.ws.onopen= ~ faucetMessage:", message) - await this.websocketConnection?.sendMessage('Faucet', message); - } - - async parseCipher(message: string) { - // try { - // JSON.parse(message) - // const router = await Routing.getInstance(); - // router.closeLoginModal() - // this.injectProcessListPage() - // } catch { - // console.log('Not proper format for cipher') - // } - try { - console.log('parsing new cipher'); - const apiReturn = await this.sdkClient.parse_cipher(message, 0.00001); - console.log("πŸš€ ~ Services ~ parseCipher ~ apiReturn:", apiReturn); - await this.handleApiReturn(apiReturn) - } catch (e) { - console.log("Cipher isn't for us"); - } - // await this.saveCipherTxToDb(parsedTx) - } - - async parseNewTx(tx: string) { - try { - // console.log('==============> sending txxxxxxx parser', tx) - const parsedTx = await this.sdkClient.parse_new_tx(tx, 0, 0.0001) - if (parsedTx) { - console.log("πŸš€ ~ Services ~ parseNewTx ~ parsedTx:", parsedTx) - try { - await this.handleApiReturn(parsedTx); - const newDevice = await this.dumpDevice(); - await this.saveDevice(newDevice); - } catch (e) { - console.error("Failed to update device with new tx"); - } + async sendNewTxMessage(message: string) { + if (!this.websocketConnection) { + throw new Error('No websocket connection'); } - } catch (e) { - console.trace(e); - } - } - - private async handleApiReturn(apiReturn: ApiReturn) { - if (apiReturn.ciphers_to_send && apiReturn.ciphers_to_send.length) { - await this.sendCipherMessages(apiReturn.ciphers_to_send) + // console.log("πŸš€ ~ WebSocketClient ~ this.ws.onopen= ~ newTxMessage:", message) + await this.websocketConnection.sendMessage('NewTx', message) } - setTimeout(async () => { - if (apiReturn.updated_process && apiReturn.updated_process.length) { - const [processCommitment, process] = apiReturn.updated_process; - console.debug('Updated Process Commitment:', processCommitment); - console.debug('Process Details:', process); + async sendCommitMessage(message: string) { + // console.log("πŸš€ ~ WebSocketClient ~ this.ws.onopen= ~ CommitMessage:", message) + await this.websocketConnection?.sendMessage('Commit', message) + } - // Save process to storage - localStorage.setItem(processCommitment, JSON.stringify(process)); - // Check if the newly updated process reveals some new information - try { - const proposals: string[] = this.sdkClient.get_update_proposals(processCommitment); - if (proposals && proposals.length != 0) { - const actual_proposal = JSON.parse(proposals[0]); // We just don't acknowledge concurrent proposals for now - console.info(actual_proposal); - let router = await Routing.getInstance(); - await router.openConfirmationModal(actual_proposal, processCommitment); + async sendCipherMessages(ciphers: string[]) { + for (let i = 0; i < ciphers.length; i++) { + const cipher = ciphers[i]; + await this.websocketConnection?.sendMessage('Cipher', cipher); + } + } + + async sendFaucetMessage(message: string): Promise { + // console.log("πŸš€ ~ WebSocketClient ~ this.ws.onopen= ~ faucetMessage:", message) + await this.websocketConnection?.sendMessage('Faucet', message); + } + async parseCipher(message: string) { + // try { + // JSON.parse(message) + // const router = await Routing.getInstance(); + // router.closeLoginModal() + // this.injectProcessListPage() + // } catch { + // console.log('Not proper format for cipher') + // } + try { + console.log('parsing new cipher'); + const apiReturn = await this.sdkClient.parse_cipher(message, 0.00001); + console.log("πŸš€ ~ Services ~ parseCipher ~ apiReturn:", apiReturn); + await this.handleApiReturn(apiReturn) + } catch (e) { + console.log("Cipher isn't for us"); + } + // await this.saveCipherTxToDb(parsedTx) + } + + async parseNewTx(tx: string) { + try { + // console.log('==============> sending txxxxxxx parser', tx) + const parsedTx = await this.sdkClient.parse_new_tx(tx, 0, 0.0001) + if(parsedTx) { + console.log("πŸš€ ~ Services ~ parseNewTx ~ parsedTx:", parsedTx) + try { + await this.handleApiReturn(parsedTx); + const newDevice = await this.dumpDevice(); + await this.saveDevice(newDevice); + } catch (e) { + console.error("Failed to update device with new tx"); } - } catch (e) { - console.error(e); } + } catch(e) { + console.trace(e); } - - if (apiReturn.updated_cached_msg && apiReturn.updated_cached_msg.length) { - apiReturn.updated_cached_msg.forEach((msg, index) => { - // console.debug(`CachedMessage ${index}:`, msg); - // Save the message to local storage - localStorage.setItem(msg.id.toString(), JSON.stringify(msg)); - }); - } - - if (apiReturn.commit_to_send) { - const commit = apiReturn.commit_to_send; - await this.sendCommitMessage(JSON.stringify(commit)); - } - - if (apiReturn.new_tx_to_send && apiReturn.new_tx_to_send.transaction.length != 0) { - await this.sendNewTxMessage(JSON.stringify(apiReturn.new_tx_to_send)) - } - }, 0) - } - - async pairDevice(prd: any, outpointCommitment: string) { - console.log("πŸš€ ~ Services ~ pairDevice ~ prd:", prd) - // const service = await Services.getInstance(); - // const spAddress = await this.getDeviceAddress() as any; - // const sender = JSON.parse(prd?.sender) - // const senderAddress = sender?.sp_addresses?.find((address: string) => address !== spAddress) - // console.log("πŸš€ ~ Services ~ pairDevice ~ senderAddress:", senderAddress) - // if(senderAddress) { - // const proposal = service.sdkClient.get_update_proposals(outpointCommitment); - // console.log("πŸš€ ~ Services ~ pairDevice ~ proposal:", proposal) - // // const pairingTx = proposal.pairing_tx.replace(/^\"+|\"+$/g, '') - // const parsedProposal = JSON.parse(proposal[0]) - - // console.log("πŸš€ ~ Services ~ pairDevice ~ parsedProposal:", parsedProposal) - // const roles = JSON.parse(parsedProposal.roles) - // console.log("πŸš€ ~ Services ~ pairDevice ~ roles:", roles, Array.isArray(roles), !roles.owner) - // if(Array.isArray(roles) || !roles.owner) return - // const proposalMembers = roles?.owner?.members - // const isFirstDevice = proposalMembers.some((member: Member) => member.sp_addresses.some(address => address === spAddress)) - // const isSecondDevice = proposalMembers.some((member: Member) => member.sp_addresses.some(address => address === senderAddress)) - // console.log("πŸš€ ~ Services ~ pairDevice ~ proposalMembers:", proposalMembers) - // if(proposalMembers?.length !== 2 || !isFirstDevice || !isSecondDevice) return - // const pairingTx = parsedProposal?.pairing_tx?.replace(/^\"+|\"+$/g, '') - - // let txid = '0'.repeat(64) - // console.log("πŸš€ ~ Services ~ pairDevice ~ pairingTx:", pairingTx, `${txid}:4294967295`) - - // const pairing = await service.sdkClient.pair_device(`${txid}:4294967295`, [senderAddress]) - // const device = this.dumpDevice() - // console.log("πŸš€ ~ Services ~ pairDevice ~ device:", device) - // this.saveDevice(device) - // // await service.sdkClient.pair_device(pairingTx, [senderAddress]) - // console.log("πŸš€ ~ Services ~ pairDevice ~ pairing:", pairing) - // // const process = await this.prepareProcessTx(spAddress, senderAddress) - // console.log("πŸš€ ~ Services ~ pairDevice ~ process:", outpointCommitment, prd, prd.payload) - // const prdString = JSON.stringify(prd).trim() - // console.log("πŸš€ ~ Services ~ pairDevice ~ prdString:", prdString) - // let tx = await service.sdkClient.response_prd(outpointCommitment, prdString, true) - // console.log("πŸš€ ~ Services ~ pairDevice ~ tx:", tx) - // if(tx.ciphers_to_send) { - // tx.ciphers_to_send.forEach((cipher: string) => service.websocketConnection?.sendMessage('Cipher', cipher)) - // } - // this.injectProcessListPage() - // } - } - - // async saveTxToDb(tx: CachedMessage) { - // const database = await Database.getInstance(); - // const indexedDb = await database.getDb(); - // await database.writeObject(indexedDb, 'messages', tx, null); - // } - - // async saveCipherTxToDb(tx: string) { - // const database = await Database.getInstance(); - // const indexedDb = await database.getDb(); - - // if(tx) { - // await database.writeObject(indexedDb, database.getStoreList().AnkCipherMessages, tx, null); - // } - // } - - async getAmount() { - const amount = await this.sdkClient.get_available_amount() - console.log("πŸš€ ~ Services ~ getAmount ~ amount:", amount) - return amount - } - - async getDeviceAddress() { - return await this.sdkClient.get_address(); - } - - async dumpDevice() { - const device = await this.sdkClient.dump_device() - // console.log("πŸš€ ~ Services ~ dumpDevice ~ device:", device) - return device - } - - async saveDevice(device: any): Promise { - // console.log("πŸš€ ~ Services ~ saveDevice ~ device:", device) - localStorage.setItem('wallet', device); - } - - async getDevice(): Promise { - return localStorage.getItem('wallet') - } - - async dumpWallet() { - const wallet = await this.sdkClient.dump_wallet() - console.log("πŸš€ ~ Services ~ dumpWallet ~ wallet:", wallet) - return wallet - } - - async createFaucetMessage() { - const message = await this.sdkClient.create_faucet_msg() - console.log("πŸš€ ~ Services ~ createFaucetMessage ~ message:", message) - return message; - } - - private addSubscription(element: Element, event: string, eventHandler: string): void { - this.subscriptions.push({ element, event, eventHandler }); - element.addEventListener(event, (this as any)[eventHandler].bind(this)); - } - - async createNewDevice() { - let spAddress = ''; - try { - spAddress = await this.sdkClient.create_new_device(0, 'regtest') - const device = await this.dumpDevice() - console.log("πŸš€ ~ Services ~ device:", device) - await this.saveDevice(device) - } catch (e) { - console.error("Services ~ Error:", e); } - this.generateQRCode(spAddress || '') - //Adress to Emoji integration - this.displayEmojis(spAddress) - //Adress to Emoji integration + private async handleApiReturn(apiReturn: ApiReturn) { + if (apiReturn.ciphers_to_send && apiReturn.ciphers_to_send.length) { + await this.sendCipherMessages(apiReturn.ciphers_to_send) + } + setTimeout(async () => { + if (apiReturn.updated_process && apiReturn.updated_process.length) { + const [processCommitment, process] = apiReturn.updated_process; + console.debug('Updated Process Commitment:', processCommitment); + console.debug('Process Details:', process); - return spAddress; - } + // Save process to storage + localStorage.setItem(processCommitment, JSON.stringify(process)); + // Check if the newly updated process reveals some new information + try { + const proposals: string[] = this.sdkClient.get_update_proposals(processCommitment); + if (proposals && proposals.length != 0) { + const actual_proposal = JSON.parse(proposals[0]); // We just don't acknowledge concurrent proposals for now + console.info(actual_proposal); + let router = await Routing.getInstance(); + await router.openConfirmationModal(actual_proposal, processCommitment); + } + } catch (e) { + console.error(e); + } + } + + if(apiReturn.updated_cached_msg && apiReturn.updated_cached_msg.length) { + apiReturn.updated_cached_msg.forEach((msg, index) => { + // console.debug(`CachedMessage ${index}:`, msg); + // Save the message to local storage + localStorage.setItem(msg.id.toString(), JSON.stringify(msg)); + }); + } + + if (apiReturn.commit_to_send) { + const commit = apiReturn.commit_to_send; + await this.sendCommitMessage(JSON.stringify(commit)); + } + + if (apiReturn.new_tx_to_send && apiReturn.new_tx_to_send.transaction.length != 0) { + await this.sendNewTxMessage(JSON.stringify(apiReturn.new_tx_to_send)) + } + }, 0) + } + + async pairDevice(prd: any, outpointCommitment: string) { + console.log("πŸš€ ~ Services ~ pairDevice ~ prd:", prd) + // const service = await Services.getInstance(); + // const spAddress = await this.getDeviceAddress() as any; + // const sender = JSON.parse(prd?.sender) + // const senderAddress = sender?.sp_addresses?.find((address: string) => address !== spAddress) + // console.log("πŸš€ ~ Services ~ pairDevice ~ senderAddress:", senderAddress) + // if(senderAddress) { + // const proposal = service.sdkClient.get_update_proposals(outpointCommitment); + // console.log("πŸš€ ~ Services ~ pairDevice ~ proposal:", proposal) + // // const pairingTx = proposal.pairing_tx.replace(/^\"+|\"+$/g, '') + // const parsedProposal = JSON.parse(proposal[0]) + + // console.log("πŸš€ ~ Services ~ pairDevice ~ parsedProposal:", parsedProposal) + // const roles = JSON.parse(parsedProposal.roles) + // console.log("πŸš€ ~ Services ~ pairDevice ~ roles:", roles, Array.isArray(roles), !roles.owner) + // if(Array.isArray(roles) || !roles.owner) return + // const proposalMembers = roles?.owner?.members + // const isFirstDevice = proposalMembers.some((member: Member) => member.sp_addresses.some(address => address === spAddress)) + // const isSecondDevice = proposalMembers.some((member: Member) => member.sp_addresses.some(address => address === senderAddress)) + // console.log("πŸš€ ~ Services ~ pairDevice ~ proposalMembers:", proposalMembers) + // if(proposalMembers?.length !== 2 || !isFirstDevice || !isSecondDevice) return + // const pairingTx = parsedProposal?.pairing_tx?.replace(/^\"+|\"+$/g, '') + + // let txid = '0'.repeat(64) + // console.log("πŸš€ ~ Services ~ pairDevice ~ pairingTx:", pairingTx, `${txid}:4294967295`) + + // const pairing = await service.sdkClient.pair_device(`${txid}:4294967295`, [senderAddress]) + // const device = this.dumpDevice() + // console.log("πŸš€ ~ Services ~ pairDevice ~ device:", device) + // this.saveDevice(device) + // // await service.sdkClient.pair_device(pairingTx, [senderAddress]) + // console.log("πŸš€ ~ Services ~ pairDevice ~ pairing:", pairing) + // // const process = await this.prepareProcessTx(spAddress, senderAddress) + // console.log("πŸš€ ~ Services ~ pairDevice ~ process:", outpointCommitment, prd, prd.payload) + // const prdString = JSON.stringify(prd).trim() + // console.log("πŸš€ ~ Services ~ pairDevice ~ prdString:", prdString) + // let tx = await service.sdkClient.response_prd(outpointCommitment, prdString, true) + // console.log("πŸš€ ~ Services ~ pairDevice ~ tx:", tx) + // if(tx.ciphers_to_send) { + // tx.ciphers_to_send.forEach((cipher: string) => service.websocketConnection?.sendMessage('Cipher', cipher)) + // } + // this.injectProcessListPage() + // } + } + + // async saveTxToDb(tx: CachedMessage) { + // const database = await Database.getInstance(); + // const indexedDb = await database.getDb(); + // await database.writeObject(indexedDb, 'messages', tx, null); + // } + + // async saveCipherTxToDb(tx: string) { + // const database = await Database.getInstance(); + // const indexedDb = await database.getDb(); + + // if(tx) { + // await database.writeObject(indexedDb, database.getStoreList().AnkCipherMessages, tx, null); + // } + // } + + async getAmount(): Promise { + const amount = await this.sdkClient.get_available_amount() + return amount + } + + async getDeviceAddress() { + return await this.sdkClient.get_address(); + } + + async dumpDevice() { + const device = await this.sdkClient.dump_device() + // console.log("πŸš€ ~ Services ~ dumpDevice ~ device:", device) + return device + } + + async saveDevice(device: any): Promise { + // console.log("πŸš€ ~ Services ~ saveDevice ~ device:", device) + localStorage.setItem('wallet', device); + } + + async getDevice(): Promise { + return localStorage.getItem('wallet') + } + + async dumpWallet() { + const wallet = await this.sdkClient.dump_wallet() + console.log("πŸš€ ~ Services ~ dumpWallet ~ wallet:", wallet) + return wallet + } + + async createFaucetMessage() { + const message = await this.sdkClient.create_faucet_msg() + console.log("πŸš€ ~ Services ~ createFaucetMessage ~ message:", message) + return message; + } + + addSubscription(element: Element, event: string, eventHandler: string): void { + this.subscriptions.push({ element, event, eventHandler }); + element.addEventListener(event, (this as any)[eventHandler].bind(this)); + } + + async createNewDevice() { + let spAddress = ''; + try { + spAddress = await this.sdkClient.create_new_device(0, 'regtest') + const device = await this.dumpDevice() + console.log("πŸš€ ~ Services ~ device:", device) + await this.saveDevice(device) + } catch (e) { + console.error("Services ~ Error:", e); + } - async restoreDevice(device: string) { - try { - await this.sdkClient.restore_device(device) - const spAddress = this.sdkClient.get_address(); this.generateQRCode(spAddress || '') //Adress to Emoji integration this.displayEmojis(spAddress) //Adress to Emoji integration - } catch (e) { - console.error(e); - } - } - - private getProcessesCache(): ProcessesCache { - // Regular expression to match 64-character hexadecimal strings - const hexU32KeyRegex: RegExp = /^[0-9a-fA-F]{64}:\d+$/; - const hexObjects: ProcessesCache = {} - - // Iterate over all keys in localStorage - for (let i = 0; i < localStorage.length; i++) { - const key = localStorage.key(i); - - if (!key) { - return hexObjects; - } - - // Check if the key matches the 32-byte hex pattern - if (hexU32KeyRegex.test(key)) { - const value = localStorage.getItem(key); - if (!value) { - continue; - } - - hexObjects[key] = JSON.parse(value); - } + return spAddress; } - return hexObjects; - } - - private getCachedMessages(): string[] { - const u32KeyRegex = /^\d+$/; - const U32_MAX = 4294967295; - const messages: string[] = []; - - for (let i = 0; i < localStorage.length; i++) { - const key = localStorage.key(i); - - if (!key) { - return messages; - } - - if (u32KeyRegex.test(key)) { - const num = parseInt(key, 10); - if (num < 0 || num > U32_MAX) { - console.warn(`Key ${key} is outside the u32 range and will be ignored.`); - continue; - } - - const value = localStorage.getItem(key); - if (!value) { - console.warn(`No value found for key: ${key}`); - continue; - } - - messages.push(value); - } - } - - return messages; - } - - public async restoreProcesses() { - const processesCache = this.getProcessesCache(); - console.log("πŸš€ ~ Services ~ restoreProcesses ~ processesCache:", processesCache); - - if (processesCache.length == 0) { - console.debug("πŸš€ ~ Services ~ restoreProcesses ~ no processes in local storage"); - return; - } - - try { - await this.sdkClient.set_process_cache(JSON.stringify(processesCache)); - } catch (e) { - console.error('Services ~ restoreProcesses ~ Error:', e); - } - } - - public async restoreMessages() { - const cachedMessages = this.getCachedMessages(); - console.log("πŸš€ ~ Services ~ restoreMessages ~ chachedMessages:", cachedMessages); - - if (cachedMessages && cachedMessages.length != 0) { + async restoreDevice(device: string) { try { - await this.sdkClient.set_message_cache(cachedMessages); + await this.sdkClient.restore_device(device) + const spAddress = this.sdkClient.get_address(); + this.generateQRCode(spAddress || '') + //Adress to Emoji integration + this.displayEmojis(spAddress) + //Adress to Emoji integration } catch (e) { - console.error('Services ~ restoreMessages ~ Error:', e); + console.error(e); } } - } + private getProcessesCache(): ProcessesCache { + // Regular expression to match 64-character hexadecimal strings + const hexU32KeyRegex: RegExp = /^[0-9a-fA-F]{64}:\d+$/; + const hexObjects: ProcessesCache = {} - private cleanSubscriptions(): void { - for (const sub of this.subscriptions) { - const el = sub.element; - const eventHandler = sub.eventHandler; - el.removeEventListener(sub.event, (this as any)[eventHandler].bind(this)); - } - this.subscriptions = []; - } + // Iterate over all keys in localStorage + for (let i = 0; i < localStorage.length; i++) { + const key = localStorage.key(i); - async injectProcessListPage(): Promise { - const container = document.getElementById('containerId'); - - if (!container) { - console.error("No html container"); - return; - } - - this.cleanSubscriptions() - - // const user = services.sdkClient.create_user('Test', 'test', 10, 1, 'Messaging') - // console.log("πŸš€ ~ Services ~ injectProcessListPage ~ user:", user) - - // const database = await Database.getInstance(); - // const indexedDb = await database.getDb(); - // await database.writeObject(indexedDb, database.getStoreList().AnkUser, user.user, null); - container.innerHTML = processPage; - const newScript = document.createElement('script'); - newScript.setAttribute('type', 'module') - newScript.textContent = processScript; - document.head.appendChild(newScript).parentNode?.removeChild(newScript); - - this.processes = await this.getProcesses(); - if (this.processes) { - this.setProcessesInSelectElement(this.processes) - } - } - - public async setProcessesInSelectElement(processList: any[]) { - const select = document.querySelector(".select-field"); - if (select) { - for (const process of processList) { - const option = document.createElement("option"); - option.setAttribute("value", process.name); - option.innerText = process.name; - select.appendChild(option); - } - } - const optionList = document.querySelector('.autocomplete-list'); - if (optionList) { - const observer = new MutationObserver((mutations, observer) => { - const options = optionList.querySelectorAll('li') - if (options) { - for (const option of options) { - this.addSubscription(option, 'click', 'showSelectedProcess') + if (!key) { + return hexObjects; } - } - }); - observer.observe(document, { - subtree: true, - attributes: true, - }); + + // Check if the key matches the 32-byte hex pattern + if (hexU32KeyRegex.test(key)) { + const value = localStorage.getItem(key); + if (!value) { + continue; + } + + hexObjects[key] = JSON.parse(value); + } + } + + return hexObjects; } - } - public async listenToOptionListPopulating(event: Event) { - const target = event.target as HTMLUListElement; - const options = target?.querySelectorAll('li') - } + private getCachedMessages(): string[] { + const u32KeyRegex = /^\d+$/; + const U32_MAX = 4294967295; + const messages: string[] = []; - public async showSelectedProcess(event: MouseEvent) { - const elem = event.target; - if (elem) { + for (let i = 0; i < localStorage.length; i++) { + const key = localStorage.key(i); - const cardContent = document.querySelector(".card-content"); + if (!key) { + return messages; + } - const processes = await this.getProcesses(); - console.log("πŸš€ ~ Services ~ showSelectedProcess ~ processes:", processes) - const process = processes.find((process: any) => process.name === (elem as any).dataset.value); - if (process) { - const processDiv = document.createElement("div"); - processDiv.className = "process"; - processDiv.id = process.name; - const titleDiv = document.createElement("div"); - titleDiv.className = "process-title"; - titleDiv.innerHTML = `${process.name} : ${process.description}`; - processDiv.appendChild(titleDiv); - for (const zone of process.zoneList) { - const zoneElement = document.createElement("div"); - zoneElement.className = "process-element"; - zoneElement.setAttribute('zone-id', zone.id.toString()) - zoneElement.innerHTML = `Zone ${zone.id} : ${zone.name}`; - this.addSubscription(zoneElement, 'click', 'goToProcessPage') - processDiv.appendChild(zoneElement); - } - if (cardContent) cardContent.appendChild(processDiv); + if (u32KeyRegex.test(key)) { + const num = parseInt(key, 10); + if (num < 0 || num > U32_MAX) { + console.warn(`Key ${key} is outside the u32 range and will be ignored.`); + continue; + } + + const value = localStorage.getItem(key); + if (!value) { + console.warn(`No value found for key: ${key}`); + continue; + } + + messages.push(value); + } + } + + return messages; + } + + public async restoreProcesses() { + const processesCache = this.getProcessesCache(); + console.log("πŸš€ ~ Services ~ restoreProcesses ~ processesCache:", processesCache); + + if (processesCache.length == 0) { + console.debug("πŸš€ ~ Services ~ restoreProcesses ~ no processes in local storage"); + return; + } + + try { + await this.sdkClient.set_process_cache(JSON.stringify(processesCache)); + } catch (e) { + console.error('Services ~ restoreProcesses ~ Error:', e); } } - } - goToProcessPage(event: MouseEvent) { - const target = event.target as HTMLDivElement; - const zoneId = target?.getAttribute('zone-id'); - const processList = document.querySelectorAll('.process-element'); - if (processList) { - for (const process of processList) { - process.classList.remove('selected') + public async restoreMessages() { + const cachedMessages = this.getCachedMessages(); + console.log("πŸš€ ~ Services ~ restoreMessages ~ chachedMessages:", cachedMessages); + + if (cachedMessages && cachedMessages.length != 0) { + try { + await this.sdkClient.set_message_cache(cachedMessages); + } catch (e) { + console.error('Services ~ restoreMessages ~ Error:', e); + } } + } - target.classList.add('selected') - console.log('=======================> going to process page', zoneId) - } + private cleanSubscriptions(): void { + for (const sub of this.subscriptions) { + const el = sub.element; + const eventHandler = sub.eventHandler; + el.removeEventListener(sub.event, (this as any)[eventHandler].bind(this)); + } + this.subscriptions = []; + } - async getProcesses(): Promise { - const processes = this.sdkClient.get_processes() - console.log("πŸš€ ~ Services ~ getProcesses ~ processes:", processes) - return [ - { - id: 1, - name: "Messaging", - description: "Encrypted messages", - zoneList: [ + public async setProcessesInSelectElement(processList: any[]) { + const select = document.querySelector(".select-field"); + if(select) { + for (const process of processList) { + const option = document.createElement("option"); + option.setAttribute("value", process.name); + option.innerText = process.name; + select.appendChild(option); + } + } + const optionList = document.querySelector('.autocomplete-list'); + if(optionList) { + const observer = new MutationObserver((mutations, observer) => { + const options = optionList.querySelectorAll('li') + if(options) { + for(const option of options) { + this.addSubscription(option, 'click', 'showSelectedProcess') + } + } + }); + observer.observe(document, { + subtree: true, + attributes: true, + }); + } + } + + public async listenToOptionListPopulating(event: Event) { + const target = event.target as HTMLUListElement; + const options = target?.querySelectorAll('li') + } + + + + getNotifications(): INotification[] { + return [ { id: 1, - name: "General", - path: '/test' - }, - ], - }, - { - id: 2, - name: "Storage", - description: "Distributed storage", - zoneList: [ - { - id: 1, - name: "Paris", - path: '/test' + title: 'Notif 1', + description: 'A normal notification', + sendToNotificationPage: false, + path: '/notif1' }, { id: 2, - name: "Normandy", - path: '/test' + title: 'Notif 2', + description: 'A normal notification', + sendToNotificationPage: false, + path: '/notif2' }, { id: 3, - name: "New York", - path: '/test' - }, - { - id: 4, - name: "Moscow", - path: '/test' - }, - ], - }, - ]; - } - - getNotifications(): INotification[] { - return [ - { - id: 1, - title: 'Notif 1', - description: 'A normal notification', - sendToNotificationPage: false, - path: '/notif1' - }, - { - id: 2, - title: 'Notif 2', - description: 'A normal notification', - sendToNotificationPage: false, - path: '/notif2' - }, - { - id: 3, - title: 'Notif 3', - description: 'A normal notification', - sendToNotificationPage: false, - path: '/notif3' + title: 'Notif 3', + description: 'A normal notification', + sendToNotificationPage: false, + path: '/notif3' + } + ] } - ] - } - async setNotification(): Promise { - const badge = document.querySelector('.notification-badge') as HTMLDivElement - const notifications = this.notifications - const noNotifications = document.querySelector('.no-notification') as HTMLDivElement - if (notifications?.length) { - badge.innerText = notifications.length.toString() - const notificationBoard = document.querySelector('.notification-board') as HTMLDivElement - noNotifications.style.display = 'none' - for (const notif of notifications) { - const notifElement = document.createElement("div"); - notifElement.className = "notification-element"; - notifElement.setAttribute('notif-id', notif.id.toString()) - notifElement.innerHTML = ` + async setNotification(): Promise { + const badge = document.querySelector('.notification-badge') as HTMLDivElement + const notifications = this.notifications + const noNotifications = document.querySelector('.no-notification') as HTMLDivElement + if(notifications?.length) { + badge.innerText = notifications.length.toString() + const notificationBoard = document.querySelector('.notification-board') as HTMLDivElement + noNotifications.style.display = 'none' + for(const notif of notifications) { + const notifElement = document.createElement("div"); + notifElement.className = "notification-element"; + notifElement.setAttribute('notif-id', notif.id.toString()) + notifElement.innerHTML = `
${notif.title}
${notif.description}
`; - // this.addSubscription(notifElement, 'click', 'goToProcessPage') - notificationBoard.appendChild(notifElement); - } - } else { - noNotifications.style.display = 'block' + // this.addSubscription(notifElement, 'click', 'goToProcessPage') + notificationBoard.appendChild(notifElement); + } + } else { + noNotifications.style.display = 'block' - } - } + } + } } diff --git a/tsconfig.json b/tsconfig.json index 87b2411..f52029d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,6 +22,6 @@ "~/*": ["src/*"] } }, - "include": ["src", "src/**/*", "./vite.config.ts", "src/index.d.ts"], + "include": ["src", "src/**/*", "./vite.config.ts", "src/index.d.ts", "src/router.ts"], "exclude": ["node_modules"] } \ No newline at end of file