const uiGlobals={},{html:html,svg:svg,render:renderElem}=uhtml,{signal:signal,computed:computed,effect:effect}=preactSignalsCore;function getRef(elementId){return document.getElementById(elementId)}uiGlobals.connectionErrorNotification=[],navigator.onLine||uiGlobals.connectionErrorNotification.push(notify("There seems to be a problem connecting to the internet, Please check you internet connection.","error")),window.addEventListener("offline",(()=>{uiGlobals.connectionErrorNotification.push(notify("There seems to be a problem connecting to the internet, Please check you internet connection.","error"))})),window.addEventListener("online",(()=>{uiGlobals.connectionErrorNotification.forEach((notification=>{getRef("notification_drawer").remove(notification)})),notify("We are back online.","success")}));const getConfirmation=(title,options={})=>new Promise((resolve=>{const{message:message="",cancelText:cancelText="Cancel",confirmText:confirmText="OK",danger:danger=!1}=options;getRef("confirm_title").innerText=title,getRef("confirm_message").innerText=message;const cancelButton=getRef("confirmation_popup").querySelector(".cancel-button"),confirmButton=getRef("confirmation_popup").querySelector(".confirm-button");confirmButton.textContent=confirmText,cancelButton.textContent=cancelText,danger?confirmButton.classList.add("button--danger"):confirmButton.classList.remove("button--danger");const{opened:opened,closed:closed}=openPopup("confirmation_popup");confirmButton.onclick=()=>{closePopup({payload:!0})},cancelButton.onclick=()=>{closePopup()},closed.then((payload=>{confirmButton.onclick=null,cancelButton.onclick=null,resolve(!!payload)}))})),debounce=(callback,wait)=>{let timeoutId=null;return(...args)=>{window.clearTimeout(timeoutId),timeoutId=window.setTimeout((()=>{callback.apply(null,args)}),wait)}};function addClass(elements,className){elements.forEach((element=>{document.querySelector(element).classList.add(className)}))}function removeClass(elements,className){elements.forEach((element=>{document.querySelector(element).classList.remove(className)}))}function getAllElements(selector){return Array.from(document.querySelectorAll(selector))}let zIndex=50;function openPopup(popupId,pinned){return void 0===popupStack.peek()&&document.addEventListener("keydown",(e=>{"Escape"===e.key&&closePopup()})),zIndex++,getRef(popupId).setAttribute("style",`z-index: ${zIndex}`),getRef(popupId).show({pinned:pinned})}function closePopup(options={}){void 0!==popupStack.peek()&&popupStack.peek().popup.hide(options)}function notify(message,mode,options={}){let icon;switch(mode){case"success":icon='';break;case"error":icon='',options.hasOwnProperty("timeout")||(options.pinned=!0)}return"error"===mode&&console.error(message),getRef("notification_drawer").push(message,{icon:icon,...options})}function getFormattedTime(timestamp,format){try{String(timestamp).length<13&&(timestamp*=1e3);let[day,month,date,year]=new Date(timestamp).toString().split(" "),minutes=new Date(timestamp).getMinutes(),hours=new Date(timestamp).getHours();(new Date).toString().split(" ");minutes=minutes<10?`0${minutes}`:minutes;let finalHours="";switch(finalHours=hours>12?`${hours-12}:${minutes}`:0===hours?`12:${minutes}`:`${hours}:${minutes}`,finalHours=hours>=12?`${finalHours} PM`:`${finalHours} AM`,format){case"date-only":return`${month} ${date}, ${year}`;case"time-only":return finalHours;default:return`${month} ${date} ${year}, ${finalHours}`}}catch(e){return console.error(e),timestamp}}function detectBrowser(){let tem,ua=navigator.userAgent,M=ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i)||[];return/trident/i.test(M[1])?(tem=/\brv[ :]+(\d+)/g.exec(ua)||[],"IE "+(tem[1]||"")):"Chrome"===M[1]&&(tem=ua.match(/\b(OPR|Edge)\/(\d+)/),null!=tem)?tem.slice(1).join(" ").replace("OPR","Opera"):(M=M[2]?[M[1],M[2]]:[navigator.appName,navigator.appVersion,"-?"],null!=(tem=ua.match(/version\/(\d+)/i))&&M.splice(1,1,tem[1]),M.join(" "))}function createRipple(event,target){const circle=document.createElement("span"),diameter=Math.max(target.clientWidth,target.clientHeight),radius=diameter/2,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([{opacity:1,transform:"scale(0)"},{transform:"scale(4)",opacity:0}],{duration:600,fill:"forwards",easing:"ease-out"});target.append(circle),rippleAnimation.onfinish=()=>{circle.remove()}}document.addEventListener("popupopened",(async e=>{if(history.pushState({type:"popup"},null,null),"profile_popup"===e.target.id)renderElem(getRef("profile_popup__content"),html`
BTC integrated with FLO
You can use your FLO private key to perform transactions on the BTC network within our
app
ecosystem. The private key is the same for both.
My FLO address
My Bitcoin address
`)})),document.addEventListener("popupclosed",(e=>{switch(zIndex--,e.target.id){case"task_popup":delete getRef("task_popup").dataset.taskId;break;case"send_update_popup":renderElem(getRef("send_update_popup__content"),html``)}void 0===popupStack.peek()&&document.removeEventListener("keydown",(e=>{"Escape"===e.key&&closePopup()}))})),window.addEventListener("popstate",(e=>{if(e.state&&"popup"===e.state.type)closePopup()}));class Router{constructor(options={}){const{routes:routes={},state:state={},routingStart:routingStart,routingEnd:routingEnd}=options;this.routes=routes,this.state=state,this.routingStart=routingStart,this.routingEnd=routingEnd,this.lastPage=null,window.addEventListener("hashchange",(e=>this.routeTo(window.location.hash)))}addRoute(route,callback){this.routes[route]=callback}handleRouting=async page=>{this.routingStart&&this.routingStart(this.state),this.routes[page]?(await this.routes[page](this.state),this.lastPage=page):this.routes[404]?this.routes[404](this.state):console.error(`No route found for '${page}' and no '404' route is defined.`),this.routingEnd&&this.routingEnd(this.state)};async routeTo(destination){try{let page,wildcards=[],params={},[path,queryString]=destination.split("?");path.includes("#")&&(path=path.split("#")[1]),path.includes("/")?[,page,...wildcards]=path.split("/"):page=path,this.state={page:page,wildcards:wildcards,lastPage:this.lastPage,params:params},queryString&&(params=new URLSearchParams(queryString),this.state.params=Object.fromEntries(params)),document.startViewTransition?document.startViewTransition((async()=>{await this.handleRouting(page)})):await this.handleRouting(page)}catch(e){console.error(e)}}}class LazyLoader{constructor(container,elementsToRender,renderFn,options={}){const{batchSize:batchSize=10,freshRender:freshRender,bottomFirst:bottomFirst=!1,domUpdated:domUpdated}=options;this.elementsToRender=elementsToRender,this.arrayOfElements="function"==typeof elementsToRender?this.elementsToRender():elementsToRender||[],this.renderFn=renderFn,this.intersectionObserver,this.batchSize=batchSize,this.freshRender=freshRender,this.domUpdated=domUpdated,this.bottomFirst=bottomFirst,this.shouldLazyLoad=!1,this.lastScrollTop=0,this.lastScrollHeight=0,this.lazyContainer=document.querySelector(container),this.update=this.update.bind(this),this.render=this.render.bind(this),this.init=this.init.bind(this),this.clear=this.clear.bind(this)}get elements(){return this.arrayOfElements}init(){this.intersectionObserver=new IntersectionObserver(((entries,observer)=>{entries.forEach((entry=>{entry.isIntersecting&&(observer.disconnect(),this.render({lazyLoad:!0}))}))})),this.mutationObserver=new MutationObserver((mutationList=>{mutationList.forEach((mutation=>{"childList"===mutation.type&&mutation.addedNodes.length&&(this.bottomFirst?this.lazyContainer.firstElementChild&&this.intersectionObserver.observe(this.lazyContainer.firstElementChild):this.lazyContainer.lastElementChild&&this.intersectionObserver.observe(this.lazyContainer.lastElementChild))}))})),this.mutationObserver.observe(this.lazyContainer,{childList:!0}),this.render()}update(elementsToRender){this.arrayOfElements="function"==typeof elementsToRender?this.elementsToRender():elementsToRender||[]}render(options={}){let{lazyLoad:lazyLoad=!1}=options;this.shouldLazyLoad=lazyLoad;const frag=document.createDocumentFragment();lazyLoad?this.bottomFirst?(this.updateEndIndex=this.updateStartIndex,this.updateStartIndex=this.updateEndIndex-this.batchSize):(this.updateStartIndex=this.updateEndIndex,this.updateEndIndex=this.updateEndIndex+this.batchSize):(this.intersectionObserver.disconnect(),this.bottomFirst?(this.updateEndIndex=this.arrayOfElements.length,this.updateStartIndex=this.updateEndIndex-this.batchSize-1):(this.updateStartIndex=0,this.updateEndIndex=this.batchSize),this.lazyContainer.innerHTML=""),this.lastScrollHeight=this.lazyContainer.scrollHeight,this.lastScrollTop=this.lazyContainer.scrollTop,this.arrayOfElements.slice(this.updateStartIndex,this.updateEndIndex).forEach(((element,index)=>{frag.append(this.renderFn(element))})),this.bottomFirst?(this.lazyContainer.prepend(frag),this.lastScrollTop+=this.lazyContainer.scrollHeight-this.lastScrollHeight,this.lazyContainer.scrollTo({top:this.lastScrollTop}),this.lastScrollHeight=this.lazyContainer.scrollHeight):this.lazyContainer.append(frag),!lazyLoad&&this.bottomFirst&&(this.lazyContainer.scrollTop=this.lazyContainer.scrollHeight),!lazyLoad&&this.freshRender&&this.freshRender()}clear(){this.intersectionObserver.disconnect(),this.mutationObserver.disconnect(),this.lazyContainer.innerHTML=""}reset(){this.arrayOfElements="function"==typeof this.elementsToRender?this.elementsToRender():this.elementsToRender||[],this.render()}}function buttonLoader(id,show){const button="string"==typeof id?document.getElementById(id):id;if(!button)return;button.dataset.hasOwnProperty("wasDisabled")||(button.dataset.wasDisabled=button.disabled);const animOptions={duration:200,fill:"forwards",easing:"ease"};if(show)button.disabled=!0,button.parentNode.append(document.createElement("sm-spinner")),button.animate([{clipPath:"circle(100%)"},{clipPath:"circle(0)"}],animOptions);else{button.disabled="true"===button.dataset.wasDisabled,button.animate([{clipPath:"circle(0)"},{clipPath:"circle(100%)"}],animOptions).onfinish=e=>{button.removeAttribute("data-original-state")};const potentialTarget=button.parentNode.querySelector("sm-spinner");potentialTarget&&potentialTarget.remove()}}let isMobileView=!1;const mobileQuery=window.matchMedia("(max-width: 40rem)");function handleMobileChange(e){isMobileView=e.matches}mobileQuery.addEventListener("change",handleMobileChange),handleMobileChange(mobileQuery);const slideInLeft=[{opacity:0,transform:"translateX(1.5rem)"},{opacity:1,transform:"translateX(0)"}],slideOutLeft=[{opacity:1,transform:"translateX(0)"},{opacity:0,transform:"translateX(-1.5rem)"}],slideInRight=[{opacity:0,transform:"translateX(-1.5rem)"},{opacity:1,transform:"translateX(0)"}],slideOutRight=[{opacity:1,transform:"translateX(0)"},{opacity:0,transform:"translateX(1.5rem)"}],slideInDown=[{opacity:0,transform:"translateY(-1.5rem)"},{opacity:1,transform:"translateY(0)"}],slideOutUp=[{opacity:1,transform:"translateY(0)"},{opacity:0,transform:"translateY(-1.5rem)"}];async function saveProfile(){const name=getRef("profile__name").value.trim(),email=getRef("profile__email").value.trim(),college=getRef("profile__college").value.trim(),course=getRef("profile__course").value.trim(),whatsappNumber=getRef("profile__whatsapp_number").value.trim(),stringifiedData=JSON.stringify({name:name,email:email,college:college,course:course,whatsappNumber:whatsappNumber});if(stringifiedData===floDapps.user.decipher(floGlobals.userProfile))return notify("No changes detected","error");if(!await getConfirmation("Save details",{message:"Are you sure you want to save these details?",confirmText:"Save"}))return;const encryptedData=floDapps.user.encipher(stringifiedData);buttonLoader("profile__save",!0),floCloudAPI.sendGeneralData({encryptedData:encryptedData},"userProfile").then((response=>{notify("Profile saved successfully","success"),floGlobals.userProfile=encryptedData})).catch((e=>{notify("An error occurred while saving the profile","error"),console.error(e)})).finally((()=>{buttonLoader("profile__save",!1)}))}async function startWorkingOnATask(id){if(!floGlobals.isUserLoggedIn)return notify("You need to be logged in to start working on a task"),void(location.hash="#/sign_in");await getConfirmation("Start working on this task?",{message:"Other tasks won't be available until you finish this task, continue?",confirmText:"Start working"})&&floCloudAPI.sendGeneralData({taskID:id},"taskApplications").then((response=>{notify("You can now start working on the task","success"),floGlobals.applications.add(id),render.availableTasks()})).catch((e=>{notify("An error occurred while sending the application","error"),console.error(e)}))}async function initSendingUpdate(id){const updateType=signal("progress");let updateForm;effect((()=>{switch(updateType.value){case"progress":updateForm=html`
`)})),openPopup("send_update_popup")}function editTask(details){const{id:id,title:title,description:description,category:category,deadline:deadline}=details;getRef("task_popup__title_input").value=title,getRef("task_popup__description").value=description,getRef("task_popup__category").value=category,getRef("task_popup__deadline").value=deadline,getRef("task_popup").dataset.taskId=id,openPopup("task_popup")}async function saveTask(){if(!await getConfirmation("Save task",{message:"Are you sure you want to save this task?",confirmText:"Save"}))return;const title=getRef("task_popup__title_input").value,description=getRef("task_popup__description").value,category=getRef("task_popup__category").value,id=getRef("task_popup").dataset.taskId||category+"_"+Math.random().toString(36).substring(2,9),deadline=getRef("task_popup__deadline").value,task={id:id,title:title,description:description,category:category,deadline:deadline,status:"open"},foundTask=floGlobals.appObjects[category].tasks.find((task=>task.id===id));if(foundTask){let taskDetailsChanged=!1;for(const key in task)task[key]!==foundTask[key]&&(taskDetailsChanged=!0,foundTask[key]=task[key]);if(!taskDetailsChanged)return notify("Please update at least one detail to save the changes","error")}else task.date=Date.now(),floGlobals.appObjects[category].tasks.unshift(task);buttonLoader("task_popup__submit",!0),floCloudAPI.updateObjectData(category).then((response=>{notify("Task saved successfully","success"),render.availableTasks()})).catch((e=>{notify("An error occurred while saving the task","error"),console.error(e)})).finally((()=>{buttonLoader("task_popup__submit",!1),closePopup()}))}async function deleteTask(id){if(!await getConfirmation("Delete task",{message:"Are you sure you want to delete this task?",confirmText:"Delete",danger:!0}))return;const[category]=id.split("_"),taskIndex=floGlobals.appObjects[category].tasks.findIndex((task=>task.id===id));if(taskIndex<0)return notify("Task not found","error");const[cloneOfTaskToBeDeleted]=floGlobals.appObjects[category].tasks.splice(taskIndex,1);floCloudAPI.updateObjectData(category).then((response=>{notify("Task deleted successfully","success")})).catch((e=>{notify("An error occurred while deleting the task","error"),floGlobals.appObjects[category].tasks.splice(taskIndex,0,cloneOfTaskToBeDeleted)})).finally((()=>{closePopup(),render.availableTasks()}))}window.smCompConfig={"sm-input":[{selector:"[data-flo-address]",customValidation:value=>value?{isValid:floCrypto.validateFloID(value),errorText:'Invalid FLO address. It usually starts with "F"'}:{isValid:!1,errorText:"Please enter a FLO address"}},{selector:"[data-btc-address]",customValidation:value=>value?{isValid:btcOperator.validateAddress(value),errorText:'Invalid address. It usually starts with "1", "3" or "bc1"'}:{isValid:!1,errorText:"Please enter a BTC address"}},{selector:"[data-private-key]",customValidation:(value,inputElem)=>{if(!value)return{isValid:!1,errorText:"Please enter a private key"};if(floCrypto.getPubKeyHex(value)){const forAddress=inputElem.dataset.forAddress;return forAddress?{isValid:btcOperator.verifyKey(forAddress,value),errorText:`This private key does not match the address ${forAddress}`}:{isValid:!0}}return{isValid:!1,errorText:"Invalid private key. Please check and try again."}}},{selector:'[type="email"]',customValidation:(value,target)=>""===value?{isValid:!1,errorText:"Please enter an email address"}:{isValid:/\S+@\S+\.\S+/.test(value),errorText:"Invalid email address"}},{selector:"#profile__whatsapp_number",customValidation:(value,target)=>value.length<10?{isValid:!1,errorText:"Number must be at least 10 digits long"}:value.length>13?{isValid:!1,errorText:"Number must be at most 13 digits long"}:{isValid:!0}}]};const render={task(details={}){const{title:title,description:description,date:date,id:id,status:status,deadline:deadline,category:category}=details;let actions="";if(floGlobals.isUserLoggedIn){if(floGlobals.isSubAdmin)actions=html`
See updates
`;else if(!floGlobals.isAdmin){const isThisActive=floGlobals.applications.has(id),hasAnyActiveTask=isThisActive||[...floGlobals.applications].some((id=>{const[category]=id.split("_");return floGlobals.appObjects[category].tasks.some((task=>floGlobals.applications.has(task.id)))}));actions=isThisActive?html`
`:hasAnyActiveTask?html``:html`
`}}else actions=html`Start working`,floGlobals.applyingForTask=id;return html`
Don't share with anyone. Once lost private key can't be recovered.
FLO address
Private key
You can use these FLO credentials with other RanchiMall apps too.
`)})),router.addRoute("",renderHome),router.addRoute("home",renderHome),router.addRoute("task",(state=>{const{params:{id:id}}=state,[category]=id.split("_");if(floGlobals.isSubAdmin){renderElem(getRef("app_body"),html`
${header()}
Back
`)}));let privKeyResolver=null;function getSignedIn(passwordType){return new Promise(((resolve,reject)=>{privKeyResolver=resolve;try{getPromptInput("Enter password","",{isPassword:!0}).then((password=>{password&&resolve(password)}))}catch(err){floGlobals.isPrivKeySecured="PIN/Password"===passwordType,["#/landing","#/sign_in","#/sign_up"].some((route=>window.location.hash.includes(route)))||(history.replaceState(null,null,"#/landing"),router.routeTo("#/landing"))}}))}function setSecurePassword(){if(!floGlobals.isPrivKeySecured){const password=getRef("secure_pwd_input").value.trim();floDapps.securePrivKey(password).then((()=>{floGlobals.isPrivKeySecured=!0,notify("Password set successfully","success"),closePopup()})).catch((err=>{notify(err,"error")}))}}function signOut(){getConfirmation("Sign out?",{message:"You are about to sign out of the app, continue?",confirmText:"Leave",cancelText:"Stay"}).then((async res=>{res&&(await floDapps.clearCredentials(),location.reload())}))}const btcAddresses={},floAddresses={};function getBtcAddress(floAddress){return btcAddresses[floAddress]||(btcAddresses[floAddress]=btcOperator.convert.legacy2bech(floAddress)),btcAddresses[floAddress]}function getFloAddress(btcAddress){return floAddresses[btcAddress]||(floAddresses[btcAddress]=floCrypto.toFloID(btcAddress)),floAddresses[btcAddress]}router.routeTo("loading"),window.addEventListener("load",(()=>{const[browserName,browserVersion]=detectBrowser().split(" "),supportedVersions={Chrome:85,Firefox:75,Safari:13};browserName in supportedVersions?parseInt(browserVersion){"Escape"===e.key&&closePopup()})),document.addEventListener("copy",(()=>{notify("copied","success")})),document.addEventListener("pointerdown",(e=>{e.target.closest("button:not(:disabled), .interactive:not(:disabled)")&&createRipple(e,e.target.closest("button, .interactive"))}));const interestedCategories=localStorage.getItem("interestedCategories")||"[]";floGlobals.interestedCategories=new Set(JSON.parse(interestedCategories)),floDapps.setMidStartup((()=>new Promise(((resolve,reject)=>{floCloudAPI.requestObjectData("rmInterns").then((()=>{["#/landing","#/sign_in","#/sign_up"].some((route=>window.location.hash.includes(route)))&&router.routeTo(window.location.hash),resolve()})).catch((err=>{console.error(err),reject()}))})))),floDapps.setCustomPrivKeyInput(getSignedIn),floDapps.launchStartUp().then((async result=>{console.log(result),floGlobals.isUserLoggedIn=!0,floGlobals.myFloID=getFloAddress(floDapps.user.id),floGlobals.myBtcID=getBtcAddress(floGlobals.myFloID),floGlobals.isSubAdmin=floGlobals.subAdmins.includes(floGlobals.myFloID),floGlobals.isAdmin=floGlobals.myFloID===floGlobals.adminID;try{if(floGlobals.isSubAdmin){const promises=[];await Promise.all(Object.keys(floGlobals.taskCategories).map((category=>floCloudAPI.requestObjectData(category))));for(const category in floGlobals.taskCategories)floGlobals.appObjects[category]||(console.log("resetting",category),floGlobals.appObjects[category]={tasks:[]},promises.push(floCloudAPI.resetObjectData(category)));promises.push(floCloudAPI.requestGeneralData("taskApplications")),promises.push(floCloudAPI.requestGeneralData("taskUpdates")),await Promise.all(promises),floGlobals.allAvailableTasks=new Set;for(const category in floGlobals.taskCategories){(floGlobals.appObjects[category].tasks||[]).forEach((task=>floGlobals.allAvailableTasks.add(task.id)))}const taskApplications=floDapps.getNextGeneralData("taskApplications","0");floGlobals.applications={};for(const application in taskApplications){const{message:{taskID:taskID},senderID:senderID}=taskApplications[application];floGlobals.applications[taskID]||(floGlobals.applications[taskID]=new Set),floGlobals.applications[taskID].add(senderID)}const taskUpdates=floDapps.getNextGeneralData("taskUpdates","0");for(const updateVC in taskUpdates){const{message:{id:id}}=taskUpdates[updateVC],[category]=id.split("_"),task=floGlobals.appObjects[category].tasks.find((task=>task.id===id));task&&(task&&!task.updates?task.updates=[updateVC]:floGlobals.appObjects[category].tasks.find((task=>task.id===id)).updates.push(updateVC))}}else if(floGlobals.isAdmin);else{floGlobals.applications=new Set;const promises=[floCloudAPI.requestGeneralData("taskApplications",{senderID:[floGlobals.myFloID,floGlobals.myBtcID]}),floCloudAPI.requestGeneralData("userProfile",{senderID:[floGlobals.myFloID,floGlobals.myBtcID]}),floCloudAPI.requestGeneralData("taskUpdates",{senderID:[floGlobals.myFloID,floGlobals.myBtcID]})];await Promise.all(promises);const taskApplications=floDapps.getNextGeneralData("taskApplications","0");floGlobals.allAvailableTasks=new Set;for(const category in floGlobals.taskCategories){(floGlobals.appObjects[category].tasks||[]).forEach((task=>floGlobals.allAvailableTasks.add(task.id)))}for(const application in taskApplications){const{message:{taskID:taskID}}=taskApplications[application];floGlobals.allAvailableTasks.has(taskID)&&floGlobals.applications.add(taskID)}const userProfile=floDapps.getNextGeneralData("userProfile","0");for(const profile in userProfile)userProfile[profile].senderID!==floGlobals.myFloID&&delete userProfile[profile];floGlobals.userProfile=Object.values(userProfile).at(-1)?.message.encryptedData}["#/landing","#/sign_in","#/sign_up"].includes(window.location.hash)?(history.replaceState(null,null,"#/home"),router.routeTo("home")):router.routeTo(window.location.hash)}catch(err){console.error(err)}})).catch((error=>console.error(error)))}));