your-ai-workflow-firebase-os 2.0.9 → 2.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{Assets-COH4Ji57.js → Assets-BKXpQmMS.js} +2 -2
- package/dist/{Assets-D7fDckSi.cjs → Assets-DoZlHuud.cjs} +1 -1
- package/dist/{Billing-kk4ZMd3z.js → Billing-A6rwfQRT.js} +2 -2
- package/dist/{Billing-DkuJdls5.cjs → Billing-CBxVy-CG.cjs} +1 -1
- package/dist/{CopyLink-C5lKLyOU.cjs → CopyLink-D6QTWSoK.cjs} +1 -1
- package/dist/{CopyLink-CNjDLzOl.js → CopyLink-kROJG9Qf.js} +1 -1
- package/dist/{DashboardNav-GgEUpyTa.cjs → DashboardNav-Bc619nqn.cjs} +1 -1
- package/dist/{DashboardNav-CEd8gGPm.js → DashboardNav-CxS3Qnl-.js} +1 -1
- package/dist/{EmailAdmin-pbQ-f9Ge.js → EmailAdmin-DbWK_5Kw.js} +4 -4
- package/dist/{EmailAdmin-d_gWd48U.cjs → EmailAdmin-sa9C5jOw.cjs} +1 -1
- package/dist/{EventCard-DAsGsicK.cjs → EventCard-D57elnQo.cjs} +1 -1
- package/dist/{EventCard-BSGLYD64.js → EventCard-DnoR91KN.js} +1 -1
- package/dist/{FormsAdmin-5KTTp6zo.cjs → FormsAdmin-Ck7ssCHd.cjs} +1 -1
- package/dist/{FormsAdmin-BNI63vEk.js → FormsAdmin-DOes2Ajy.js} +4 -4
- package/dist/{Inbox-DjslBakx.cjs → Inbox-ChBLxjCi.cjs} +1 -1
- package/dist/{Inbox-D9Y5K8Se.js → Inbox-CyteB2LL.js} +2 -2
- package/dist/{MyBookings-CkEioQIj.cjs → MyBookings-B424zfVj.cjs} +1 -1
- package/dist/{MyBookings-B4DndHV6.js → MyBookings-DLQefkDS.js} +3 -3
- package/dist/{PageTitle-DQkvCB11.cjs → PageTitle-BL50s4qY.cjs} +1 -1
- package/dist/{PageTitle-DCoUQWw6.js → PageTitle-CkZriz8K.js} +1 -1
- package/dist/{PagesAdmin-YdYgmuEB.cjs → PagesAdmin-1U73GM_o.cjs} +1 -1
- package/dist/PagesAdmin-8smM_SDx.cjs +1 -0
- package/dist/{PagesAdmin-DzLJWKBJ.js → PagesAdmin-CORR24DJ.js} +8 -8
- package/dist/{PagesAdmin-D0qgoZtW.js → PagesAdmin-hhVAwuuy.js} +1 -1
- package/dist/{PaymentsAdmin-C3cEOeIs.js → PaymentsAdmin-CoaSATtY.js} +9 -9
- package/dist/{PaymentsAdmin-B5l-f0mp.cjs → PaymentsAdmin-DdP5FeXc.cjs} +1 -1
- package/dist/{ProviderMark--adeeajP.cjs → ProviderMark-BCQRu5Gs.cjs} +1 -1
- package/dist/{ProviderMark-BvEMlZAm.js → ProviderMark-Celkjuth.js} +1 -1
- package/dist/{PublishApp-Bc82Ijkq.cjs → PublishApp-CYHX36oo.cjs} +1 -1
- package/dist/{PublishApp-B9Fo6xN0.js → PublishApp-Dagc4TYm.js} +4 -4
- package/dist/{ScheduleAdmin-bk3GgxKP.js → ScheduleAdmin-D8siv7ZQ.js} +4 -4
- package/dist/{ScheduleAdmin-Dh_hW6p4.cjs → ScheduleAdmin-ohFzK-5E.cjs} +1 -1
- package/dist/{SchedulePicker-CN0755Ek.cjs → SchedulePicker-BpPGI5VZ.cjs} +1 -1
- package/dist/{SchedulePicker-DO4PewPJ.js → SchedulePicker-sZIZec9L.js} +1 -1
- package/dist/{Setup-_G-s5y5Q.js → Setup-DOGI-_8f.js} +2 -2
- package/dist/{Setup-R4r6_tbV.cjs → Setup-DiFnnzdd.cjs} +1 -1
- package/dist/{SetupPayments-CuFk9REC.cjs → SetupPayments-BLq0W5DU.cjs} +1 -1
- package/dist/{SetupPayments-CkolcOtv.js → SetupPayments-ICqCoZeQ.js} +3 -3
- package/dist/{SignInAdmin-BLEn0rId.js → SignInAdmin-CQzPqUui.js} +5 -5
- package/dist/{SignInAdmin-B1yLLaQu.cjs → SignInAdmin-JnhCefKY.cjs} +1 -1
- package/dist/{SupportBar-DI_XbEsG.js → SupportBar-0nIiQp-_.js} +105 -104
- package/dist/SupportBar-DR52UpBq.cjs +1 -0
- package/dist/{TemplateDrive-DNBwL0oy.js → TemplateDrive-6aV9Hmh3.js} +2 -2
- package/dist/{TemplateDrive-BJN-ReA_.cjs → TemplateDrive-ElNPzwv3.cjs} +1 -1
- package/dist/ThemeAdmin-B4CIxIjh.cjs +1 -0
- package/dist/ThemeAdmin-B9VnH5xH.js +2 -0
- package/dist/{ThemeAdmin-DkgmjW3g.cjs → ThemeAdmin-BhaTfgKX.cjs} +1 -1
- package/dist/{ThemeAdmin-Cnqefrz6.js → ThemeAdmin-C_8phTKX.js} +3 -3
- package/dist/{TransactionsAdmin-C5wQRR1g.cjs → TransactionsAdmin-BiV8VgD0.cjs} +1 -1
- package/dist/{TransactionsAdmin-Brs-CEcG.js → TransactionsAdmin-DAENRmVO.js} +3 -3
- package/dist/{Users-B16L9cKI.cjs → Users-Ayu_S4cd.cjs} +1 -1
- package/dist/{Users-CbI4K_Le.js → Users-CNRVFf3-.js} +5 -5
- package/dist/{appIcons-CCArfCDe.js → appIcons-DfjKL0tw.js} +1 -1
- package/dist/{appIcons-C90OKlV5.cjs → appIcons-Xjk-LuQ5.cjs} +1 -1
- package/dist/{arrivalRoads-Cc6AZM-d.cjs → arrivalRoads-1OeHArA0.cjs} +0 -0
- package/dist/{arrivalRoads-CGXm9Ntm.js → arrivalRoads-BZ4SWRAw.js} +0 -0
- package/dist/components/TutorialVideo.d.ts +3 -1
- package/dist/index.d.ts +1 -0
- package/dist/{paidSessions-D-zHC4oG.cjs → paidSessions-BK9qlIyL.cjs} +1 -1
- package/dist/{paidSessions-B8e5RHi4.js → paidSessions-C9392hZH.js} +2 -2
- package/dist/{recordsKey-C4E2vOti.cjs → recordsKey-B3lWGd8C.cjs} +1 -1
- package/dist/{recordsKey-Cd216nq1.js → recordsKey-CJL-dAYF.js} +1 -1
- package/dist/{roles-BBDIJzox.cjs → roles-BmnoAilb.cjs} +1 -1
- package/dist/{roles-DiwP6-WQ.js → roles-D3T8p-hA.js} +2 -2
- package/dist/server.cjs.js +1 -1
- package/dist/server.es.js +1 -1
- package/dist/vite.cjs.js +1 -1
- package/dist/vite.es.js +1 -1
- package/dist/your-ai-workflow-firebase-os.cjs.js +13 -13
- package/dist/your-ai-workflow-firebase-os.es.js +2184 -2189
- package/package.json +1 -1
- package/scripts/postinstall.js +2 -1
- package/src/pages/Home.tsx +11 -14
- package/dist/PagesAdmin-KUxCI1Mr.cjs +0 -1
- package/dist/SupportBar-DLWruzQb.cjs +0 -1
- package/dist/ThemeAdmin-CoE_c5-P.cjs +0 -1
- package/dist/ThemeAdmin-DI7QaZ-0.js +0 -2
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { t as e } from "./forms-C2IxnO9p.js";
|
|
2
|
-
import { t } from "./PageTitle-
|
|
2
|
+
import { t } from "./PageTitle-CkZriz8K.js";
|
|
3
3
|
import { Ft as n, Mt as r, S as i, b as a, c as o, g as s, i as c, jt as ee, m as l, mi as u, nt as d, o as f, rt as p, ui as m, w as te } from "./TimeZoneField-oIMwb5_X.js";
|
|
4
|
-
import { S as ne, T as re, t as ie } from "./DashboardNav-
|
|
4
|
+
import { S as ne, T as re, t as ie } from "./DashboardNav-CxS3Qnl-.js";
|
|
5
5
|
import { $t as ae, Mt as oe, Vt as se, a as ce, an as le, en as h, r as ue } from "./schedule-C13m_kiO.js";
|
|
6
6
|
import { n as g, t as _ } from "./chevron-down--LwXEv9w.js";
|
|
7
7
|
import { y as de } from "./scheduleData-DR6A-Q7Z.js";
|
|
8
8
|
import { t as fe } from "./ContactPopup-Fs7wzrOX.js";
|
|
9
|
-
import { t as pe } from "./SupportBar-
|
|
9
|
+
import { t as pe } from "./SupportBar-0nIiQp-_.js";
|
|
10
10
|
import { t as v } from "./eye-DBR-sZWU.js";
|
|
11
11
|
import { n as me } from "./VideoPlayer-QI1Jc3bS.js";
|
|
12
12
|
import { r as y, t as b } from "./x-hax8aKt8.js";
|
|
@@ -16,7 +16,7 @@ import { t as ge } from "./trash-6Wj66gJi.js";
|
|
|
16
16
|
import { t as _e } from "./ConfirmModal-BW9e6Y7d.js";
|
|
17
17
|
import { i as ve } from "./AccessNotice-DGsp8Xfl.js";
|
|
18
18
|
import { n as ye } from "./useIsPhone-gAClfVGG.js";
|
|
19
|
-
import { n as be, t as xe } from "./SchedulePicker-
|
|
19
|
+
import { n as be, t as xe } from "./SchedulePicker-sZIZec9L.js";
|
|
20
20
|
import { useEffect as Se, useRef as Ce, useState as S } from "react";
|
|
21
21
|
import { Fragment as we, jsx as C, jsxs as w } from "react/jsx-runtime";
|
|
22
22
|
import { collection as Te, deleteDoc as T, doc as E, getDocs as Ee, setDoc as D } from "firebase/firestore";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
require(`./chunk-CiTBaPhY.cjs`);const e=require(`./PageTitle-
|
|
1
|
+
require(`./chunk-CiTBaPhY.cjs`);const e=require(`./PageTitle-BL50s4qY.cjs`),t=require(`./TimeZoneField-Ckn1pKAL.cjs`),n=require(`./DashboardNav-Bc619nqn.cjs`),r=require(`./schedule-BAea6q8_.cjs`),i=require(`./chevron-down-lyDK1rfL.cjs`),a=require(`./arrow-left-C39sNUA7.cjs`),o=require(`./FileViewerPopup-CkLUYCNo.cjs`),s=require(`./FormNote-DP0GK9ya.cjs`),c=require(`./x-Ci8c5p6T.cjs`),l=require(`./trash-D-CpYHCs.cjs`),u=require(`./user-round-DUV_u2Tg.cjs`),d=require(`./Loader-QHqQsXLr.cjs`),f=require(`./address-D88ICQCR.cjs`),p=require(`./transactions-CIU2NcKh.cjs`),m=require(`./tabAudience-2fJAN1aD.cjs`),ee=require(`./ConfirmModal-BUNtss4a.cjs`),h=require(`./SystemTabContent-BWhRHoXx.cjs`),te=require(`./useIsPhone-CoiQVcCo.cjs`),g=require(`./contentKey-BwicZ0gK.cjs`),_=require(`./Attachments-BMuQ0CD4.cjs`);let v=require(`react`),y=require(`react/jsx-runtime`),b=require(`firebase/firestore`),ne=require(`react-router-dom`);var x={name:`arrow-down-to-line`,size:24,node:[[`path`,{d:`M12 17V3`,key:`1cwfxf`}],[`path`,{d:`m6 11 6 6 6-6`,key:`12ii2o`}],[`path`,{d:`M19 21H5`,key:`150jfl`}]]};x.node;var S=i.n(x),C={name:`arrow-up-from-line`,size:24,node:[[`path`,{d:`m18 9-6-6-6 6`,key:`kcunyi`}],[`path`,{d:`M12 3v14`,key:`7cf3v8`}],[`path`,{d:`M5 21h14`,key:`11awu3`}]]};C.node;var w=i.n(C),T={name:`reply`,size:24,node:[[`path`,{d:`M20 18v-2a4 4 0 0 0-4-4H4`,key:`5vmcpk`}],[`path`,{d:`m9 17-5-5 5-5`,key:`nvlc11`}]]};T.node;var re=i.n(T),E={anyone:{collectionName:`user_submissions`,chip:`Anyone`,said:`Not signed in`,filterLabel:`From anyone`},signedIn:{collectionName:`user_requests`,chip:`Signed-in user`,said:`Signed-in user`,filterLabel:`From signed-in users`}},D=[`id`,`source`,`uid`,`submittedAt`,`avatarUrl`,`isArchived`,`name`,`full_name`,`email`,`contactEmail`,`topic`],O=e=>e==null?``:typeof e==`boolean`?e?`Yes`:`No`:Array.isArray(e)?e.map(O).filter(Boolean).join(`
|
|
2
2
|
`):typeof e==`object`?typeof e.toDate==`function`?j(e):Object.entries(e).filter(([e])=>!p.i(e)).map(([e,t])=>`${e}: ${O(t)}`).join(` · `):String(e),k=`That message is gone.`,A=e=>{let t=e.submittedAt;if(!t)return 0;if(typeof t.toMillis==`function`)return t.toMillis();if(typeof t.toDate==`function`)return t.toDate().getTime();let n=new Date(t).getTime();return Number.isNaN(n)?0:n},j=e=>{if(!e)return`Just now`;let t=e.toDate?e.toDate():new Date(e);return new Intl.DateTimeFormat(`en-US`,{month:`short`,day:`numeric`,hour:`numeric`,minute:`numeric`}).format(t)},M=e=>{if(!e)return`now`;let t=e.toDate?e.toDate():new Date(e),n=new Date;return t.toDateString()===n.toDateString()?new Intl.DateTimeFormat(`en-US`,{hour:`numeric`,minute:`numeric`}).format(t):new Intl.DateTimeFormat(`en-US`,t.getFullYear()===n.getFullYear()?{month:`short`,day:`numeric`}:{month:`short`,year:`numeric`}).format(t)},ie=e=>{let t=new Date(e);return new Date(t.getFullYear(),t.getMonth(),t.getDate()).getTime()},N=e=>{let t=A(e);if(!t)return`Older`;let n=Math.round((ie(Date.now())-ie(t))/864e5);return n<=0?`Today`:n===1?`Yesterday`:n<7?`This week`:n<30?`This month`:`Older`},ae=e=>e.reduce((e,t)=>{let n=N(t),r=e[e.length-1];return r&&r.label===n?r.items.push(t):e.push({label:n,items:[t]}),e},[]),oe=e=>e.submitterName||e.name||e.full_name||`Anonymous`,P=e=>e.contactEmail||e.email||``,F=e=>`${e.source}:${e.id}`,se=e=>{let t=e.indexOf(`:`),n=t>0?e.slice(0,t):``;return n===`anyone`||n===`signedIn`?{source:n,id:e.slice(t+1)}:{source:null,id:e}},ce=(e,t)=>se(t).source?F(e)===t:e.id===t,le=e=>{let t=Object.entries(e).filter(([t])=>!D.includes(t)&&!t.toLowerCase().startsWith(`submitter`)&&t.toLowerCase()!==`formid`&&!f.l(t,e));return e.topic?[[`topic`,e.topic],...t]:t},I=e=>e.replace(/_/g,` `).replace(/\b\w/g,e=>e.toUpperCase()),ue=e=>{let n=le(e).filter(([e])=>e!==`topic`),r=n.find(([,e])=>!t.I(e)&&O(e).trim()),i=n.filter(([,e])=>t.I(e)).reduce((e,[,n])=>e+t.P(n).length,0),a=(r?O(r[1]):i>0?`${i} ${i===1?`file`:`files`} attached`:P(e)).replace(/\s*\n+\s*/g,` · `).replace(/\s+/g,` `).trim();return[e.topic?String(e.topic).trim():``,a].filter(Boolean).join(` — `).slice(0,200)},L=e=>e.replace(/_/g,` `).replace(/^\w/,e=>e.toUpperCase()),R=(e,t)=>{let n={};for(let[r,i]of t)n[r]={...i?.config||{},...e[r]||{}};for(let[t,r]of Object.entries(e)){let i=String(r?.fileId||``);i&&i!==t&&!e[i]?(n[t]={...n[i]||{},...r},delete n[i]):n[t]||(n[t]=r)}return Object.entries(n)};function z(t,r={},i=n.x()){let a=g.n(t);if(!a)return{name:`Contact`,Icon:e.h};let o=typeof window<`u`&&window.__FBOS_FORMS__||{},s=o[a]||o[String(t)],c=null;for(let[e,t]of R(r,i)){let n=new Set([e,t?.contentKey,t?.pageId,t?.tabName,t?.pageName,t?.title].map(g.n).filter(e=>e.length>=3));for(let e of n)(a===e||a.startsWith(e))&&(!c||e.length>c.key.length)&&(c={key:e,page:t})}let l=c?.page;return{name:String(l?.tabName||l?.pageName||l?.title||s?.title||``).trim()||L(a),Icon:e.p(l?.iconName)||e.h}}var de=()=>{try{let e=localStorage.getItem(`fbos_nav_tabs`),t=e?JSON.parse(e):null;return t&&typeof t==`object`?t:{}}catch{return{}}};function B(){let[e,n]=(0,v.useState)(de);return(0,v.useEffect)(()=>t.Zr(`sys_tabs`,()=>(0,b.collection)(t.ui,`sys_tabs`),e=>{let t={};for(let n of e.docs||[])t[n.id]=n.data();n(t)},()=>{}),[]),(0,v.useCallback)(t=>z(t,e),[e])}var V=`fbos_inbox_seen_at`,H=`fbos_inbox_opened`,fe=500,pe=()=>{try{let e=Number(localStorage.getItem(V));if(e>0||localStorage.getItem(V)===`0`)return e;let t=Date.now();return localStorage.setItem(V,String(t)),t}catch{return Date.now()}},me=()=>{try{let e=JSON.parse(localStorage.getItem(H)||`[]`);return new Set(Array.isArray(e)?e.map(String):[])}catch{return new Set}};function he(){let[e,t]=(0,v.useState)(me);return[e,(0,v.useCallback)(e=>{t(t=>{if(t.has(e))return t;let n=new Set(t);n.add(e);try{localStorage.setItem(H,JSON.stringify([...n].slice(-fe)))}catch{}return n})},[])]}var U=new Map,W=e=>{let n=U.get(e);return n||(n=(0,b.getDoc)((0,b.doc)(t.ui,`user_profiles`,e)).then(e=>e.exists()?e.data():null).catch(t=>(console.error(`Failed to fetch profile`,t),U.delete(e),null)),U.set(e,n)),n},G=e=>!(e.formId===`booking`||r.nt(e)||p.a(e)),K=(e,t,n)=>Promise.all(e.filter(e=>G(e.data())).map(async e=>{let r={...e.data()},i=``;if(n&&r.uid&&r.uid!==`guest`){let e=await W(r.uid);e&&((e.avatar||e.photoURL)&&(i=e.avatar||e.photoURL),r.name||=e.name||e.displayName,r.email||=e.email,r.contactEmail||=e.email)}return{...r,id:e.id,source:t,avatarUrl:i}}));function ge(e,n,r){let[i,a]=(0,v.useState)([]),[o,s]=(0,v.useState)(!0),[c,l]=(0,v.useState)(null),[u,d]=(0,v.useState)({answeredFor:0,more:!1,reachedBack:0,lastStamp:null});return(0,v.useEffect)(()=>{let i=!1,o=0,c=E[e].collectionName,u=(0,b.onSnapshot)((0,b.query)((0,b.collection)(t.ui,c),(0,b.orderBy)(`submittedAt`,`desc`),(0,b.limit)(r)),async t=>{let c=++o,u=await K(t.docs,e,n);if(i||c!==o)return;let f=t.docs.length>=r,p=f?t.docs[t.docs.length-1].data():null;a(u),d({answeredFor:r,more:f,reachedBack:p?A(p):0,lastStamp:p?.submittedAt??null}),l(null),s(!1)},e=>{console.error(`Error loading ${c}:`,e),i||(l(e),d({answeredFor:r,more:!1,reachedBack:0,lastStamp:null}),s(!1))});return()=>{i=!0,u()}},[e,n,r]),{items:i,loading:o,refused:c,...u,waiting:u.answeredFor!==r}}function q(e,n,r,i){let[a,o]=(0,v.useState)({items:[],answered:!1,failed:null});return(0,v.useEffect)(()=>{if(r==null||i==null){o(e=>e.answered||e.items.length?{items:[],answered:!1,failed:null}:e);return}let a=!1,s=0,c=E[e].collectionName,l=(0,b.onSnapshot)((0,b.query)((0,b.collection)(t.ui,c),(0,b.orderBy)(`submittedAt`,`desc`),(0,b.startAt)(r),(0,b.endAt)(i)),async t=>{let r=++s,i=await K(t.docs,e,n);!a&&r===s&&o({items:i,answered:!0,failed:null})},e=>{console.error(`Error reading further back in ${c}:`,e),a||o({items:[],answered:!0,failed:e})});return()=>{a=!0,l()}},[e,n,r,i]),a}var _e=[.16,1,.3,1];function J({on:e,onClick:t,label:n,short:r,count:i}){return(0,y.jsxs)(`button`,{type:`button`,onClick:t,"aria-pressed":e,"aria-label":n,className:`h-7 px-2.5 inline-flex items-center gap-1.5 rounded-full text-[12.5px] font-medium border whitespace-nowrap transition-colors cursor-pointer active:scale-[0.98] ${e?`bg-accent/10 border-accent/30 text-accent`:`border-[var(--panel-border)] text-foreground/60 hover:text-foreground hover:bg-foreground/[0.03]`}`,children:[r?(0,y.jsxs)(y.Fragment,{children:[(0,y.jsx)(`span`,{className:`sm:hidden`,children:r}),(0,y.jsx)(`span`,{className:`max-sm:hidden`,children:n})]}):n,i?(0,y.jsx)(`span`,{className:`tabular-nums text-[11.5px] opacity-70`,children:i}):null]})}var Y=`w-8 h-8 inline-flex items-center justify-center rounded-lg text-foreground/50 hover:text-foreground hover:bg-foreground/[0.06] transition-colors cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-accent/50`;function ve({item:e,look:t,selected:n,unread:r,onSelect:i,onArchive:a,onDelete:o}){let s=oe(e),c=t.Icon,u=!!(a||o);return(0,y.jsxs)(`div`,{className:`group relative px-2 md:px-3`,children:[(0,y.jsxs)(`button`,{type:`button`,onClick:i,"aria-current":n?`true`:void 0,"aria-label":`Show details from ${s}`,"data-unread":r?`true`:void 0,className:`w-full flex items-center gap-3 px-3 py-2.5 rounded-xl text-left transition-colors cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-accent/40 ${n?`bg-accent/[0.1]`:r?`bg-accent/[0.05] hover:bg-accent/[0.08]`:`hover:bg-foreground/[0.03]`}`,children:[(0,y.jsx)(`span`,{"aria-hidden":`true`,className:`w-1.5 h-1.5 rounded-full shrink-0 ${r?`bg-accent`:`bg-transparent`}`}),(0,y.jsx)(c,{"aria-hidden":`true`,className:`w-4 h-4 shrink-0 ${n?`text-accent`:`text-foreground/45`}`}),(0,y.jsx)(`span`,{className:`shrink-0 max-w-[42%] truncate text-[13.5px] ${r?`font-semibold text-foreground`:`font-medium text-foreground/85`}`,children:s}),(0,y.jsx)(`span`,{className:`flex-1 min-w-0 truncate text-[13px] ${r?`text-foreground/65`:`text-foreground/50`}`,children:ue(e)}),(0,y.jsx)(`span`,{className:`shrink-0 text-[11.5px] tabular-nums text-foreground/40 transition-opacity ${u?`group-hover:opacity-0`:``}`,children:M(e.submittedAt)})]}),u&&(0,y.jsxs)(`div`,{className:`absolute right-4 md:right-5 top-1/2 -translate-y-1/2 flex items-center gap-0.5 rounded-lg bg-background/90 backdrop-blur-sm opacity-0 group-hover:opacity-100 focus-within:opacity-100 transition-opacity`,children:[a&&(0,y.jsx)(`button`,{type:`button`,onClick:a,"aria-label":e.isArchived?`Restore`:`Archive`,title:e.isArchived?`Restore`:`Archive`,className:Y,children:e.isArchived?(0,y.jsx)(w,{className:`w-4 h-4`}):(0,y.jsx)(S,{className:`w-4 h-4`})}),o&&(0,y.jsx)(`button`,{type:`button`,onClick:o,"aria-label":`Delete`,title:`Delete`,className:Y,children:(0,y.jsx)(l.t,{className:`w-4 h-4`})})]})]})}function ye({item:e,look:n,canOpenProfile:r,actions:i,onOpenFile:a}){let o=oe(e),s=P(e),c=le(e),l=!!e.uid&&e.uid!==`guest`;return(0,y.jsxs)(`article`,{"aria-label":`Message from ${o}`,className:`px-5 py-6 sm:px-8 sm:py-8 lg:px-10 flex flex-col gap-6 max-w-3xl`,children:[(0,y.jsxs)(`header`,{className:`flex flex-col gap-4`,children:[(0,y.jsxs)(`div`,{className:`flex items-start justify-between gap-4`,children:[(0,y.jsxs)(`div`,{className:`min-w-0 flex flex-col gap-1`,children:[(0,y.jsx)(`p`,{className:`text-[12.5px] font-medium text-foreground/50`,children:n.name}),(0,y.jsx)(`h2`,{className:`text-[22px] sm:text-2xl font-semibold tracking-tight text-foreground leading-tight [overflow-wrap:anywhere]`,children:o}),(0,y.jsx)(`p`,{className:`text-[13px] text-foreground/60 flex flex-wrap items-center gap-x-2 gap-y-0.5`,children:[s?(0,y.jsx)(`span`,{className:`[overflow-wrap:anywhere]`,children:s},`email`):null,(0,y.jsx)(`span`,{children:E[e.source].said},`who`),(0,y.jsx)(`span`,{className:`tabular-nums`,children:j(e.submittedAt)},`when`)].filter(Boolean).map((e,t)=>(0,y.jsxs)(`span`,{className:`inline-flex items-center gap-x-2`,children:[t>0&&(0,y.jsx)(`span`,{"aria-hidden":`true`,className:`text-foreground/30`,children:`·`}),e]},e.key))})]}),i&&(0,y.jsx)(`div`,{className:`flex items-center gap-1.5 shrink-0`,children:i})]}),l&&r&&(0,y.jsxs)(ne.Link,{to:`/users/${e.uid}`,className:`self-start inline-flex items-center gap-1.5 text-[13px] font-medium text-accent hover:underline`,children:[(0,y.jsx)(u.t,{className:`w-3.5 h-3.5`,"aria-hidden":`true`}),`Open this person’s profile`]})]}),c.length>0?(0,y.jsx)(`dl`,{className:`border-t border-[var(--panel-border)]/70 divide-y divide-[var(--panel-border)]/50`,children:c.map(([e,n])=>(0,y.jsxs)(`div`,{className:`py-3.5 sm:grid sm:grid-cols-[minmax(7rem,11rem)_minmax(0,1fr)] sm:gap-6`,children:[(0,y.jsx)(`dt`,{className:`text-[13px] text-foreground/60 mb-1 sm:mb-0 sm:pt-px`,children:I(e)}),(0,y.jsx)(`dd`,{className:`min-w-0`,children:t.I(n)?(0,y.jsx)(_.t,{value:n,onOpen:a}):(0,y.jsx)(`p`,{className:`text-[14.5px] text-foreground leading-relaxed whitespace-pre-wrap break-words [overflow-wrap:anywhere]`,children:O(n)||`No data provided`})})]},e))}):(0,y.jsx)(`p`,{className:`border-t border-[var(--panel-border)]/70 pt-4 text-[13.5px] text-foreground/50`,children:`This form only asked for a name and email.`})]})}function be({items:r,loading:i,refused:u,onArchive:f,onDelete:p,opensUsers:m,formLook:g,initialOpen:_=null,more:b=!1,loadingMore:x=!1,onShowMore:C,onFind:T,found:D=null}){let k=te.n(),j=t.tt(),[M,ie]=(0,v.useState)(`all`),[N,se]=(0,v.useState)(`all`),[I,ue]=(0,v.useState)(!1),[L,R]=(0,v.useState)(!1),[z,de]=(0,v.useState)(``),B=(0,v.useDeferredValue)(z.trim().toLowerCase()),[V,H]=(0,v.useState)(_),[fe,me]=(0,v.useState)(null),[U,W]=(0,v.useState)(``),[G,K]=(0,v.useState)(null),[ge,q]=(0,v.useState)(!1),[Y,be]=(0,v.useState)(null),[X,xe]=(0,v.useState)(``),[Se]=(0,v.useState)(pe),[Ce,we]=he(),Te=(0,v.useCallback)(e=>A(e)>Se&&!Ce.has(F(e)),[Se,Ce]),Ee=(0,v.useCallback)(e=>{let t=F(e);H(t),W(``),xe(``),we(t)},[we]),[De,Oe]=(0,ne.useSearchParams)(),Z=De.get(`open`);(0,v.useEffect)(()=>{if(!Z||i)return;let e=r.find(e=>ce(e,Z));if(e){e.isArchived&&R(!0),Ee(e),Oe({},{replace:!0});return}if(T){if(D?.key!==Z){T(Z);return}D.gone&&(H(null),xe(D.words||`That message is gone.`),Oe({},{replace:!0}))}},[Z,i,r,D]),(0,v.useEffect)(()=>{_&&r.find(e=>F(e)===_)?.isArchived&&R(!0)},[_]);let ke=k&&!!V;(0,v.useEffect)(()=>{if(!ke||typeof document>`u`)return;let e=document.body.style.overflow;return document.body.style.overflow=`hidden`,()=>{document.body.style.overflow=e}},[ke]);let Ae=(0,v.useMemo)(()=>{let e=new Map;for(let t of r){let n=String(t.formId||``);e.has(n)||e.set(n,g(t.formId))}return e},[r,g]),je=[...Ae.entries()],Q=(0,v.useCallback)(e=>Ae.get(String(e.formId||``))||g(e.formId),[Ae,g]),Me=r.filter(e=>e.isArchived).length,Ne=r.filter(e=>!e.isArchived&&Te(e)).length,Pe=(0,v.useMemo)(()=>r.filter(e=>!(!!e.isArchived!==L||M!==`all`&&e.source!==M||N!==`all`&&String(e.formId||``)!==N||I&&!Te(e)||B&&![oe(e),P(e),Q(e).name,...le(e).map(([,e])=>t.I(e)?t.P(e).map(t.N).join(` `):O(e))].join(`
|
|
3
3
|
`).toLowerCase().includes(B))),[r,L,M,N,I,B,Te,Q]),$=V&&r.find(e=>F(e)===V)||null,Fe=async e=>{if(!f)return;let n=F(e);me(n),W(``);try{await f(e),we(n),V===n&&H(null)}catch(e){W(t.ii(e,`The message could not be moved.`))}me(null)},Ie=async()=>{if(!(!G||!p)){q(!0),W(``);try{await p(G),V===F(G)&&H(null),K(null)}catch(e){W(t.ii(e,`The message could not be deleted.`)),K(null)}q(!1)}},Le=[{key:`all`,label:`Everything`,short:`All`},{key:`anyone`,label:E.anyone.filterLabel,short:`Anyone`},{key:`signedIn`,label:E.signedIn.filterLabel,short:`Signed in`}],Re=(e,n=!1)=>{let r=P(e);return r?(0,y.jsxs)(`a`,{href:`mailto:${r}`,title:`Reply by email`,"aria-label":`Reply by email`,className:`${t.a} ${n?`max-sm:w-8 max-sm:px-0 max-sm:gap-0 max-sm:border-transparent max-sm:hover:border-transparent max-sm:hover:bg-foreground/[0.06]`:``}`,children:[(0,y.jsx)(re,{className:`w-3.5 h-3.5 shrink-0`,"aria-hidden":`true`}),n?(0,y.jsx)(`span`,{className:`max-sm:hidden`,children:`Reply`}):`Reply`]}):null},ze=(e,n=!1)=>(0,y.jsxs)(y.Fragment,{children:[Re(e,n),f&&(0,y.jsx)(t.o,{icon:e.isArchived?w:S,onClick:()=>Fe(e),busy:fe===F(e),compact:n,title:e.isArchived?`Restore`:`Archive`,children:e.isArchived?`Restore`:`Archive`}),p&&(0,y.jsx)(t.o,{icon:l.t,tone:`danger`,onClick:()=>K(e),compact:n,title:`Delete`,children:`Delete`})]}),Be=b&&C?(0,y.jsx)(`div`,{className:`flex justify-center px-5 pb-5`,children:(0,y.jsx)(t.o,{busy:x,onClick:C,children:`Show older messages`})}):null,Ve=Pe.length===0?(0,y.jsx)(`p`,{className:`px-6 py-14 text-center text-[13.5px] text-foreground/50`,children:L?`Nothing archived matches.`:Me>0&&r.length===Me?`Everything here is archived.`:`Nothing matches.`}):(0,y.jsx)(t.E,{className:`flex flex-col pb-3`,children:ae(Pe).flatMap(e=>[(0,y.jsx)(`p`,{className:`px-5 md:px-6 pt-4 pb-1.5 text-[11.5px] font-medium uppercase tracking-[0.14em] text-foreground/40 select-none`,children:e.label},`h:${e.label}`),...e.items.map(e=>(0,y.jsx)(ve,{item:e,look:Q(e),selected:V===F(e),unread:Te(e),onSelect:()=>Ee(e),onArchive:!k&&f?()=>Fe(e):void 0,onDelete:!k&&p?()=>K(e):void 0},F(e)))])}),He=(0,y.jsxs)(`div`,{className:`p-4 md:p-5 flex flex-col gap-3 border-b border-[var(--panel-border)]/60`,children:[(0,y.jsxs)(`div`,{className:t.l,children:[(0,y.jsx)(c.n,{className:`w-4 h-4 mr-2.5 text-foreground/30 shrink-0`,"aria-hidden":`true`}),(0,y.jsx)(`input`,{type:`text`,value:z,onChange:e=>de(e.target.value),placeholder:`Search messages`,"aria-label":`Search messages`,className:`${t.f} no-glow`}),z&&(0,y.jsx)(`button`,{type:`button`,onClick:()=>de(``),"aria-label":`Clear search`,className:`ml-2 -mr-1 w-7 h-7 inline-flex items-center justify-center rounded-lg text-foreground/40 hover:text-foreground hover:bg-foreground/[0.06] transition-colors cursor-pointer`,children:(0,y.jsx)(c.t,{className:`w-3.5 h-3.5`})})]}),(0,y.jsxs)(`div`,{className:`flex flex-wrap items-center gap-1.5`,children:[Le.map(e=>(0,y.jsx)(J,{on:M===e.key,onClick:()=>ie(e.key),label:e.label,short:e.short},e.key)),(0,y.jsx)(`span`,{"aria-hidden":`true`,className:`w-px h-3.5 mx-0.5 bg-[var(--panel-border)]`}),(0,y.jsx)(J,{on:I,onClick:()=>ue(e=>!e),label:`Unread`,count:Ne}),je.length>1&&(0,y.jsxs)(y.Fragment,{children:[(0,y.jsx)(`span`,{"aria-hidden":`true`,className:`w-px h-3.5 mx-0.5 bg-[var(--panel-border)]`}),je.map(([e,t])=>(0,y.jsx)(J,{on:N===e,onClick:()=>se(t=>t===e?`all`:e),label:t.name},e||`_`))]}),Me>0&&(0,y.jsxs)(y.Fragment,{children:[(0,y.jsx)(`span`,{"aria-hidden":`true`,className:`w-px h-3.5 mx-0.5 bg-[var(--panel-border)]`}),(0,y.jsx)(J,{on:L,onClick:()=>R(e=>!e),label:`Archived`,count:Me})]})]})]}),Ue=i?(0,y.jsx)(`div`,{className:`flex-1 min-h-0 md:grid md:grid-cols-[minmax(340px,430px)_minmax(0,1fr)]`,children:(0,y.jsxs)(`div`,{className:`p-4 md:p-5 flex flex-col gap-3 md:border-r md:border-[var(--panel-border)]/70`,"aria-busy":`true`,children:[(0,y.jsx)(d.n,{className:`h-10 rounded-xl`}),(0,y.jsxs)(`div`,{className:`flex gap-1.5`,children:[(0,y.jsx)(d.n,{className:`h-8 w-24 rounded-full`}),(0,y.jsx)(d.n,{className:`h-8 w-28 rounded-full`}),(0,y.jsx)(d.n,{className:`h-8 w-20 rounded-full`})]}),(0,y.jsx)(`div`,{className:`flex flex-col gap-1.5 pt-2`,children:[0,1,2,3,4,5].map(e=>(0,y.jsx)(d.n,{className:`h-10 rounded-xl`,style:{opacity:1-e*.12}},e))})]})}):u&&r.length===0?(0,y.jsx)(`div`,{className:`flex-1 flex items-center justify-center p-8`,children:(0,y.jsx)(s.t,{tone:`error`,children:t.ii(u,`The messages could not be read.`)})}):r.length===0&&!b?(0,y.jsxs)(`div`,{className:`flex-1 flex flex-col items-center justify-center text-center gap-1 px-8 py-20`,children:[(0,y.jsx)(`p`,{className:`text-[14px] font-medium text-foreground/70`,children:`Nothing here yet`}),(0,y.jsx)(`p`,{className:`text-[13px] text-foreground/45`,children:`Everything people send you through a form on your site lands here.`})]}):k?(0,y.jsxs)(`div`,{className:`flex flex-col`,children:[He,X&&(0,y.jsx)(`p`,{className:`px-5 md:px-6 pt-4 text-[13.5px] text-foreground/60`,children:X}),Ve,Be]}):(0,y.jsxs)(`div`,{className:`flex-1 min-h-0 grid grid-cols-[minmax(340px,430px)_minmax(0,1fr)]`,children:[(0,y.jsxs)(`div`,{className:`flex flex-col min-h-0 border-r border-[var(--panel-border)]/70`,children:[He,(0,y.jsxs)(`div`,{className:`flex-1 min-h-0 overflow-y-auto`,children:[Ve,Be]})]}),(0,y.jsx)(`div`,{className:`min-h-0 overflow-y-auto`,children:(0,y.jsx)(t.nt.div,{initial:j?!1:{opacity:0,y:8},animate:{opacity:1,y:0},transition:{duration:.25,ease:_e},className:`min-h-full flex flex-col`,children:$?(0,y.jsxs)(y.Fragment,{children:[U&&(0,y.jsx)(`div`,{className:`px-8 pt-6 lg:px-10`,children:(0,y.jsx)(s.t,{tone:`error`,children:U})}),(0,y.jsx)(ye,{item:$,look:Q($),canOpenProfile:m,actions:ze($),onOpenFile:be})]}):(0,y.jsx)(`div`,{className:`flex-1 flex items-center justify-center p-8`,children:(0,y.jsx)(`p`,{className:`text-[13.5px] ${X?`text-foreground/60`:`text-foreground/40`}`,children:X||`Select a message to read it.`})})},$?F($):`none`)})]});return(0,y.jsxs)(`main`,{className:`flex-1 w-full max-w-7xl mx-auto p-4 pt-2 md:p-8 md:pt-4 z-10 flex flex-col min-h-screen`,children:[(0,y.jsxs)(t.nt.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:`mb-6`,children:[(0,y.jsx)(e.t,{children:`Inbox`}),(0,y.jsxs)(`div`,{className:`flex items-center gap-2 text-foreground/40 font-bold uppercase tracking-[0.2em] text-[11px]`,children:[(0,y.jsx)(`span`,{className:`w-8 h-[1px] bg-foreground/10`}),`/inbox`]})]}),(0,y.jsxs)(`div`,{className:`flex flex-col gap-6 flex-1 pb-16`,children:[(0,y.jsx)(`div`,{className:`flex justify-start`,children:(0,y.jsx)(n.t,{})}),(0,y.jsx)(h.n,{tab:`inbox`}),(0,y.jsx)(t.T,{as:`section`,className:`glass-panel border border-[var(--panel-border)] rounded-2xl md:rounded-3xl shadow-2xl bg-[var(--panel-bg)] overflow-hidden flex flex-col fbos-tab-fill min-h-[420px] md:h-[clamp(560px,calc(100dvh-14rem),960px)]`,children:Ue})]}),(0,y.jsx)(t.rt,{children:ke&&$&&(0,y.jsxs)(t.nt.div,{role:`dialog`,"aria-label":`Message from ${oe($)}`,initial:j?{opacity:0}:{x:`100%`},animate:j?{opacity:1}:{x:0},exit:j?{opacity:0}:{x:`100%`},transition:{duration:.28,ease:_e},className:`fixed inset-0 z-[70] bg-background overflow-y-auto`,children:[(0,y.jsxs)(`div`,{className:`sticky top-0 z-10 flex items-center justify-between gap-2 px-3 h-14 bg-background/85 backdrop-blur-xl border-b border-[var(--panel-border)]/60`,children:[(0,y.jsxs)(`button`,{type:`button`,onClick:()=>H(null),"aria-label":`Back to the list`,className:`inline-flex items-center gap-1.5 h-9 pl-2 pr-3 rounded-xl text-[13px] font-medium text-foreground/70 hover:text-foreground hover:bg-foreground/[0.05] transition-colors cursor-pointer`,children:[(0,y.jsx)(a.t,{className:`w-4 h-4`,"aria-hidden":`true`}),`Inbox`]}),(0,y.jsx)(`div`,{className:`flex items-center gap-1`,children:ze($,!0)})]}),U&&(0,y.jsx)(`div`,{className:`px-5 pt-4`,children:(0,y.jsx)(s.t,{tone:`error`,children:U})}),(0,y.jsx)(ye,{item:$,look:Q($),canOpenProfile:m,onOpenFile:be})]},`phone-sheet`)}),(0,y.jsx)(ee.t,{isOpen:!!G,title:`Delete this message?`,message:`This removes it for good. There is no undo — archive it instead if you only want it out of the way.`,onConfirm:Ie,onCancel:()=>K(null),isProcessing:ge,confirmText:`Yes, delete`}),(0,y.jsx)(o.t,{open:!!Y,onClose:()=>be(null),src:Y?.src||``,name:Y?.name})]})}function X(){let{userRole:e}=t.Ft(),{access:i}=n.a(),a=r.wn(e),o=m.i(e,m.o(i,`users`)),s=a||r.Sn(e)||o,[c,l]=(0,v.useState)(100),u=ge(`anyone`,s,c),d=ge(`signedIn`,s,c),f=B(),p=u.loading||d.loading,ee=u.refused||d.refused,[h,te]=(0,v.useState)(null),g=(0,v.useRef)({anyone:u,signedIn:d});(0,v.useEffect)(()=>{g.current={anyone:u,signedIn:d}});let _=(0,v.useRef)(``),ne=(0,v.useCallback)(async e=>{_.current=e,te({key:e,gone:!1});let n=se(e),r=t=>{_.current===e&&te(t)},i=null;for(let a of n.source?[n.source]:[`anyone`,`signedIn`]){let o;try{o=await(0,b.getDoc)((0,b.doc)(t.ui,E[a].collectionName,n.id))}catch(e){i=e;continue}if(!o.exists())continue;let s=o.data()||{};if(!G(s)||!A(s))return r({key:e,gone:!0,words:`That message is not in your Inbox.`});let c=A(s),l={};for(let e of[`anyone`,`signedIn`]){let t=g.current[e];t.more&&t.reachedBack>=c&&t.lastStamp!=null&&(l[e]=t.lastStamp)}return r({key:e,gone:!1,to:s.submittedAt,toMs:c,from:l})}r(i?{key:e,gone:!0,words:t.ii(i,`That message could not be opened.`)}:{key:e,gone:!0,words:k})},[]),x=q(`anyone`,s,h?.from?.anyone??null,h?.to??null),S=q(`signedIn`,s,h?.from?.signedIn??null,h?.to??null),C=(e,t)=>e.more?t.answered&&h?.toMs?Math.min(e.reachedBack,h.toMs):e.reachedBack:0,w=Math.max(C(u,x),C(d,S)),T=(0,v.useMemo)(()=>{let e=new Set;return[...u.items,...d.items,...x.items,...S.items].filter(t=>{let n=F(t);return e.has(n)?!1:(e.add(n),!0)}).filter(e=>A(e)>=w).sort((e,t)=>A(t)-A(e))},[u.items,d.items,x.items,S.items,w]),re=(0,v.useCallback)(()=>l(e=>e+100),[]),D=(0,v.useMemo)(()=>{if(!h)return null;if(h.gone)return{key:h.key,gone:!0,words:h.words};let e=h.from?.anyone!=null&&x.answered||h.from?.signedIn!=null&&S.answered;if(!((h.from?.anyone==null||x.answered)&&(h.from?.signedIn==null||S.answered))||T.some(e=>ce(e,h.key)))return{key:h.key,gone:!1};let n=h.from?.anyone!=null&&x.failed||h.from?.signedIn!=null&&S.failed;return n?{key:h.key,gone:!0,words:t.ii(n,`That message could not be opened.`)}:e?{key:h.key,gone:!0,words:k}:{key:h.key,gone:!1}},[h,x.answered,x.failed,S.answered,S.failed,T]),O=(0,v.useCallback)(async e=>{await(0,b.updateDoc)((0,b.doc)(t.ui,E[e.source].collectionName,e.id),{isArchived:!e.isArchived})},[]),j=(0,v.useCallback)(async e=>{await(0,b.deleteDoc)((0,b.doc)(t.ui,E[e.source].collectionName,e.id))},[]);return(0,y.jsx)(be,{items:T,loading:p,refused:ee,onArchive:a?O:void 0,onDelete:a?j:void 0,opensUsers:o,formLook:f,more:u.more||d.more,loadingMore:u.waiting||d.waiting,onShowMore:re,onFind:ne,found:D})}exports.Inbox=X;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { h as e, p as t, t as n } from "./PageTitle-
|
|
1
|
+
import { h as e, p as t, t as n } from "./PageTitle-CkZriz8K.js";
|
|
2
2
|
import { E as r, Ft as i, I as a, N as o, P as s, T as c, Zr as l, a as ee, f as te, ii as u, l as d, nt as f, o as p, rt as ne, tt as re, ui as m } from "./TimeZoneField-oIMwb5_X.js";
|
|
3
|
-
import { a as ie, t as ae, x as h } from "./DashboardNav-
|
|
3
|
+
import { a as ie, t as ae, x as h } from "./DashboardNav-CxS3Qnl-.js";
|
|
4
4
|
import { Sn as g, nt as _, wn as oe } from "./schedule-C13m_kiO.js";
|
|
5
5
|
import { n as v } from "./chevron-down--LwXEv9w.js";
|
|
6
6
|
import { t as se } from "./arrow-left-DdRja6es.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
require(`./chunk-CiTBaPhY.cjs`);const e=require(`./PageTitle-
|
|
1
|
+
require(`./chunk-CiTBaPhY.cjs`);const e=require(`./PageTitle-BL50s4qY.cjs`),t=require(`./TimeZoneField-Ckn1pKAL.cjs`),n=require(`./DashboardNav-Bc619nqn.cjs`),r=require(`./schedule-BAea6q8_.cjs`),i=require(`./scheduleData-BXjNXVHY.cjs`),a=require(`./calendar-clock-D59cGNoL.cjs`),o=require(`./paidSessions-BK9qlIyL.cjs`),s=require(`./user-round-DUV_u2Tg.cjs`),c=require(`./email-Sya6gl4F.cjs`),l=require(`./SystemTabContent-BWhRHoXx.cjs`);let u=require(`react`),d=require(`react/jsx-runtime`);var f=new Set;function p(){let{user:p}=t.Ft(),m=r.et(),{loading:h,bookings:g,error:_}=i.b(p?.uid||``,p?.email||``),{docs:v}=i.S(),y=(0,u.useMemo)(()=>i.O(v),[v]),b=(0,u.useMemo)(()=>i.k(g,y),[g,y]),{checkouts:x}=o.t(b),[S]=(0,u.useState)(()=>Date.now()),C=(0,u.useMemo)(()=>b.map(e=>i.M(e,x[e.id],f,S)),[b,x,S]);return(0,d.jsxs)(`main`,{className:`flex-1 w-full max-w-7xl mx-auto p-4 pt-2 md:p-8 md:pt-4 z-10 flex flex-col min-h-screen`,children:[(0,d.jsxs)(t.nt.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:`mb-6`,children:[(0,d.jsx)(e.t,{children:`My bookings`}),(0,d.jsxs)(`div`,{className:`flex items-center gap-2 text-foreground/40 font-bold uppercase tracking-[0.2em] text-[11px]`,children:[(0,d.jsx)(`span`,{className:`w-8 h-[1px] bg-foreground/10`}),`/my-bookings`]})]}),(0,d.jsxs)(`div`,{className:`flex flex-col gap-6 flex-1 pb-16`,children:[(0,d.jsx)(n.t,{}),(0,d.jsx)(l.n,{tab:`mybookings`}),(0,d.jsx)(`div`,{className:`glass-panel border border-[var(--panel-border)] rounded-3xl p-4 sm:p-5 md:p-8 shadow-2xl relative bg-background flex flex-col fbos-tab-fill min-h-[600px]`,children:(0,d.jsxs)(`div`,{className:`flex flex-col gap-4`,children:[(0,d.jsxs)(`p`,{className:`text-[13px] font-medium text-foreground/60 leading-relaxed px-1`,children:[`Every meeting booked with your email address — including any you booked before you had an account. Shown in your time, `,r.nn(m),`.`]}),h?(0,d.jsx)(`p`,{className:`${t.s} px-1`,children:`Loading your bookings…`}):_?(0,d.jsx)(`p`,{className:`text-[12px] font-semibold text-red-500 px-1`,children:_}):C.length===0?(0,d.jsx)(t.m,{icon:a.t,title:`Nothing booked yet`,description:`Meetings you book appear here.`,children:(0,d.jsxs)(`p`,{className:`${t.s} px-1`,children:[`When you book a time through one of `,p?.displayName?`their`:`our`,` booking links, it lands here — and stays here afterwards, so you always have the record.`]})}):(0,d.jsx)(t.m,{icon:a.t,title:`Your calendar`,description:`Press a day to see what is on it. Everything you have booked is here, including the meetings that have been and the ones called off.`,children:(0,d.jsx)(o.n,{bookings:C,zone:m,side:`booker`,onCancel:async(e,t)=>{let n=await i.r(e.id,{ids:e.copyIds,reason:t,side:`booker`,by:e.name.trim()||String(p?.displayName||``)});if(!n){let n=r.Zt(e,m);c.r(`heads_up`,{title:`Booking cancelled`,summary:`${e.name.trim()||`Someone`} cancelled ${r.B(e)} — ${n.day}, ${n.time}`,details:{Who:e.name.trim(),Email:e.email,When:`${n.day}, ${n.time}`,Reason:t}}).catch(()=>{})}return n}})}),!h&&!_&&C.length>0&&(0,d.jsxs)(`p`,{className:`text-[11px] sm:text-[11.5px] text-foreground/40 font-medium leading-snug px-1 flex items-start gap-1.5`,children:[(0,d.jsx)(s.t,{className:`w-3.5 h-3.5 shrink-0 mt-[1px]`,"aria-hidden":!0}),(0,d.jsx)(`span`,{children:`Cancelling gives the time back straight away. To MOVE a meeting, cancel it and book another — or reply to its confirmation email.`})]})]})})]})]})}exports.MyBookings=p;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { t as e } from "./PageTitle-
|
|
1
|
+
import { t as e } from "./PageTitle-CkZriz8K.js";
|
|
2
2
|
import { Ft as t, m as n, nt as r, s as i } from "./TimeZoneField-oIMwb5_X.js";
|
|
3
|
-
import { t as a } from "./DashboardNav-
|
|
3
|
+
import { t as a } from "./DashboardNav-CxS3Qnl-.js";
|
|
4
4
|
import { B as o, Zt as s, et as c, nn as l } from "./schedule-C13m_kiO.js";
|
|
5
5
|
import { M as u, O as d, S as f, b as p, k as m, r as h } from "./scheduleData-DR6A-Q7Z.js";
|
|
6
6
|
import { t as g } from "./calendar-clock-CrYtc9Ft.js";
|
|
7
|
-
import { n as _, t as v } from "./paidSessions-
|
|
7
|
+
import { n as _, t as v } from "./paidSessions-C9392hZH.js";
|
|
8
8
|
import { t as y } from "./user-round-BXAihGcZ.js";
|
|
9
9
|
import { r as b } from "./email-PBHbXXgR.js";
|
|
10
10
|
import { n as x } from "./SystemTabContent-CMyT7mDN.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const e=require(`./chunk-CiTBaPhY.cjs`),t=require(`./TimeZoneField-Ckn1pKAL.cjs`),n=require(`./chevron-down-lyDK1rfL.cjs`),r=require(`./x-Ci8c5p6T.cjs`),i=require(`./iconNames-DEdRA_U7.cjs`),a=require(`./mediaKind-ButDya5f.cjs`);let o=require(`react`);o=e.a(o,1);let s=require(`react/jsx-runtime`);var c={appName:`Your AI Firebase`,defaultTheme:`light`,showThemeToggle:!0,logoUrl:`https://firebasestorage.googleapis.com/v0/b/fir-os-47863.firebasestorage.app/o/pub_files%2F1776321238933_favicon_smaller.png?alt=media&token=efecb55c-2456-4cbe-a20a-b86db54a1e55`,faviconUrl:`https://firebasestorage.googleapis.com/v0/b/fir-os-47863.firebasestorage.app/o/pub_files%2F1776321238933_favicon_smaller.png?alt=media&token=efecb55c-2456-4cbe-a20a-b86db54a1e55`,fonts:{},colors:{dark:{background:`#07070f`,backgroundSecondary:`#0a0a18`,foreground:`#f0eeff`,accent:`#a78bfa`,buttonText:`#ffffff`},light:{background:`#fcfaff`,backgroundSecondary:`#f7f3ff`,foreground:`#1e1b4b`,accent:`#7c3aed`,buttonText:`#ffffff`}},cornerRounding:`default`,cornerRadii:{buttonRadius:.75,inputRadius:.75,cardRadius:1.5,modalRadius:2.5}},l=`2.0.
|
|
1
|
+
const e=require(`./chunk-CiTBaPhY.cjs`),t=require(`./TimeZoneField-Ckn1pKAL.cjs`),n=require(`./chevron-down-lyDK1rfL.cjs`),r=require(`./x-Ci8c5p6T.cjs`),i=require(`./iconNames-DEdRA_U7.cjs`),a=require(`./mediaKind-ButDya5f.cjs`);let o=require(`react`);o=e.a(o,1);let s=require(`react/jsx-runtime`);var c={appName:`Your AI Firebase`,defaultTheme:`light`,showThemeToggle:!0,logoUrl:`https://firebasestorage.googleapis.com/v0/b/fir-os-47863.firebasestorage.app/o/pub_files%2F1776321238933_favicon_smaller.png?alt=media&token=efecb55c-2456-4cbe-a20a-b86db54a1e55`,faviconUrl:`https://firebasestorage.googleapis.com/v0/b/fir-os-47863.firebasestorage.app/o/pub_files%2F1776321238933_favicon_smaller.png?alt=media&token=efecb55c-2456-4cbe-a20a-b86db54a1e55`,fonts:{},colors:{dark:{background:`#07070f`,backgroundSecondary:`#0a0a18`,foreground:`#f0eeff`,accent:`#a78bfa`,buttonText:`#ffffff`},light:{background:`#fcfaff`,backgroundSecondary:`#f7f3ff`,foreground:`#1e1b4b`,accent:`#7c3aed`,buttonText:`#ffffff`}},cornerRounding:`default`,cornerRadii:{buttonRadius:.75,inputRadius:.75,cardRadius:1.5,modalRadius:2.5}},l=`2.0.10`,u={name:`cloud-upload`,size:24,node:[[`path`,{d:`M12 13v8`,key:`1l5pq0`}],[`path`,{d:`M4 14.899A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.242`,key:`1pljnt`}],[`path`,{d:`m8 17 4-4 4 4`,key:`1quai1`}]],aliases:[`upload-cloud`]};u.node;var d=n.n(u),f={name:`copy`,size:24,node:[[`rect`,{width:`14`,height:`14`,x:`8`,y:`8`,rx:`2`,ry:`2`,key:`17jyea`}],[`path`,{d:`M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2`,key:`zix9uf`}]]};f.node;var p=n.n(f),m={name:`layers`,size:24,node:[[`path`,{d:`M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z`,key:`zw3jo`}],[`path`,{d:`M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12`,key:`1wduqc`}],[`path`,{d:`M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17`,key:`kqbvx6`}]],aliases:[`layers-3`]};m.node;var h=n.n(m),g={name:`mail`,size:24,node:[[`path`,{d:`m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7`,key:`132q7q`}],[`rect`,{x:`2`,y:`4`,width:`20`,height:`16`,rx:`2`,key:`izxlao`}]]};g.node;var _=n.n(g),v=e=>e.toLowerCase().replace(/[^a-z0-9]/g,``),y=null,b=new Map,x=()=>{if(y)return y;y=new Map;for(let e of i.n.split(`
|
|
2
2
|
`))e&&(b.set(e,b.size),y.set(v(e),e));for(let e of i.t.split(`
|
|
3
3
|
`)){let[t,n]=e.split(` `);t&&n&&!y.has(v(t))&&y.set(v(t),n)}return y},S=e=>{let t=v(String(e??``));if(!t)return``;let n=x();return n.get(t)||n.get(t.replace(/^lucide/,``).replace(/icon$/,``))||``},C=new Map,w=new Set,T=e=>(w.add(e),()=>{w.delete(e)}),E=null,D=()=>(E??=Promise.resolve().then(()=>require(`./iconLoaders-BDz89ZHs.cjs`)).then(e=>e.iconLoaders).catch(e=>{throw E=null,e}),E),O=new Set,k=e=>{if(C.has(e)||O.has(e))return;O.add(e),x();let t=b.get(e);D().then(e=>t===void 0?void 0:e[t]?.()).then(t=>{!t||t.name!==e||!Array.isArray(t.node)||(C.set(e,t),w.forEach(e=>e()))}).catch(()=>{}).finally(()=>{O.delete(e)})},A=!1,ee=()=>{if(A||E||typeof window>`u`)return;A=!0;let e=()=>{D().catch(()=>{A=!1})};typeof window.requestIdleCallback==`function`?window.requestIdleCallback(e,{timeout:4e3}):window.setTimeout(e,1500)},j=e=>{for(let t of e){let e=S(t);e&&!L(e)&&k(e)}},te=`firebase-os:icons`,M=64,ne=new Set([`path`,`circle`,`rect`,`line`,`ellipse`,`polyline`,`polygon`]),N=(e,t)=>{let n=t;return!!n&&n.name===e&&Array.isArray(n.node)&&n.node.every(e=>Array.isArray(e)&&ne.has(e[0])&&e.length===2&&e[1]!==null&&typeof e[1]==`object`&&Object.entries(e[1]).every(([e,t])=>!/^on/i.test(e)&&e!==`dangerouslySetInnerHTML`&&(typeof t==`string`||typeof t==`number`)))},P=null,F=()=>{if(P)return P;P=[];try{let e=JSON.parse(localStorage.getItem(`firebase-os:icons`)||`{}`);for(let[t,n]of Object.entries(e??{}))!N(t,n)||C.has(t)||(C.set(t,n),P.push(t))}catch{}return P},I=null,re=e=>{let t=F();t.includes(e)||(t.push(e),t.length>M&&t.splice(0,t.length-M),!I&&(I=setTimeout(()=>{I=null;try{let e={};for(let n of t){let t=C.get(n);t&&(e[n]=t)}localStorage.setItem(te,JSON.stringify(e))}catch{}},500)))},L=e=>(F(),C.get(e)),ie=(e,t)=>{let r={name:e,node:[]},i=(0,o.forwardRef)((i,a)=>{let c=(0,o.useSyncExternalStore)(T,()=>L(e),()=>L(e));return(0,o.useEffect)(()=>{c?t&&re(e):k(e)},[c]),(0,s.jsx)(n.r,{...i,ref:a,icon:c||r})});return i.displayName=`Icon(${e})`,i},ae=new Map,oe=new Map,R=new WeakSet,se=e=>(typeof e==`object`||typeof e==`function`)&&e!==null&&R.has(e),z=(e,{remember:t=!0}={})=>{let n=S(e);if(!n)return null;let r=t?ae:oe,i=r.get(n);return i||(i=ie(n,t),R.add(i),r.set(n,i)),i},ce=e=>e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).replace(/([A-Z])([A-Z][a-z])/g,`$1-$2`).toLowerCase(),B=e=>{let t=e.replace(/-/g,` `);return t.charAt(0).toUpperCase()+t.slice(1)},le=i.n.split(`
|
|
4
4
|
`).filter(Boolean),V=`layers.house.layout-dashboard.list.table.kanban.calendar.clock.file-text.files.folder.hard-drive.upload.download.paperclip.book-open.notebook-pen.users.user.user-plus.contact.building.briefcase.handshake.mail.message-square.message-circle.send.inbox.bell.megaphone.phone.shopping-cart.package.truck.receipt.credit-card.banknote.wallet.tag.percent.chart-bar.chart-line.chart-pie.trending-up.target.gauge.activity.settings.sliders-horizontal.wrench.shield.lock.key.eye.search.star.heart.bookmark.flag.pin.map-pin.globe.circle-check.circle-alert.info.circle-question-mark.life-buoy.sparkles.zap.rocket.camera.image.video.music.mic.palette.pen-tool.scissors.stethoscope.graduation-cap.utensils.plane.car.dumbbell.leaf.sun.moon`.split(`.`),ue={money:[`banknote`,`wallet`,`credit-card`,`coins`,`dollar-sign`,`receipt`],cash:[`banknote`,`coins`,`wallet`],payment:[`credit-card`,`banknote`,`receipt`],invoice:[`receipt`,`file-text`],price:[`tag`,`dollar-sign`,`receipt`],people:[`users`,`user`,`contact`],customer:[`users`,`contact`,`user-round`],client:[`users`,`contact`,`briefcase`],team:[`users`,`users-round`],staff:[`users`,`id-card`],chat:[`message-circle`,`message-square`,`messages-square`],message:[`message-circle`,`mail`,`send`],email:[`mail`,`send`,`inbox`],task:[`list-checks`,`square-check`,`clipboard-check`],todo:[`list-checks`,`square-check`],project:[`kanban`,`folder-kanban`,`briefcase`],board:[`kanban`,`layout-dashboard`],photo:[`image`,`camera`,`images`],picture:[`image`,`images`],document:[`file-text`,`files`,`file`],doc:[`file-text`,`file`],shop:[`shopping-cart`,`store`,`shopping-bag`],store:[`store`,`shopping-bag`,`shopping-cart`],order:[`shopping-cart`,`package`,`receipt`],delivery:[`truck`,`package`],home:[`house`,`house-heart`],booking:[`calendar-check`,`calendar`,`clock`],appointment:[`calendar-clock`,`calendar`,`clock`],schedule:[`calendar-days`,`calendar`,`clock`],event:[`calendar`,`party-popper`,`ticket`],report:[`chart-bar`,`chart-line`,`file-chart-column`],stats:[`chart-bar`,`chart-line`,`chart-pie`],analytics:[`chart-line`,`chart-bar`,`activity`],help:[`circle-question-mark`,`life-buoy`,`info`],support:[`life-buoy`,`headset`,`circle-question-mark`],idea:[`lightbulb`,`sparkles`],health:[`heart-pulse`,`stethoscope`,`activity`],food:[`utensils`,`chef-hat`,`pizza`],travel:[`plane`,`map`,`luggage`],location:[`map-pin`,`map`,`globe`],address:[`map-pin`,`house`],security:[`shield`,`lock`,`key`],password:[`key`,`lock`],settings:[`settings`,`sliders-horizontal`,`wrench`],file:[`file`,`file-text`,`files`,`folder`],upload:[`upload`,`cloud-upload`],video:[`video`,`film`,`clapperboard`],school:[`graduation-cap`,`book-open`,`school`],course:[`graduation-cap`,`book-open`],gym:[`dumbbell`,`activity`],garden:[`leaf`,`flower`,`sprout`],car:[`car`,`car-front`],pet:[`paw-print`,`dog`,`cat`],note:[`notebook-pen`,`sticky-note`,`pencil`],write:[`pencil`,`pen-tool`,`notebook-pen`],time:[`clock`,`timer`,`hourglass`],star:[`star`,`sparkles`],favourite:[`star`,`heart`,`bookmark`],favorite:[`star`,`heart`,`bookmark`],album:[`images`,`image`,`camera`],gallery:[`images`,`image`,`camera`],profile:[`circle-user`,`user-round`,`id-card`],account:[`circle-user`,`user-round`,`id-card`],member:[`users`,`user-round`,`id-card`],membership:[`id-card`,`users`,`award`],subscription:[`credit-card`,`repeat`,`wallet`],plan:[`clipboard-list`,`layout-list`,`credit-card`],ticket:[`ticket`,`tickets`,`inbox`],request:[`inbox`,`send`,`file-text`],progress:[`trending-up`,`gauge`,`activity`],result:[`chart-bar`,`clipboard-check`,`trophy`],score:[`trophy`,`target`,`star`],library:[`library`,`book-open`,`folder`],lesson:[`graduation-cap`,`book-open`],session:[`calendar-clock`,`clock`,`video`],service:[`wrench`,`handshake`,`briefcase`],statement:[`file-text`,`receipt`,`banknote`],saved:[`bookmark`,`heart`,`star`],list:[`list`,`list-checks`,`layout-list`],detail:[`file-text`,`info`],referral:[`user-plus`,`share`,`gift`],reward:[`gift`,`trophy`,`award`],badge:[`award`,`badge`,`medal`],certificate:[`award`,`file-badge`,`scroll`],download:[`download`,`cloud-download`],history:[`rotate-ccw-clock`,`clock`,`rotate-ccw`],feedback:[`message-square`,`star`,`thumbs-up`],review:[`star`,`message-square`],wishlist:[`heart`,`bookmark`,`star`],cart:[`shopping-cart`,`shopping-bag`],credit:[`coins`,`wallet`,`credit-card`],dashboard:[`layout-dashboard`,`gauge`],welcome:[`hand`,`house`,`sparkles`],onboarding:[`rocket`,`list-checks`,`user-plus`],benefit:[`gift`,`sparkles`,`award`],perk:[`gift`,`sparkles`],resource:[`folder`,`book-open`,`files`],guide:[`book-open`,`compass`,`map`],faq:[`circle-question-mark`,`message-circle`],contract:[`file-pen`,`file-text`,`scroll`],agreement:[`handshake`,`file-pen`],quote:[`file-text`,`receipt`,`tag`],enquiry:[`message-square`,`mail`],inquiry:[`message-square`,`mail`],application:[`file-text`,`clipboard-list`,`send`],form:[`clipboard-list`,`file-text`],submission:[`inbox`,`send`,`file-text`],record:[`folder`,`file-text`,`database`],log:[`rotate-ccw-clock`,`list`,`file-text`],product:[`package`,`tag`,`shopping-bag`],inventory:[`package`,`boxes`,`warehouse`],stock:[`package`,`boxes`,`warehouse`],catalogue:[`book-open`,`package`,`layout-grid`],catalog:[`book-open`,`package`,`layout-grid`],item:[`package`,`tag`,`list`],supplier:[`truck`,`factory`,`handshake`],vendor:[`store`,`truck`,`handshake`],checkout:[`shopping-cart`,`credit-card`,`receipt`],shipping:[`truck`,`package`,`map-pin`],sale:[`trending-up`,`tag`,`banknote`],pricing:[`tag`,`banknote`,`receipt`],deal:[`handshake`,`tag`,`trending-up`],lead:[`user-plus`,`target`,`trending-up`],discount:[`percent`,`badge-percent`,`tag`],coupon:[`ticket-percent`,`tag`,`percent`],return:[`rotate-ccw`,`package`,`receipt`],refund:[`rotate-ccw`,`banknote`,`receipt`],warranty:[`shield-check`,`file-badge`,`wrench`],licence:[`file-badge`,`award`,`key`],license:[`file-badge`,`award`,`key`],insurance:[`shield`,`umbrella`,`file-text`],job:[`briefcase`,`hammer`,`clipboard-list`],shift:[`clock`,`calendar-clock`,`users`],rota:[`calendar-days`,`clock`,`users`],timesheet:[`clock`,`calendar-check`,`table`],expense:[`receipt`,`banknote`,`wallet`],budget:[`wallet`,`chart-pie`,`banknote`],policy:[`file-text`,`shield`,`book-open`],handbook:[`book-open`,`file-text`,`scroll`],training:[`graduation-cap`,`book-open`,`dumbbell`],candidate:[`user-search`,`user-plus`,`file-text`],applicant:[`user-search`,`user-plus`,`file-text`],volunteer:[`hand-heart`,`users`,`heart`],partner:[`handshake`,`users`,`building`],sponsor:[`handshake`,`badge-dollar-sign`,`award`],donation:[`heart-handshake`,`gift`,`banknote`],listing:[`list`,`house`,`tag`],property:[`house`,`building`,`key`],room:[`door-open`,`bed`,`layout-grid`],venue:[`building`,`map-pin`,`house`],vehicle:[`car`,`truck`,`car-front`],equipment:[`wrench`,`hard-hat`,`package`],tool:[`wrench`,`hammer`,`settings`],maintenance:[`wrench`,`hard-hat`,`settings`],asset:[`package`,`hard-drive`,`boxes`],issue:[`circle-alert`,`bug`,`triangle-alert`],complaint:[`message-square-warning`,`triangle-alert`,`face-slightly-frowning`],case:[`folder`,`briefcase`,`file-text`],testimonial:[`quote`,`star`,`message-square`],patient:[`stethoscope`,`user-round`,`heart-pulse`],student:[`graduation-cap`,`users`,`backpack`],class:[`graduation-cap`,`users`,`presentation`],prescription:[`pill`,`file-text`,`stethoscope`],measurement:[`ruler`,`scale`,`activity`],habit:[`repeat`,`circle-check`,`calendar-check`],workout:[`dumbbell`,`activity`,`heart-pulse`],meal:[`utensils`,`salad`,`chef-hat`],recipe:[`chef-hat`,`utensils`,`book-open`],announcement:[`megaphone`,`bell`,`newspaper`],newsletter:[`mail`,`newspaper`,`send`],campaign:[`megaphone`,`target`,`chart-line`],advert:[`megaphone`,`monitor-play`,`target`],ads:[`megaphone`,`monitor-play`,`target`],blog:[`rss`,`newspaper`,`pen-line`],editor:[`pen-line`,`file-pen`,`pencil`],writer:[`pen-line`,`notebook-pen`,`feather`],author:[`pen-line`,`book-open`,`feather`],manager:[`clipboard-list`,`briefcase`,`user-cog`],owner:[`crown`,`key`,`house`],founder:[`crown`,`rocket`,`star`],director:[`crown`,`briefcase`,`presentation`],moderator:[`shield-check`,`gavel`,`flag`],reviewer:[`star`,`clipboard-check`,`message-square`],approver:[`clipboard-check`,`stamp`,`circle-check`],agent:[`headset`,`briefcase`,`handshake`],broker:[`handshake`,`briefcase`,`chart-line`],consultant:[`briefcase`,`lightbulb`,`handshake`],contractor:[`hard-hat`,`hammer`,`wrench`],freelancer:[`laptop`,`pen-tool`,`briefcase`],driver:[`truck`,`car-front`,`map-pin`],courier:[`package`,`truck`,`bike`],seller:[`store`,`tag`,`handshake`],buyer:[`shopping-bag`,`shopping-cart`,`wallet`],subscriber:[`bell`,`repeat`,`credit-card`],affiliate:[`share`,`link`,`percent`],guest:[`door-open`,`bed`,`hand`],host:[`door-open`,`hand`,`calendar-check`],visitor:[`door-open`,`footprints`,`eye`],coach:[`megaphone`,`dumbbell`,`clipboard-check`],trainer:[`dumbbell`,`graduation-cap`,`activity`],tutor:[`graduation-cap`,`book-open`,`presentation`],teacher:[`presentation`,`graduation-cap`,`book-open`],mentor:[`graduation-cap`,`handshake`,`lightbulb`],parent:[`baby`,`house`,`heart`],nurse:[`stethoscope`,`heart-pulse`,`syringe`],doctor:[`stethoscope`,`heart-pulse`,`pill`],therapist:[`brain`,`heart-pulse`,`stethoscope`],artist:[`palette`,`paintbrush`,`pen-tool`],designer:[`palette`,`pen-tool`,`ruler`],developer:[`code`,`terminal`,`laptop`],photographer:[`camera`,`image`,`aperture`],investor:[`trending-up`,`banknote`,`chart-line`],donor:[`heart-handshake`,`gift`,`banknote`],vip:[`crown`,`gem`,`star`],guard:[`shield`,`lock`,`eye`],cleaner:[`sparkles`,`spray-can`,`brush`],chef:[`chef-hat`,`utensils`,`salad`],waiter:[`utensils`,`concierge-bell`,`coffee`],stylist:[`scissors`,`palette`,`sparkles`],therapy:[`heart-pulse`,`brain`,`hand-heart`],premium:[`crown`,`gem`,`star`],gold:[`crown`,`medal`,`star`],silver:[`medal`,`award`,`star`],bronze:[`medal`,`award`],platinum:[`gem`,`crown`,`award`],elite:[`crown`,`gem`,`trophy`],lifetime:[`infinity`,`crown`,`calendar-heart`],starter:[`rocket`,`sprout`,`flag`],basic:[`circle`,`square`,`layers`]},H=new Set([`my`,`our`,`your`,`their`,`the`,`a`,`an`,`all`,`new`,`page`,`pages`,`of`,`and`,`for`,`to`,`in`,`on`,`at`,`is`,`it`,`this`,`that`]),U=new Set([`item`,`items`,`list`,`lists`,`record`,`records`,`thing`,`things`]),de=e=>{let t=[e];return e.endsWith(`ies`)&&e.length>4&&t.push(`${e.slice(0,-3)}y`),e.endsWith(`es`)&&e.length>3&&t.push(e.slice(0,-2)),e.endsWith(`s`)&&t.push(e.slice(0,-1)),t},fe=(e,t)=>{if(Math.abs(e.length-t.length)>2)return 3;let n=Array.from({length:t.length+1},(e,t)=>t);for(let r=1;r<=e.length;r++){let i=n[0];n[0]=r;for(let a=1;a<=t.length;a++){let o=n[a];n[a]=Math.min(n[a]+1,n[a-1]+1,i+(e[r-1]===t[a-1]?0:1)),i=o}}return n[t.length]},pe=(e,t)=>{let n=0;for(let r of t)r===e[n]&&n++;return n===e.length};function W(e,t=96,n=le,r=!0){let i=e.trim().toLowerCase().replace(/\s+/g,`-`).replace(/[^a-z0-9-]/g,``);if(!i)return[];let a=i.split(`-`).filter(Boolean),o=new Set(n),s=new Map,c=(e,t)=>{o.has(e)&&s.set(e,Math.max(s.get(e)||0,t))};for(let e of n){let t=e.split(`-`);if(e===i){c(e,100);continue}if(e.startsWith(i)){c(e,90);continue}if(t.some(e=>e===i)){c(e,85);continue}if(t.some(e=>e.startsWith(i))){c(e,75);continue}if(e.includes(i)){c(e,65);continue}if(a.length>1&&a.every(e=>t.some(t=>t.startsWith(e)))){c(e,60);continue}}let l=e=>{let t=U.has(e)?80:95;for(let n of de(e))(ue[n]||[]).forEach((e,n)=>c(e,t-n))};for(let e of a)l(e);if(s.size===0&&a.length>1){let e=[...a].reverse().filter(e=>!H.has(e)&&e.length>=3);for(let i of[...e.filter(e=>!U.has(e)),...e.filter(e=>U.has(e))]){let e=W(i,t,n,r);if(e.length)return e}}if(r&&s.size===0&&i.length>=3)for(let e of n)e.split(`-`).some(e=>fe(i,e)<=(i.length>5?2:1))?c(e,40):i.length>=4&&pe(i,e.replace(/-/g,``))&&c(e,20);let u=e=>{let t=V.indexOf(e);return t===-1?V.length:t};return Array.from(s.entries()).sort((e,t)=>t[1]-e[1]||u(e[0])-u(t[0])||e[0].length-t[0].length||e[0].localeCompare(t[0])).slice(0,t).map(([e])=>e)}function me(e,{remember:t=!0}={}){return z(e,{remember:t})||h}function G({name:e,className:t,remember:n=!0}){return(0,o.createElement)(me(e,{remember:n}),{className:t})}function he({label:e=`Icon`,hint:n=`Shown next to the name in the menu.`,value:i,onChange:a}){let[c,l]=(0,o.useState)(``),u=(i||``).trim();(0,o.useEffect)(()=>{j(V)},[]);let d=(0,o.useMemo)(()=>{let e=W(c);return j(e),e},[c]),f=c.trim().length>0;return(0,s.jsx)(t.i,{label:e,hint:n,children:(0,s.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,s.jsxs)(`div`,{className:t.l,children:[u&&!f?(0,s.jsxs)(`span`,{className:`inline-flex items-center gap-2 mr-2.5 shrink-0 min-w-0 text-accent`,children:[(0,s.jsx)(`span`,{className:`w-7 h-7 -ml-1 rounded-lg bg-accent/[0.08] border border-accent/25 flex items-center justify-center shrink-0`,children:(0,s.jsx)(G,{name:u,className:`w-4 h-4`})}),(0,s.jsx)(`span`,{className:`text-[13px] font-semibold truncate`,children:B(ce(u))}),(0,s.jsx)(t.At,{className:`w-3.5 h-3.5 shrink-0`})]}):(0,s.jsx)(r.n,{className:`w-4 h-4 mr-2.5 text-foreground/30 shrink-0`}),(0,s.jsx)(`input`,{type:`text`,value:c,onChange:e=>l(e.target.value),placeholder:u?`Type a word to change it`:`Type a word, e.g. calendar`,"aria-label":`Search icons`,className:`${t.f} no-glow`})]}),f&&(0,s.jsx)(`div`,{className:`rounded-[var(--input-radius,0.75rem)] border border-[var(--panel-border)] bg-[var(--panel-bg)] p-2 max-h-56 overflow-y-auto`,children:d.length>0?(0,s.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:d.map(e=>{let t=S(u)===e;return(0,s.jsx)(`button`,{type:`button`,title:B(e),"aria-label":B(e),"aria-pressed":t,onClick:()=>{a(e),l(``)},className:`w-9 h-9 rounded-lg flex items-center justify-center transition-all cursor-pointer ${t?`bg-accent text-[var(--button-fg,#fff)] ring-2 ring-accent/40`:`text-foreground/60 hover:text-foreground hover:bg-foreground/[0.06]`}`,children:(0,s.jsx)(G,{name:e,className:`w-4 h-4`,remember:!1})},e)})}):(0,s.jsx)(`span`,{className:`block px-2 py-2 text-[12px] font-medium text-foreground/45`,children:`Nothing close to that. Try a simpler word, like calendar or people.`})})]})})}function ge({name:e,glyph:t,label:n,open:r=!1,onClick:i,tone:a=`quiet`}){let c=e||!t?(0,s.jsx)(G,{name:e,className:`w-4 h-4`}):(0,o.createElement)(t,{className:`w-4 h-4`}),l=a===`accent`?`text-accent`:`text-foreground/60`;return i?(0,s.jsx)(`button`,{type:`button`,title:n,"aria-label":n,"aria-expanded":r,onClick:i,className:`w-8 h-8 shrink-0 rounded-xl border flex items-center justify-center transition-all cursor-pointer ${r?`border-accent/50 bg-accent/[0.08] text-accent`:`border-[var(--panel-border)] bg-foreground/[0.03] ${l} hover:border-accent/40 hover:text-accent`}`,children:c}):(0,s.jsx)(`span`,{"aria-hidden":`true`,className:`w-8 h-8 shrink-0 rounded-xl border border-transparent flex items-center justify-center ${a===`accent`?`text-accent/70`:`text-foreground/45`}`,children:c})}function _e({label:e,hint:n,value:i,onPick:a,resetLabel:o,resetTitle:c,onReset:l}){return(0,s.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,s.jsx)(he,{label:e,hint:n,value:i,onChange:a}),l&&o&&(0,s.jsx)(t.o,{icon:r.t,compact:!0,title:c||o,onClick:l,children:o})]})}var ve=/(<[A-Z][A-Za-z0-9]*(?:\s[^<>]*)?\/?>|src\/[A-Za-z0-9_./-]*[A-Za-z0-9_-]|'[A-Za-z0-9_@./-]+')/g,ye=/(https?:\/\/[^\s]+)/g,K=e=>e.split(ye).flatMap((e,t)=>t%2==1?[{text:e,kind:`value`}]:e.split(ve).map((e,t)=>({text:e,kind:t%2==1?`code`:void 0}))).filter(e=>e.text),be=/exactly: |Here is (?:what|how) [^:]*: |It should ask for: |Where the form belongs on the page: |a button that says /,xe=e=>{let t=be.exec(e);if(!t)return K(e);let n=t.index+t[0].length,r=e.slice(0,n),i=e.slice(n),a=i.indexOf(` — `);return[...K(r),{text:a===-1?i:i.slice(0,a),kind:`value`},...K(a===-1?``:i.slice(a))]},Se=`text-accent font-semibold bg-accent/[0.08] rounded-[4px] px-1 -mx-[1px] [overflow-wrap:anywhere]`,Ce=`font-mono text-[0.92em] text-foreground/75 bg-foreground/[0.055] border border-[var(--panel-border)]/60 rounded-[4px] px-1 py-[1px] [overflow-wrap:anywhere]`;function q({text:e}){return(0,s.jsx)(s.Fragment,{children:xe(e).map((e,t)=>e.kind?(0,s.jsx)(`span`,{className:e.kind===`value`?Se:Ce,children:e.text},t):(0,s.jsx)(o.default.Fragment,{children:e.text},t))})}function we({title:e=`Ask your assistant`,description:n,prompt:i,compact:a=!1,locked:c=!1,busy:l=!1,onCopied:u}){let[d,f]=(0,o.useState)(!1),m=i.includes(`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const e=require(`./chunk-CiTBaPhY.cjs`),t=require(`./PageTitle-
|
|
1
|
+
const e=require(`./chunk-CiTBaPhY.cjs`),t=require(`./PageTitle-BL50s4qY.cjs`),n=require(`./TimeZoneField-Ckn1pKAL.cjs`),r=require(`./DashboardNav-Bc619nqn.cjs`),i=require(`./Trouble-KQZyf6aY.cjs`),a=require(`./schedule-BAea6q8_.cjs`),o=require(`./chevron-down-lyDK1rfL.cjs`),s=require(`./arrow-right-CGvbxks5.cjs`),c=require(`./boxes-CpGWLEM7.cjs`),l=require(`./scheduleData-BXjNXVHY.cjs`),u=require(`./SupportBar-DR52UpBq.cjs`),d=require(`./FileViewerPopup-CkLUYCNo.cjs`),f=require(`./eye-off-zYG7T389.cjs`),p=require(`./eye-DU2g57PD.cjs`),m=require(`./VideoPlayer-CggwpVXH.cjs`),h=require(`./FormNote-DP0GK9ya.cjs`),g=require(`./arrivalRoads-1OeHArA0.cjs`),_=require(`./link-2-C7A-6PW6.cjs`),v=require(`./x-Ci8c5p6T.cjs`),y=require(`./lock-xMnTQLRt.cjs`),b=require(`./pencil-Ca8JSmp0.cjs`),x=require(`./plus-zsWFCu4F.cjs`),S=require(`./trash-D-CpYHCs.cjs`),C=require(`./user-round-DUV_u2Tg.cjs`),w=require(`./Button-Ccy4wFZ1.cjs`),T=require(`./mediaKind-ButDya5f.cjs`),E=require(`./formPage-DoDEEg1-.cjs`),D=require(`./email-Sya6gl4F.cjs`),O=require(`./roles-BmnoAilb.cjs`),k=require(`./tabAudience-2fJAN1aD.cjs`),A=require(`./ConfirmModal-BUNtss4a.cjs`),j=require(`./recordsKey-B3lWGd8C.cjs`),M=require(`./bookingPages-Dx1ViiwW.cjs`),N=require(`./pageFiles-Cn0YQ4Ur.cjs`),P=require(`./recordLock-CiulizO1.cjs`),ee=require(`./AccessNotice-BClqr7A9.cjs`),F=require(`./SystemTabContent-BWhRHoXx.cjs`),I=require(`./SchedulePicker-BpPGI5VZ.cjs`),te=require(`./contentKey-BwicZ0gK.cjs`),ne=require(`./NeedsService-DIF7mEHq.cjs`);require(`./ThemeAdmin-BhaTfgKX.cjs`);let L=require(`react`);L=e.a(L,1);let R=require(`react/jsx-runtime`),z=require(`firebase/firestore`),re=require(`react-router-dom`),ie=require(`react-dom`);var ae={name:`file-code-corner`,size:24,node:[[`path`,{d:`M4 12.15V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.706.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2h-3.35`,key:`1wthlu`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`m5 16-3 3 3 3`,key:`331omg`}],[`path`,{d:`m9 22 3-3-3-3`,key:`lsp7cz`}]],aliases:[`file-code-2`]};ae.node;var oe=o.n(ae),se={name:`folder-open`,size:24,node:[[`path`,{d:`m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2`,key:`usdka0`}]]};se.node;var ce=o.n(se),le={name:`layout-grid`,size:24,node:[[`rect`,{width:`7`,height:`7`,x:`3`,y:`3`,rx:`1`,key:`1g98yp`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`3`,rx:`1`,key:`6d4xhi`}],[`rect`,{width:`7`,height:`7`,x:`14`,y:`14`,rx:`1`,key:`nxv5o0`}],[`rect`,{width:`7`,height:`7`,x:`3`,y:`14`,rx:`1`,key:`1bb6yr`}]]};le.node;var ue=o.n(le),de={name:`life-buoy`,size:24,node:[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`path`,{d:`m4.93 4.93 4.24 4.24`,key:`1ymg45`}],[`path`,{d:`m14.83 9.17 4.24-4.24`,key:`1cb5xl`}],[`path`,{d:`m14.83 14.83 4.24 4.24`,key:`q42g0n`}],[`path`,{d:`m9.17 14.83-4.24 4.24`,key:`bqpfvv`}],[`circle`,{cx:`12`,cy:`12`,r:`4`,key:`4exip2`}]]};de.node;var fe=o.n(de),B={name:`wand-sparkles`,size:24,node:[[`path`,{d:`m21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72`,key:`ul74o6`}],[`path`,{d:`m14 7 3 3`,key:`1r5n42`}],[`path`,{d:`M5 6v4`,key:`ilb8ba`}],[`path`,{d:`M19 14v4`,key:`blhpug`}],[`path`,{d:`M10 2v2`,key:`7u0qdc`}],[`path`,{d:`M7 8H3`,key:`zfb6yr`}],[`path`,{d:`M21 16h-4`,key:`1cnmox`}],[`path`,{d:`M11 3H9`,key:`1obp7u`}]],aliases:[`wand-2`]};B.node;var pe=o.n(B);function V({roads:e}){let[t,r]=(0,L.useState)(null);(0,L.useEffect)(()=>(0,z.onSnapshot)((0,z.doc)(n.ui,`sys_configs`,g.t),e=>r(g.n(e.exists()?e.data():null)),()=>{}),[]);let i=e?JSON.stringify(e):``;return(0,L.useEffect)(()=>{if(!i||!t)return;let e=JSON.parse(i);g.r(e,t)||(0,z.setDoc)((0,z.doc)(n.ui,`sys_configs`,g.t),{roads:e}).catch(()=>{})},[i,t]),null}function H(e){if(!e.length)return``;let t=e.length===1;return[`My app checked the files you wrote for it and found ${t?`one thing`:`${e.length} things`} wrong. This is a repair, not a redesign: keep every page exactly as you designed it — the same layout, the same steps in the same order, every element where it is now, the same words and the same styling. Fix ${t?`it`:`every one of them`}, exactly as ${t?`the line`:`each line`} says, with the smallest change that does it, and change nothing else. Where a line tells you to delete, add or replace something, do only that, in the place the old one stood, and leave everything around it as it is. Open only the files ${t?`the line names`:`these lines name`}, and no others — my logo and my favicon live in configs/theme.config.ts, which nothing here is asking about, and they are never to be cleared, swapped or "improved", today or ever.`,`Some of what is on these pages is MINE, not yours: my logo, every picture already there and the exact link it carries, my app’s name, my words, and the addresses my buttons lead to. Not one of them is ever the thing you take away to make a line go away. Where a line is about one of them, change HOW it is written and leave WHAT it is alone — a picture written the wrong way is rewritten the right way with the same link, never deleted, never swapped for a placeholder or a picture of your own, and a button that goes nowhere is pointed somewhere, never removed. ${t?`The line`:`Each line`} names its file first:`,...e.map((e,t)=>`${t+1}. ${e}`),`Before you finish, look at each page against how it was: nothing moved, nothing restyled, nothing reworded, and no step added, taken away or put in a different order — unless a line above asked for exactly that. And check that everything of mine is still where it was: my logo and my favicon untouched, every picture still on its page with the link it had, my words, my app’s name, and every button still leading where it led.`].join(`
|
|
2
2
|
`)}function U(e){let t=new Set;for(let n of e){let e=n.match(/([A-Za-z0-9_-]+)Content\.tsx/)?.[1]||(/\bHome\.tsx\b/.test(n)?`Home`:``);e&&t.add(e.replace(/([a-z0-9])([A-Z])/g,`$1 $2`))}return[...t]}function W(e,t){let n=new Map(t.keys.map((e,n)=>[e,t.findings[n]])),r=0,i=0;return e.keys.forEach((t,a)=>{n.has(t)?n.get(t)!==e.findings[a]&&i++:r++}),{fixed:r,left:t.findings.length,partly:i}}function me(e){if(!e)return null;if(e===`failed`)return{said:`Could not check just now.`,next:`Try again in a moment.`};if(!e.left)return null;let t=e.left===1?`one`:String(e.left);return!e.fixed&&e.partly?{said:`Partly put right — ${t} still to fix.`,next:`Copy the sentence again — it now lists only what is left.`}:e.fixed?{said:`${e.fixed===1?`One`:e.fixed} put right, ${t} still to fix.`,next:`Copy the sentence again — it now lists only what is left.`}:{said:`Nothing put right yet — ${t} still to fix.`,next:`If your assistant says it is done, paste the sentence again.`}}var he=15*1e3,ge=600,_e=5*1e3,ve=20*1e3,ye=(e,t)=>e.length===t.length&&e.every((e,n)=>e===t[n]),G={loading:!1,findings:[],keys:[],checking:!1,checked:null,allFixed:!1};function K(){let{user:e,isAdmin:t,roleConfirmed:r}=n.Ft(),i=!!e?.uid&&t&&r,[a,o]=(0,L.useState)({...G,loading:!0}),s=(0,L.useRef)(0),c=(0,L.useRef)(!1),l=(0,L.useRef)(!1),u=(0,L.useRef)(!0),d=(0,L.useRef)(0),f=(0,L.useCallback)(async e=>{if(!i||e===`quiet`&&(c.current||l.current||Date.now()-s.current<he))return;let t=e===`pressed`,r=Date.now(),a=++d.current;s.current=r,t?(l.current=!0,o(e=>({...e,checking:!0}))):c.current=!0;let f=new AbortController,p=setTimeout(()=>f.abort(),ve);try{let e=await n.li?.currentUser?.getIdToken();if(!e)throw Error(`signed out`);let i=await fetch(`/api/checks`,{headers:{Authorization:`Bearer ${e}`},cache:`no-store`,signal:f.signal});if(!i.ok||!String(i.headers.get(`content-type`)||``).includes(`json`))throw Error(`no checks`);let s=await i.json(),c=s?.sources===!0,l=c&&Array.isArray(s.findings)?s.findings:[],p=c&&Array.isArray(s.keys)&&s.keys.length===l.length?s.keys:[],m={findings:[],keys:[]};l.forEach((e,t)=>{typeof e!=`string`||!e.trim()||(m.findings.push(e),m.keys.push(typeof p[t]==`string`&&p[t]?p[t]:e))});let{findings:h}=m;if(t&&await new Promise(e=>setTimeout(e,Math.max(0,ge-(Date.now()-r)))),!u.current||a!==d.current)return;o(e=>({loading:!1,...m,checking:t?!1:e.checking,checked:t?W(e,m):ye(e.findings,h)?e.checked:null,allFixed:c&&e.findings.length>0&&!h.length}))}catch{u.current&&a===d.current&&o(e=>({...e,loading:!1,checking:t?!1:e.checking,checked:t?`failed`:e.checked}))}finally{clearTimeout(p),t?l.current=!1:c.current=!1}},[i]);(0,L.useEffect)(()=>{if(u.current=!0,!i){o(G);return}f(`first`);let e=()=>{document.visibilityState===`visible`&&f(`quiet`)};return document.addEventListener(`visibilitychange`,e),window.addEventListener(`focus`,e),()=>{u.current=!1,document.removeEventListener(`visibilitychange`,e),window.removeEventListener(`focus`,e)}},[i,f]),(0,L.useEffect)(()=>{if(!a.allFixed)return;let e=setTimeout(()=>o(e=>({...e,allFixed:!1,checked:null})),_e);return()=>clearTimeout(e)},[a.allFixed]);let p=(0,L.useCallback)(()=>{f(`pressed`)},[f]),m=(0,L.useCallback)(()=>{f(`quiet`)},[f]),{keys:h,...g}=a;return{...g,again:p,look:m}}var be=e=>e.length<=1?e.join(``):`${e.slice(0,-1).join(`, `)} and ${e[e.length-1]}`,q=20*1e3,J=`glass-panel border border-[var(--panel-border)] rounded-3xl p-4 sm:p-6`;function xe(){let{loading:e,findings:r,checking:a,checked:o,allFixed:s,again:c,look:l}=K(),[u,d]=(0,L.useState)(``),f=(0,L.useRef)(null),p=!e&&r.length>0;(0,L.useEffect)(()=>{if(!p)return;let e=!0,t=f.current,n=t&&typeof IntersectionObserver<`u`?new IntersectionObserver(([t])=>{e=!!t?.isIntersecting,e&&l()}):null;n&&t&&n.observe(t);let r=setInterval(()=>{e&&document.visibilityState===`visible`&&l()},q);return()=>{clearInterval(r),n?.disconnect()}},[p,l]);let m=H(r),h=!!m&&u===m;if(e)return null;if(!r.length)return s?(0,R.jsxs)(`div`,{role:`status`,className:`${J} flex items-center gap-2.5 text-[13.5px] font-semibold text-foreground/80`,children:[(0,R.jsx)(n.At,{className:`w-4 h-4 shrink-0 text-accent`}),`All fixed — your assistant put everything right.`]}):null;let g=U(r),_=g.length?` on ${be(g.slice(0,4))}${g.length>4?` and more`:``}`:``,v=a?null:me(o);return(0,R.jsxs)(`div`,{ref:f,className:`${J} flex flex-col gap-3`,children:[(0,R.jsx)(t.o,{title:`Your assistant left ${r.length===1?`one thing`:`${r.length} things`} to fix${_}`,description:`My app checked what it built. Copy this into your assistant's chat and it will put them right — then come back and press Check again.`,prompt:m,compact:!0,onCopied:()=>d(m)}),(0,R.jsxs)(`div`,{className:`flex items-center justify-between gap-3 min-w-0 px-1`,children:[(0,R.jsx)(`p`,{role:`status`,className:`min-w-0 text-[12.5px] font-medium leading-relaxed text-foreground/50`,children:v?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`span`,{className:`font-semibold text-foreground/80`,children:v.said}),(0,R.jsxs)(`span`,{className:`max-sm:hidden`,children:[` `,v.next]})]}):(0,R.jsx)(`span`,{className:`max-sm:hidden`,children:a?`Checking what your assistant changed…`:`When your assistant has finished, check again — this goes once everything is put right.`})}),(0,R.jsx)(n.o,{icon:i.a,busy:a,onClick:c,className:h&&!a?`border-accent/40 text-accent hover:text-accent`:``,children:a?`Checking`:`Check again`})]})]})}function Se(e){let[t,r]=(0,L.useState)(null),[i,a]=(0,L.useState)(!1);return(0,L.useEffect)(()=>{if(e)return(0,z.onSnapshot)((0,z.query)((0,z.collection)(n.ui,n.M),(0,z.orderBy)(`createdAt`,`desc`),(0,z.limit)(500)),e=>r(e.docs.map(e=>{let t=e.data(),n=Number(t.fileSize);return{id:e.id,url:String(t.downloadURL||``),name:String(t.fileName||``),type:String(t.fileType||``),...n>0?{size:n}:{},...t.smallURL?{small:String(t.smallURL)}:{},...t.mediumURL?{medium:String(t.mediumURL)}:{}}}).filter(e=>e.url)),()=>a(!0))},[e]),{assets:t,failed:i}}var Ce=[{id:`all`,label:`Everything`},{id:`pictures`,label:`Pictures`},{id:`videos`,label:`Videos`},{id:`files`,label:`Files`}],we=(e,t)=>t===`all`||t===`pictures`&&e===`image`||t===`videos`&&(e===`video`||e===`audio`)||t===`files`&&e!==`image`&&e!==`video`&&e!==`audio`;function Te({asset:e,chosen:t,taken:r,onToggle:i,onAdd:a}){let o=T.o(e.name)||T.o(e.url),[s,c]=(0,L.useState)(!1);return(0,R.jsxs)(`button`,{type:`button`,disabled:r,onClick:i,onDoubleClick:a,"aria-pressed":t,title:e.name,className:`group relative flex flex-col text-left rounded-2xl border overflow-hidden bg-[var(--panel-bg)] transition-all cursor-pointer disabled:cursor-default ${t?`border-accent ring-2 ring-accent/35`:`border-[var(--panel-border)] hover:border-accent/40`} ${r?`opacity-55`:``}`,children:[(0,R.jsxs)(`span`,{className:`relative block w-full aspect-[4/3] bg-foreground/[0.03] overflow-hidden`,children:[e.kind===`image`&&!s?(0,R.jsx)(n.O,{src:e.url,small:e.small,medium:e.medium,alt:``,className:`absolute inset-0`,onError:()=>c(!0)}):e.kind===`video`?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(`video`,{src:`${e.url}#t=0.5`,preload:`metadata`,muted:!0,playsInline:!0,className:`absolute inset-0 w-full h-full object-cover pointer-events-none`}),(0,R.jsx)(`span`,{className:`absolute inset-0 m-auto w-9 h-9 rounded-full bg-black/55 text-white flex items-center justify-center`,children:(0,R.jsx)(m.r,{className:`w-4 h-4 fill-current translate-x-px`})})]}):(0,R.jsxs)(`span`,{className:`absolute inset-0 flex flex-col items-center justify-center gap-1.5`,children:[(0,R.jsx)(`span`,{className:`${d.r} w-11 h-11`,children:(0,R.jsx)(d.i,{kind:e.kind,name:e.name||e.url,className:`w-5 h-5`})}),o&&(0,R.jsx)(`span`,{className:`text-[10.5px] font-bold text-foreground/40 uppercase tracking-wide`,children:o})]}),t&&(0,R.jsx)(`span`,{className:`absolute top-2 right-2 w-6 h-6 rounded-full bg-accent text-[var(--button-fg,#fff)] flex items-center justify-center shadow`,children:(0,R.jsx)(n.At,{className:`w-3.5 h-3.5`})}),r&&(0,R.jsxs)(`span`,{className:`absolute top-2 left-2 inline-flex items-center gap-1.5 h-6 px-2 rounded-full bg-background/90 text-[11px] font-semibold text-foreground/70`,children:[(0,R.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full bg-emerald-500`}),` On the page`]})]}),(0,R.jsxs)(`span`,{className:`flex flex-col gap-0.5 px-3 py-2.5 min-w-0`,children:[(0,R.jsx)(`span`,{className:`text-[12.5px] font-semibold text-foreground truncate`,children:e.name||`Untitled`}),(0,R.jsx)(`span`,{className:`text-[11px] font-medium text-foreground/45`,children:T.t[e.kind]})]})]})}function Ee({open:e,onClose:t,onPick:r,taken:i=[]}){let a=Se(e),o=a.failed,s=(0,L.useMemo)(()=>a.assets&&a.assets.map(e=>({...e,kind:T.u(e.url,e.type)})),[a.assets]),[c,l]=(0,L.useState)(``),[u,d]=(0,L.useState)(`all`),[f,p]=(0,L.useState)([]),m=(0,L.useMemo)(()=>new Set(i),[i]),h=(0,L.useMemo)(()=>{let e=c.trim().toLowerCase();return(s||[]).filter(t=>we(t.kind,u)&&(!e||t.name.toLowerCase().includes(e)))},[s,u,c]),g=()=>{p([]),l(``),t()},_=e=>{let t=(s||[]).filter(t=>e.includes(t.url)).map(({url:e,name:t,type:n,size:r})=>({url:e,name:t,type:n,...r?{size:r}:{}}));t.length&&r(t),g()},y=e=>p(t=>t.includes(e)?t.filter(t=>t!==e):[...t,e]);return typeof document>`u`?null:(0,ie.createPortal)((0,R.jsx)(n.rt,{children:e&&(0,R.jsxs)(`div`,{role:`dialog`,"aria-modal":`true`,"aria-label":`Your assets`,className:`fixed inset-0 z-[9998] flex items-center justify-center p-3 sm:p-6`,children:[(0,R.jsx)(n.nt.div,{onClick:g,initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},className:`absolute inset-0 bg-background/80 backdrop-blur-xl cursor-pointer`}),(0,R.jsxs)(n.nt.div,{initial:{opacity:0,scale:.97,y:8},animate:{opacity:1,scale:1,y:0},exit:{opacity:0,scale:.97,y:8},transition:{duration:.18},className:`relative z-10 w-full max-w-4xl max-h-[min(88vh,820px)] flex flex-col rounded-3xl glass-popover overflow-hidden`,children:[(0,R.jsx)(`div`,{"aria-hidden":!0,className:`pointer-events-none absolute top-0 inset-x-0 h-[2px] bg-gradient-to-r from-transparent via-accent/60 to-transparent`}),(0,R.jsxs)(`div`,{className:`flex items-start gap-4 px-5 sm:px-7 pt-6 sm:pt-7 pb-5`,children:[(0,R.jsx)(`span`,{className:`w-11 h-11 sm:w-12 sm:h-12 rounded-2xl flex items-center justify-center shrink-0 border border-[var(--panel-border)]/50 bg-accent/10 text-accent`,children:(0,R.jsx)(ce,{className:`w-5 h-5 sm:w-[22px] sm:h-[22px]`})}),(0,R.jsxs)(`div`,{className:`flex flex-col gap-1 min-w-0 flex-1 pt-0.5`,children:[(0,R.jsx)(`h2`,{className:`text-[18px] sm:text-[20px] font-bold text-foreground tracking-tight leading-tight`,children:`Your assets`}),(0,R.jsx)(`p`,{className:`text-[13px] text-foreground/50 leading-relaxed max-w-md`,children:`Everything you have uploaded. Pick what goes on this page — tap to choose, tap again to drop it.`})]}),(0,R.jsx)(`button`,{type:`button`,onClick:g,"aria-label":`Close`,className:`w-9 h-9 shrink-0 rounded-xl border border-[var(--panel-border)]/60 flex items-center justify-center text-foreground/50 hover:text-foreground hover:border-accent/40 hover:bg-foreground/[0.06] transition-all cursor-pointer`,children:(0,R.jsx)(v.t,{className:`w-[18px] h-[18px]`})})]}),(0,R.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2.5 px-5 sm:px-7 pb-5 border-y border-[var(--panel-border)]/50 pt-5 bg-foreground/[0.015]`,children:[(0,R.jsxs)(`div`,{className:`w-full h-11 flex items-center px-4 rounded-[var(--input-radius,0.75rem)] border border-[var(--panel-border)] bg-[var(--panel-bg)] transition-all duration-300 hover:border-accent/40 focus-within:border-accent console-field !h-11 flex-1 min-w-[200px] gap-2.5`,children:[(0,R.jsx)(v.n,{className:`w-4 h-4 text-foreground/35 shrink-0`}),(0,R.jsx)(`input`,{value:c,onChange:e=>l(e.target.value),placeholder:`Search by name`,"aria-label":`Search your assets`,className:`flex-1 min-w-0 h-full bg-transparent border-none outline-none shadow-none text-[14px] text-foreground placeholder:text-foreground/35 disabled:cursor-not-allowed no-glow`})]}),(0,R.jsx)(`div`,{role:`tablist`,"aria-label":`Show`,className:`inline-flex p-1 rounded-xl border border-[var(--panel-border)] bg-background/60 max-sm:w-full max-sm:overflow-x-auto`,children:Ce.map(e=>(0,R.jsx)(`button`,{type:`button`,role:`tab`,"aria-selected":u===e.id,onClick:()=>d(e.id),className:`h-9 px-3 sm:px-3.5 rounded-lg text-[12.5px] sm:text-[13px] font-semibold whitespace-nowrap transition-colors cursor-pointer max-sm:flex-1 ${u===e.id?`bg-foreground/[0.07] text-foreground shadow-sm`:`text-foreground/55 hover:text-foreground`}`,children:e.label},e.id))})]}),(0,R.jsx)(`div`,{className:`flex-1 min-h-0 overflow-y-auto overscroll-contain px-5 sm:px-7 py-5`,children:o?(0,R.jsx)(`p`,{className:`py-20 text-center text-[13.5px] font-medium text-red-500`,children:`Your assets could not be read. Reload and try again.`}):s?s.length?h.length?(0,R.jsxs)(`div`,{className:`grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-3 sm:gap-3.5`,children:[h.map(e=>(0,R.jsx)(Te,{asset:e,chosen:f.includes(e.url),taken:m.has(e.url),onToggle:()=>y(e.url),onAdd:()=>_([e.url])},e.id)),(s||[]).length>=500&&(0,R.jsxs)(`p`,{className:`col-span-full text-[12.5px] font-medium text-foreground/45 text-center pt-2`,children:[`The `,500,` newest are shown. Older uploads are still in Assets.`]})]}):(0,R.jsx)(`p`,{className:`py-20 text-center text-[13.5px] font-medium text-foreground/50`,children:`Nothing here matches.`}):(0,R.jsxs)(`div`,{className:`py-20 flex flex-col items-center text-center gap-1.5`,children:[(0,R.jsx)(`p`,{className:`text-[15px] font-bold text-foreground/70`,children:`Nothing in your assets yet`}),(0,R.jsx)(`p`,{className:`text-[13px] text-foreground/45 max-w-xs leading-relaxed`,children:`Upload from the row instead — whatever you upload lands in your assets too.`})]}):(0,R.jsx)(`div`,{className:`py-20 flex justify-center`,children:(0,R.jsx)(v.r,{className:`w-6 h-6 text-accent animate-spin`})})}),(0,R.jsxs)(`div`,{className:`flex items-center justify-between gap-3 px-5 sm:px-7 py-4 border-t border-[var(--panel-border)]/60 bg-foreground/[0.015]`,children:[(0,R.jsx)(`span`,{className:`text-[13px] font-medium text-foreground/50 truncate`,children:f.length?`${f.length} chosen`:`Choose one or more`}),(0,R.jsxs)(`div`,{className:`flex items-center gap-2 shrink-0`,children:[(0,R.jsx)(`button`,{type:`button`,onClick:g,className:`inline-flex items-center justify-center gap-1.5 h-8 px-2.5 sm:h-9 sm:px-3 shrink-0 whitespace-nowrap rounded-[var(--btn-radius,0.75rem)] text-[12.5px] font-semibold border border-[var(--panel-border)] bg-transparent text-foreground/60 hover:text-foreground hover:border-accent/40 hover:bg-foreground/[0.04] active:scale-[0.98] transition-all cursor-pointer disabled:opacity-40 disabled:pointer-events-none`,children:`Cancel`}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>_(f),disabled:!f.length,className:`btn-primary h-10 px-5 rounded-xl text-[13px] font-bold cursor-pointer disabled:opacity-40 disabled:pointer-events-none`,children:f.length>1?`Add ${f.length}`:`Add`})]})]})]})]})}),document.body)}var Y={image:`First card — The Montreal: a rigid bag with a top handle`,video:`Plays big under the heading, with a Watch our story title`,audio:`A small player under the episode list`,pdf:`A View our menu button that opens it in a popup`,text:`Laid out as a table under the prices`,document:`A Download the price list button at the bottom`,file:`A Download button beside the form`,link:`A Book on Fresha button in the top corner`},De=`h-11 px-3 sm:px-3.5 shrink-0 inline-flex items-center justify-center gap-2 rounded-[var(--input-radius,0.75rem)] border border-[var(--panel-border)] bg-[var(--panel-bg)] text-[13px] font-semibold text-foreground/65 hover:text-foreground hover:border-accent/40 transition-all cursor-pointer disabled:opacity-40 disabled:pointer-events-none`;function Oe({item:e,kind:t}){let[r,i]=(0,L.useState)(!1),a=t===`video`&&!r?T.r(e.url):null;return t===`image`&&!r?(0,R.jsx)(n.O,{src:e.url,alt:``,className:`absolute inset-0`,onError:()=>i(!0)}):t===`video`?(0,R.jsxs)(R.Fragment,{children:[a?(0,R.jsx)(n.O,{src:a,alt:``,className:`absolute inset-0`,onError:()=>i(!0)}):T.a(e.url)?(0,R.jsx)(`span`,{className:`absolute inset-0 bg-gradient-to-br from-accent/30 via-black to-black`}):(0,R.jsx)(`video`,{src:`${e.url}#t=0.5`,preload:`metadata`,muted:!0,playsInline:!0,className:`absolute inset-0 w-full h-full object-cover pointer-events-none`}),(0,R.jsx)(`span`,{className:`absolute inset-0 m-auto w-7 h-7 rounded-full bg-black/55 text-white flex items-center justify-center`,children:(0,R.jsx)(m.r,{className:`w-3.5 h-3.5 fill-current translate-x-px`})})]}):(0,R.jsx)(`span`,{className:`absolute inset-0 flex items-center justify-center`,children:(0,R.jsx)(`span`,{className:`${d.r} w-9 h-9`,children:(0,R.jsx)(d.i,{kind:t,name:e.name||e.url})})})}function ke({items:e,onChange:r,note:i=``,onNote:a,onNoteBlur:o,onBusyChange:s}){let{user:c}=n.Ft(),l=e.filter(e=>e.url),u=(0,L.useRef)(l);(0,L.useEffect)(()=>{u.current=l});let f=e=>{u.current=e,r(e)},[p,m]=(0,L.useState)({}),[h,g]=(0,L.useState)(0),[y,b]=(0,L.useState)(``),[x,S]=(0,L.useState)(!1),[C,w]=(0,L.useState)(!1),[E,D]=(0,L.useState)(``),[O,k]=(0,L.useState)(null),A=async e=>{if(!e.length||h)return;b(``),g(e.length),s?.(!0);let t=await Promise.allSettled(e.map(async e=>{let{url:t,file:r}=await n.H(e,c);return{url:t,where:``,name:r.name,type:r.type,...await n.K(r)}})),r=t.flatMap(e=>e.status===`fulfilled`?[e.value]:[]),i=t.find(e=>e.status===`rejected`);r.length&&f([...u.current,...r]),i&&b(n.z(i.reason)),g(0),s?.(!1)},j=e=>{let t=Array.from(e.target.files||[]);e.target.value=``,A(t)},{over:M,dropProps:N}=n.A({multiple:!0,disabled:!!h||C,onFiles:A}),P=async e=>{let t=new Map;await Promise.all(e.map(async e=>{if(T.u(e.url,e.type)!==`image`)return;let r=await n.J(e.url);n.G(r)&&t.set(e.url,r)})),t.size&&f(u.current.map(e=>t.has(e.url)?{...e,...t.get(e.url)}:e))},ee=e=>{let t=new Set(u.current.map(e=>e.url)),n=e.filter(e=>!t.has(e.url)).map(e=>({url:e.url,where:``,name:e.name,type:e.type,...e.size?{size:e.size}:{}}));n.length&&(f([...u.current,...n]),P(n))},F=()=>{let e=E.trim();if(!/^https?:\/\/[^\s/]+\.[^\s]+/i.test(e)){b(`Paste the whole link — it starts with https://`);return}if(l.some(t=>t.url===e)){b(`That link is already on this page.`);return}f([...l,{url:e,where:``}]),D(``),w(!1),b(``)},I=e=>{let t=p[e];if(t===void 0)return;m(t=>{let n={...t};return delete n[e],n});let n=l.find(t=>t.url===e);n&&n.where!==t.trim()&&f(l.map(n=>n.url===e?{...n,where:t.trim()}:n))};return(0,R.jsxs)(`div`,{className:`flex flex-col gap-3`,children:[l.length>0&&(0,R.jsx)(`ol`,{className:`flex flex-col gap-2`,"aria-label":`Your media`,children:l.map((e,t)=>{let r=T.u(e.url,e.type),i=e.name||T.s(e.url),a=n.X(e);return(0,R.jsxs)(`li`,{className:`flex items-center gap-3 p-2 pr-2.5 rounded-2xl border border-[var(--panel-border)]/70 bg-[var(--panel-bg)]`,children:[(0,R.jsxs)(`button`,{type:`button`,onClick:()=>k(e),"aria-label":`Open ${i}`,title:`Open it`,className:`relative w-14 h-14 sm:w-16 sm:h-16 shrink-0 rounded-xl overflow-hidden border border-[var(--panel-border)] bg-foreground/[0.03] cursor-pointer hover:border-accent/40 transition-colors`,children:[(0,R.jsx)(Oe,{item:e,kind:r}),(0,R.jsx)(`span`,{"aria-hidden":!0,className:`absolute top-1 left-1 min-w-[18px] h-[18px] px-1 rounded-full bg-background/90 text-[10.5px] font-bold text-foreground flex items-center justify-center`,children:t+1})]}),(0,R.jsxs)(`div`,{className:`flex-1 min-w-0 flex flex-col gap-1.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2 min-w-0`,children:[(0,R.jsx)(`span`,{className:`min-w-0 text-[13px] font-semibold text-foreground truncate`,title:i,children:i}),(0,R.jsxs)(`span`,{className:`max-sm:hidden sm:inline-flex items-center gap-1.5 shrink-0 text-[11px] font-medium text-foreground/50`,children:[(0,R.jsx)(`span`,{className:`w-1.5 h-1.5 rounded-full bg-accent`}),T.t[r],a?` · ${a}`:``]}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>f(l.filter((e,n)=>n!==t)),"aria-label":`Remove ${i}`,title:`Take it off this page`,className:`ml-auto w-7 h-7 shrink-0 rounded-lg flex items-center justify-center text-foreground/40 hover:text-red-500 hover:bg-red-500/10 transition-colors cursor-pointer`,children:(0,R.jsx)(v.t,{className:`w-3.5 h-3.5`})})]}),(0,R.jsx)(`input`,{type:`text`,value:p[e.url]??e.where,onChange:t=>m(n=>({...n,[e.url]:t.target.value})),onBlur:()=>I(e.url),onKeyDown:e=>{e.key===`Enter`&&e.currentTarget.blur()},placeholder:Y[r],"aria-label":`How is ${i} used?`,className:`w-full h-11 px-4 rounded-[var(--input-radius,0.75rem)] border border-[var(--panel-border)] bg-[var(--panel-bg)] text-[14px] text-foreground outline-none transition-all duration-300 placeholder:text-foreground/35 hover:border-accent/40 focus:border-accent disabled:opacity-50 disabled:cursor-not-allowed console-field !h-9 !px-3 !text-[13px]`})]})]},`${e.url}-${t}`)})}),(0,R.jsx)(`div`,{...N,className:`flex items-center gap-2 min-w-0`,children:C?(0,R.jsxs)(R.Fragment,{children:[(0,R.jsxs)(`div`,{className:`${n.l} gap-2 flex-1 min-w-0`,children:[(0,R.jsx)(_.t,{className:`w-4 h-4 text-foreground/35 shrink-0`}),(0,R.jsx)(`input`,{autoFocus:!0,value:E,onChange:e=>{D(e.target.value),y&&b(``)},onKeyDown:e=>{e.key===`Enter`&&(e.preventDefault(),F()),e.key===`Escape`&&(w(!1),D(``),b(``))},placeholder:`https://www.youtube.com/watch?v=… or any link`,"aria-label":`Paste a link`,className:`${n.f} no-glow`})]}),(0,R.jsx)(`button`,{type:`button`,onClick:F,disabled:!E.trim(),className:`btn-primary h-11 px-4 shrink-0 rounded-[var(--input-radius,0.75rem)] text-[13px] font-bold cursor-pointer disabled:opacity-40`,children:`Add`}),(0,R.jsx)(`button`,{type:`button`,onClick:()=>{w(!1),D(``),b(``)},"aria-label":`Cancel the link`,className:`${De} !px-0 w-11`,children:(0,R.jsx)(v.t,{className:`w-4 h-4`})})]}):(0,R.jsxs)(R.Fragment,{children:[(0,R.jsxs)(`label`,{className:`group/up flex-1 min-w-0 ${h?`pointer-events-none`:`cursor-pointer`}`,title:`Upload media`,children:[(0,R.jsxs)(`span`,{className:`${n.l} gap-2.5 select-none text-[14px] group-hover/up:border-accent/40 group-focus-within/up:border-accent ${M?`border-accent bg-accent/[0.04] text-accent`:h?`text-foreground/50`:`text-foreground/40`}`,children:[h?(0,R.jsx)(v.r,{className:`w-4 h-4 animate-spin text-accent shrink-0`}):(0,R.jsx)(t.v,{className:`w-4 h-4 shrink-0 ${M?`text-accent`:`text-foreground/40 group-hover/up:text-accent`}`}),(0,R.jsx)(`span`,{className:`truncate`,children:M?`Drop it here`:h?`Uploading ${h===1?`your file`:`${h} files`}…`:`Upload media, or drop it here`})]}),(0,R.jsx)(`input`,{type:`file`,multiple:!0,onChange:j,disabled:!!h,"aria-label":`Upload media`,className:`sr-only`})]}),(0,R.jsxs)(`button`,{type:`button`,onClick:()=>S(!0),title:`Pick from your assets`,"aria-label":`Pick from your assets`,className:De,children:[(0,R.jsx)(ce,{className:`w-4 h-4`}),(0,R.jsx)(`span`,{className:`max-sm:hidden`,children:`From assets`})]}),(0,R.jsxs)(`button`,{type:`button`,onClick:()=>{w(!0),b(``)},title:`Paste a link`,"aria-label":`Paste a link`,className:De,children:[(0,R.jsx)(_.t,{className:`w-4 h-4`}),(0,R.jsx)(`span`,{className:`max-sm:hidden`,children:`Link`})]})]})}),y&&(0,R.jsx)(`p`,{className:`-mt-1 px-1 text-[11.5px] font-semibold text-red-500 leading-snug`,children:y}),i.trim()!==``&&a&&(0,R.jsx)(n.y,{label:`How should the pictures be used?`,hint:`From before each item had its own line — clear it once the lines above say it.`,value:i,onChange:a,onBlur:o}),(0,R.jsx)(Ee,{open:x,onClose:()=>S(!1),onPick:ee,taken:l.map(e=>e.url)}),(0,R.jsx)(d.t,{open:!!O,onClose:()=>k(null),src:O?.url||``,name:O?.name,type:O?.type})]})}var Ae={route:`/page_1`,pageName:`New Page`,pageTitle:`My New Page`,template:`none`,form:``},je={tabName:`New Page`,iconName:``,route:`/new-page`,tabTitle:`Your Page`,template:`none`,form:``},Me={tabName:`New Admin Page`,iconName:``,route:`/new-admin-page`,tabTitle:`Admin Page`,template:`none`,form:``},Ne={tabName:`New Team Page`,iconName:``,route:`/new-team-page`,tabTitle:`Team Page`,template:`none`,form:``},Pe=(e=`c_${Date.now().toString(36)}`)=>({id:e,how:``}),Fe=e=>Array.isArray(e?.customPayments)?e.customPayments.map((e,t)=>({id:String(e?.id||`c${t}`),how:String(e?.how??``)})):[],Ie=e=>Fe(e).map(e=>({...e,how:e.how.trim()})).filter(e=>e.how!==``),Le=e=>Fe(e).some(e=>!e.how.trim())?`Say how the dynamic payment works out what to charge — or remove it.`:``,X=`At checkout they pay whatever is in their basket — every item they added, plus 5 for delivery on orders under 50.`,Re=(e=n.Fr())=>`This payment has no fixed price — the page works out what to charge. Take it with <BuyButton amount={total}${n.lr(e)} productName='…'>: total is a plain number the page works out from my words below at the moment they pay (25 is 25 in my Stripe account's currency, never under 0.50 and never over 10,000), and productName says in a few words what they are paying for. Show the buyer that amount before they press the button, and while there is nothing to pay yet say so where the button would be. An amount outside those two is refused, so say that where the button would be as well; NEVER round, cap or change the total to fit — the amount charged is always exactly the amount shown. The browser sends that amount, so it is a convenience for the buyer, never a figure anybody is held to: never tell them or me it is enforced.`;Re(null);var ze=/\b(?:baskets?|carts?|shopping bag|bag|check[- ]?out|trolley)\b/i,Be=(e,t=n.Fr())=>`This payment has no fixed price — it is whatever is in the buyer's basket, and the basket, its checkout and what happens after paying are ALL my app's own pieces from 'your-ai-workflow-firebase-os': none of it is built by hand. (1) const basket = useBasket() wherever something is added or counted, and basket.add({ id, name, options, price, picture, max }) puts a thing in — id is the record's own id, name what it is called, options the choices made, in words ('Sand, 50 ml'), price the price of ONE as a plain number, picture the web address of its main picture, max how many of it are in stock so nobody orders more than there are; any key of your own beside those (a variant's id) rides along onto the order. It opens the basket by itself, so the buyer sees the thing land. (2) <BasketButton /> is the bag with how many are in it: put it in the page's own top row, where the page begins — on a long page that row may stay in view with sticky top-0 — my menu bar scrolls away with the page, so the row rides at the very top of the screen — and never fixed or floating in a corner of the screen, where it sits over my menu bar on every page. It draws the bag itself, so put NO icon of your own inside it, only words if any (<BasketButton>View bag</BasketButton>): a bag icon inside it is two bags on one button. (3) ONE <Basket formId='${e}'${n.lr(t)} phone address /> near the top of the page is the whole of the rest: the lines with their quantity buttons and Remove, what it comes to, then who is paying and the ONE Pay button. It asks for the name, the email, the phone number and the delivery address itself (phone / address: true to require it, 'optional' to offer it, left out when my words do not ask for it), saves the order whole, and only then takes the money. Delivery or anything else my words ADD to the amount is extras={[{ label: 'Delivery', amount: 5 }]}, worked out on the page from basket.subtotal; a discount is never an extra and never a minus line — it is a Stripe promotion code the buyer types at checkout. So NEVER a basket kept in useVisitorState or in state of your own, never a basket page, a checkout page, a drawer, a window or a step of your own for it, never quantity buttons of your own, never a <Checkout>, a <BuyerDetails>, a <PayButton> or a form for it, and never a box of your own for a name, an email, a phone number or an address. The amount is exactly the lines and the extras — never rounded, capped or changed to fit; one under 0.50 or over 10,000 is refused, and the basket says so itself. Where the things in the basket come from a pub_ collection this page reads, <Basket> also names it — collection='pub_products_records' for a Products page's copy, letter for letter as this page reads it, never a name shortened — and my app then checks each line's price against that record before charging. Without it the browser sends that amount, so it is a convenience for the buyer, never a figure anybody is held to: never tell them or me it is enforced. Where no page of mine keeps them, the things this page sells and their prices are the ones my words below give: one list at the top of this page's file, const PRODUCTS = [ … ], each name and price exactly as I wrote it, and nothing added to it.`,Ve=`What happens when they come back from paying is my app's own as well: <CheckoutReturn basket='basket' orderPath='…' /> from the same package, written ONCE near the top of the page, outside the basket and any window or step. The buyer ALWAYS lands back on this page first — never set successPath — and it asks the server whether the money really moved, and only then empties the basket, thanks them and offers one button to orderPath. orderPath is the page a line further down says their order lands on, when there is one; otherwise the page of mine my words say they go to after paying (orderPath='/dashboard' for "the dashboard"); otherwise '/billing', the app's own page where what they bought is. Never read session_id off the web address, never call confirmPayment, never empty the basket yourself, and never build a thank-you, an order confirmation, a receipt or a notification of your own: my app emails the buyer their receipt and me my sale alert by itself, and the bell tells them their order is placed and tells me a payment came in — so nothing about email goes in the basket's metadata. Never send them to /login or /register, and never make anybody sign in BEFORE they pay: somebody whose email already has an account pays as a guest and is emailed their way in afterwards.`,He=(e,t=``,r)=>r?[Be(r.formId),`Here is how it works and how the amount is worked out, in my words: ${e.how.trim()}`,Ve]:[Re(),`Here is how it works and how the amount is worked out, in my words: ${e.how.trim()}`,n.Xn,n.tr,...n.ar(t)],Ue=(e,t)=>Ie(e).filter(e=>!t||!t.some(t=>t.id===e.id&&t.how===e.how)).map(e=>e.how).join(`
|
|
3
3
|
`),We=e=>e.trim()&&n.br(e)===null?`Just a number, like 25.`:void 0;function Ge({item:e,index:t,onChange:r,onRemove:i,removable:a}){let o=We(e.amount);return(0,R.jsxs)(`div`,{className:`flex flex-col gap-1`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,R.jsx)(`input`,{type:`text`,value:e.name,onChange:t=>r({...e,name:t.target.value}),placeholder:t===0?`A one-hour call`:`A two-hour call`,"aria-label":`Thing ${t+1} — its name`,className:`${n.c} flex-1 min-w-0`}),(0,R.jsx)(`input`,{type:`text`,inputMode:`decimal`,value:e.amount,onChange:t=>r({...e,amount:t.target.value}),placeholder:`25`,"aria-label":`Thing ${t+1} — its price`,className:`${n.c} w-24! shrink-0 text-right ${o?`border-red-500/50`:``}`}),a&&(0,R.jsx)(n.o,{icon:S.t,tone:`danger`,compact:!0,title:`Remove ${e.name.trim()||`thing ${t+1}`}`,onClick:i,children:`Remove`})]}),o&&(0,R.jsx)(`span`,{className:`text-[11.5px] font-semibold text-red-500 leading-snug px-1`,children:o})]})}function Ke(){let e=n.Cn();return e.loading||e.on?.emailLink===!0?null:(0,R.jsxs)(`p`,{className:n.s,children:[`A buyer gets an account when they give their details before paying. We recommend switching on`,` `,(0,R.jsx)(re.Link,{to:`/sign-in`,className:`text-accent font-semibold hover:underline`,children:`Email link, no password`}),` `,`on your Sign in screen: it is the easiest way back in on another device. Until then they sign in with Reset password.`]})}var qe=[{value:`custom`,label:`Dynamic — the page works out the amount`},{value:`once`,label:`One-time — a price you set`},{value:`subscription`,label:`Subscription — renews`}];function Je({product:e,on:t,onClick:r}){return(0,R.jsxs)(`button`,{type:`button`,role:`checkbox`,"aria-checked":t,"aria-label":n.Er(e),onClick:r,className:`w-full flex items-center gap-2.5 px-2 py-2 text-left cursor-pointer rounded-xl hover:bg-foreground/[0.04] transition-colors`,children:[(0,R.jsx)(`span`,{"aria-hidden":!0,className:`w-[18px] h-[18px] rounded-md border flex items-center justify-center shrink-0 transition-colors ${t?`bg-accent border-accent`:`border-[var(--panel-border)]`}`,children:t&&(0,R.jsx)(n.At,{className:`w-3 h-3 text-[var(--button-fg,#fff)]`})}),(0,R.jsx)(`span`,{className:`text-[13px] font-medium text-foreground/80 truncate min-w-0`,children:n.Er(e)})]})}function Ye({payment:e,label:t,onChange:r,onRemove:i,onBlur:a}){return(0,R.jsxs)(`div`,{className:`flex flex-col gap-3 rounded-2xl border border-[var(--panel-border)]/60 px-4 py-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,R.jsx)(`span`,{className:`text-[11px] font-bold uppercase tracking-widest text-foreground/40`,children:t}),(0,R.jsx)(n.o,{icon:S.t,tone:`danger`,compact:!0,title:`Remove the ${t.toLowerCase()}`,onClick:i,children:`Remove`})]}),(0,R.jsx)(n.y,{label:`How does it work, and what do they pay?`,hint:`The page works the amount out as they pay — say from what: a basket, the hours they pick, an amount they choose. Whatever you skip, your assistant decides.`,value:e.how,onChange:t=>r({...e,how:t},!1),onBlur:a,placeholder:X})]})}function Xe({pageId:e,products:t,ticked:r,team:i,custom:a,note:o,notePlaceholder:c,onToggle:l,onCreateOnce:u,onCustomChange:d,onCustomBlur:f,onNote:p,onBlur:m}){let h=(0,re.useNavigate)(),[g,_]=(0,L.useState)(!1),[y,b]=(0,L.useState)(``),[S,C]=(0,L.useState)([n.or()]),[w,T]=(0,L.useState)(!1),[E,D]=(0,L.useState)(``),O=t.filter(e=>n.wr(e));if(i)return O.length?(0,R.jsxs)(`div`,{className:`flex flex-col gap-3`,children:[(0,R.jsx)(`div`,{className:`flex flex-col rounded-2xl border border-[var(--panel-border)]/60 px-2 py-1.5`,role:`group`,"aria-label":`Payments on this page`,children:O.map(e=>(0,R.jsx)(Je,{product:e,on:r.includes(e.id),onClick:()=>l(e)},e.id))}),r.length>0&&(0,R.jsx)(n.y,{label:`What should your team see here?`,hint:`Every sale, who, what, when — laid out the way your team reads it.`,value:o,onChange:p,onBlur:m,placeholder:c})]}):(0,R.jsx)(`p`,{className:n.s,children:`Nothing sold yet — once a payment is on one of your pages, tick it here to follow its sales.`});let k=()=>{_(!1),b(``),C([n.or()]),D(``)},A=e=>{if(D(``),e===`custom`){d([...a,Pe()],!0),k();return}b(e)},j=n.Sr({...n.cr(`new`),kind:`once`,items:S}),M=async()=>{if(j||w)return;T(!0);let e=await u(S.map(e=>({name:e.name.trim(),amount:e.amount.trim()})));if(T(!1),e){D(e);return}k()},N=t.filter(e=>e.kind===`subscription`),P=N.filter(e=>n.wr(e)),ee=P.filter(e=>!r.includes(e.id)),F=N.find(e=>!n.wr(e));return(0,R.jsxs)(`div`,{className:`flex flex-col gap-3`,children:[O.length>0&&(0,R.jsx)(`div`,{className:`flex flex-col rounded-2xl border border-[var(--panel-border)]/60 px-2 py-1.5`,role:`group`,"aria-label":`Payments on this page`,children:O.map(e=>(0,R.jsx)(Je,{product:e,on:r.includes(e.id),onClick:()=>l(e)},e.id))}),(a.length>0||r.length>0)&&(0,R.jsx)(Ke,{}),a.map((e,t)=>(0,R.jsx)(Ye,{payment:e,label:a.length>1?`Dynamic payment ${t+1}`:`Dynamic payment`,onChange:(t,n)=>d(a.map(n=>n.id===e.id?t:n),n),onRemove:()=>d(a.filter(t=>t.id!==e.id),!0),onBlur:f},e.id)),g?(0,R.jsxs)(`div`,{className:`flex flex-col gap-3 rounded-2xl border border-[var(--panel-border)]/60 px-4 py-3.5`,children:[(0,R.jsxs)(`div`,{className:`flex items-center justify-between gap-3`,children:[(0,R.jsx)(`span`,{className:`text-[11px] font-bold uppercase tracking-widest text-foreground/40`,children:`A new payment`}),(0,R.jsx)(n.o,{icon:v.t,compact:!0,title:`Cancel adding a payment`,onClick:k,children:`Cancel`})]}),(0,R.jsx)(n.g,{label:`What kind of payment?`,value:y,onChange:A,options:qe,placeholder:`Choose one`}),y===`once`&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(n.i,{label:`What are you selling?`,hint:`Each thing with its price — just the number: 25 charges 25 in your Stripe account's currency. It goes on your Payments screen too.`,children:(0,R.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[S.map((e,t)=>(0,R.jsx)(Ge,{item:e,index:t,onChange:e=>C(S.map((n,r)=>r===t?e:n)),onRemove:()=>C(S.filter((e,n)=>n!==t)),removable:S.length>1},t)),(0,R.jsx)(n.o,{icon:x.t,className:`self-start`,onClick:()=>C([...S,n.or()]),children:`Add another`})]})}),(0,R.jsxs)(`div`,{className:`flex flex-wrap items-center justify-between gap-3`,children:[E?(0,R.jsx)(`span`,{className:`text-[11.5px] font-semibold text-red-500`,children:E}):(0,R.jsx)(`span`,{className:`text-[11px] sm:text-[11.5px] text-foreground/40 font-medium leading-snug`,children:j}),(0,R.jsx)(n.o,{icon:n.At,busy:w,disabled:!!j,onClick:M,children:`Create`})]})]}),y===`subscription`&&(ee.length>0?(0,R.jsx)(n.i,{label:`Which subscription?`,hint:`Pick one you have — or make another on the Payments screen.`,children:(0,R.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,R.jsx)(`div`,{className:`flex flex-col rounded-2xl border border-[var(--panel-border)]/60 px-2 py-1.5`,children:ee.map(e=>(0,R.jsx)(Je,{product:e,on:!1,onClick:()=>{l(e),k()}},e.id))}),(0,R.jsx)(n.o,{icon:s.t,className:`self-start`,onClick:()=>h(n.hr(e)),children:`Create a new subscription`})]})}):(0,R.jsxs)(`div`,{className:`flex flex-col gap-2 px-1`,children:[(0,R.jsx)(`p`,{className:`text-[11px] sm:text-[11.5px] text-foreground/40 font-medium leading-snug`,children:P.length?`Every subscription you have is already on this page.`:F?`${n.xr(F)===`this product`?`Your subscription`:n.xr(F)} is not finished yet.`:`You have no subscriptions yet.`}),F&&!P.length?(0,R.jsx)(n.o,{icon:s.t,className:`self-start`,onClick:()=>h(n.ur(F.id,e)),children:`Finish it first`}):(0,R.jsx)(n.o,{icon:s.t,className:`self-start`,onClick:()=>h(n.hr(e)),children:P.length?`Create another subscription`:`Create a subscription first`})]}))]}):(0,R.jsx)(n.o,{icon:x.t,className:`self-start`,onClick:()=>_(!0),children:`Add a payment`}),r.length>0&&(0,R.jsx)(n.y,{label:`How will paying work here?`,hint:`Where the buttons sit, what surrounds them, and what happens after they pay.`,value:o,onChange:p,onBlur:m,placeholder:c})]})}var Ze=`Whatever look I have chosen — bold or soft, playful or luxurious — make it modern and minimal, with room to breathe: generous space around and between everything, nothing crowded, squeezed together or packed edge to edge, so the screen always feels calm and uncluttered. Icons are rare: never one on every heading, button, card or list item. And bring it to life with smooth animation that suits my app, everywhere — the app’s own ready-made animations wherever it has one, never one written by hand in its place: sections and items ease in as they come into view, one after another; buttons, cards and links respond softly to hover and press; and anything that opens, closes, changes step or updates glides rather than jumps. Keep every animation quick, gentle and subtle — never bouncy, never slow, never in the way of using the page — and keep it still for anybody whose device asks for less motion.`,Qe=`Never leave an empty spot or a bare, bland section because I have not given you something yet. Where a section needs a picture I have not given you — or more pictures than I gave — draw a clean, neutral placeholder there: a soft tint of my theme in the shape the design wants there, with a simple line drawing of what belongs there in my theme’s own colours, drawn in the code itself, so the section already looks designed. And never one of my pictures a second time to fill it: each picture I gave you is drawn ONCE, in its own spot, and every other spot that wants a picture — a band, a background, a second hero — gets a placeholder, unless my words name the picture that goes there. Keep each placeholder one plain frame with only the drawing inside it — any words about it go under the frame, never inside. When I give you a picture for a placeholder, it takes that placeholder’s whole frame — same place, same size, same shape — and fills it corner to corner: the tint, the drawing and any padding inside the frame go, and the picture is never a smaller one sitting in the middle of it. The section never changes shape to suit the picture. A placeholder has no words on it, is never a photo from the internet and never a grey box with a picture icon in the middle, and it only ever stands in for a picture: products, prices, names and claims still come only from me.`,$e=`Make it effortless to use — simple, obvious and visual, step by step, with nothing asked or done twice. Count the presses it takes to do what this page is for, and take out every one that is not needed. Never ask for what the app already knows or what was given a moment ago: nobody is asked for a name or an email the app already has, what was chosen or typed on one step is carried to the next, pressing a thing opens it with THAT thing already chosen, and an only choice is already made. One press where one will do: a list narrows as I pick and type with no “Apply” button, nothing needs a “Refresh”, only a delete asks “Are you sure?”, no message waits for an “OK”, and adding several things in a row never means opening the same window again each time. Where the choices are a known few, show every one to press — pills, swatches, cards with their picture, the chosen one plainly marked — never a box to type the answer into and never a dropdown for three choices. If there is a lot to give, take me through it in short steps in the order I would think of it, with everything shown back to me before the last button; a few boxes are one simple view, never a step for every box. The main button says exactly what it does (“Add product”, never “Submit” or “OK”), a button I cannot press yet says why, an empty list carries the button that adds the first thing, and when I finish I land where the result is, looking at it. And show rather than explain: a thing is its picture and its name, a state is a small label I can see without opening anything, progress is a bar — never a paragraph of instructions.`,Z=`Make it feel alive while somebody is using it. Anything that is loading or saving says so, everywhere on the page: every list, number, card and box that reads something shows a loading state until what it reads has actually arrived — never the empty line first, which tells people there is nothing there when there is — and a button that saves goes to a working state, disabled while it runs so nobody can press it twice, then back. When something has saved, say so briefly and empty the boxes it came from, so the next one starts blank and nothing is sent twice. And never make me type anything twice: a change to something that is already there saves itself as I make it, with no Save button to hunt for, and anything I am half-way through is kept — the whole half-finished thing, every box I filled in and every picture I already added, not the last one — so clicking away and back keeps it, and RELOADING THE PAGE keeps it too. A product I was half-way through adding when the page reloaded is still there, filled in as I left it, until I send it or clear it myself. But a form I have not touched is not half-finished work: keep nothing until I have really typed something, never tell me I have an unfinished draft when I have typed nothing, and when I discard one it is gone for good — never offered back to me the next time I open the page. And if it takes me through steps, the web address says which thing I am working on and which step I am on (?product=k3f9&step=3, a question on the page’s own address and never a new address), so reloading, going back or sending somebody the link opens that same step with everything still in it. That saving happens quietly in the background and never freezes anything: the page never locks up, greys out or waits for it, nothing turns into a spinner while it saves, the box I am typing in is never disabled and never loses a letter, and a small “Saving…” that becomes “Saved” beside it is the only sign. And never write over what I have already put in: do not fill anything in with a zero or a blank of your own until you have read what is already saved, or every time I open the page you wipe the numbers I set the last time I was here. And never tell me something saved unless it really did — if the save did not go through, say so and leave what I typed on the screen.`,et=`And finish it the way a professional would, without my having to ask. Anything that opens over the page — a product’s details, a basket, a step — is the app’s own pop-up, so it closes when somebody clicks outside it, presses Escape or taps its ✕, the page behind it holds still, and it fits a phone. Everything somebody presses answers at once, right where they are looking: the app’s own brief confirmation (“Added to your bag”), the button itself saying so for a moment, and any number the press changed — how many are in the bag — kept somewhere that is always on screen; what a press did is never something they have to go and find. Loading is the app’s own loader, or soft blocks in the shape of what is coming — never a spinning character. One main button in each view and never two that do the same thing; whatever can be pressed is a real button, big enough for a thumb; no words smaller than small print. And an icon is a real icon — never an emoji, never a character like ✕, ✓ or →.`,tt=`And the hard parts are the app’s own pieces, never built by hand — each ONLY if what I asked for has it: if things are dragged between stages or into an order, it has to work under a finger on a phone, not only a mouse; if a list has columns — orders, clients, invoices — a phone shows each one as a readable block, never a table to scroll sideways; if something is done in steps, a line across the top shows where I am and a reload keeps my place; if a picture opens large, the rest of its set is a swipe away; if long writing is shown, it reads as an article, with its paragraphs kept; and every price is written by the app’s own money formatter, never a “$” typed in front of a number.`,nt=`Do not add a board, a table or a gallery to a page I did not ask it for.`,rt=`If this page keeps many things — orders, requests, clients — show them the way a professional tool does, so a dozen can be seen at once without my asking for it: each one a compact card or a single row saying only what tells it apart — its number or name, who it is for, its stage as a small label, when, how much, who has it — and pressing one opens the whole of it in the app’s own pop-up, where everything done to it is: its stage, its notes, handing it over. Where things move through stages, the people who work on them see a board of those stages; somebody who only follows their own sees theirs as a short list. Never every one drawn open, one big box under another. Inside the opened one, keep it tidy and even: the pop-up is its one frame, so its parts are set apart by space or a thin rule and never each in a bordered box of its own, nothing boxed inside a box; a clear grid, each label in small print above its value at the page’s ordinary size, one spacing throughout, boxes and buttons that sit side by side the same height, and what can be done to it — its stage, who holds it, a note — together in one place at the end rather than scattered through it; nothing on it pulses, and every word on it is mine or the entry’s, never a made-up place, carrier or name standing in for one that is missing. Do not add a gallery to a page I did not ask it for.`,it=e=>e?`${et} Open the page with its name as its heading — a page of my website gets no title from the app, so without yours nothing says what page this is. Size that heading to suit the page, never as big as it will go: on a page that is about its things — a shop, a list, a gallery — it is a calm one and the things are the show, and only a page that opens on a big picture or a band of colour carries a very large one. And give it room to breathe: clear space between the menu and the heading, at least as much as the heading is tall — never pressed up under the bar. And size a set of things for the screen it is on: two across on a phone, three or four across on a wide screen, each card small — its picture, its name, its price and at most one more line, plus the swatches or names that switch a thing that comes in colours or sizes, the rest in its pop-up — never one giant card to a row. ${tt} ${nt}`:`${et} Write no title of your own at the top — the app already draws this screen’s name. ${tt} ${rt}`,at=`This is a change to a page that is already built — not a rebuild of the page. What I ask for below is YOURS to change, as far as my words reach: if I ask for something to be redesigned, made nicer, moved or laid out differently, do it properly — its layout, its spacing, its sizes, its wording, its motion and the way the pictures in it sit are all yours there, and you are never limited to the smallest edit that would answer me. The limit is WHICH parts of the page you touch, never how much you may change them. So everything I have NOT mentioned comes back exactly as it went in: every other section, its layout and spacing, the size of its headings, its words, its animations and its pictures. Every picture already on the page is mine — never drop one, never swap one for a placeholder or a picture of your own, and keep its link exactly as it is; one inside the part I am changing may move or be resized with it, and every other one stays where it is. Do not rewrite, re-order or tidy up anything I did not mention, and hand the file back whole, never a shortened copy with parts left out.`,ot=`One last time, because it is what goes wrong most: that is the whole change — all of it, taken as far as my words reach, and nothing outside them. Everything else in the file comes back exactly as it went in — every other section, its words, every picture with its link, the same order, the same sizes, the same styling and spacing. Nothing else rewritten, nothing re-ordered, nothing removed to make room for what is new, nothing tidied up along the way. If something else looks wrong to you, leave it as it is and tell me about it in a line at the end instead of changing it. And what you add still follows every rule of my app, as the first build did: wherever the app has its own piece for the job, use it — never one you made yourself in its place.`,st=`A small change follows every rule of my app just as the first build did. If it asks somebody for an address or a phone number, that is the app’s own box for it — the address box that looks addresses up, the phone box with the country code, and on a form the form’s own address or phone question — never a plain box of your own; and any address, phone number or email shown on the page is mine, never one you made up.`,ct=`If it opens anything over the page, that is the app’s own pop-up — it closes on a click outside it, on Escape and on its ✕ — never a layer of your own; if it adds a button, pressing it answers at once where the person is looking, with the app’s own brief confirmation and never a message of your own that can end up hidden; and any icon is a real icon, never an emoji. If it adds dragging, a list with columns, steps or a price, that is the app’s own piece for it — dragging that works under a finger, a list a phone can read without scrolling sideways, the step kept in the web address, the app’s own money formatter — never one built by hand. If it is about how a list of many things is shown, each is a compact card or row that opens whole in the app’s own pop-up, with a board of the stages where they move through stages — never every one drawn open, one under another.`,lt=`A section I ask for arrives with my own word for it as its heading — “Collection section — …” or “add a collection section” is a section headed Collection, in the style of the page’s other headings. That word is mine: not an invention of yours, and not an extra nobody asked for. And design it the way the rest of the page was designed — its own shape, its own rhythm, real space round it, and motion like everything else. If it is a set of my pictures, arrange them: vary how much room each one takes, let one carry the weight, break or offset the row, and let a picture somebody can press answer the pointer — never three equal tiles side by side. Each picture still keeps its own shape and fills its own frame.`,ut=lt,dt=`Anything new you draw for this change should look as if it was always part of the page: my theme’s own styles, never colours of your own; the app’s own Button and SectionHeading, and — only if the change needs a dropdown — its CustomSelect, never the browser’s <select>; nothing I did not ask for — no extra section, icon, line, frame or box; real and working, with nothing invented and nothing shown twice to fill space; as easy to use as the rest — never asking for anything the app already knows or that was given a moment ago, one press where one will do, and a button that says exactly what it does; saying so while it loads or saves — a loading state on anything it reads, an edit to something already there saving itself quietly in the background, never freezing the page or the box being typed in, and anything half-finished kept through a reload; and with the same room to breathe and the same smooth, subtle animation as the rest of the page. ${lt} ${ct} ${st}`,ft=e=>e?`${dt} A new section keeps the side padding the others have (px-4 md:px-8 at the least), and where it needs a picture I have not given you, draw a clean placeholder in my theme’s colours rather than leaving it bare.`:`${dt} It stays inside the main container the page already has, within the menu’s width.`,pt=`If a picture above is for a placeholder that is on the page now, it takes that placeholder’s WHOLE frame — same place, same size, same shape — and fills it corner to corner, cropped at the edges where it must be. The placeholder’s tint, drawing, grid and inner padding all go, so nothing shows between the picture and the edge of the frame; any words that sat inside the frame go right under it. Never a smaller picture sitting in the middle of the frame, never fit="contain" for a photo, and the section never changes shape to suit the picture. The one exception is a tile in a gallery, a portfolio or a grid of products: there the tile takes its own picture’s shape — the two numbers in its brackets as width and height on <Picture> — so the whole picture fills it with nothing cut off.`,mt=/\b(?:basket|cart|checkout|check[- ]out page|thank[- ]you page|confirmation page|(?:new|another|separate|second|extra|more|own|each|every)\s+pages?|pages?\s+(?:of (?:its|their) own|for each|each))\b/i,ht=e=>mt.test(String(e||``)),gt=e=>/\bhero\b|\bbanner\b|first screen/i.test(String(e||``)),_t={inbox:`admin`,users:`admin`,signin:`admin`,pages:`admin`,schedule:`internal`,mybookings:``,billing:``,payments:`admin`,transactions:`admin`,email:`admin`,ai:`admin`,forms:`admin`,theme:`admin`,assets:`admin`,publish:`admin`},vt=(e,t)=>{let r=_t[e];return r?r===`internal`?`${n.qr(`internal`,t)} + ${n.qr(`admin`,t)}`:n.qr(r,t):e===`mybookings`?`Anyone who has booked`:e===`billing`?`Anyone who has bought`:``},yt=`Who can see this tab`,bt=`Needs the rules pasted from /setup at 1.14.49 or later.`,xt=`Your team and roles of your own only — never everybody who signs up.`,St={inbox:`They read every message that comes in. Archiving and deleting stay with your admins.`,users:`They see everybody who signed up and what they answered. Changing a role, switching somebody off and deleting stay with your admins.`,transactions:`They see every payment and what the buyer told you. Deleting one stays with your admins.`},Ct=(e,t)=>k.s(t)?`${St[e]} ${bt}`:`Admins always see it. ${xt}`,wt=e=>[...[`internal`,`admin`].map(t=>({value:t,label:n.qr(t,e)})),...e.map(e=>({value:e.id,label:e.name}))],Tt=(e,t)=>{let r=e.filter(e=>e!==`admin`&&e!==`user`).map(e=>e===`internal`?`my team`:`everyone marked ${n.qr(e,t)}`);return r.length>1?`${r.slice(0,-1).join(`, `)} and ${r[r.length-1]}`:r[0]||``},Et={inbox:`A count at the top of how many entries came in this week, and from which form.`,users:`A line at the top saying how many people signed up this month.`,schedule:`A note for the team at the top: we close at 3pm on Fridays in August.`,mybookings:`Our cancellation policy at the top: cancel up to a day before at no charge.`,assets:`A note at the top: logos go here, and every file is named after its client.`},Dt=`Make it one line instead of three, and link it to the contact page.`,Ot={inbox:`which only my admins open`,users:`which only my admins open`,schedule:`which my whole team opens`,mybookings:`where each signed-in person sees the meetings they have booked`,assets:`which only my admins open`},kt={inbox:`An admin reads every collection in the app, so your file may read whatever it needs — but never write to user_submissions, user_requests or user_profiles from it, and never change how the tab itself lists, archives or deletes an entry: that part is the app’s.`,users:`An admin reads every collection in the app, so your file may read whatever it needs — but never write to user_profiles from it: a person’s role and whether they are switched off are set by the tab itself, and only there.`,schedule:`The team reads mem_ collections, but hours and bookings come only from the package: useTeamHours() for the week each person keeps, useBookings() for what is booked, and never mem_bookings, pub_bookings, sys_schedules or sys_bookingpages read or written by hand.`,mybookings:`Every signed-in person opens this tab, and the pasted rules let such a person read only pub_ collections and their own user_ records — nothing in mem_, admin_, user_profiles or another person’s records. A file that reads any of those shows every member a permission error instead of what you wrote, and a permission error is never an empty list. The meetings the tab already lists are theirs; your file draws above them and reads only what a member may read.`,assets:`An admin reads every collection in the app, so your file may read whatever it needs — but files are put up and removed by the tab itself: never write to pub_files or upload from your file.`},At=e=>k.s(e)?[...e.filter(e=>e!==`admin`),`admin`]:[],jt=(e,t)=>{let r=n.qr(e,t);return e===`admin`&&r===n.Vr.admin?`You and your admins`:r},Mt={internal:`See the count of what came in this week, and nothing about who sent it.`,admin:`Everything you add — and only we see the breakdown by form.`,role:`See only the note at the top about how fast we answer.`},Q=e=>Mt[a.Dn(e)?`role`:e===`admin`?`admin`:`internal`],Nt=(e,t)=>{let n={};for(let r of At(t)){let t=String(e?.canDo?.[r]??``).trim();t&&(n[r]=t)}return n},Pt=(e,t)=>{let r=n.qr(e,t);return e===`internal`?r===n.Vr.internal?`My team`:r:e===`admin`?r===n.Vr.admin?`Me and my admins`:r:`The people I have marked ${r}`},Ft=(e,t,n)=>{let r=t?Nt(e,t):{},i=Object.keys(r);return i.length?[`What each of them gets in what you add, in my own words — draw each group exactly what its line gives it and nothing its line leaves out, telling them apart with userRole from useAuth(). This is about YOUR file only: what the tab itself lets anybody do is the app’s, and nothing here lets your file write anything:`,...i.map(e=>`${Pt(e,n)}: ${r[e]}`)]:[]},It=e=>e in F.t,Lt=e=>F.t[e].split(`_`).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(``)+`Content`,Rt=`Make it match the rest of my app: style with the app’s own theme styles so it looks right in light and dark, and do not pick your own colors. Build it from the app’s own pieces — import { SectionHeading, Card, Button } from 'your-ai-workflow-firebase-os'. Put it in a main container of its own like the ones on my other tabs (glass-panel border border-[var(--panel-border)] rounded-3xl) and design freely inside it — what it holds is yours, having one is what makes it look like part of my app rather than words lying on the background. Do not add a dropdown, a filter, a picker or a switch I did not ask for, and keep everything readable: nothing light on light or dark on dark.`,zt=`Anything I have not decided — the words, the layout, what goes in a box — decide yourself and build it finished; do not stop to ask me.`,Bt={inbox:`the Inbox’s own two collections, user_submissions and user_requests`,users:`user_profiles`},Vt={inbox:`Never write to user_submissions, user_requests or user_profiles from it, and never change how the tab itself lists, archives or deletes an entry: that part is the app’s.`,users:`Never write to user_profiles from it: a person’s role and whether they are switched off are set by the tab itself, and only there.`},Ht=(e,t,n)=>k.r(e)&&t&&k.s(t)?`which my admins open, and ${Tt(t,n)} too — they only read it`:Ot[e],Ut=(e,t,n)=>k.r(e)&&t&&k.s(t)&&Bt[e]?`My admins read every collection in the app, but ${Tt(t,n)} open this tab too, and the pasted rules let them read only ${Bt[e]}, pub_ collections and their own user_ records — so your file reads only those. Anything more shows them a permission error instead of what you wrote, and a permission error is never an empty list. ${Vt[e]}`:kt[e],Wt=(e,t,n,i)=>{let a=r.n[e],o=Lt(e),s=`src/your-ai-workflow-firebase-os/microcomponents/${o}.tsx`,c=`import ${o} from './${o}'; and registerMicrocomponent('${F.t[e]}', ${o});`,l=String(t?.words||``).trim(),u=!!t?.sent;return[`My app already has the ${a.label} tab at ${a.path}, ${Ht(e,n,i)} — it comes with the app. Do not create a page, a web address or a settings file, do not touch src/App.tsx, and do not edit any other file except what this request asks for by name below.`,u?`What is added to that tab is one file: ${s}. Change that file. If it is not there, write it with a default export and add two lines to src/your-ai-workflow-firebase-os/microcomponents/registry.ts: ${c} — never remove another page's lines from that file.`:`Add to it by writing one file: ${s}, with a default export. Then add two lines to src/your-ai-workflow-firebase-os/microcomponents/registry.ts so the app loads your file: ${c} — registerMicrocomponent is imported there from 'your-ai-workflow-firebase-os'. Never remove another page's lines from that file.`,u?`The app draws that file on the ${a.label} tab under its heading and its menu, above everything the tab already shows — all of which is the app's and stays exactly as it is.`:`The app draws that file on the ${a.label} tab under its heading and its menu, above everything the tab already shows. The heading, the menu and what the tab already shows are the app's and stay exactly as they are — do not rebuild, repeat or restyle any of them, and write no page heading, menu or page wrapper of your own. Keep everything inside the menu's width and fill it: your container starts and ends exactly where the menu above it does, never a narrow strip down the middle, no max-w-* with mx-auto wrapped around it, nothing wider than the menu, nothing fixed to the screen.`,Ut(e,n,i),...Ft(t,k.r(e)?n:void 0,i),...u?[at,ft(!1)]:[Rt,$e,Z,Ze,it(!1),zt],`Here is what I would like ${u?`changed`:`added`}: ${l||`___`}`,...u?[ot]:[]].join(`
|
|
4
4
|
`)},Gt=`fbos_swr_tab_briefs`,Kt=()=>{try{let e=localStorage.getItem(Gt);return e?JSON.parse(e):{}}catch{return{}}};function qt({hiddenIds:e,onToggleHidden:i,order:a,onMove:s}){let[c,l]=(0,L.useState)(Kt),u=O.l(),{access:d,live:m}=r.a(),g=r.u(),[_,v]=(0,L.useState)(``),[y,x]=(0,L.useState)(null),[S,C]=(0,L.useState)({}),[w,T]=(0,L.useState)(null);(0,L.useEffect)(()=>(0,z.onSnapshot)((0,z.doc)(n.ui,`sys_configs`,`tab_briefs`),e=>{let t=e.exists()?e.data():{};l(t);try{localStorage.setItem(Gt,JSON.stringify(t))}catch{}},e=>{console.warn(`tab_briefs snapshot error:`,e)}),[]);let E=(0,L.useRef)(new Set);(0,L.useEffect)(()=>{if(m)for(let e of k.l(d))E.current.has(e)||(E.current.add(e),r.i(e,k.o(d,e)).catch(e=>console.warn(`tab_access could not be cleaned:`,e)))},[d,m]);let D=(e,t)=>{let r={...c[e],...t};l(t=>({...t,[e]:r})),(0,z.setDoc)((0,z.doc)(n.ui,`sys_configs`,`tab_briefs`),{[e]:r},{merge:!0}).catch(e=>console.warn(`tab_briefs write failed:`,e))},A=(e,t)=>{let n=c[e];D(e,{words:t,sent:Date.now(),copied:{sent:n?.copied?n.copied.sent:n?.sent??0}}),T(t=>t===e?null:t)},j=e=>{c[e]?.copied&&(C(t=>({...t,[e]:``})),D(e,{words:``,copied:null})),T(e)},M=(e,t)=>{if(t===`admin`)return;let i=k.o(d,e),a=i.includes(t)?i.filter(e=>e!==t):[...i,t];x(null),r.i(e,a).catch(t=>x({id:e,words:n.ii(t,`That could not be saved. Try again.`)}))},N=(e,t)=>(0,R.jsx)(`div`,{className:t?`w-full min-w-0`:`shrink-0 min-w-0 max-w-[14rem]`,onClick:e=>e.stopPropagation(),children:(0,R.jsx)(n.Z,{multiple:!0,compact:!t,dense:!!t,portal:!0,direction:`auto`,className:`console-select`,label:t,ariaLabel:yt,values:k.o(d,e),options:wt(u),onChange:t=>M(e,t)})});return(0,R.jsx)(n.nt.div,{initial:{opacity:0,y:10},animate:{opacity:1,y:0},className:`flex flex-col relative`,children:(0,R.jsx)(n.m,{icon:ue,title:`System tabs`,description:`The tabs that come with the app — reorder or hide them, press an icon to change it, add to some, and pick who else sees Inbox, Users and Transactions.`,children:(0,R.jsx)(`div`,{className:`flex flex-col gap-4`,children:a.map((l,m)=>{let x=r.n[l],E=e.has(l),O=It(l),M=k.r(l),P=O||M,ee=P&&w===l,F=O&&c[l]?.copied||null,I=F?F.sent:c[l]?.sent,te=O&&!!I,ne=O&&!!c[l]?.sent&&(!ee||!!F),L=O?S[l]??c[l]?.words??``:``,z=O&&M?At(k.o(d,l)):[],ie=e=>S[`${l}:${e}`]??c[l]?.canDo?.[e]??``,ae=Object.fromEntries(z.map(e=>[e,ie(e)]));return(0,R.jsxs)(`div`,{id:`tab-${l}`,onClick:()=>{P&&T(ee?null:l)},className:`group flex flex-col p-3.5 sm:py-4 sm:px-5 glass-panel border transition-all rounded-2xl hover:shadow-sm ${P?`cursor-pointer hover:border-accent/40`:``} ${E?`opacity-60 bg-foreground/[0.01] border-[var(--panel-border)]/50`:`border-transparent hover:border-[var(--panel-border)]`}`,children:[(0,R.jsxs)(`div`,{className:`flex items-center justify-between w-full gap-2 sm:gap-3`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2.5 flex-1 min-w-0`,children:[(0,R.jsx)(t.l,{tone:`accent`,name:g[l],glyph:x.icon,label:`Change the icon for ${x.label}`,open:_===l,onClick:e=>{e.stopPropagation(),v(_===l?``:l)}}),(0,R.jsx)(`h3`,{className:`text-[14.5px] font-bold text-foreground tracking-tight truncate`,children:x.label}),!M&&(0,R.jsx)(`span`,{className:`max-sm:hidden text-[12px] font-medium text-foreground/45 truncate`,children:vt(l,u)})]}),(0,R.jsxs)(`div`,{className:`flex items-center gap-1 sm:gap-2 shrink-0`,children:[(0,R.jsx)(n.d,{label:x.label,canUp:m>0,canDown:m<a.length-1,onMove:e=>s(l,e)}),M&&!ee&&(0,R.jsx)(`div`,{className:`max-sm:hidden min-w-0`,children:N(l)}),ne&&(0,R.jsx)(n.o,{icon:b.t,compact:!0,title:`Change the ${x.label} tab`,onClick:e=>{e.stopPropagation(),j(l)},children:`Edit`}),(0,R.jsx)(n.C,{to:x.path,title:`View the ${x.label} tab`,children:`View tab`}),(0,R.jsx)(n.o,{icon:E?p.t:f.t,compact:!0,title:E?`Show this tab`:`Hide this tab`,onClick:e=>{e.stopPropagation(),i(l)},children:E?`Show`:`Hide`}),P?(0,R.jsx)(`div`,{className:`p-1.5 transition-transform duration-300 text-foreground/40 shrink-0 ${ee?`rotate-180`:``}`,children:(0,R.jsx)(o.t,{className:`w-3.5 h-3.5`})}):(0,R.jsx)(`div`,{className:`w-[24px] shrink-0`})]})]}),_===l&&(0,R.jsx)(`div`,{className:`mt-3`,onClick:e=>e.stopPropagation(),children:(0,R.jsx)(t.s,{label:`${x.label} is drawn as`,hint:`Type a word — anything close comes up. It changes in the dashboard menu at once.`,value:g[l],onPick:e=>{v(``),r.l(l,e).catch(e=>console.warn(`tab_icons write failed:`,e))},resetLabel:g[l]?`Use the icon it came with`:void 0,resetTitle:`Go back to the icon ${x.label} came with`,onReset:g[l]?()=>{v(``),r.l(l,``).catch(e=>console.warn(`tab_icons write failed:`,e))}:void 0})}),(0,R.jsx)(n.rt,{children:ee&&(0,R.jsxs)(n.nt.div,{initial:{height:0,opacity:0},animate:{height:`auto`,opacity:1},exit:{height:0,opacity:0},transition:n.w,className:`overflow-hidden mt-4 pt-4 border-t border-[var(--panel-border)]/50 pb-1 flex flex-col gap-4`,onClick:e=>e.stopPropagation(),children:[M&&(0,R.jsxs)(`div`,{className:`flex flex-col gap-1.5`,children:[N(l,`Who can see this tab`),(0,R.jsx)(`span`,{className:`text-[11px] sm:text-[11.5px] text-foreground/40 font-medium leading-snug ml-1 ${k.s(k.o(d,l))?``:`max-sm:hidden`}`,children:Ct(l,k.o(d,l))}),y?.id===l&&(0,R.jsx)(h.t,{tone:`error`,children:y.words})]}),z.length>0&&(0,R.jsxs)(`div`,{className:`flex flex-col gap-3`,children:[(0,R.jsxs)(`div`,{className:`flex flex-col gap-0.5 ml-1`,children:[(0,R.jsx)(`span`,{className:`text-[13px] font-bold text-foreground tracking-tight`,children:`Who can do what`}),(0,R.jsx)(`span`,{className:`text-[11px] sm:text-[11.5px] text-foreground/40 font-medium leading-snug max-sm:hidden`,children:`Optional — what each of them gets in what you add below. The tab itself is the same for everybody: they read it, your admins change it.`})]}),z.map(e=>(0,R.jsx)(n.y,{label:jt(e,u),value:ie(e),placeholder:Q(e),onChange:t=>C(n=>({...n,[`${l}:${e}`]:t})),onBlur:()=>{ie(e)!==(c[l]?.canDo?.[e]??``)&&D(l,{canDo:{...c[l]?.canDo||{},[e]:ie(e)}})}},e))]}),O&&(0,R.jsxs)(R.Fragment,{children:[(0,R.jsx)(re.Link,{to:x.path,className:`w-fit text-[12px] font-medium text-foreground/45 underline decoration-foreground/20 underline-offset-2 hover:text-accent hover:decoration-accent transition-colors`,title:`Open this tab`,children:x.path}),(0,R.jsx)(n.y,{label:te?`What would you like changed on this tab?`:`What would you like to add to this tab?`,value:L,placeholder:te?Dt:Et[l],onChange:e=>C(t=>({...t,[l]:e})),onBlur:()=>{L!==(c[l]?.words??``)&&D(l,{words:L})}}),(0,R.jsx)(t.o,{compact:!0,title:te?`Change what is on the ${x.label} tab`:`Add to the ${x.label} tab`,description:F?`Copied — paste it into your assistant’s chat. Press Edit to change the tab after that.`:void 0,prompt:Wt(l,{...c[l],sent:I,words:L,canDo:ae},M?k.o(d,l):void 0,u),locked:!L.trim(),onCopied:()=>A(l,L)})]})]})})]},l)})})})})}var Jt=new Set(`login.register.reset-password.verify.confirm-email.two-step.your-details.payment-complete.payment-cancelled.guide.templates.drive.users.sign-in.inbox.payments.transactions.schedule.my-calendar.my-bookings.email.submissions.requests.calendar.bookings.book.booking.assets.theme.pages.forms.settings.profile.billing.dashboard.setup.publish`.split(`.`)),Yt=e=>Jt.has(String(e||``).replace(/^\/+/,``).split(`/`)[0].toLowerCase()),Xt=new Set([`calendar`,`bookings`,`book`,`booking`]),Zt=e=>{let t=String(e||``).replace(/^\/+/,``),n=t.split(`/`)[0].toLowerCase();return Xt.has(n)?`The app keeps /${t} for a screen coming in a later version.`:Yt(t)?`The app already uses /${t} for a screen of its own.`:`Another page already lives at /${t}.`},Qt=`fbos_pages_held_saves`,$t=()=>{try{let e=localStorage.getItem(Qt),t=e?JSON.parse(e):{};return t&&typeof t==`object`?t:{}}catch{return{}}},en=e=>{try{Object.keys(e).length?localStorage.setItem(Qt,JSON.stringify(e)):localStorage.removeItem(Qt)}catch{}},tn=0;function nn(e,t){let n=`${Date.now()}-${++tn}`,r=$t();return r[e]={token:n,at:Date.now(),val:t},en(r),n}function rn(e,t){let n=$t();n[e]?.token===t&&(delete n[e],en(n))}function an(e,t){return $t()[e]?.token===t}function on(e){let t=$t();e in t&&(delete t[e],en(t))}function sn(e=Date.now()){let t=$t(),n={},r=!1;for(let[i,a]of Object.entries(t)){if(!a||typeof a.val!=`object`||!a.val||!(e-a.at<=2592e5)){delete t[i],r=!0;continue}n[i]=a.val}return r&&en(t),n}var cn=e=>`system:${e}`,ln=[`pub_files/pages`,`pub_form_uploads/pages`],un=e=>String(e??``).toLowerCase().replace(/[^a-z0-9]+/g,`_`).replace(/^_+|_+$/g,``);function dn(e,t,n=``){let r=[e?.recordsKey,e?.tabName,e?.pageName,e?.title,e?.pageId,e?.contentKey,n,String(e?.route??``).replace(/^\/+/,``),t];return[...new Set(r.map(un).filter(Boolean))]}function fn(e,t){if(e===`public`)return[`pub_`];let n=a.Rn(t);return[a.mn.admin,a.mn.internal,a.mn.user,a.pn,...n?[`role_${n}_`]:[]]}function pn(e,t){let n=new Set(t.flatMap(e=>dn(e.config,e.id,e.fileId))),r=dn(e.config,e.id,e.fileId).filter(e=>!n.has(e)),i=[];for(let t of fn(e.type,e.config)){let e=`${t}files`;for(let n of r)i.push({collection:`${t}${n}_records`,folders:[e,...ln],assets:t===`case_`?``:e}),t===`case_`&&i.push({collection:`${t}${n}_entries`,folders:[e,...ln],assets:``})}return i}var mn=e=>[...new Set([e.id,e.fileId,String(e.config?.contentKey||``).trim()].filter(Boolean))],hn=(e,t)=>t.includes(String(e??``).trim()),gn=(e,t)=>[...e.map(e=>({path:a.U(e.id),id:e.id,kind:`link`,title:a.Vt(e)})),...t.map(e=>({path:M.l(e.id),id:e.id,kind:`page`,title:M.s(e)}))],_n=[],vn=e=>{_n=e},yn=()=>_n,bn=e=>(Array.isArray(e?.bookingLinks)?e.bookingLinks:[]).filter(e=>typeof e==`string`).map(e=>e.trim()).filter(Boolean),xn=e=>String(e?.bookingLinksNote||``).trim(),Sn=(e,t=yn())=>bn(e).map(e=>t.find(t=>t.path===e)).filter(e=>!!e),Cn=`Never build a calendar, a time picker, a list of free times, a booking form or a schedule question because of one of those links, and never make a bookings collection of your own — the page each one opens already does all of that, inside my app. What the link says and where it sits on the page are yours to decide from my words. If my words ask for it to open in a pop-up, a panel or a window of its own rather than as a page, show that same address inside an overlay on this page — an <iframe> of it filling a dialog, with a close button — and still build no part of the booking yourself.`;function wn(e,t=yn(),n){let r=Sn(e,t).filter(e=>!n||n.includes(e.path));if(!r.length)return[];let i=r.map(e=>e.kind===`link`?`Put a link on this page to ${e.title} — my app's own booking page for that meeting, at ${e.path}. Link to that exact address with bookingPath('${e.id}') from 'your-ai-workflow-firebase-os'; it opens the booking page my app already has and the visitor books there.`:`Put a link on this page to ${e.title} — the booking page I made on my Schedule screen, at ${e.path}, which offers every meeting on it. Link to that exact address with meetPath('${e.id}') from 'your-ai-workflow-firebase-os'; it opens the page my app already has and the visitor books there.`);i.push(Cn);let a=xn(e);return a&&i.push(`Here is where those links should sit on this page and how they should open: ${a}`),i}var Tn=(e,t=yn())=>{let n=t.find(t=>t.path===e);return`This page no longer links to ${n?n.title:`the booking page`} at ${e} — take that link off the page, and leave the booking page itself as it is.`},En=e=>(e||``).split(/[^a-zA-Z0-9]+/).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()).join(``),Dn=`loading`,On=e=>{Dn=e},kn=()=>Dn,An=()=>Dn===`ready`||Dn===`practice`,jn=`loading`,Mn=e=>{jn=e},Nn=()=>jn,Pn=()=>jn===`ready`,Fn=[{id:`home`,title:`Home`,path:`/`,type:`public`,isSystem:!0,enabled:!0},{id:`contact`,title:`Contact`,path:`/contact`,type:`public`,isSystem:!0,enabled:!0},{id:`dashboard`,title:`Dashboard`,path:`/dashboard`,type:`user`,isSystem:!0,enabled:!0},{id:`support`,title:`Support`,path:`/support`,type:`user`,isSystem:!0,enabled:!0},{id:`profile`,title:`Profile`,path:`/profile`,type:`user`,isSystem:!0,enabled:!0}],In=new Set([`home`,`dashboard`,`profile`]),Ln=e=>[...e.filter(e=>!e.isSystem||Fn.some(t=>t.id===e.id)),...Fn.filter(t=>!e.some(e=>e.id===t.id))],Rn=(e,t)=>e===`public`?`Anyone`:n.qr(e,t);n.Vr.user,n.Vr.internal,n.Vr.admin;var zn={public:`Website Pages`,tabs:`Tabs`},Bn=e=>[`user`,`internal`,`admin`].map(t=>({value:t,label:Rn(t,e)})),Vn=e=>a.Gn(e).map(e=>`${n.qr(e)} is \`${e}\``).join(`, `),Hn=(e,t)=>{let n=j.n(e);return[`Every entry on this page is SENT to people, and only they see it. Its records go in collections whose names begin ${t} — ${`${j.t(e,t)}, ${t}${n}_notes`}, whatever this page needs — and every record there carries two lists of its own: access, who may see it, and editors, who may change it, delete it or send it on. My security rules read both on every single request, so an entry really is invisible to anybody not on its list — not hidden from them, invisible.`,`A name on a list is built for me: forPerson(uid) for one person, forRole('${a.Gn(e).filter(a.Dn)[0]||`internal`}') for everybody marked with a role, both imported from 'your-ai-workflow-firebase-os'. Use them and never write a key by hand. The roles on this page, by the id each one is: ${Vn(e)}.`,`Read them with const { loading, records, error } = useCases('${j.t(e,t)}') from the same package — the entries are records, under that name and no other, so a list read under any other name is empty for ever — which hands each person exactly the entries sent to them, live — a plain query on one of these collections is refused for everybody but my admins, so never call getDocs or onSnapshot on one. The person who adds an entry is always on both of its lists. Who ELSE it goes to, at once or when somebody presses a button, comes from my words: "send it to X" is sendTo(collection, id, { roles: ['x'] }), ASSIGNING it to one person — who holds it, who works on it — is my app's own <HandOver entry={entry} collection={…} /> and never a picker of yours, letting one more person SEE it is sendTo(collection, id, { people: [uid] }) with the person picked from usePeople('x'), and "they can see it but not change it" is sendTo(..., { canEdit: false }). Taking it back is takeBack(collection, id, ...). Never a second copy of a record kept somewhere else.`,...j.s(String(e?.template??``))?[]:[`Changing an entry — its stage, its notes, who holds it — is actions.updateRecord(id, change): my app hands your content file actions bound to that same ${j.t(e,t)}. actions.records is the very list useCases gives you, await actions.saveRecord(record) adds an entry with its author on both lists and answers its id, actions.deleteRecord(id) deletes one and its files, and updateRecord also writes who made the change and when, so the entry can say so. Never updateDoc, setDoc or deleteDoc an entry by hand; sendTo and takeBack are the only other things that touch one.`],`What one group must never see is never a field on a record they can read — whoever may read a record reads every field of it — so it is its OWN record, with its own two lists. Two people who may both change one entry cannot be told apart by my rules: give them different buttons where my words give them different jobs, and say so rather than pretending it is a wall. Files uploaded through the app’s upload box follow the record they are saved on, so whoever may open the entry may open its files and nobody else can.`,`Everything somebody ADDS to an entry — a note, a tick, a file put up through the app’s upload box — is a change to that entry, so it only works for somebody on its editors list: my rules refuse the write and refuse the upload for anybody who is only on access, and a page that draws an upload box for them shows an error every time. So where my words say a group both looks at an entry and puts something on it, they go on as editors (sendTo with canEdit left alone) and the buttons they must not have are simply not drawn for them. canEdit: false is for somebody who only ever reads. If what they add must be theirs alone rather than a change to somebody else’s entry, it is an entry of its own, added by them, with its own two lists.`]},Un=(e,t)=>{let n=j.t(e,t),r=a.Gn(e).filter(e=>e===`internal`||a.Dn(e)),i=a.Gn(e).filter(a.Dn)[0]||`internal`;return[`What somebody makes on this page is THEIRS, and they publish it when they are ready. Its records go in collections whose names begin ${t} — ${n}, whatever this page needs — and every record there carries two lists of its own: access, who may see it, and editors, who may change it or delete it. My security rules read both on every single request, so a thing nobody has published yet is invisible to everybody but the person who made it — not hidden from them, invisible.`,`Publishing it is one call: publish('${n}', id), and unpublish('${n}', id) takes it back down again — both imported from 'your-ai-workflow-firebase-os', and isPublished(record) is how you know which it is. Nothing moves and nothing is copied: it is the same record with the same id, which is why an edit after it goes out is just an edit and taking it down leaves no copy behind. Never write the word everyone into a list yourself, and never put it on editors — my rules refuse that outright, because on editors it would mean anybody signed in may rewrite or delete anybody's.`,`Published means everybody SIGNED IN — including people who cannot open this page. It never means the open internet: somebody with no account sees none of it. So do not build a pub_ copy of any of this, and do not say "public" anywhere a person can read it.`,`There are three reads and no others. What the person reading made themselves, drafts and published alike: const { loading, records, error } = useCases('${n}', { mine: true }). Everything anybody has published: const { loading, records, error } = usePublished('${n}'). ONE of them by its id: const { loading, record, error } = useCase('${n}', id) — record, singular, on that one. Those names and no others: a list read under any other name is empty for ever. Never call getDocs, onSnapshot or a query of your own on one of these collections — my rules refuse a plain query for everybody but my admins, and a refusal is never an empty list.`,`A published thing stays its author’s: only they may change it, take it down or delete it, and my rules keep that rather than the page. Draw Edit, Publish, Unpublish and Delete only where canEdit(record) says so — on somebody else’s they give an error and nothing else. Everything else about it is the same for everyone looking.`,`Anything published needs somewhere to BE, or it cannot be sent to anybody: show one on this same page at ?thing=<id> — my addresses are matched whole, so never a path of its own — read it there with useCase, and give the person who made it a button that copies that link. A link to something unpublished answers "this one has not been shared with you", which is a sentence to show as it is rather than a page saying nothing is there.`,r.length?`Handing one to a PERSON instead of to everybody still works and is worth building where my words ask for it: sendTo('${n}', id, { people: [uid] }) with the person picked from usePeople('${i}'), { canEdit: false } for somebody who may only look, takeBack(...) to take it off them again. It works on a draft as well as on a published one.`:`Publishing is the whole of how a thing reaches anybody here: the people on this page cannot list one another, so never build a picker of people, a way to send one to somebody by name, or anything that asks who somebody wants to share it with. Theirs, or everybody’s.`,`Pictures and files put up through the app’s upload box follow the record, so a published thing’s photographs open for everybody and an unpublished one’s for nobody but its author.`]},Wn=e=>j.s(String(e?.template??``))?[]:[`The list this page is ABOUT is handed to its code and is never named there: my app hands the content file actions — actions.records is that list, live, already from this page’s own collection; await actions.saveRecord(record) adds one and answers the new record’s id; actions.updateRecord(id, change) changes one; actions.deleteRecord(id) deletes it and its files. Those are the page’s only reads and writes of its own records: never write the collection’s name out, never open a listener or a query on it, never pass a collection to saveRecord, and never call useCases for it — useCases reads only a page whose entries are SENT to people, and given anything else it reads nothing at all, so the page stays empty however much is saved. Any OTHER collection this page keeps beside its records is the one place a name of mine is written out.`],Gn=e=>{if(!e?.pageType)return[];let t=a.Gn(e),r=t.filter(a.Dn),i=r.map(e=>n.qr(e)).join(` or `),o=a.Rn(e),s=a.Mn(e),c=a.Pn(e)===`shared`,l=[`${r.length?t.includes(`user`)?`This page is for the people I have marked ${i} as well as everybody else who signs in.`:t.includes(`internal`)?`This page is for the people I have marked ${i} and for my team, and for nobody else who signs in.`:`This page is only for the people I have marked ${i}: the app turns everybody else away at the address itself.`:a.jn(e.pageType)===`admin`?`This page is for me and my admins alone.`:a.jn(e.pageType)===`internal`?`This page is for my team${t.includes(`admin`)?` and my admins`:``}, and for nobody else who signs in.`:`This page is for everybody who signs in.`} The app decides who may open it — never write a guard, a redirect or a sign-in check of your own on it.`];return a.Pn(e)===`case`?(l.push(...Hn(e,s)),l):a.Pn(e)===`publish`?(l.push(...Un(e,s)),l):c?(l.push(o?`Whatever everybody marked ${i} SHARES on this page — one list they all read, add to and edit — goes in collections whose names begin role_${o}_: role_${o}_projects, role_${o}_notes, whatever it needs. My security rules open those to the people marked ${i}, to my admins, and to nobody else, and every one of them reads and writes the SAME records there.`:`Everybody who can open this page SHARES what is on it: its records go in collections whose names begin ${s} — ${s}jobs, ${s}notes, whatever this page needs — which my security rules open to ${s===`admin_`?`me and my admins`:`my team and my admins`} and to nobody else. All of them read, add to and edit the SAME records there, so build one list and not a copy each.`),s!==`admin_`&&l.push(o?`Whatever belongs to ONE of them and the others must not see — their own documents, their own answers, the files they upload for themselves — stays in the ordinary user_ collections instead, where each person only ever reads the records that carry their own uid, and their uploads go with them. Nothing anybody marked ${i} has to read may sit in a mem_, admin_ or pub_ collection: mem_ and admin_ answer them with a permission error, and pub_ is the open internet.`:`Whatever belongs to ONE of them and the others must not see — their own documents, their own answers, the files they upload for themselves — stays in the ordinary user_ collections instead, where each person only ever reads the records that carry their own uid, and their uploads go with them. Only my admins read everybody’s.`),l.push(...Wn(e)),l):(l.push(`Nothing on this page is shared. Every record it keeps belongs to ONE person and lives in the ordinary user_ collections, with that person’s own uid on every document — my security rules then hand each of them their own and nobody else’s, and every file they upload through the app’s upload box goes to their own folder the same way. Never build a list everybody here shares, and never keep anything this page holds anywhere my team, my admins or a role of mine would read it: two people on the same page see two different lists, and a query that reaches for somebody else’s records is refused, not empty. Only my admins read everybody’s.`),l.push(...Wn(e)),!o&&r.length&&l.push(`There is no space the people marked ${i} could share with anybody else on this list — my rules open no collection to two audiences at once, short of pub_, which is the open internet. If what I described needs ONE list they all share, say so and tell me the page has to be kept for that one role, on its own, and set to a shared page.`),l)},Kn=e=>e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`),qn=e=>{let t=e.map(e=>String(e.name||``).trim()).filter(Boolean).map(Kn);return[{key:`admin`,re:/\b(admins?|administrators?|only i|only me|just me|myself|nobody but me)\b/gi},{key:`team`,re:/\b(my team|the team|our team|team members?|teammates?|staff|colleagues?|internal(?: users?| members?| people| staff)?)\b/gi},...t.length?[{key:`role`,re:RegExp(`\\b(${t.join(`|`)})s?\\b`,`gi`)}]:[],{key:`named`,re:/\b(clients?|customers?|suppliers?|vendors?|partners?|patients?|students?|tenants?|contractors?|subscribers?)\b/gi},{key:`guest`,re:/\b(guests?|visitors?|the public|anyone not signed in)\b/gi},{key:`member`,re:/\b(members?|free users?|signed[- ]in (?:users?|people|visitors?))\b/gi}]},Jn=(e,t=n.Kr())=>{let r=` ${String(e||``)} `,i=[];for(let e of qn(t)){let t=r;r=r.replace(e.re,` `),r!==t&&i.push(e.key)}return i},Yn=/\b(only|cannot|can not|can'?t|must not|should ?n[o’']?t|not allowed|no access|hidden from|kept from|never sees?|does ?n[o’']?t see|do not see|read[ -]only|view only)\b/i,Xn=/[^.!?;\n]+/g,Zn=(e,t=n.Kr())=>{let r=String(e||``);return r.trim()?Jn(r,t).length>1?!0:(r.match(Xn)||[]).some(e=>Jn(e,t).length>0&&Yn.test(e)):!1},Qn=/\b(assign(?:ed|s|ing|ment|ments)?|allocated|responsible for|each of (?:my|our|the) (?:team|staff|people|users)|their own records?)\b/i,$n=`Then show each person only the sections that are theirs: read const { userRole } = useAuth() from 'your-ai-workflow-firebase-os' — 'admin' is one of my admins, 'internal' is my team, a role of my own arrives as that role's own plain word, and anything else is an ordinary member. Leave a section OUT of the page for somebody it is not for rather than rendering it: a section that reads a collection that person may not read answers with a permission error, and a permission error is never an empty list — never draw it as “nothing here yet”.`,er=`Only the groups my words actually name, and only INSIDE the page: never invent a group or a role word of your own, never add a check for anybody I did not mention, and never guard the page itself, redirect anyone or test whether they are signed in — who may open this page is my app’s decision and it is already made.`,tr=`Anything one group must not see is its OWN document in one of those collections, never a field sitting beside what they do see: whoever may read a document reads every field of it. And where my words say a group may look at something without changing it, or may remove a record without editing it, build them exactly those buttons and leave the others out of their view.`,nr=[`Where my words say somebody sees only what is assigned to them, that is not a uid on a record and not a query — it is who the entry was sent to. Handing one to ONE person is my app’s own piece and nothing of yours: <HandOver entry={entry} collection={…} role='<their role>' name={…} />, imported from 'your-ai-workflow-firebase-os' — collection is the case_ collection the entry is kept in, role the group my words hand it to, name what that entry is called (“Ticket 42”) for the bell. It shows who holds the entry by their picture and their name, and for whoever may hand it over it is the picker of those people: picking one hands it over there and then, takes whoever had it off, keeps who holds it on the entry and rings them. Draw it on each entry’s card (compact) and inside the opened entry (label='Assigned to').`,`WHO gets that picker is my words’ to say: a group whose own line gives it the assigning, the handing over or the passing on gets <HandOver> as it is, and every other group gets <HandOver readOnly … /> — who holds it, and nothing to press. A group my words only hand entries TO is never given the picker. Never a picker, an Assign button, a usePeople, a notify() or a sendTo to one person of your own for this, and never who holds it written on the entry by hand. Sending an entry to a whole ROLE is still sendTo(collection, id, { roles: ['x'] }), and takeBack takes it back.`],rr=[`Where my words say each of my team sees only what is assigned to them, those records go in a user_ collection with the assignee’s own uid on every document — my rules then show each of them their own and nobody else’s, and a colleague cannot so much as list them. Read them back with a query on that uid, never by fetching the collection and filtering afterwards.`,`Handing a record to somebody else is an ADMIN’s doing: only an admin may write a document carrying another person’s uid, so put the assigning where an admin does it, and never build a team member a button that assigns a record to a colleague — it answers with a permission error.`],ir=/\b(?:only|just)\s+(?:sees?|views?|gets?|shows?|lists?)\b[^.\n]{0,80}\bassigned\b|\b(?:sees?|views?|gets?|shows?|lists?)\s+only\b[^.\n]{0,80}\bassigned\b/i,ar=(e,t,r=String(t?.brief||``),i=!1)=>{if(!Ra(e,t))return[];let o=a.jn(t?.pageType);if(o===`admin`||sr(t).length<2)return[];let s=n.Kr();if(!i&&!Zn(r,s))return[];let c=a.Pn(t),l=c===`shared`,u=c===`case`,d=c===`publish`,f=l&&o===`internal`,p=f?``:l?a.Rn(t):``,m=p?n.qr(p,s):``,h=p?`what everybody marked ${m} shares in role_${p}_ collections and what belongs to one of them in user_ collections, as above, and — the third space — what only my admins may ever see, in admin_ collections`:`${f?`what my whole team works on stays in mem_ collections, `:``}what only my admins may ever see goes in admin_ collections, and what belongs to ONE person alone goes in user_ collections with that person’s own uid on every document`,g=d?[`What I say about this page gives different people different things on it. Build that by WHOSE each thing is and whether it has been published, before anything else — never a second collection, and never a section merely hidden in the code. The person who made a thing is the only one who can change it or take it down, published or not; everybody signed in sees it once it is out, and nobody at all before.`,`Where my words let one group put things up and another only browse, that is the buttons each group is drawn — say so as a button rather than as a wall, because anybody signed in may add one of their own and my rules cannot tell two of them apart. What really is kept apart is whose a thing is and whether it is published, and both of those my rules hold by themselves.`,`My admins read every document in these collections, so where my words give my admins the whole lot — everybody’s drafts included — it is the same hook without the filter, never a second copy of the records kept somewhere else.`]:u?[`What I say about this page gives different people different things on it. Build that by WHO EACH ENTRY IS SENT TO, before anything else — the two lists on the record, never a second collection and never a check in the code. An entry that one group must not see is simply not on their list, so they cannot read it at all; a group who may look and not touch goes on access and not on editors. Work out from my words which of them an entry starts with and who it goes to next, and build the button that sends it on.`,`My admins read every document in every one of these collections, so where my words give my admins the whole lot it is the list they already get from the same hook — never a second copy of the records kept somewhere else, and never a list on the page that everybody can read.`]:l?[`What I say about this page gives different people different things to see on it. Build that by WHERE each thing is kept, before anything else: ${h}. My security rules hold those apart by themselves, so a thing kept in the right place is really kept from everybody else — a section merely hidden in the code is not kept from anybody, because the database is still open to them.`,`My admins read every document in all of those collections, so where my words give my admins the whole list it is the same query with nobody’s uid on it — never a second copy of the records kept somewhere else.`]:[`What I say about this page gives different people different things on it, and this is a private page: every record on it is one person’s own, in a user_ collection carrying their uid, and there is nowhere else on this page to put anything. So the difference between my groups is never one of them reading another’s records — it is what each of them may DO with their own: which sections they are shown, which of them may add, change or delete, and how much they are allowed. Build exactly that.`,`My admins read every document in the database, so where my words give my admins everybody’s records it is the same query with nobody’s uid on it, opened by this page itself on that same collection — ${j.r(t,`user_`,String(t?.pageId||``))}, the one place its name is written — only while userRole === 'admin' (anybody else is refused, not empty), while actions.records stays each person’s own — never a second copy of the records kept somewhere else, and never a collection of your own that everybody here can read.`];return l&&!f&&!p&&!a.Gn(t).some(a.Dn)&&g.push(`There is no space on this page that every member shares: a list they could all read would have to be a pub_ one, open to the whole internet. So keep to per-person records unless my words ask for something I would not mind a stranger reading.`),!f&&!u&&a.Gn(t).includes(`internal`)&&g.push(`${o===`internal`?`My team is on this page, but here`:`My team can open this page too, but on it`} they are like everybody else who signs in: each of them reads only the records that carry their own uid, never anybody else’s — only my admins read everybody’s. Where my words give my team other people’s records, build that for my admins alone and tell me my team cannot have it on this page.`),g.push($n,er,tr),Qn.test(r)&&(u||a.Gn(t).includes(`internal`))&&(u?g.push(...nr):(!l||ir.test(r))&&g.push(...rr)),p&&Jn(r,s).includes(`team`)&&g.push(`One thing this page cannot do: the people I have marked internal do not read role_${p}_ collections at all — only the people marked ${m} and my admins do. So anything my TEAM has to see belongs on a team page of its own rather than here, and on this page “my team” means my admins.`),g},or=e=>{let t=e=>e===`user`?0:e===`internal`?1:e===`admin`?3:2;return[...new Set(e)].sort((e,n)=>t(e)-t(n))},sr=e=>{let t=a.vn(e);return or(t.includes(`user`)?[...t,`admin`]:t)},cr=e=>{if(!e?.pageType)return[];let t=or(a.vn(e));return t.length>1?t:[]},lr=(e,t)=>{let r=n.qr(e,t);return e===`admin`&&r===n.Vr.admin?`You and your admins`:r},ur={user:`See and change only what they added themselves.`,internal:`See every job and move it along, but never delete one.`,admin:`Everything — and only we see what each job was charged.`,role:`See their own projects and the shared price list, and add notes — never delete anything.`},dr={user:`Raise a request and see their own, and nothing anybody else raised.`,internal:`See every issue sent to them, answer it, and pass it on to whoever it belongs to.`,admin:`Everything — and only we see what anything was charged.`,role:`Add an issue, and see only the ones they raised and any a supervisor shares with them.`},fr={user:`Browse everything that is up, and put up their own — nobody else’s is theirs to change.`,internal:`Put things up, and take down anything that should not be there.`,admin:`Everything — and only we see what has been put up but not published yet.`,role:`Put up their own listings and edit them any time; everybody else only browses.`},pr=e=>!!e?.pageType&&e?.notifications===!0,mr=e=>pr(e)&&e?.notifyEmail===!0,hr={user:`They get a notification when their job is finished.`,internal:`They get a notification when a new job comes in.`,admin:`We get a notification when a job is marked done.`,role:`They get a notification when a note is added to their project.`},gr={user:`They get a notification when somebody answers their request.`,internal:`They get a notification when an issue is sent to them.`,admin:`We get a notification when an issue is closed.`,role:`They get a notification when a supervisor sends their issue on.`},_r={user:`They get a notification when something new is published.`,internal:`They get a notification when something new is put up.`,admin:`We get a notification when a listing is taken down.`,role:`They get a notification when one of their listings is taken down.`},vr={user:`Email them a month before their contract ends.`,internal:`Email them when a job has waited two days.`,admin:`Email us a week before a contract ends.`,role:`Email them a week before their project is due.`},yr=(e,t=!1,n=!1)=>{let r=e===`publish`?fr:e===`case`?dr:ur;if(!t)return r;let i=e===`publish`?_r:e===`case`?gr:hr,a=e=>n?` ${vr[e]}`:``;return{user:`${r.user} ${i.user}${a(`user`)}`,internal:`${r.internal} ${i.internal}${a(`internal`)}`,admin:`${r.admin} ${i.admin}${a(`admin`)}`,role:`${r.role} ${i.role}${a(`role`)}`}},br=e=>!e?.pageType||cr(e).length?``:or(a.vn(e))[0]||``,xr=(e,t)=>{let r=br(e),i=r?n.qr(r,t):``;return`What notifications will ${r?r===`internal`&&i===n.Vr.internal?`your team`:r===`admin`&&i===n.Vr.admin?`you and your admins`:i:`they`} see?`},Sr={user:`When their request is answered — and tell me when a new one comes in.`,internal:`When a job is handed to them, and when one is marked done.`,admin:`When one of us adds a job, and when one is marked done.`,role:`When their project moves to the next stage — and tell me when they add a note.`},Cr=(e,t=!1)=>t?`${Sr[e]} ${vr[e]}`:Sr[e],wr=e=>pr(e)&&br(e)?String(e?.notifyWish??``).trim():``,Tr=e=>{let t=`Optional — the bell in your app tells people when something happens on this page.`;return pr(e)?cr(e).length?`${t} Say what each group is notified about in its own box below. Whatever you skip, your assistant decides.`:`${t} Whatever you skip, your assistant decides.`:t},Er=e=>{let t=e?.canDo&&typeof e.canDo==`object`?e.canDo:{},n={};for(let r of[...cr(e)].sort()){let e=String(t[r]??``).trim();e&&(n[r]=e)}return n},Dr=e=>{let t=n.qr(e);return e===`user`?`${t} (everybody who signs in)`:e===`internal`?t===n.Vr.internal?`My team`:t:e===`admin`?t===n.Vr.admin?`Me and my admins`:t:`The people I have marked ${t}`},Or=`What each of them may do on this page, in my own words — build each group exactly the sections, and the add, change and delete buttons, its line gives it. A group I say nothing about here is yours to decide:`,kr=`What each of them may do on this page has changed. This is the whole of it now, in place of what I said before — build each group exactly the sections, and the add, change and delete buttons, its line gives it:`,Ar=(e,t=Or)=>{let n=Er(e),r=cr(e).filter(e=>n[e]);return r.length?[t,...r.map(e=>`${Dr(e)}: ${n[e]}`)]:[]},jr=`Only me and my admins may delete anything on this page. My app enforces it — every record saved through actions.saveRecord carries a lock, and my database refuses everybody else’s delete whatever the page shows — so draw a Delete button only where actions.canDelete(record) is true, and never decide it from a role yourself. Where it is false there is no button at all: not greyed, not explained. Changing a record is not deleting it — everybody who could change one still can.`,Mr=`From now on ${jr.charAt(0).toLowerCase()}${jr.slice(1)} Change nothing else.`,Nr=`Anybody who can change a record on this page may delete it again — my app has lifted the lock. Draw Delete wherever actions.canDelete(record) is true, which it now is for everybody who can change one, and change nothing else.`,Pr=`Nothing on this page may be deleted — not by me, not by my admins, not by anybody. My app enforces it: every record saved through actions.saveRecord carries a lock my database honours. So never draw a Delete, a Remove, a bin or any other way of throwing a record away here — actions.canDelete(record) is false for everybody on this page, and you never decide it from a role yourself. Changing a record is not deleting it — everybody who could change one still can.`,Fr=`From now on nothing on this page may be deleted — not by me, not by my admins, not by anybody. My app has locked every record: take away every Delete, Remove and bin this page has, and never draw one again. Changing a record is not deleting it — everybody who could change one still can. Change nothing else.`,Ir=/\b(?:delet(?:e|es|ed|ing)|remov(?:e|es|ed|ing)|throw(?:n|s)? (?:it |them |one )?away|discard(?:s|ed)?|eras(?:e|es|ed)|bin (?:it|them|one))\b/i,Lr=e=>{let t=P.o(e),n=[`admin`,`all`,`none`,``].includes(e?.deleteBy),r=[e?.brief,...Object.values(Er(e)||{})].join(`
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require(`./chunk-CiTBaPhY.cjs`),require(`./TimeZoneField-Ckn1pKAL.cjs`);const e=require(`./PagesAdmin-1U73GM_o.cjs`);exports.PagesAdmin=e.gt;
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { a as e, c as t, n, o as r, r as i, s as a, t as o, u as s } from "./mediaKind-BtaMpGy8.js";
|
|
2
|
-
import { _ as c, l, o as u, s as d, t as f, u as p, v as m } from "./PageTitle-
|
|
2
|
+
import { _ as c, l, o as u, s as d, t as f, u as p, v as m } from "./PageTitle-CkZriz8K.js";
|
|
3
3
|
import { $n as h, A as g, At as _, C as v, Cn as y, Dn as b, Dr as x, Dt as S, Er as C, F as w, Fr as T, Ft as E, G as ee, H as D, J as te, K as O, Kr as k, M as A, Mr as j, Mt as ne, Nr as M, O as N, Or as re, Qn as ie, Rr as ae, S as oe, Sr as se, Tr as ce, Vr as le, X as ue, Xn as de, Z as fe, Zn as P, Zr as pe, _r as F, ar as I, b as me, br as he, c as ge, cr as _e, d as ve, er as ye, f as be, fi as xe, fr as Se, g as Ce, hr as we, i as L, ii as Te, jr as Ee, jt as De, kr as Oe, l as R, li as ke, lr as Ae, m as je, mr as Me, nr as Ne, nt as Pe, o as z, or as Fe, p as Ie, q as Le, qr as B, rr as Re, rt as ze, s as Be, tr as Ve, ui as V, ur as He, vr as Ue, w as We, wr as H, x as Ge, xr as Ke, y as qe, z as Je, zn as Ye } from "./TimeZoneField-oIMwb5_X.js";
|
|
4
|
-
import { N as Xe, a as Ze, b as Qe, i as $e, l as et, n as tt, t as nt, u as rt, v as it, x as at, y as ot } from "./DashboardNav-
|
|
4
|
+
import { N as Xe, a as Ze, b as Qe, i as $e, l as et, n as tt, t as nt, u as rt, v as it, x as at, y as ot } from "./DashboardNav-CxS3Qnl-.js";
|
|
5
5
|
import { a as st, s as ct } from "./Trouble-CtFq7tjk.js";
|
|
6
6
|
import { $t as lt, Ct as ut, Dn as U, En as dt, Gn as W, Hn as ft, J as pt, Mn as G, Nn as mt, Ot as ht, Pn as K, Rn as gt, U as _t, V as vt, Vn as yt, Vt as bt, Wn as xt, _n as St, bt as Ct, en as wt, gn as Tt, jn as Et, kt as Dt, lt as Ot, mn as kt, pn as At, tn as jt, vn as Mt, vt as Nt, xn as Pt, yt as Ft } from "./schedule-C13m_kiO.js";
|
|
7
7
|
import { n as It, t as Lt } from "./chevron-down--LwXEv9w.js";
|
|
8
8
|
import { t as Rt } from "./arrow-right-C6OLl8Zh.js";
|
|
9
9
|
import { t as zt } from "./boxes-DcQnzrdY.js";
|
|
10
10
|
import { y as Bt } from "./scheduleData-DR6A-Q7Z.js";
|
|
11
|
-
import { t as Vt } from "./SupportBar-
|
|
11
|
+
import { t as Vt } from "./SupportBar-0nIiQp-_.js";
|
|
12
12
|
import { i as Ht, r as Ut, t as Wt } from "./FileViewerPopup-gqhRT22v.js";
|
|
13
13
|
import { t as Gt } from "./eye-off-CgKkn1b3.js";
|
|
14
14
|
import { t as Kt } from "./eye-DBR-sZWU.js";
|
|
15
15
|
import { n as qt, r as Jt } from "./VideoPlayer-QI1Jc3bS.js";
|
|
16
16
|
import { t as Yt } from "./FormNote-DJ9HBokL.js";
|
|
17
|
-
import { _ as Xt, a as Zt, c as Qt, d as $t, h as en, n as tn, r as nn, t as rn, u as an } from "./arrivalRoads-
|
|
17
|
+
import { _ as Xt, a as Zt, c as Qt, d as $t, h as en, n as tn, r as nn, t as rn, u as an } from "./arrivalRoads-BZ4SWRAw.js";
|
|
18
18
|
import { t as on } from "./link-2-CtDUJiNU.js";
|
|
19
19
|
import { n as sn, r as cn, t as ln } from "./x-hax8aKt8.js";
|
|
20
20
|
import { t as un } from "./lock-CeHdSreq.js";
|
|
@@ -25,19 +25,19 @@ import { t as mn } from "./user-round-BXAihGcZ.js";
|
|
|
25
25
|
import { t as hn } from "./Button-BGN6q7lY.js";
|
|
26
26
|
import { n as gn } from "./formPage-BcnATn6R.js";
|
|
27
27
|
import { a as _n } from "./email-PBHbXXgR.js";
|
|
28
|
-
import { l as vn, n as yn, o as bn } from "./roles-
|
|
28
|
+
import { l as vn, n as yn, o as bn } from "./roles-D3T8p-hA.js";
|
|
29
29
|
import { l as xn, o as Sn, r as Cn, s as wn } from "./tabAudience-DJ6H5Uth.js";
|
|
30
30
|
import { t as Tn } from "./ConfirmModal-BW9e6Y7d.js";
|
|
31
|
-
import { a as En, l as Dn, n as On, r as kn, s as An, t as jn } from "./recordsKey-
|
|
31
|
+
import { a as En, l as Dn, n as On, r as kn, s as An, t as jn } from "./recordsKey-CJL-dAYF.js";
|
|
32
32
|
import { i as Mn, l as Nn, s as Pn } from "./bookingPages-BFSY3Riv.js";
|
|
33
33
|
import { a as Fn, c as In, r as Ln, s as Rn, t as zn } from "./pageFiles-ZFPSCDZz.js";
|
|
34
34
|
import { c as Bn, i as Vn, n as Hn, o as Un, r as Wn, s as Gn, t as Kn } from "./recordLock-CMOiezNC.js";
|
|
35
35
|
import { i as qn } from "./AccessNotice-DGsp8Xfl.js";
|
|
36
36
|
import { t as Jn } from "./SystemTabContent-CMyT7mDN.js";
|
|
37
|
-
import { n as Yn } from "./SchedulePicker-
|
|
37
|
+
import { n as Yn } from "./SchedulePicker-sZIZec9L.js";
|
|
38
38
|
import { t as Xn } from "./contentKey-DEiV3vR8.js";
|
|
39
39
|
import { t as Zn } from "./NeedsService-SxEZO5Fa.js";
|
|
40
|
-
import "./ThemeAdmin-
|
|
40
|
+
import "./ThemeAdmin-C_8phTKX.js";
|
|
41
41
|
import { useCallback as Qn, useEffect as q, useMemo as $n, useRef as J, useState as Y } from "react";
|
|
42
42
|
import { Fragment as er, jsx as X, jsxs as Z } from "react/jsx-runtime";
|
|
43
43
|
import { collection as tr, deleteDoc as nr, deleteField as rr, doc as Q, getDoc as ir, getDocs as ar, limit as or, onSnapshot as sr, orderBy as cr, query as lr, setDoc as $ } from "firebase/firestore";
|