"use strict"; // Global variables const appPages = ['dashboard', 'settings']; // Global variables const { html, render: renderElem } = uhtml; //Checks for internet connection status if (!navigator.onLine) floGlobals.connectionErrorNotification = notify('There seems to be a problem connecting to the internet, Please check you internet connection.', 'error') window.addEventListener('offline', () => { floGlobals.connectionErrorNotification = notify('There seems to be a problem connecting to the internet, Please check you internet connection.', 'error') }) window.addEventListener('online', () => { getRef('notification_drawer').remove(floGlobals.connectionErrorNotification) notify('We are back online.', 'success') }) // Use instead of document.getElementById const domRefs = {}; function getRef(elementId) { if (!domRefs.hasOwnProperty(elementId)) { domRefs[elementId] = { count: 1, ref: null, }; return document.getElementById(elementId); } else { if (domRefs[elementId].count < 3) { domRefs[elementId].count = domRefs[elementId].count + 1; return document.getElementById(elementId); } else { if (!domRefs[elementId].ref) domRefs[elementId].ref = document.getElementById(elementId); return domRefs[elementId].ref; } } } // Use when a function needs to be executed after user finishes changes const debounce = (callback, wait) => { let timeoutId = null; return (...args) => { window.clearTimeout(timeoutId); timeoutId = window.setTimeout(() => { callback.apply(null, args); }, wait); }; } //Function for displaying toast notifications. pass in error for mode param if you want to show an error. function notify(message, mode, options = {}) { let icon switch (mode) { case 'success': icon = `` break; case 'error': icon = `` options.pinned = true break; } if (mode === 'error') { console.error(message) } return getRef("notification_drawer").push(message, { icon, ...options }); } function getFormattedTime(timestamp, format) { try { timestamp = parseInt(timestamp) if (String(timestamp).length < 13) timestamp *= 1000 let [day, month, date, year] = new Date(timestamp).toString().split(' '), minutes = new Date(timestamp).getMinutes(), hours = new Date(timestamp).getHours(), currentTime = new Date().toString().split(' ') minutes = minutes < 10 ? `0${minutes}` : minutes let finalHours = ``; if (hours > 12) finalHours = `${hours - 12}:${minutes}` else if (hours === 0) finalHours = `12:${minutes}` else finalHours = `${hours}:${minutes}` finalHours = hours >= 12 ? `${finalHours} PM` : `${finalHours} AM` switch (format) { case 'date-only': return `${month} ${date}, ${year}`; case 'time-only': return finalHours; case 'relative': return relativeTime.from(timestamp) default: return `${month} ${date}, ${year} at ${finalHours}`; } } catch (e) { console.error(e); return timestamp; } } window.addEventListener('hashchange', e => routeTo(window.location.hash)) window.addEventListener("load", () => { document.body.classList.remove('hidden') document.addEventListener("pointerdown", (e) => { if (e.target.closest("button, .interact")) { createRipple(e, e.target.closest("button, .interact")); } }); document.addEventListener('copy', () => { notify('copied', 'success') }) document.addEventListener('keydown', e => { if (e.key === '/') { e.preventDefault(); getRef('search_payments').focusIn() } }) getRef('search_payments').addEventListener('input', e => { const searchQuery = e.target.value.toLowerCase(); const filteredInterns = [] floGlobals.internTxs.forEach((intern, floId) => { if (floId.toLowerCase().includes(searchQuery) || floGlobals.appObjects.RIBC.internList[floId].toLowerCase().includes(searchQuery)) filteredInterns.push({ floId, name: floGlobals.appObjects.RIBC.internList[floId] }) }) // sort filtered by relevance to search query (name first, then floId) filteredInterns.sort((a, b) => { if (a.name.toLowerCase().includes(searchQuery) && b.name.toLowerCase().includes(searchQuery)) { return a.name.toLowerCase().indexOf(searchQuery) - b.name.toLowerCase().indexOf(searchQuery) } else if (a.name.toLowerCase().includes(searchQuery)) { return -1 } else if (b.name.toLowerCase().includes(searchQuery)) { return 1 } else { return a.floId.toLowerCase().indexOf(searchQuery) - b.floId.toLowerCase().indexOf(searchQuery) } }) renderElem(getRef("intern_payment_list"), html`${filteredInterns.map(intern => render.internCard(intern.floId))}`); }) }); function createRipple(event, target) { const circle = document.createElement("span"); const diameter = Math.max(target.clientWidth, target.clientHeight); const radius = diameter / 2; const targetDimensions = target.getBoundingClientRect(); circle.style.width = circle.style.height = `${diameter}px`; circle.style.left = `${event.clientX - (targetDimensions.left + radius)}px`; circle.style.top = `${event.clientY - (targetDimensions.top + radius)}px`; circle.classList.add("ripple"); const rippleAnimation = circle.animate( [ { transform: "scale(3)", opacity: 0, }, ], { duration: 1000, fill: "forwards", easing: "ease-out", } ); target.append(circle); rippleAnimation.onfinish = () => { circle.remove(); }; } const appState = { params: {}, } function routeTo(targetPage) { const routingAnimation = { in: slideInUp, out: slideOutUp } let pageId let subPageId1 let searchParams let params if (targetPage === '') { pageId = 'home' history.replaceState(null, null, '#/home'); } else { if (targetPage.includes('/')) { if (targetPage.includes('?')) { const splitAddress = targetPage.split('?') searchParams = splitAddress.pop(); [, pageId, subPageId1] = splitAddress.pop().split('/') } else { [, pageId, subPageId1] = targetPage.split('/') } } else { pageId = targetPage } } if (!getRef(pageId)?.classList.contains('page')) return appState.currentPage = pageId if (searchParams) { const urlSearchParams = new URLSearchParams('?' + searchParams); params = Object.fromEntries(urlSearchParams.entries()); } if (params) appState.params = params switch (pageId) { case 'intern': if (params && params.id) { render.intern(params.id) } break; } switch (appState.lastPage) { case 'intern': routingAnimation.in = slideInRight; routingAnimation.out = slideOutRight; break; } switch (pageId) { case 'intern': routingAnimation.in = slideInLeft; routingAnimation.out = slideOutLeft; break; } if (appState.lastPage !== pageId) { document.querySelectorAll('.page').forEach(page => page.classList.add('hidden')) getRef(pageId).closest('.page').classList.remove('hidden') if (appState.lastPage) { getRef(appState.lastPage).animate(routingAnimation.out, { duration: floGlobals.prefersReducedMotion ? 0 : 150, fill: 'forwards', easing: 'ease' }).onfinish = (e) => { e.target.effect.target.classList.add('hidden') } } getRef(pageId).classList.remove('hidden') getRef(pageId).animate(routingAnimation.in, { duration: floGlobals.prefersReducedMotion ? 0 : 150, fill: 'forwards', easing: 'ease' }).onfinish = (e) => { appState.lastPage = pageId } } } const slideInLeft = [ { opacity: 0, transform: 'translateX(1rem)' }, { opacity: 1, transform: 'translateX(0)' } ] const slideOutLeft = [ { opacity: 1, transform: 'translateX(0)' }, { opacity: 0, transform: 'translateX(-1rem)' }, ] const slideInRight = [ { opacity: 0, transform: 'translateX(-1rem)' }, { opacity: 1, transform: 'translateX(0)' } ] const slideOutRight = [ { opacity: 1, transform: 'translateX(0)' }, { opacity: 0, transform: 'translateX(1rem)' }, ] const slideInDown = [ { opacity: 0, transform: 'translateY(-1rem)' }, { opacity: 1, transform: 'translateY(0)' }, ] const slideOutDown = [ { opacity: 1, transform: 'translateY(0)' }, { opacity: 0, transform: 'translateY(1rem)' }, ] const slideInUp = [ { opacity: 0, transform: 'translateY(1rem)' }, { opacity: 1, transform: 'translateY(0)' }, ] const slideOutUp = [ { opacity: 1, transform: 'translateY(0)' }, { opacity: 0, transform: 'translateY(-1rem)' }, ] floGlobals.payer = 'FThgnJLcuStugLc24FJQggmp2WgaZjrBSn'; floGlobals.internTxs = new Map() function formatAmount(amount = 0) { if (!amount) return '₹0'; return amount.toLocaleString(`en-IN`, { style: 'currency', currency: 'inr' }) } function fetchRibcData() { return floCloudAPI.requestObjectData("RIBC", { application: "InternManage", receiverID: "FMyRTrz9CG4TFNM6rCQgy3VQ5NF23bY2xD", senderID: [ "FCja6sLv58e3RMy41T5AmWyvXEWesqBCkX", "FFS5hFXG7DBtdgzrLwixZLpenAmsCKRddm", "FS4jMAcSimRMrhoRhk5cjuJERS2otiwq4A" ], }) } function fetchTransactions() { return floTokenAPI.getAllTxs(floGlobals.payer) } const render = { internCard(floId) { const { total, txs } = floGlobals.internTxs.get(floId); return html`
Last payment: ${formatAmount(txs[0].amount)} on ${getFormattedTime(txs[0].time, 'date-only')}
Total paid: ${formatAmount(total)}
${formatAmount(amount)}
View transactionFLO Address
Total paid: ${formatAmount(floGlobals.internTxs.get(floId).total)}