const dev={error(){},log(){}};class ___plugin___{static plugins={plugins:[],use:{render:[]}};constructor(e){dev.log(`Plugin ${e} loading.`)}useRender(e){___plugin___.plugins.use.render.push(e)}}String.prototype.prettyHashCode=function(){for(var e=0,t=0;t{for(let e of htmlTags)window["_"+e]=(...t)=>_(e,...t)})();class ___render___{static __placedOphoseInstances=[];static toNode(e){if(null==e||!1===e){let t=document.createElement("div");return t.style.display="none",t}if(!___render___.isOphoseObject(e)){dev.error("RenderException: Invalid ophose object:"),console.log(e);return}let a=(e,t)=>{for(let a in e){if(ophAttrs.includes(a)){t.setAttribute(a,e[a]);continue}if(e[a]===defined&&t.setAttribute(a,""),e.hasOwnProperty(a)){if(void 0!==e[a]&&htmlAttrs.includes(a)){t.setAttribute(a,e[a]),htmlProperties.includes(a)&&(t[a]=e[a]);continue}if(htmlEvents.includes(a)){t[a]=e[a];continue}if(e.className||e.class)for(let s of(e.class&&(e.className=e.class),e.className.split(" ")))""!=s&&t.classList.add(s)}}};if(Array.isArray(e)){let s=document.createDocumentFragment(),l=[];if(0==e.length){let i=___render___.toNode(void 0);i.fromFragment=s,s.appendChild(i),l.push(i)}else for(let r of e){let o=___render___.toNode(r);o&&(s.appendChild(o),l.push(o),o.fromFragment=s)}return s.oList=l,s}if(e instanceof Node)return e;if("string"==typeof e||"number"==typeof e)return document.createTextNode(e);if(e instanceof ___component___){let n=e.render();n instanceof PlacedLive&&(n.selfClassName=e.__getComponentUniqueId());let c=___render___.toNode(n),d=c;if(e.__propsOn)for(let p of c.children){let u=p.getAttribute("_name");if(u&&u==e.__propsOn){d=p;break}}return a(e.props,d),c.o=e,c}if(e instanceof PlacedLive||e instanceof Live){e instanceof Live&&(e=dyn(e,e=>e));let m=e.lives,g=e.callback;for(let h of m){let f=()=>{let t=g(...m.map(e=>e.get())),a=___render___.toNode(t);if(e.node instanceof DocumentFragment){let s=e.node.oList;for(let l=1;le.get()),x=___render___.toNode(g(...y));return e.node=x,e.selfClassName&&e.node.classList.add(e.selfClassName),x}if("object"==typeof e){for(let b of ___plugin___.plugins.use.render){let v=b(e);v&&(e=v)}let N=document.createElement(e._);if(e.c&&(e.children=e.c),e.watch){try{N.value=e.watch.get(),setTimeout(()=>{N.value=e.watch.get()},50)}catch(w){}e.watch.subscribe(()=>{N.value=e.watch.get()}),N.addEventListener("input",t=>{e.watch.set(N.value)}),N.addEventListener("change",t=>{e.watch.set(N.value)})}if(e.children){if(Array.isArray(e.children))for(let S of e.children){if(Array.isArray(S)){for(let C of S){let E=___render___.toNode(C);E&&N.appendChild(E)}continue}let k=___render___.toNode(S);k&&N.appendChild(k)}else{let P=___render___.toNode(e.children);P&&N.appendChild(P)}}return e.text&&(N.textContent=e.text),a(e,N),(e.html||e.innerHTML)&&(N.innerHTML=e.html||e.innerHTML),N}}static isOphoseObject(e){return"string"==typeof e||"number"==typeof e||e instanceof ___component___||e instanceof Live||e instanceof PlacedLive||"object"==typeof e&&e._||Array.isArray(e)||e instanceof Node}}function _(e,...t){let a={_:e},s=[];for(let l of(t[0]&&!___render___.isOphoseObject(t[0])&&(a={...a,...t.shift()}),t)){if(Array.isArray(l)){s.push(...l);continue}s.push(l)}return s.length>0&&(a.children=s),a}const observer=new MutationObserver((e,t)=>{for(let a of e){if("childList"===a.type){let s=e=>{if(e.o&&(e.o.__processRemove(),e.o.__place(e),e.o.onPlace(e)),e.children)for(let t of e.children)s(t)};for(let l of a.addedNodes)s(l)}if(a.removedNodes.length>0)for(let i of a.removedNodes)i.o&&i.o.__processRemove()}}),config={childList:!0,subtree:!0};document.addEventListener("DOMContentLoaded",()=>{observer.observe(document.body,config)});const render=___render___.toNode;class ___import___{static __imported=[];static __lastExport=void 0;static __fixedPath(e){return e.startsWith("@/")&&(e=e.replace("@/","ext/")),e.trim().replaceAll("//","/")}static __use(e){!___import___.__imported.includes(e)&&(__OPH_APP_BUILD__||(___import___.__imported.push(e),___script___.run(e)))}static useComponent(e){___import___.__use("/@component/"+___import___.__fixedPath(e)+".js")}static useModule(e){___import___.__use("/@module/"+___import___.__fixedPath(e)+".js")}static useEnvironment(e){___import___.__use(___import___.__fixedPath("/@envjs/"+e))}static importCss(e){let t=document.createElement("link");t.rel="stylesheet",t.type="text/css",t.href=e,document.head.appendChild(t)}static importScript(e){$.ajax({url:e,dataType:"script",async:!1})}}const importCss=___import___.importCss,importScript=___import___.importScript,oimpc=___import___.useComponent,oimpm=___import___.useModule,oimpe=___import___.useEnvironment;class ___script___{static run(e,t=!1,a=null,s=null){$.ajax({url:e,dataType:"script",async:t,success:a,error:s})}}var page=void 0;class ___app___{static __base=void 0;static __$nodePage;static __$baseAppNode;static __$pageStyle;static __$baseStyle;static __histories=[];static __loadedPages={};static __currentURL=null;static CURRENT_URL=null;static __lastShared=void 0;static __loadBase(){if(___app___.__base)return;___app___.__base=new Base({children:{_:"main",id:"oapp"}});let e=___app___.__base,t=___render___.toNode(e);document.body.appendChild(t),___app___.__$baseAppNode=document.getElementById("oapp"),___render___.__placedOphoseInstances=[],___app___.__$pageStyle=document.createElement("style"),document.head.appendChild(___app___.__$pageStyle)}static async __go(url){return(___app___.__loadBase(),(url=url.split("#")[0].split("?")[0])==___app___.__currentURL)?null:await fetch("/@resolve/",{method:"POST",body:JSON.stringify({url})}).then(e=>e.json()).then(async r=>{let js=r.js,query=r.query,url=r.url,data=r.data,get=window.location.search.substring(1).split("&").map(e=>e.split("=")).reduce((e,t)=>(e[t[0]]=t[1],e),{});if(!___app___.__loadedPages[js]){let script;eval(`${await fetch("/pages/"+js).then(e=>e.text())}`),___app___.__loadedPages[js]={cls:___app___.__getShared()}}let c,page=new ___app___.__loadedPages[js].cls({query,url,data,get}),node=___render___.toNode(page);if(___app___.__$baseAppNode instanceof DocumentFragment){let list=___app___.__$baseAppNode.oList;for(let i=1;i{null!==e.state&&___app___.__go(e.state)});class ___element___{constructor(){}style(){return""}getBase(){return ___app___.__base}}class ___component___ extends ___element___{static __allComponents={};static __SCREENS_SIZES={sm:576,md:768,lg:992,xl:1200};static getComponent(e){return ___component___.__allComponents[e]}constructor(e={}){super(),this.props=e&&"object"==typeof e&&e||{},this.props.c&&(this.props.children=this.props.c),this.__propsOn,this.__styleNode=void 0,this.__node=void 0,this.__loadingContext=null,this.compUID=this.constructor.name.toLowerCase(),this.__componentUniqueClassName="__oc_"+this.compUID,this.__componentUniqueClassName=this.__componentUniqueClassName.prettyHashCode(),this.__componentUniqueId=this.__componentUniqueClassName+(Object.keys(___component___.__allComponents).length+1),___component___.__allComponents[this.__componentUniqueId]=this,this.__myModules=[],this.__lives=[]}__setNode(e){this.__node=e}__getComponentUniqueId(){return this.__componentUniqueId}styles(){return null}__getStyleNode(){return this.__styleNode}__createStyleNode(){if(this.__getStyleNode())return;let e=document.createElement("style");return document.head.append(e),this.__styleNode=e,e}___reloadStyle(){let e=this.style().replaceAll("%self","."+this.__getComponentUniqueId()),t=this.styles();if(t)for(let a in t){if(!___component___.__SCREENS_SIZES[a]){dev.error("Invalid screen size: "+a);continue}let s=t[a].replaceAll("%self","."+this.__getComponentUniqueId());e+="\n@media screen and (max-width: "+___component___.__SCREENS_SIZES[a]+"px) {\n"+s+"\n}\n"}this.__getStyleNode().innerText=e}__applyStyle(){this.__getStyleNode()||(this.__createStyleNode(),Live.__currentReadingStyleComponent=this,this.___reloadStyle(),Live.__currentReadingStyleComponent=void 0)}propsOn(e){this.__propsOn=e}getNode(){return this.__node}__place(e){if(e instanceof DocumentFragment)for(let t of e.oList)t.classList.add(this.__getComponentUniqueId());else e.classList.add(this.__getComponentUniqueId());this.__setNode(e),this.__applyStyle()}render(){}remove(){this.__processRemove(),this.__node.remove(),___render___.__placedOphoseInstances.splice(___render___.__placedOphoseInstances.indexOf(this),1)}appendChild(e){this.__node.append(___render___.toNode(e))}__processRemove(){for(let e of(this.onRemove(this.__node),this.__myModules))e.__onRemove(this,this.__node);this.__styleNode&&(this.__styleNode.remove(),this.__styleNode=void 0),___component___.__allComponents[this.__componentUniqueId]=void 0}findFirstParentComponentOfType(e){let t=this.__node.parentElement;for(;t;){if(t.ophoseInstance&&t.ophoseInstance instanceof e)return t.ophoseInstance;t=t.parentElement}return null}onPlace(e){}onRemove(e){}addModule(e){this.__myModules.push(e),e.addComponent(this)}}class ___module___ extends ___element___{static __addedModuleStyles={};constructor(){super(),this.__moduleUID="__ocmodule__"+this.constructor.name.toLowerCase(),this.__components=[],this.__applyStyle()}_getClassName(){return this.__moduleUID}__getStyleNode(){return ___module___.__addedModuleStyles[this._getClassName()]}__reloadStyle(){let e=this.__getStyleNode();e&&(e.innerText=this.style().replaceAll("%self","."+this._getClassName()))}__applyStyle(){if(this.__getStyleNode())return;let e=document.createElement("style");___module___.__addedModuleStyles[this._getClassName()]=e,document.head.append(e),this.__reloadStyle()}addComponent(e){this.__components.includes(e)&&(this.__components.push(e),this.onComponentAdded(e))}getComponents(){return this.__components}removeComponent(e){0==this.__components.length&&this.__getStyleNode().remove(),this.onComponentRemoved(e)}onComponentAdded(e){}onComponentRemoved(e){}onPlace(e,t){}onRemove(e,t){}__onRemove(e,t){this.__components.splice(this.__components.indexOf(e),1),this.onRemove(e,t)}}class ___page___ extends ___component___{constructor(e){super(),e||(e={}),this.query=e.query,this.get=e.get,this.url=e.url,this.data=e.data}onCreate(){}onLeave(){}onLoad(){}onPlace(e){super.onPlace(e),___event___.callEvent("onPageLoaded",app.CURRENT_URL)}redirect(e){if(this.__redirected){dev.error("This page has already been redirected.");return}this.__redirected=e}}class ___base___ extends ___component___{constructor(e){super(e)}usePlugin(e){if("function"==typeof e&&e.prototype instanceof ___plugin___){-1===___plugin___.plugins.plugins.indexOf(e)?(___plugin___.plugins.plugins.push(e),new e,dev.log(`Plugin ${e.name} loaded.`)):dev.error(`Plugin ${e.name} already loaded.`);return}dev.error(`Invalid plugin ${e}. Plugin must be a class.`)}}class ___route___{static go(e){if(null!=e){if(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/.test(e)){window.location=e;return}"#"==e[0]&&(document.querySelector(e)?.scrollIntoView({behavior:"smooth"}),window.history.pushState(e,"",e)),___app___.__go(e).then(e=>{e&&e.url!==window.location.pathname&&window.history.pushState(e.url,"",e.url)})}}}const route=___route___;class ___env___{static async post(e,t=null,a=null){let s=null,l=!1;if(t instanceof Live&&(t=t.value),a={method:"POST",headers:{},useDirectives:!0,toFormData:!1,...a},t&&t.options&&(t.options=void 0),a.toFormData){let i=new FormData;for(let r in t)i.append(r,t[r]);t=i}if(t instanceof FormData||("object"==typeof t?(a.headers["Content-Type"]="application/json",t=JSON.stringify(Live.flatten(t))):"string"!=typeof t&&"number"!=typeof t&&"boolean"!=typeof t&&null!==t||(null===t&&(t=""),a.headers["Content-Type"]="text/plain")),await $.ajax({type:a.method,url:e.startsWith("/@/")||e.startsWith("/api/")?e:"/@/"+e,data:t,cache:!1,processData:!1,contentType:!1,beforeSend(e){let t=document.querySelector('meta[name="csrf-token"]').getAttribute("content");for(let s in e.setRequestHeader("X-Csrf-Token",t),a.headers)e.setRequestHeader(s,a.headers[s])},success(e){s=e},error(e){l=!0;try{s=JSON.parse(e.responseText)}catch(t){s=e.responseText}}}),l)throw s;if(a.useDirectives&&s?.ophose_encoded_directives){for(let o of s.ophose_encoded_directives)"redirect"===o.type&&route.go(o.data);return}return s}static async sendFiles(e,t,a,s,l,i=!1,r="*"){let o=___env___.constructURL(e,t),n=document.createElement("form");n.enctype="multipart/form-data";let c=document.createElement("input");c.type="file",c.accept=r,i&&(c.multiple=!0),c.id=a,c.name=a,n.appendChild(c),c.click(),c.onchange=e=>{let t=new FormData(n);$.ajax({url:o,dataType:"json",cache:!1,contentType:!1,processData:!1,data:t,type:"POST",method:"POST",success(e){s(e)},error(e){l(e)}})}}}class ___env_entity___{constructor(e,t){this.__id=e,this.data=t}getId(){return this.__id}update(e){}}class ___env_entity_manager___{constructor(e,t=!0){this.__EntityClass=e,this.__entities={},this.__saveEntitiesInCache=t}async getEntity(e){return this.saveEntitiesInCache&&this.__entities[e]?this.__entities[e]:await this.__generateEntity(e)}async __generateEntity(e){let t=await this.createEntity(e);if(void 0!==t)return this.saveEntitiesInCache&&(this.__entities[e]=t),t}async createEntity(e){return null}saveEntity(e,t){if(this.__saveEntitiesInCache){if(this.__entities[e]){this.__entities[e].data=t,this.__entities[e].update(t);return}this.__entities[e]=new this.__EntityClass(e,t)}}cleanEntities(){this.__entities={}}}const oenv=___env___.post,oenvSendFiles=___env___.sendFiles;class Live{static __currentReadingStyleComponent=void 0;static __calledLives={};__processValue(e,t=this){if("object"==typeof e&&null!==e&&!Array.isArray(e)&&e.constructor===Object){t.__valueIsObject=!0;let a=new Set;for(let s in e)a.add(s),t[s]instanceof Live?t[s].set(e[s]):t[s]=new Live(e[s]).setParent(t),t.__objectUsedKeys.add(s);if(!t.__keepValuesOnUpdateIfNotInObject)for(let l of t.__objectUsedKeys)a.has(l)||t[l].set(void 0);return}this.__valueIsObject=!1,t.__value=e}constructor(e){this.__objectUsedKeys=new Set,this.__valueIsObject=!1,this.__processValue(e),this.__placedStyleComponents=[],this.__dynCallbacks=[],this.__callbackListeners=[],this.__ruleId=""+Math.random(),this.__rules=[],this.__rulesDependencies=[],this.__updateOnlyIfValueChanges=!0,this.__keepValuesOnUpdateIfNotInObject=!0}keepValues(e){return this.__keepValuesOnUpdateIfNotInObject=e,this}setParent(e){return this.__parent=e,this}get value(){return this.get()}set value(e){this.set(e)}subscribe(e){return this.__callbackListeners.push(e),this}unsubscribe(e){this.__callbackListeners.splice(this.__callbackListeners.indexOf(e),1)}toggle(){if("boolean"!=typeof this.__value){dev.error("Cannot toggle a non-boolean value",this.__value);return}return this.set(!this.__value),this.__value}get(){if(this.__valueIsObject){let e={};for(let t of this.__objectUsedKeys)e[t]=this[t].get();return e}if(Live.__currentReadingStyleComponent){let a=Live.__currentReadingStyleComponent;this.__placedStyleComponents.push(a),a.__lives.push(this)}for(let s in Live.__calledLives)s!==this.__ruleId&&Live.__calledLives[s].push(this);return"object"==typeof this.__value?Live.flatten(this.__value):this.__value}set(e){let t=this.__value;for(let a of(this.__processValue(e),this.__rules))this.__value=a(this.__value,t);(!this.__updateOnlyIfValueChanges||"object"==typeof this.__value||this.__value!==t)&&Live.__onValueChange(this,this.__value,t)}refresh(){Live.__onValueChange(this,this.__value,this.__value)}update(e){let t=e(this.__value);return this.set(t),t}rule(e){for(let t of(this.__rules.push(e),Live.__calledLives[this.__ruleId]=[],e(this.__value,this.__value),Live.__calledLives[this.__ruleId]))-1===this.__rulesDependencies.indexOf(t)&&(this.__rulesDependencies.push(t),t.subscribe(()=>{this.set(this.__value)}));return delete Live.__calledLives[this.__ruleId],this}min(e){return e instanceof Live?(e.subscribe(()=>this.set(this.__value)),this.rule(t=>Math.max(t,e.get()))):this.rule(t=>Math.max(t,e))}max(e){return e instanceof Live?(e.subscribe(()=>this.set(this.__value)),this.rule(t=>Math.min(t,e.get()))):this.rule(t=>Math.min(t,e))}updateOnlyIfValueChanges(e){return this.__updateOnlyIfValueChanges=e,this}add(e){if(Array.isArray(this.__value)){this.__value.push(e),this.set(this.__value);return}this.set(e+this.__value)}remove(e){if(Array.isArray(this.__value)){this.__value.splice(this.__value.indexOf(e),1),this.set(this.__value);return}this.set(this.__value-e)}removeAt(e){if(Array.isArray(this.__value)){this.__value.splice(e,1),this.set(this.__value);return}dev.error("Cannot remove at index from a non-array value",this.__value)}static __onValueChange(e,t,a){for(let s of e.__callbackListeners)s(t,a);for(let l of e.__placedStyleComponents)l.___reloadStyle();e.__parent&&Live.__onValueChange(e.__parent,e.__parent.__value,e.__parent.__value)}static __localLives={};static local(e,t=null){e="__local_live."+e;let a=localStorage.getItem(e),s=Live.__localLives[e];return null===a&&(localStorage.setItem(e,t),a=t),void 0===s&&((s=new Live(a)).subscribe(t=>{localStorage.setItem(e,t)}),Live.__localLives[e]=s),s}static flatten(e){return JSON.parse(JSON.stringify(e,(e,t)=>t instanceof Live?t.get():t))}push(...e){if(!Array.isArray(this.__value)){dev.error("Cannot push to a non-array value",this.__value);return}return this.set(this.__value.concat(e)),this.__value.length}pop(){if(!Array.isArray(this.__value)){dev.error("Cannot pop from a non-array value",this.__value);return}let e=this.__value.pop();return this.set(this.__value),e}shift(){if(!Array.isArray(this.__value)){dev.error("Cannot shift from a non-array value",this.__value);return}let e=this.__value.shift();return this.set(this.__value),e}unshift(...e){if(!Array.isArray(this.__value)){dev.error("Cannot unshift to a non-array value",this.__value);return}return this.set(e.concat(this.__value)),this.__value.length}splice(e,t){if(!Array.isArray(this.__value)){dev.error("Cannot splice from a non-array value",this.__value);return}let a=this.__value.splice(e,t);return this.set(this.__value),a}reverse(){if(!Array.isArray(this.__value)){dev.error("Cannot reverse a non-array value",this.__value);return}this.set(this.__value.reverse())}sort(e){if(!Array.isArray(this.__value)){dev.error("Cannot sort a non-array value",this.__value);return}this.set(this.__value.sort(e))}join(e){if(!Array.isArray(this.__value)){dev.error("Cannot join a non-array value",this.__value);return}return this.__value.join(e)}slice(e,t){if(!Array.isArray(this.__value)){dev.error("Cannot slice a non-array value",this.__value);return}return this.__value.slice(e,t)}filter(e){if(!Array.isArray(this.__value)){dev.error("Cannot filter a non-array value",this.__value);return}return this.__value.filter(e)}map(e){if(!Array.isArray(this.__value)){dev.error("Cannot map a non-array value",this.__value);return}return this.__value.map(e)}reduce(e,t){if(!Array.isArray(this.__value)){dev.error("Cannot reduce a non-array value",this.__value);return}return this.__value.reduce(e,t)}find(e){if(!Array.isArray(this.__value)){dev.error("Cannot find in a non-array value",this.__value);return}return this.__value.find(e)}findIndex(e){if(!Array.isArray(this.__value)){dev.error("Cannot find index in a non-array value",this.__value);return}return this.__value.findIndex(e)}get length(){if(!Array.isArray(this.__value)){dev.error("Cannot get length of a non-array value",this.__value);return}return this.__value.length}at(e){if(!Array.isArray(this.__value)){dev.error("Cannot get value at index of a non-array value",this.__value);return}return this.__value[e]}setAt(e,t){if(!Array.isArray(this.__value)){dev.error("Cannot set value at index of a non-array value",this.__value);return}this.__value[e]=t,this.set(this.__value)}indexOf(e){if(!Array.isArray(this.__value)){dev.error("Cannot get index of a non-array value",this.__value);return}return this.__value.indexOf(e)}lastIndexOf(e){if(!Array.isArray(this.__value)){dev.error("Cannot get last index of a non-array value",this.__value);return}return this.__value.lastIndexOf(e)}clear(){if(!Array.isArray(this.__value)){dev.error("Cannot clear a non-array value",this.__value);return}this.set([])}_(e){return dyn(this,e)}valueCallbacked(e){return"function"==typeof e?e:()=>e}_map(e){if(!Array.isArray(this.__value)){dev.error("Cannot map a non-array value",this.__value);return}return dyn(this,t=>t.map(e))}_if(e,t){return dyn(this,a=>a?this.valueCallbacked(e)(a):this.valueCallbacked(t)(a))}_switch(e){return dyn(this,t=>void 0===e[t]&&void 0!==e.default?this.valueCallbacked(e.default)(t):this.valueCallbacked(e[t])(t))}_empty(e){if(!Array.isArray(this.__value)){dev.error("Cannot check if empty a non-array value",this.__value);return}return dyn(this,t=>{if(0===t.length)return this.valueCallbacked(e)(t)})}_notEmpty(e){if(!Array.isArray(this.__value)){dev.error("Cannot check if not empty a non-array value",this.__value);return}return dyn(this,t=>{if(0!==t.length)return this.valueCallbacked(e)(t)})}}class PlacedLive{constructor(...e){let t=e.pop();this.lives=e,this.callback=t,this.node=void 0,this.selfClassName=void 0}}function dyn(...e){return new PlacedLive(...e)}function live(e){return new Live(e instanceof Live?e.get():e)}function watchAfter(...e){let t=e.pop();for(let a of e)a.subscribe(async()=>{t(...e.map(e=>e.get()))})}function watch(...e){let t=e.pop();for(let a of e)a.subscribe(async()=>{t(...e.map(e=>e.get()))});setTimeout(()=>t(...e.map(e=>e.get())),0)}var __OPH_APP_BUILD__=!1,__OPHOSE_PAGES={};const Ophose={App:___app___,Render:___render___,Base:___base___,Component:___component___,Page:___page___,Module:___module___,Environment:___env___,Event:___event___,Plugin:___plugin___},ofi={};__OPH_APP_BUILD__=!0;class PaymentButton extends Ophose.Component{constructor(e){super(e,{paymentEndpoint:null,paymentData:null}),this.paymentEndpoint=e.paymentEndpoint}style(){return` %self { display: flex; align-items: center; justify-content: center; gap: 10px; } `}createLoading(){let e=document.createElement("div");e.style.position="fixed",e.style.top="0",e.style.left="0",e.style.width="100%",e.style.height="100%",e.style.backgroundColor="rgba(0, 0, 0, 0.5)",e.style.zIndex="1000",document.body.appendChild(e);let t=document.createElement("div");return t.style.position="fixed",t.style.top="50%",t.style.left="50%",t.style.transform="translate(-50%, -50%)",t.style.width="100px",t.style.height="100px",t.style.borderRadius="50%",t.style.border="5px solid #f3f3f3",t.style.borderTop="5px solid #3498db",t.style.animation="spin 2s linear infinite",e.appendChild(t),e}pay(){if(!this.paymentEndpoint)throw Error("Payment endpoint is not defined.");let e=this.createLoading();oenv(this.paymentEndpoint,this.props.paymentData).then(t=>{if(this.props.beforePay&&!this.props.beforePay(t)){document.body.removeChild(e);return}let a=t.paymentUrl;if(!a){document.body.removeChild(e),this.props.onPaymentFail&&this.props.onPaymentFail(t),console.log("Payment URL is not defined.");return}let s=window.open(a,"popup","width=600,height=600"),l=setInterval(()=>{s.closed&&(clearInterval(l),document.body.removeChild(e),this.onPaymentComplete())},1e3)}).catch(t=>{this.props.beforePay&&this.props.beforePay(t),this.props.onPaymentFail&&this.props.onPaymentFail(t),document.body.removeChild(e)})}onPaymentComplete(){if(this.props.onCompleteUrl){route.go(this.props.onCompleteUrl);return}window.location.reload()}render(){return{_:"button",onclick:()=>this.pay(),children:[this.props.children]}}}class ESteps extends Ophose.Component{constructor(e){super(e)}render(){let e=this.props.currentStep,t=(t,a,s=!1)=>s?_div({className:"w-full rounded-xl bg-gray-200 px-4 py-2 flex-col gap-2 select-none cursor-pointer text-white transition bg-gradient-to-br from-gray-800 to-gray-700",onclick:()=>e.set(t)},_h3({className:"font-medium"},a)):_div({className:"flex items-center gap-4 cursor-pointer",onclick(){e.set(t)}},e._(e=>_div({className:`w-8 h-8 rounded-full flex items-center justify-center ${e==t&&"bg-gradient-to-b from-indigo-500 to-pink-500 text-white"||e>t&&"bg-indigo-500 text-white"||"bg-gray-200 text-gray-500"}`},t)),e._(e=>_h3({className:`${e==t?"text-gray-800":"text-gray-400"} font-medium`},a))),a=t=>e._(e=>_div({className:`ml-3 w-2 h-8 rounded-full ${e>t?"bg-indigo-500":"bg-gray-200"}`}));return _div({className:"w-full rounded-3xl bg-gray-50 p-8 flex flex-col gap-2 select-none"},t(1,"Project details"),a(1),t(2,"Concerned persons"),a(2),t(3,"Features"),a(3),t(4,"Functional requirements"),a(4),t(5,"Technical constraints"),a(5),t(6,"UI/UX"),a(6),t(7,"Project estimation"),a(7),t(8,"Appendices"),a(8),t(9,"Generate estimate",!0))}}class EProgressBar extends Ophose.Component{constructor(e){super(e)}style(){return` %self { } `}render(){return _div({className:"w-full bg-gray-50 rounded-full"},this.props.progress._(e=>_div({className:"h-2 bg-gradient-to-r from-pink-500 to-indigo-500 rounded-full px-1",style:`width: ${e}%`})))}}class ESavedState extends Ophose.Component{constructor(e){super(e)}style(){return` %self { } `}render(){return this.props.savedState._switch({unsaved:_div({className:"flex items-center gap-2 bg-gray-50 rounded-full px-4 py-2 font-medium"},_i({className:"bi bi-pencil text-gray-500"}),_span({className:"text-gray-500"},"Changes not saved")),saving:_div({className:"flex items-center gap-2 bg-yellow-50 rounded-full px-4 py-2 font-medium"},_i({className:"bi bi-pencil text-yellow-500"}),_span({className:"text-yellow-500"},"Saving...")),saved:_div({className:"flex items-center gap-2 bg-green-50 rounded-full px-4 py-2 font-medium"},_i({className:"bi bi-pencil text-green-500"}),_span({className:"text-green-500"},"Saved"))})}}const ESDetails=e=>[{id:"project_name",type:"text",label:"Project name",placeholder:"Enter project name (i.e. My awesome project)",target:e.name,required:!0,colSpan:4},{id:"due_date",type:"date",label:"Due date",target:e.dueDate,required:!0,colSpan:2},{id:"client_name",type:"text",label:"Client name",placeholder:"Enter client name",target:e.client_name,colSpan:3,required:!0},{id:"client_email",type:"text",label:"Client email",placeholder:"Enter client email",target:e.client_email,required:!0,colSpan:3},{id:"project_description",type:"textarea",label:"Project description",placeholder:"Enter a brief description of the project",target:e.project.description,ai:!0,ai_cost:1,required:!0},{id:"project_type",type:"suggestions",label:"Project type",description:"What type of project is this?",suggestions:[{label:"Web application"},{label:"Website"},{label:"Mobile application"},{label:"Desktop software"}],target:e.project.type,required:!0},{id:"industry_sector",type:"suggestions",label:"Industry sector",description:"What industry sector does this project belong to?",suggestions:[{label:"Healthcare"},{label:"Finance"},{label:"Retail"},{label:"Technology"},{label:"Real estate"},{label:"Education"},{label:"Legal"},{label:"Hospitality"},{label:"Automotive"},{label:"Manufacturing"},{label:"Agriculture"},{label:"Non-profit"},{label:"Other"}],target:e.project.industry_sector,required:!0},{id:"target_users",type:"suggestions",label:"Target users",target:e.project.target_users,description:"Who are the target users for this project?",suggestions:[{label:"Individuals"},{label:"Businesses"},{label:"Developers"},{label:"Designers"},{label:"Students"}]}],ESFeatures=e=>[{id:"project_features",type:"list",fields:[{id:"feature_name",type:"text",label:"Feature name",placeholder:"Enter feature name (i.e. User authentication)",required:!0,colSpan:4},{id:"feature_estimated_hours",type:"number",label:"Estimated hours",placeholder:"Enter estimated hours for this feature",required:!0,colSpan:2},{id:"feature_description",type:"textarea",label:"Feature description",placeholder:"Enter a brief description of the feature",required:!0},{id:"feature_type",type:"suggestions",label:"Feature type",description:"What type of feature is this?",suggestions:[{label:"Core feature"},{label:"Secondary feature"},{label:"Nice-to-have feature"},{label:"Future feature"},]},{id:"feature_priority",type:"progress",label:"Feature priority",description:"How important is this feature?",options:["Low","Medium","High","Critical"]},{id:"feature_output",type:"suggestions",label:"Feature output",description:"What should the feature produce as an output?",suggestions:[{label:"Data"},{label:"Report"},{label:"Notification"},{label:"Action"}]},{id:"feature_notes",type:"textarea",label:"Additional notes",placeholder:"Enter any additional notes for this feature"}],label:"Features",description:"What features does this project have? It can be a list of features, functionalities or deliverables that the project will have.",target:e.project.features,required:!0,ai:!0,ai_cost:5}],ESPersons=e=>[{id:"concerned_persons",type:"list",label:"Concerned persons",target:e.project.concerned_persons,description:"People who are involved in the project",fields:[{id:"name",type:"text",label:"Name",placeholder:"Enter name",required:!0,colSpan:3},{id:"email",type:"text",label:"Email",placeholder:"Enter email",required:!0,colSpan:3},{id:"role",type:"suggestions",label:"Role",description:"What is the role of this person?",suggestions:[{label:"Project manager"},{label:"Developer"},{label:"Designer"},{label:"Tester"},{label:"Client"},{label:"Other"}],required:!0}]}],ESFunctional=e=>[{id:"access_mode",type:"suggestions",label:"Access mode",description:"How will users access the application?",suggestions:[{label:"Browser"},{label:"Mobile"},{label:"API"}],target:e.project.functional.access_mode,required:!0},{id:"multi_language_support",type:"boolean",label:"Multi-language support",description:"Will the application support multiple languages?",target:e.project.functional.multi_language_support,required:!0},{id:"platform",type:"suggestions",label:"Platform",description:"What platforms will the application run on?",suggestions:[{label:"Web"},{label:"Mobile (iOS, Android)"},{label:"Desktop (Windows, Mac, Linux)"}],target:e.project.functional.platform,required:!0}],ESTechnical=e=>[{id:"preferred_technology_stack",type:"list",target:e.project.technical.technology_stack,label:"Preferred technology stack",description:"What technology stack would you prefer?",fields:[{id:"technology_stack",type:"suggestions",label:"Technology stack",description:"What technology stack would you prefer?",suggestions:[{label:"Ophose"},{label:"React"},{label:"Vue"},{label:"React Native"},{label:"Flutter"},{label:"Django"},{label:"Ruby on Rails"},{label:"Laravel"},{label:"Spring Boot"},{label:"Express"},{label:"Flask"},{label:"NestJS"}],required:!0},{id:"technology_stack_information",type:"textarea",label:"Additional information for this technology stack",placeholder:"Enter additional information for this technology stack"}]},{id:"preferred_database",type:"suggestions",label:"Preferred database",target:e.project.technical.database,description:"What database would you prefer?",suggestions:[{label:"MySQL"},{label:"PostgreSQL"},{label:"MongoDB"},{label:"Cassandra"},{label:"SQLite"},{label:"MariaDB"},{label:"Firebase"},]},{id:"hosting",type:"suggestions",label:"Hosting",target:e.project.technical.hosting,description:"Where would you like to host the application?",suggestions:[{label:"Amazon Web Services (AWS)"},{label:"Google Cloud Platform (GCP)"},{label:"Microsoft Azure"},{label:"Dedicated server"},{label:"Virtual Private Server (VPS)"},{label:"Local server"}]},{id:"third_party_integrations",type:"suggestions",label:"Third party integrations",target:e.project.technical.third_party_integrations,description:"What third party integrations would you like to have?",suggestions:[{label:"Payment gateway"},{label:"SMS gateway"},{label:"Email service"},{label:"Social media login"},{label:"Location service"},{label:"Analytics"}]},{id:"expected_traffic",type:"progress",label:"Expected traffic",description:"What is the expected traffic for the application?",target:e.project.technical.expected_traffic,guide:[_h1({className:"text-2xl font-bold text-gray-800 mb-8"},"Which option best describes the expected traffic for your application?"),_div({className:"flex flex-col gap-4"},_p(_b("Low:")," This option is suitable for small companies, personal projects or prototypes with a limited number of users. We recommend this option if you expect:",_ul({className:"list-disc ml-8 text-gray-500 text-sm"},_li("Concurrent Connections: Up to 10 users connected simultaneously."),_li("Database Size: Up to 5 GB of data (e.g., small customer lists, simple product catalogs)."),_li("Requests per Second (RPS): 10–50 RPS (e.g., occasional API calls or limited browsing)."),_li("Daily Requests: Up to 10,000."),_li("Data Growth Rate: Minimal (e.g., static content or rare updates)."))),_p(_b("Medium:")," This option is ideal for moderate-sized applications or systems handling a growing user base and moderate data volumes. We recommend this option if you expect:",_ul({className:"list-disc ml-8 text-gray-500 text-sm"},_li("Concurrent Connections: 10–100 users connected simultaneously."),_li("Database Size: 5–50 GB (e.g., medium-sized customer databases, moderate product catalogs)."),_li("Requests per Second (RPS): 50–200 RPS (e.g., moderately active applications)."),_li("Daily Requests: 10,000–100,000."),_li("Data Growth Rate: Steady (e.g., daily updates or transactional systems)."))),_p(_b("High:")," This option is suited for large-scale systems handling significant user activity and substantial data volumes. We recommend this option if you expect:",_ul({className:"list-disc ml-8 text-gray-500 text-sm"},_li("Concurrent Connections: 100–1,000 users connected simultaneously."),_li("Database Size: 50–500 GB (e.g., large product catalogs, extensive transactional data)."),_li("Requests per Second (RPS): 200–2,000 RPS (e.g., high-traffic websites, SaaS applications)."),_li("Daily Requests: 100,000–1,000,000."),_li("Data Growth Rate: Rapid (e.g., frequent updates, high transaction volumes)."))),_p(_b("Very High:")," This option is built for enterprise-grade systems or applications requiring massive scalability and extremely high data handling capabilities. We recommend this option if you expect:",_ul({className:"list-disc ml-8 text-gray-500 text-sm"},_li("Concurrent Connections: Over 1,000 users connected simultaneously."),_li("Database Size: Over 500 GB, potentially into multiple terabytes (e.g., big data platforms, analytics systems)."),_li("Requests per Second (RPS): Over 2,000 RPS (e.g., global-scale applications, high-frequency transactions)."),_li("Daily Requests: Over 1,000,000."),_li("Data Growth Rate: Exponential (e.g., real-time data streams, global-scale services)."))))],options:["Low","Medium","High","Very high"]}],ESUiUx=e=>[{id:"visual_references",type:"files",label:"Visual References",placeholder:"Enter any examples of designs or interfaces the client prefers",required:!0},{id:"brand_guidelines",type:"textarea",label:"Brand Guidelines",placeholder:"Enter any brand guidelines (logos, colors, typography)",target:e.project.ui_ux.brand_guidelines},{id:"simplicity_vs_complexity",type:"suggestions",label:"Simplicity vs Complexity",description:"How simple or complex should the design be?",suggestions:[{label:"Simple"},{label:"Moderate"},{label:"Complex"}],target:e.project.ui_ux.simplicity_vs_complexity,required:!0},{id:"user_experience",type:"suggestions",label:"User Experience",description:"What user experience considerations should be made?",suggestions:[{label:"Responsive design"},{label:"Users with disabilities"}],target:e.project.ui_ux.user_experience,required:!0}],ESQuote=e=>[{id:"estimation_method",type:"suggestions",label:"Estimation method",target:e.project.quote.estimation_method,description:"How would you like to estimate the project?",suggestions:[{label:"Fixed price"},{label:"Time-based"},{label:"Feature-based"}]},{id:"additional_fees",type:"list",label:"Additional fees",target:e.project.quote.additional_fees,description:"Are there any additional that should be considered?",ai:!0,ai_cost:4,fields:[{id:"additional_fee",type:"text",label:"Additional fee",placeholder:"Enter additional fee",required:!0},{id:"additional_fee_amount",type:"number",label:"Amount (in $)",placeholder:"Enter amount",required:!0,colSpan:3},{id:"additional_fee_period",type:"suggestions",label:"Period",colSpan:3,suggestions:[{label:"One-time"},{label:"Monthly"},{label:"Yearly"},{label:"Per user"},{label:"Per transaction"}]},{id:"additional_fee_description",type:"textarea",label:"Description",placeholder:"Enter description"}]},{id:"hourly_rates",type:"list",label:"Hourly rates",target:e.project.quote.hourly_rates,description:"What are the hourly rates?",fields:[{id:"role",type:"text",label:"Role",placeholder:"Enter role",required:!0},{id:"rate",type:"number",label:"Rate",placeholder:"Enter rate",required:!0,colSpan:3},{id:"rate_currency",type:"suggestions",label:"Currency",colSpan:3,suggestions:[{label:"USD"},{label:"EUR"},{label:"GBP"},{label:"JPY"},{label:"CNY"}]}]},{id:"fixed_margin",type:"number",label:"Fixed margin",target:e.project.quote.fixed_margin,description:"What is the fixed margin?",placeholder:"Enter fixed margin"},{id:"additional_packages",type:"list",label:"Additional packages",target:e.project.quote.additional_packages,description:"Are there any additional packages that should be considered?",fields:[{id:"additional_package",type:"text",label:"Additional package",placeholder:"Enter additional package",required:!0},{id:"additional_package_amount",type:"number",label:"Amount",placeholder:"Enter amount",required:!0,colSpan:3},{id:"additional_package_period",type:"suggestions",label:"Period",colSpan:3,suggestions:[{label:"One-time"},{label:"Monthly"},{label:"Yearly"},{label:"Per user"},{label:"Per transaction"}]},{id:"additional_package_description",type:"textarea",label:"Description",placeholder:"Enter description"}]},{id:"delivery_time",type:"list",label:"Delivery time",target:e.project.quote.delivery_time,description:"What is the delivery time?",fields:[{id:"delivery_time",type:"date",label:"Delivery time",placeholder:"Enter delivery time",required:!0},{id:"delivery_time_description",type:"textarea",label:"Description",placeholder:"Enter description"}]}],ESAppendices=e=>[{id:"additional_documents",type:"files",label:"Additional documents",description:"Add additional documents"},{id:"links_similar_projects",type:"list",label:"Links to similar projects",target:e.project.appendices.additional_documents,description:"Links to concurrents or similar projects",ai:!0,ai_cost:4,fields:[{id:"link",type:"text",label:"Link",placeholder:"Enter link",required:!0}]}];class EGenerate extends Ophose.Component{constructor(e){super(e)}render(){return _div({className:"text-gray-800 rounded-3xl p-8 shadow-lg flex flex-col gap-4"},_p({className:"text-pink-500 text-lg italic font-semibold"},"Congratulations! You're almost done. \uD83D\uDE04"),_h2({className:"text-2xl font-bold"},"Generate estimate"),_p({className:"text-gray-400"},"Please review the following information and make sure everything is correct."),this.props.steps.map(e=>_div({className:"flex flex-col gap-4 p-4 bg-gray-50 rounded-xl"},_h3({className:"font-medium text-xl"},e.title),_div({className:"grid grid-cols-6 gap-4"},e.fields.map(e=>this.props.fieldGenerator(e,!0,e.target?.value,!0))))))}}class EAIPreview extends Ophose.Component{constructor(e){super(e)}render(){let e=live(null),t=live(!0),a=live(null),s=()=>{e.value=null,oenv("estimate/generate/"+this.props.projectState.id.value,{key:this.props.field.id}).then(s=>{t.value=!0,a.value=s.expected_output,e.value=s.response,session.credits.value=s.user_credits}).catch(a=>{t.value=!1,e.value=a.responseJSON.error})};s();let l=()=>{switch(a.value){case"text":this.props.field.target.value=e.value;break;case"json":let t=JSON.parse(e.value);this.props.field.target.value=t}this.remove()},i=e=>e.split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" "),r=(e,t)=>{switch(t){case"text":return _div({className:"bg-gray-800 p-4 rounded-lg"},e);case"json":let a=JSON.parse(e);Array.isArray(a)||(a=[a]);let s=[];return a.map((e,t)=>{Object.keys(e).map(t=>{s.push(_div({className:"grid grid-cols-4 gap-4 text-sm"},_p({className:"text-gray-400"},i(t)),_p({className:"text-gray-200 col-span-3"},e[t])))}),tthis.remove()},_div({className:"bg-gray-900 p-8 rounded-3xl w-1/2 text-gray-100 relative flex flex-col gap-4",style:"max-height: 80vh; overflow-y: auto",onclick:e=>e.stopPropagation()},_i({className:"bi bi-x-circle absolute top-4 right-4 text-2xl cursor-pointer",onclick:()=>this.remove()}),_h1({className:"text-2xl font-bold"},_i({className:"text-indigo-400 bi bi-stars mr-2"}),"AI Preview"),_p({className:"text-gray-400 mb-4 text-sm"},"You can use the AI preview to help you fill in the details of your estimate. The AI will generate a preview based on the details you've already provided. Note that depending demand and server load, the AI may take a few seconds to generate the preview."),_p({className:"text-gray-200 text-sm font-bold"},this.props.field.label),_p({className:"text-gray-400 text-sm"},"AI Generated Estimate"),dyn(e,t,(e,t)=>null===e?_div({className:"animate-pulse bg-gray-800 h-20 rounded-lg"}):!1===t?_div({className:"bg-gray-800 p-4 rounded-lg text-red-500"},e):r(e,a.value)),dyn(e,t,(e,t)=>{if(e&&t)return _div({className:"grid grid-cols-2 gap-4"},_button({className:"bg-gray-700 text-gray-100 rounded-lg py-2",onclick:s},"Generate New Answer"),_button({className:"bg-indigo-500 text-gray-100 rounded-lg py-2",onclick:l},"Save"))})))}}const aiPreview=e=>{document.body.appendChild(render(new EAIPreview(e)))};oimpc("app/steps/ESDetails"),oimpc("app/steps/ESFeatures"),oimpc("app/steps/ESPersons"),oimpc("app/steps/ESFunctional"),oimpc("app/steps/ESTechnical"),oimpc("app/steps/ESUiUx"),oimpc("app/steps/ESQuote"),oimpc("app/steps/ESAppendices"),oimpc("app/EGenerate"),oimpc("app/steps/EAIPreview");class EStep extends Ophose.Component{constructor(e){super(e)}render(){let e=e=>e.every(e=>{if(e.required){if("text"===e.type||"textarea"===e.type)return null!==e.target.value&&""!==e.target.value.trim();if("list"===e.type)return e.target.length>0;if("files"!==e.type)return null!==e.target.value&&""!==e.target.value}return!0}),t=e=>{let t=()=>document.getElementById("guide-modal").remove();document.body.append(render(_div({className:"fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50",id:"guide-modal",onclick:t},_div({className:"bg-white rounded-xl p-8 w-1/2 relative overflow-auto h-5/6",onclick:e=>e.stopPropagation()},_i({className:"bi bi-x-circle text-gray-400 absolute top-4 right-4 cursor-pointer",onclick:t}),e))))},a=(s,l=!1,i=null,r=!1)=>{let o=i;l&&null===i&&(i="N/A");let n=[_div({className:"flex items-center"},_label({className:"text-gray-400 mr-auto text-sm",for:!l&&s.id},l&&_span({className:"text-gray-500 text-xs"},s.label),!l&&s.label,!l&&s.required&&_span({className:"text-red-500 ml-1"},"*"),!l&&!s.required&&_span({className:"text-gray-400 ml-1 text-sm font-normal"},"(optional)")),!l&&s.ai&&_button({className:"text-xs text-white bg-gradient-to-r from-indigo-500 to-indigo-600 px-2 py-1 rounded-lg font-medium flex items-center gap-1",onclick:()=>aiPreview({field:s,projectState:this.props.projectState})},_i({className:"bi bi-stars"}),_span({className:"hidden md:block"},"Answer with AI"),_span({className:"text-xs font-normal"},`(${s.ai_cost} credit${s.ai_cost>1?"s":""})`)),s.guide&&_button({className:"text-xs text-gray-400 px-2 py-1 rounded-lg font-medium flex items-center gap-1",onclick:()=>t(s.guide)},_i({className:"bi bi-question-circle"}),"Guide")),!l&&s.description&&_p({className:"text-gray-400 text-xs mb-2"},s.description),],c=s.colSpan??6,d=l?"flex flex-col gap-1":"flex flex-col gap-2 p-3 bg-white rounded-xl";switch(d+=` col-span-6 lg:col-span-${c}`,s.type){case"date":return _div({className:d},n,!l&&_input({className:"w-full border-none outline-none transition-colors focus:text-indigo-800 font-medium",type:"date",placeholder:s.placeholder,id:s.id,name:s.id,watch:s.target}),l&&_p({className:"text-gray-800 font-medium"},new Date(i).toLocaleDateString()));case"text":return _div({className:d},n,!l&&_input({className:"w-full border-none outline-none transition-colors focus:text-indigo-800 font-medium",placeholder:s.placeholder,id:s.id,name:s.id,watch:s.target,spellcheck:!1}),l&&_p({className:"text-gray-800 font-medium"},i));case"number":return _div({className:d},n,!l&&_input({className:"w-full border-none outline-none transition-colors focus:text-indigo-800 font-medium",type:"number",placeholder:s.placeholder,id:s.id,name:s.id,watch:s.target,precision:2}),l&&_p({className:"text-gray-800 font-medium"},i));case"textarea":return _div({className:d},n,!l&&_textarea({className:"w-full border-none outline-none transition-colors focus:text-indigo-800 font-medium resize-y text-sm h-32",placeholder:s.placeholder,id:s.id,name:s.id,watch:s.target,spellcheck:!1}),l&&_p({className:"text-gray-800 font-medium text-sm whitespace-pre-wrap"},i));case"choice":return _div({className:d},n,!l&&_div({className:"flex flex-wrap gap-2"},s.target._(()=>s.options.map(e=>_button({className:`font-medium py-2 px-4 rounded-lg transition-colors ${s.target.value===e.value?"bg-indigo-500 text-white":"bg-gray-50 text-gray-500"}`,onclick:()=>s.target.value=e.value},e.label)))),l&&_p({className:"text-gray-800 font-medium"},i));case"files":let p=live({rows:[]}),u=()=>{oenv("estimate/files/"+this.props.projectState.id.value,{key:s.id}).then(e=>{p.value=e})};u();let m=e=>{let t=e.target.files[0]??null;t&&oenv("estimate/upload/"+this.props.projectState.id.value,{file:t,key:s.id},{toFormData:!0}).then(()=>{u()})},g=(e,t)=>{e.preventDefault(),oenv("estimate/file/"+t.id+"/delete").then(()=>u())};return _div({className:d},n,_div({className:"grid grid-cols-2 xl:grid-cols-4 gap-4"},p.rows._map(e=>_a({className:"relative rounded-xl overflow-hidden transform hover:scale-105 transition",href:e.url,default:!0,target:"_blank"},e.content_type.startsWith("image/")&&_img({className:"w-full h-32 object-cover",src:e.url}),!e.content_type.startsWith("image/")&&_div({className:"w-full h-32 bg-gray-200 flex items-center justify-center flex-col gap-2"},_i({className:"bi bi-file-earmark-text text-gray-400 text-4xl"}),_p({className:"text-gray-400 text-sm"},e.file_name)),!l&&_button({className:"absolute top-2 right-2 text-white bg-red-500 px-2 py-1 rounded-lg font-medium",onclick(t){g(t,e)}},_i({className:"bi bi-trash"})))),!l&&_div({className:"relative rounded-xl overflow-hidden bg-gray-50 flex items-center justify-center cursor-pointer hover:bg-gray-100 transition-colors h-32"},_i({className:"bi bi-plus-circle text-gray-400 text-4xl"}),_input({type:"file",className:"absolute inset-0 opacity-0 cursor-pointer",onchange:m}))));case"suggestions":return _div({className:d},n,!l&&_div({className:"flex flex-wrap gap-2"},s.target._(()=>s.suggestions.map(e=>_button({className:`font-medium py-1 px-2 text-sm rounded-lg transition-colors ${s.target.value?.toLowerCase()===e.label.toLowerCase()?"bg-indigo-500 text-white":"bg-gray-50 text-gray-500"}`,onclick:()=>s.target.value=e.label},e.label)))),!l&&_input({className:"w-full bg-gray-50 p-2 rounded-lg border-none outline-none transition-colors focus:text-indigo-800 font-medium",placeholder:"Enter type",id:s.id,name:s.id,watch:s.target,spellcheck:!1}),l&&_p({className:"text-gray-800 font-medium"},i));case"progress":return _div({className:d},n,!l&&_div({className:"flex gap-2 items-center"},s.target._(()=>{let e=s.options.findIndex(e=>e===s.target.value),t=t=>{if(t===e){s.target.value=null;return}s.target.value=s.options[t]};return s.options.map((a,s)=>_div({className:"flex flex-col items-center gap-1 flex-1 hover:cursor-pointer hover:text-indigo-500 transition font-medium select-none transition-colors p-2 rounded-lg "+(e!==s||l?"bg-gray-50":"bg-indigo-50 text-indigo-500"),onclick:()=>!l&&t(s)},_div({className:"text-sm"},a)))})),!l&&_div({className:"flex gap-1 items-center"},s.options.map((e,t)=>_div({className:"flex-1 h-1 bg-gray-200 rounded-full"},s.target._(e=>_div({className:"flex-1 h-1 rounded-full "+(s.options.findIndex(t=>t===e)>=t?"bg-indigo-500":"bg-gray-200")}))))),l&&o&&_div({className:"flex gap-1 items-center"},s.options.map((e,t)=>_div({className:"flex flex-col items-center gap-1 flex-1 hover:cursor-pointer hover:text-indigo-500 transition font-medium select-none transition-colors p-2 rounded-lg "+(s.options.findIndex(e=>e===i)>=t?"bg-indigo-50 text-indigo-500":"bg-gray-50")},_div({className:"text-sm"},e)))),l&&!o&&_p({className:"text-gray-800 font-medium"},"N/A"));case"boolean":return _div({className:d},n,!l&&_div({className:"flex gap-2 items-center"},s.target._(()=>[_button({className:`font-medium py-2 px-4 rounded-lg transition-colors ${s.target.value?"bg-indigo-500 text-white":"bg-gray-50 text-gray-800"}`,onclick:()=>s.target.value=!0},"Yes"),_button({className:`font-medium py-2 px-4 rounded-lg transition-colors ${s.target.value?"bg-gray-50 text-gray-800":"bg-indigo-500 text-white"}`,onclick:()=>s.target.value=!1},"No")])),l&&_p({className:"text-gray-800 font-medium"},i?"Yes":"No"));case"list":let h={};s.fields.forEach(e=>h[e.id]=null),h=live(h);let f=()=>{if(!e(s.fields))return;let t=h.value;s.target.add(t),s.fields.forEach(e=>h[e.id].value=null)};return _div({className:d},n,_div({className:"flex flex-col gap-8"},!l&&_div({className:"flex flex-col gap-2 rounded-xl p-4 bg-gray-100"},_div({className:"grid grid-cols-6 gap-4"},s.fields.map(e=>(e.target=h[e.id],a(e)))),h._(()=>_div({className:"flex items-center justify-between"},_button({className:"text-white bg-green-500 px-4 py-2 rounded-lg font-medium flex items-center gap-1 ml-auto "+(e(s.fields)?"":"opacity-50 cursor-default"),onclick:f},_i({className:"bi bi-plus-circle"}),"Add item")))),s.target&&s.target._map((e,t)=>_div({className:"flex flex-col gap-2 rounded-xl p-4 bg-gray-100 relative"},_div({className:"grid grid-cols-6 gap-4"},s.fields.map(t=>a({...t,target:null},!0,e[t.id]))),_div({className:"flex items-center justify-between"},!r&&_button({className:"bg-gray-200 px-2 py-1 text-sm rounded-lg font-medium flex items-center gap-1 absolute top-4 right-4",onclick:()=>s.target.removeAt(t)},_i({className:"bi bi-trash"}),"Remove")))),s.target&&s.target._(e=>0===e.length&&!r&&_p({className:"text-gray-400 text-sm text-center p-4"},"You don't have any items yet")),s.target&&s.target._(e=>0===e.length&&r&&_p({className:"text-gray-800 font-medium"},"N/A"))))}},s=(t,s)=>_div({className:"bg-gray-100 rounded-3xl p-4 lg:p-8 flex flex-col gap-4"},_h3({className:"text-gray-600 text-lg font-bold"},t),_p({className:"text-gray-400 text-sm"},"Please provide the following details to continue and make sure to fill in all required fields."),_div({className:"grid grid-cols-6 gap-4"},s.map(e=>a(e))),_div({className:"grid grid-cols-2 gap-4"},dyn(this.props.currentStep,this.props.data,t=>{let a="bg-gray-50 text-gray-800 py-2 px-4 rounded-lg border border-gray-200 font-medium transition-colors hover:bg-gray-100",l="bg-gradient-to-r from-indigo-500 to-indigo-600 text-white py-2 px-4 rounded-lg font-medium transition-colors hover:from-indigo-600 hover:to-indigo-700";return e(s)||(l+=" opacity-50 cursor-default"),1===t&&(a+=" opacity-50 cursor-default"),[_button({className:a,onclick:()=>t>1&&this.props.currentStep.remove(1)},"Back"),_button({className:l,onclick:()=>e(s)&&this.props.currentStep.add(1)},"Next")]})));return _div(this.props.currentStep._switch({1:s("Project details",ESDetails(this.props.data)),2:s("Concerned persons",ESPersons(this.props.data)),3:s("Features",ESFeatures(this.props.data)),4:s("Functional requirements",ESFunctional(this.props.data)),5:s("Technical constraints",ESTechnical(this.props.data)),6:s("UI/UX",ESUiUx(this.props.data)),7:s("Project estimation",ESQuote(this.props.data)),8:s("Appendices",ESAppendices(this.props.data)),9:new EGenerate({data:this.props.data,fieldGenerator:a,steps:[{title:"Project details",fields:ESDetails(this.props.data)},{title:"Concerned persons",fields:ESPersons(this.props.data)},{title:"Features",fields:ESFeatures(this.props.data)},{title:"Functional requirements",fields:ESFunctional(this.props.data)},{title:"Technical constraints",fields:ESTechnical(this.props.data)},{title:"UI/UX",fields:ESUiUx(this.props.data)},{title:"Project estimation",fields:ESQuote(this.props.data)},{title:"Appendices",fields:ESAppendices(this.props.data)}]})}))}}oimpc("app/ESteps"),oimpc("app/EProgressBar"),oimpc("app/ESavedState"),oimpc("app/steps/EStep");class Estimate extends Ophose.Component{constructor(e){super(e)}render(){let e=this.props.projectState;return _div({className:"flex flex-col gap-4"},_div({className:"grid grid-cols-2 gap-8 items-center"},new EProgressBar({progress:e.progress}),_div({className:"flex items-center gap-4 justify-end"},new ESavedState({savedState:e.savedState}))),_div({className:"grid lg:grid-cols-3 gap-8"},new ESteps({currentStep:e.currentStep,className:"sticky top-24 z-10 hidden lg:flex",style:"height: min-content;"}),new EStep({currentStep:e.currentStep,className:"lg:col-span-2",data:this.props.data,projectState:e})))}}oimpc("app/EProgressBar");class LastProjects extends Ophose.Component{constructor(e){super(e)}render(){let e=live({rows:[],totalPages:1,page:1,perPage:10,count:0}),t=live(1).min(1).max(e.totalPages),a=live("");watch(t,a,(t,a)=>{oenv("/estimate/list",{page:t,search:a}).then(t=>{e.value=t,this.props.count&&""==a&&(this.props.count.value=t.count)})});let s=e=>{oenv("/estimate/delete/"+e).then(()=>t.refresh())},l=e=>{let t={name:e.client_name,email:e.client_email};return _tr({className:"border-t border-gray-200 py-2"},_td({className:"text-sm text-gray-600 p-2"},_div({className:"flex items-center gap-2"},_img({src:"https://ui-avatars.com/api/?name="+e.name+"&size=32",className:"rounded-full w-8 h-8 object-cover"}),_div({className:"flex flex-col font-semibold flex-1"},e.name||"Unknown project",_div({className:"flex items-center gap-2 text-gray-400 font-normal"},Math.round(e.progress)+"%",new EProgressBar({progress:live(e.progress)}))))),_td({className:"text-sm text-gray-600 p-2 hidden md:table-cell"},_div({className:"flex flex-col"},t.name||"Unknown client",t.email&&_a({href:"mailto:"+t.email,className:"text-indigo-500 hover:underline"},t.email))),_td({className:"text-sm text-gray-600 p-2 hidden md:table-cell"},new Date(e.due_date).toLocaleDateString()),_td({className:"text-sm text-gray-600 p-2"},_div({className:"flex items-center gap-2 flex-wrap"},_a({href:"/app/estimate/"+e.id,className:"px-2 py-1 bg-gradient-to-br from-indigo-500 to-blue-500 text-white rounded-lg hover:from-indigo-600 hover:to-blue-600"},_i({className:"bi bi-eye"}),_span({className:"hidden md:inline ml-2"},"View")),_button({className:"px-2 py-1 bg-gray-200 text-gray-600 rounded-lg hover:bg-gray-300 hover:text-gray-700",onclick:t=>s(e.id)},_i({className:"bi bi-trash"}),_span({className:"hidden md:inline ml-2"},"Delete")))))};return _div({className:"flex flex-col gap-4"},_h2({className:"text-xl font-bold col-span-2"},"Last projects"),_div({className:"flex items-center justify-between gap-4"},_input({type:"text",placeholder:"Search projects",className:"p-2 border border-gray-200 rounded-lg xl:w-96",watch:a,cooldown:500}),_div({className:"flex items-center gap-2 font-semibold"},_button({className:"bg-gray-200 text-gray-600 font-medium py-1 px-2 rounded-xl text-sm",onclick:()=>t.value--},_i({className:"bi bi-chevron-left"})),_span({className:"text-sm text-gray-600"},t," of ",e.totalPages),_button({className:"bg-gray-200 text-gray-600 font-medium py-1 px-2 rounded-xl text-sm",onclick:()=>t.value++},_i({className:"bi bi-chevron-right"})))),e.rows._notEmpty(_table({className:"table-auto w-full border-collapse"},_thead({},_tr({},_th({className:"text-left text-xs text-gray-500 p-2"},"Project"),_th({className:"text-left text-xs text-gray-500 p-2 hidden md:table-cell"},"Client"),_th({className:"text-left text-xs text-gray-500 p-2 hidden md:table-cell"},"Due date"),_th({className:"text-left text-xs text-gray-500 p-2"},"Actions"))),_tbody(e.rows._map(e=>l(e))))),e.rows._empty(_div({className:"text-gray-400 text-center flex items-center gap-2 justify-center"},"No projects found. ",_p({onclick:EstimateService.createEstimate,className:"text-indigo-500 hover:underline cursor-pointer"},"Create a new project"))))}}class LastProject extends Ophose.Component{constructor(e){super(e)}style(){return` %self { } `}render(){return this.props.id&&_div({className:"flex flex-col gap-2 bg-gray-50 p-4 rounded-3xl"},_h2({className:"text-lg font-bold"},"Last project"),_p({className:"text-lg font-medium text-gray-500"},this.props.name??"Not defined"),_p({className:"text-sm text-gray-500"},"Client: ",this.props.client_name??"Not defined"),_p({className:"text-sm text-gray-500"},"Due date: ",new Date(this.props.due_date).toLocaleDateString()??"Not defined"),_div({className:"flex gap-4"},_a({href:"/app/estimate/"+this.props.id,className:"bg-gradient-to-br from-indigo-500 to-blue-500 text-white py-1 px-2 rounded-lg"},_i({className:"bi bi-eye mr-2"}),"View")))}}class Billing extends Ophose.Component{constructor(e){super(e)}render(){let e=live({rows:[],totalPages:1,page:1,perPage:5,count:0}),t=live(1).min(1).max(e.totalPages);return watch(t,()=>{oenv("/estimate/billing",{page:t.value}).then(t=>{e.value=t})}),_div({className:"flex flex-col gap-4"},_h1({className:"text-2xl font-semibold"},"Billing"),_div({className:"flex flex-col gap-4"},e.rows._map(e=>_div({className:"flex flex-col gap-2"},_div({className:"flex items-center gap-2"},_div({className:"text-gray-600"},e.name),_div({className:"text-gray-400"},new Date(e.date).toLocaleDateString()),_div({className:"text-gray-400"},e.amount+" €")),_div({className:"text-gray-500"},e.description))),e.rows._notEmpty(_div({className:"flex justify-center gap-4"},_button({className:"px-4 py-2 bg-gray-200 text-gray-600 rounded-lg",onClick:()=>t.value--},"Previous"),_button({className:"px-4 py-2 bg-gray-200 text-gray-600 rounded-lg",onClick:()=>t.value++},"Next")))))}}class HomeQuestion extends Ophose.Component{constructor(e){super(e),this.currentStep=live(0)}steps(){return[{title:"Project details",fields:[{title:"Project name",type:"one-line"},{title:"Project description",type:"multi-line"},{title:"Project type",type:"suggestions",suggestions:[{label:"Web application"},{label:"Mobile application"},{label:"Desktop application"},{label:"API"},{label:"Other"},]},]},{title:"Features",fields:[{title:"Features",type:"list",fields:[{title:"Feature",type:"one-line"},{title:"Description",type:"multi-line"},{title:"Priority",type:"suggestions",suggestions:[{label:"Low"},{label:"Medium"},{label:"High"},]},]},]},{title:"Generate specification",fields:[{title:"Project name",type:"one-line"},{title:"Project description",type:"multi-line"},{title:"Project type",type:"suggestions",suggestions:[{label:"Web application"},{label:"Mobile application"},{label:"Desktop application"},{label:"API"},{label:"Other"}]},{title:"Features",type:"multi-line"},]}]}onPlace(e){this.timer=setInterval(()=>{this.currentStep.update(e=>(e+1)%this.steps().length)},3e3)}onRemove(){clearInterval(this.timer)}stepList(){return _div({className:"bg-gray-50 p-6 rounded-3xl flex flex-col gap-6"},_div({className:"h-2 w-full bg-gray-200 rounded-full"},this.currentStep._(e=>_div({className:"h-2 px-1 bg-gradient-to-br from-green-500 to-green-400 rounded-full",style:`width: ${50*e}%`}))),this.steps().map((e,t)=>_div({className:"flex items-center gap-2 text-lg font-medium text-gray-500"},this.currentStep._(a=>a>t?[_div({className:"h-8 w-8 rounded-full bg-green-500 flex items-center justify-center"},_i({className:"bi bi-check text-white"})),_span({className:"text-gray-400"},e.title)]:a===t?[_div({className:"h-8 w-8 rounded-full bg-green-500 flex items-center justify-center"},_i({className:"bi bi-check text-white"})),_span({className:"text-green-500"},e.title)]:[_div({className:"h-8 w-8 rounded-full bg-gray-200 flex items-center justify-center"},t+1),_span({className:"text-gray-400"},e.title)]))))}stepFields(e,t=!1){let a=e=>{switch(e.type){case"one-line":return _div({className:"flex flex-col gap-2"},_p({className:"text-sm font-medium text-gray-800"},e.title),_div({className:"h-4 w-1/2 bg-gray-200 rounded-full animate-pulse"}));case"multi-line":return _div({className:"flex flex-col gap-2"},_p({className:"text-sm font-medium text-gray-800"},e.title),_div({className:"h-4 w-3/4 bg-gray-200 rounded-lg animate-pulse"}),_div({className:"h-4 w-full bg-gray-200 rounded-lg animate-pulse"}),_div({className:"h-4 w-2/3 bg-gray-200 rounded-lg animate-pulse"}));case"suggestions":let t=Math.floor(Math.random()*e.suggestions.length);return _div({className:"flex flex-col gap-2"},_p({className:"text-sm font-medium text-gray-800"},e.title),_div({className:"flex gap-2 flex-wrap"},e.suggestions.map((e,a)=>_div({className:`py-2 px-3 text-sm font-medium rounded-full bg-gray-200 flex items-center justify-center ${t===a?"bg-indigo-500 text-white":"bg-gray-100 text-gray-500 animate-pulse"}`},e.label))));case"list":return _div({className:"flex flex-col gap-4"},_div({className:"flex flex-col gap-4 bg-gray-100 p-4 rounded-3xl"},_div({className:"flex items-center justify-between gap-4"},_h3({className:"text-lg font-medium text-gray-800"},e.title),_button({className:"bg-gradient-to-br from-indigo-500 to-blue-500 text-white font-medium py-1.5 px-3 text-sm rounded-xl"},"Add")),e.fields.map(a)))}};return _div({className:"bg-gray-50 p-6 rounded-3xl flex flex-col gap-6 lg:col-span-2"},e.fields.map(a),_button({className:"bg-gradient-to-br from-indigo-500 to-blue-500 text-white font-medium py-2 px-4 rounded-xl w-max self-end"},t?"Generate specification":"Next"))}render(){return _div({className:"w-3/4 mx-auto transform -translate-y-16 text-gray-600 grid lg:grid-cols-3 gap-4 select-none items-start h-full lg:h-96"},this.stepList(),this.currentStep._(e=>this.stepFields(this.steps()[e],e===this.steps().length-1)))}}class HomeAbout extends Ophose.Component{constructor(e){super(e)}render(){return _section({className:"bg-gray-50 py-16 border-b text-gray-700 flex flex flex-col gap-32",id:"about"},_div({className:"container mx-auto grid md:grid-cols-2 gap-8"},_div({className:"flex flex-col gap-8"},_h4({className:"font-semibold uppercase"},"Simply generate estimates and specifications"),_h1({className:"text-2xl md:text-6xl font-bold"},"Estimate your project in minutes with AI")),_div({className:"flex flex-col gap-16"},_p({className:"text-xl font-medium"},"This SaaS has been designed to help you or your team to generate estimates and specifications for your projects in few clicks. Not only it saves you time, but with help of AI it will also generate ",_b("UML, mandatory standards "),"depending on the project type and region ",_b("and more.")),_button({className:"bg-gradient-to-br from-indigo-500 to-blue-500 text-white font-medium py-2 px-4 rounded-xl flex items-center gap-2 w-max self-end"},_i({className:"bi bi-plus-circle text-white"}),"Create a free account"))),_div({className:"container mx-auto grid md:grid-cols-3 gap-8"},_div({className:"bg-white p-8 rounded-3xl flex flex-col gap-4"},_i({className:"bi bi-lightbulb text-4xl text-indigo-500"}),_h3({className:"text-2xl font-semibold"},"AI-powered analyze"),_p({className:"text-lg"},"Estimaa uses AI to analyze your project requirements and generate a detailed estimate and specification document.")),_div({className:"bg-white p-8 rounded-3xl flex flex-col gap-4"},_i({className:"bi bi-clock text-4xl text-indigo-500"}),_h3({className:"text-2xl font-semibold"},"Getting started fast"),_p({className:"text-lg"},"You can start generating estimates and specifications for your projects in minutes. No need to wait for days.")),_div({className:"bg-white p-8 rounded-3xl flex flex-col gap-4"},_i({className:"bi bi-pen text-4xl text-indigo-500"}),_h3({className:"text-2xl font-semibold"},"Update in real-time"),_p({className:"text-lg"},"You can make changes to your project requirements and see the updated estimate and specification in real-time."))),_div({className:"container mx-auto grid md:grid-cols-2 gap-16"},_div({className:"flex flex-col gap-8"},_h4({className:"font-semibold uppercase"},"Estimaa in action"),_h1({className:"text-2xl md:text-6xl font-bold"},"Generate estimates and specifications in minutes"),_p({className:"text-xl font-medium"},"Estimaa is a tool that helps you generate estimates and specifications for your projects in minutes. It uses AI to analyze your project requirements and generate a detailed estimate and specification document."),_button({className:"bg-gradient-to-br from-indigo-500 to-blue-500 text-white font-medium py-2 px-4 rounded-xl flex items-center gap-2 w-max self-end"},_i({className:"bi bi-plus-circle text-white"}),"Learn more")),_div({className:"flex flex-col gap-16"},_img({src:"https://placehold.co/600x400",className:"rounded-3xl w-full h-96 object-cover"}))))}}class HomePricing extends Ophose.Component{constructor(e){super(e)}render(){return _section({className:"py-16 flex flex flex-col gap-16 text-gray-700",id:"pricing"},_div({className:"container mx-auto gap-8"},_div({className:"flex flex-col gap-8 text-center md:w-1/2 mx-auto"},_h4({className:"font-semibold uppercase"},"Pay as you go"),_h1({className:"text-4xl md:text-7xl font-bold bg-gradient-to-r from-indigo-500 to-pink-400 text-transparent bg-clip-text"},"Pay only for what you use"))),_div({className:"container mx-auto grid lg:grid-cols-2 gap-16 items-start"},_div({className:"flex flex-col gap-4"},_h3({className:"text-2xl font-bold"},"Why paying as you go?"),_p({className:"text-lg"},"Estimaa is a tool that helps you generate estimates and specifications for your projects in minutes. Then only paying for what you use is the best way to keep our costs low and your satisfaction high. No hidden fees, no surprises."),_div({className:"flex items-center gap-4 bg-gradient-to-br from-gray-900 to-gray-700 p-4 text-white rounded-2xl"},_i({className:"bi bi-gift text-4xl text-pink-400"}),_p({className:"text-lg font-semibold"},"Get started with 10 free credits when you create an account."))),_div({className:"grid grid-cols-2 xl:grid-cols-3 gap-4"},_div({className:"flex flex-col bg-gradient-to-br from-gray-100 to-gray-50 p-4 rounded-2xl"},_h3({className:"text-lg font-medium"},"10 credits"),_h4({className:"text-2xl font-bold"},"$2.99")),_div({className:"flex flex-col bg-gradient-to-br from-gray-100 to-gray-50 p-4 rounded-2xl"},_h3({className:"text-lg font-medium"},"25 credits"),_h4({className:"text-2xl font-bold"},_span({className:"line-through text-gray-400 font-normal text-lg"},"$7.45")," $6.99")),_div({className:"flex flex-col bg-gradient-to-br from-gray-100 to-gray-50 p-4 rounded-2xl"},_h3({className:"text-lg font-medium"},"50 credits"),_h4({className:"text-2xl font-bold"},_span({className:"line-through text-gray-400 font-normal text-lg"},"$14.95")," $12.99")),_div({className:"flex flex-col bg-gradient-to-br from-gray-100 to-gray-50 p-4 rounded-2xl"},_h3({className:"text-lg font-medium"},"100 credits"),_h4({className:"text-2xl font-bold"},_span({className:"line-through text-gray-400 font-normal text-lg"},"$29.90")," $23.99")),_div({className:"flex flex-col bg-gradient-to-br from-gray-100 to-gray-50 p-4 rounded-2xl"},_h3({className:"text-lg font-medium"},"200 credits"),_h4({className:"text-2xl font-bold"},_span({className:"line-through text-gray-400 font-normal text-lg"},"$59.80")," $45.99")),_div({className:"flex flex-col bg-gradient-to-br from-gray-100 to-gray-50 p-4 rounded-2xl"},_h3({className:"text-lg font-medium"},"500 credits"),_h4({className:"text-2xl font-bold"},_span({className:"line-through text-gray-400 font-normal text-lg"},"$149.50")," $89.99")))))}}class Header extends Ophose.Component{constructor(e){super(e)}onPlace(e){let t=()=>{window.scrollY>10?e.classList.add("shadow","bg-white","border-b","border-gray-200"):e.classList.remove("shadow","bg-white","border-b","border-gray-200")};window.addEventListener("scroll",t),t()}render(){return _header({className:"sticky top-0 select-none z-20 transition-all duration-300"},currentUser._if(()=>_div({className:"container mx-auto py-4 flex items-center gap-4"},_nav({className:"flex items-center gap-4 font-medium"},_a({href:"/app",className:"text-gray-700 hover:text-gray-800 flex items-center gap-2"},_i({className:"bi bi-house-door text-xl"}),_span({className:"hidden md:block"},"Dashboard")),_a({href:"/app/estimates",className:"text-gray-700 hover:text-gray-800 flex items-center gap-2"},_i({className:"bi bi-file-earmark-text text-xl"}),_span({className:"hidden md:block"},"Estimates")),_a({href:"/documentation",className:"text-gray-700 hover:text-gray-800 flex items-center gap-2"},_i({className:"bi bi-book text-xl"}),_span({className:"hidden md:block"},"Docs"))),_a({href:"/",className:"mx-auto hidden lg:block"},_h1({className:"bg-gradient-to-br from-indigo-500 to-pink-500 text-white font-bold py-1 px-2 rounded-xl"},"estimaa")),_a({href:"/app/ai-credits",className:"bg-gradient-to-br from-gray-900 to-gray-800 text-white font-semibold py-2 px-4 rounded-xl flex items-center gap-2 ml-auto"},_i({className:"bi bi-wallet2 text-indigo-500"}),_span({className:"hidden lg:block"},"AI Credits: "),session.credits),EstimateService.loadingCreateEstimate._if(_button({className:"bg-gray-50 font-semibold py-2 px-4 rounded-xl flex items-center gap-2 cursor-not-allowed"},_i({className:"bi bi-plus-circle text-indigo-500"}),_span({className:"hidden md:block"},"Creating estimate...")),_button({className:"cursor-pointer bg-gray-50 font-semibold py-2 px-4 rounded-xl flex items-center gap-2",onclick:EstimateService.createEstimate},_i({className:"bi bi-plus-circle text-indigo-500"}),_span({className:"hidden md:block"},"Create a specification"))),_a({href:"/app/profile",className:"font-semibold rounded-xl flex items-center gap-2"},_img({src:"/pfp.jpg",className:"rounded-full w-8 h-8 object-cover"}),_span({className:"hidden lg:block"},"Profile"))),_div({className:"container mx-auto py-4 flex items-center gap-4"},_a({href:"/"},_h1({className:"bg-gradient-to-br from-indigo-500 to-pink-500 text-white font-bold py-1 px-2 rounded-xl"},"estimaa")),_h3({className:"hidden lg:block text-gray-500 text-xs"},"Your estimate is a few clicks away"),_a({href:"/app",className:"bg-gray-50 font-bold py-2 px-4 rounded-xl hidden xl:flex items-center gap-2"},_i({className:"bi bi-plus-circle text-indigo-500"}),"Create a specification"),_nav({className:"flex items-center gap-4 ml-auto font-medium"},_a({href:"#about",className:"hidden md:block text-gray-700 hover:text-gray-800"},"About"),_a({href:"#pricing",className:"hidden md:block text-gray-700 hover:text-gray-800"},"Pricing"),_a({href:"/documentation",className:"hidden md:block text-gray-700 hover:text-gray-800"},"Documentation"),_a({href:"/auth/login",className:"text-gray-700 hover:text-gray-800 ml-8 font-medium py-2 px-4 rounded-xl border-2 border-gray-700 box-border"},"Login"),_a({href:"/auth/register",className:"bg-gradient-to-br from-indigo-500 to-pink-500 text-white font-bold py-2 px-4 rounded-xl"},_span({className:"hidden md:block"},"Create a free account"),_span({className:"md:hidden"},"Sign up"))))))}}class Footer extends Ophose.Component{constructor(e){super(e)}render(){return currentUser._if(null,_footer({className:"bg-gray-50 py-8"},_div({className:"container mx-auto flex flex-col gap-4 items-center"},_p({className:"text-gray-500 text-center text-sm"},"\xa9 2024 Estimaa. All rights reserved."),_div({className:"flex items-center gap-4"},_a({href:"#",className:"text-gray-500 hover:text-gray-600"},_i({className:"bi bi-facebook"})),_a({href:"#",className:"text-gray-500 hover:text-gray-600"},_i({className:"bi bi-twitter"})),_a({href:"#",className:"text-gray-500 hover:text-gray-600"},_i({className:"bi bi-instagram"})),_a({href:"#",className:"text-gray-500 hover:text-gray-600"},_i({className:"bi bi-linkedin"}))))))}}class SEO{static info={};static update(e){let t={...SEO.info,...e};for(let a in t)switch(a){case"title":document.title=t.callbacks.title(t.title);break;case"description":let s=document.querySelector('meta[name="description"]');s||((s=document.createElement("meta")).name="description",document.head.appendChild(s)),s.content=t.description;break;case"favicon":let l=document.querySelector('link[rel="icon"]');l||((l=document.createElement("link")).rel="icon",l.href="/favicon.ico",l.type="image/x-icon",l.id="favicon",document.head.appendChild(l)),l.href=t.favicon;break;case"lang":document.documentElement.lang=t.lang;break;case"callbacks":for(let i in SEO.info.callbacks||(SEO.info.callbacks={}),t.callbacks)SEO.info.callbacks[i]=t.callbacks[i];break;default:project.productionMode||console.warn(`SEO: Unknown key ${a}`)}SEO.info=t}}SEO.update({title:"Welcome",description:"Project description",favicon:"/favicon.ico",lang:"en",callbacks:{title:e=>e+" | "+project.name}});class OphosePlugin extends Ophose.Plugin{constructor(){super("OphosePlugin"),this.useRender(e=>{if(e._.includes(".")){let t=e._.split("."),a=t.shift(),s=t.join(" ");e._=a,e.className=" "+s}if("a"==e._&&e.href&&!e.default&&(e.onclick=t=>{t.preventDefault(),route.go(e.href)}),e.cooldown){let l=e.watch;if(!l)return dev.error("The cooldown attribute requires a watch attribute"),e;let i=live(l);e.watch=i;let r=Date.now();watch(i,t=>{r=Date.now(),setTimeout(()=>{Date.now()-r>e.cooldown&&(l.value=t)},e.cooldown)})}return e})}}class EstimateService{static loadingCreateEstimate=live(!1);static createEstimate(){EstimateService.loadingCreateEstimate.set(!0),oenv("estimate/create").then(e=>{EstimateService.loadingCreateEstimate.set(!1),route.go("/app/estimate/"+e)})}}const currentUser=live(null);class Auth{static async logout(e){return e&&e.preventDefault(),await oenv("ah4/auth/logout").then(()=>{currentUser.set(null),route.go("/")})}static async login(e){return await oenv("ah4/auth/login",e).then(e=>{currentUser.set(e)})}static async register(e){return await oenv("ah4/auth/register",e)}static init(){oenv("ah4/auth/user").then(e=>{e&&e.user&¤tUser.set(e.user)})}}oimpc("base/Header"),oimpc("base/Footer"),oimpe("ophose"),oimpe("estimate"),oimpe("ah4/auth"),oimpc("@/ah4/seo/SEO");const session=live({credits:0});class Base extends Ophose.Base{constructor(e){super(e),this.usePlugin(OphosePlugin),SEO.update({title:"Welcome to Estimate",description:"Estimate is a simple app to manage your projects and clients."}),Auth.init(),watch(currentUser,e=>{e&&oenv("/estimate/ai_credits").then(e=>session.credits.value=e.ai_credits)}),importCss("https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css"),importCss("https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css")}style(){return` * { scroll-margin-top: 8rem; } .container { padding-left: 1rem; padding-right: 1rem; } `}render(){return _main({className:"text-gray-800"},new Header,_("div",{style:"min-height: 70vh;"},this.props.children),new Footer)}}