your-ai-workflow-firebase-os 2.0.8 → 2.0.9
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-Dd_96avv.js → Assets-COH4Ji57.js} +5 -5
- package/dist/{Assets-CBBNIHrw.cjs → Assets-D7fDckSi.cjs} +1 -1
- package/dist/{Attachments-C6QrTcNt.cjs → Attachments-BMuQ0CD4.cjs} +1 -1
- package/dist/{Attachments-YyjQmhBx.js → Attachments-Co1UkdWB.js} +2 -2
- package/dist/{Billing-B6f49cGH.cjs → Billing-DkuJdls5.cjs} +1 -1
- package/dist/{Billing-BZafAizg.js → Billing-kk4ZMd3z.js} +4 -4
- package/dist/{BookingCalendar-DYsA71vl.cjs → BookingCalendar-BcvJiyaq.cjs} +1 -1
- package/dist/{BookingCalendar-_xoRa2tL.js → BookingCalendar-Bej__mIs.js} +1 -1
- package/dist/{Button-DSldWACF.js → Button-BGN6q7lY.js} +1 -1
- package/dist/{Button-PyTaaoyu.cjs → Button-Ccy4wFZ1.cjs} +1 -1
- package/dist/{ConfirmModal-CQ73WYUg.cjs → ConfirmModal-BUNtss4a.cjs} +1 -1
- package/dist/{ConfirmModal-C1dM-bzk.js → ConfirmModal-BW9e6Y7d.js} +3 -3
- package/dist/{ContactPopup-D5Hh0bfE.cjs → ContactPopup-D8aSSlmS.cjs} +1 -1
- package/dist/{ContactPopup-CL4AMwK9.js → ContactPopup-Fs7wzrOX.js} +7 -7
- package/dist/{CopyLink-BnYpVy6H.cjs → CopyLink-C5lKLyOU.cjs} +1 -1
- package/dist/{CopyLink-rLr_5eNM.js → CopyLink-CNjDLzOl.js} +2 -2
- package/dist/{DashboardNav-B0G943ux.js → DashboardNav-CEd8gGPm.js} +3 -3
- package/dist/{DashboardNav-DOl9gJuu.cjs → DashboardNav-GgEUpyTa.cjs} +1 -1
- package/dist/{EmailAdmin-CWHMMybh.cjs → EmailAdmin-d_gWd48U.cjs} +1 -1
- package/dist/{EmailAdmin-humrSTzI.js → EmailAdmin-pbQ-f9Ge.js} +9 -9
- package/dist/{EventCard-CrPswwyG.js → EventCard-BSGLYD64.js} +2 -2
- package/dist/{EventCard-6eCfvOA-.cjs → EventCard-DAsGsicK.cjs} +1 -1
- package/dist/{FileViewerPopup-DQmhXMSg.cjs → FileViewerPopup-CkLUYCNo.cjs} +1 -1
- package/dist/{FileViewerPopup-Dnl3td2o.js → FileViewerPopup-gqhRT22v.js} +2 -2
- package/dist/{FormNote-BWGLs9lx.js → FormNote-DJ9HBokL.js} +1 -1
- package/dist/{FormNote-CX2rSBDB.cjs → FormNote-DP0GK9ya.cjs} +1 -1
- package/dist/{FormsAdmin-Tg20B0iA.cjs → FormsAdmin-5KTTp6zo.cjs} +1 -1
- package/dist/{FormsAdmin-CHwmKnYU.js → FormsAdmin-BNI63vEk.js} +9 -9
- package/dist/{Inbox-Cgq4MALU.js → Inbox-D9Y5K8Se.js} +9 -9
- package/dist/{Inbox-BPwIiThg.cjs → Inbox-DjslBakx.cjs} +1 -1
- package/dist/{Loader-DP_dL5qC.js → Loader-CVoz1Zf0.js} +1 -1
- package/dist/{Loader-p3eNQDUU.cjs → Loader-QHqQsXLr.cjs} +1 -1
- package/dist/{ManagePlanButton-BRW7Sevd.cjs → ManagePlanButton-Buwfs2bU.cjs} +1 -1
- package/dist/{ManagePlanButton-CNLCxK-o.js → ManagePlanButton-CE4uyh_7.js} +2 -2
- package/dist/{MyBookings-C_pqsSEk.js → MyBookings-B4DndHV6.js} +7 -7
- package/dist/{MyBookings-BC5sn_fE.cjs → MyBookings-CkEioQIj.cjs} +1 -1
- package/dist/{PageTitle-DFGW71q8.js → PageTitle-DCoUQWw6.js} +2 -2
- package/dist/{PageTitle-BWmE74WQ.cjs → PageTitle-DQkvCB11.cjs} +1 -1
- package/dist/PagesAdmin-D0qgoZtW.js +3 -0
- package/dist/{PagesAdmin-jjnDLYmF.js → PagesAdmin-DzLJWKBJ.js} +21 -21
- package/dist/PagesAdmin-KUxCI1Mr.cjs +1 -0
- package/dist/{PagesAdmin-BZZ3by92.cjs → PagesAdmin-YdYgmuEB.cjs} +1 -1
- package/dist/{PaymentsAdmin-CI0zXraR.cjs → PaymentsAdmin-B5l-f0mp.cjs} +1 -1
- package/dist/{PaymentsAdmin-DeBMmFFo.js → PaymentsAdmin-C3cEOeIs.js} +15 -15
- package/dist/{Popup-DmPEk98h.js → Popup-Bi63lzoS.js} +1 -1
- package/dist/{Popup-nq7YNM4N.cjs → Popup-COnHpbrY.cjs} +1 -1
- package/dist/{ProviderMark-DJ5mYjYn.cjs → ProviderMark--adeeajP.cjs} +1 -1
- package/dist/{ProviderMark-CAeOnBsB.js → ProviderMark-BvEMlZAm.js} +1 -1
- package/dist/{PublishApp-mMMwf_in.js → PublishApp-B9Fo6xN0.js} +7 -7
- package/dist/{PublishApp-DI96gX9b.cjs → PublishApp-Bc82Ijkq.cjs} +1 -1
- package/dist/{Said-DAD7Ctp_.js → Said-BvSRaEfZ.js} +1 -1
- package/dist/{Said-DlJOjNMN.cjs → Said-W3KFi5uX.cjs} +1 -1
- package/dist/{ScheduleAdmin-dWj_N_tf.cjs → ScheduleAdmin-Dh_hW6p4.cjs} +1 -1
- package/dist/{ScheduleAdmin-C4W8Ls0D.js → ScheduleAdmin-bk3GgxKP.js} +14 -14
- package/dist/{SchedulePicker-CwKId9JF.cjs → SchedulePicker-CN0755Ek.cjs} +1 -1
- package/dist/{SchedulePicker-BOSJEcfL.js → SchedulePicker-DO4PewPJ.js} +2 -2
- package/dist/{Setup-DcZzh6Xd.cjs → Setup-R4r6_tbV.cjs} +1 -1
- package/dist/{Setup-NOvtplUS.js → Setup-_G-s5y5Q.js} +3 -3
- package/dist/{SetupPayments-DrXK0LQa.js → SetupPayments-CkolcOtv.js} +5 -5
- package/dist/{SetupPayments-CZ0KqXdR.cjs → SetupPayments-CuFk9REC.cjs} +1 -1
- package/dist/{SignInAdmin-CwIUAJrv.cjs → SignInAdmin-B1yLLaQu.cjs} +1 -1
- package/dist/{SignInAdmin-Cb65ChHL.js → SignInAdmin-BLEn0rId.js} +9 -9
- package/dist/{SupportBar-528kXe-Z.js → SupportBar-DI_XbEsG.js} +4 -4
- package/dist/{SupportBar-CNVXSYwT.cjs → SupportBar-DLWruzQb.cjs} +1 -1
- package/dist/{SystemTabContent-EegzTuLd.cjs → SystemTabContent-BWhRHoXx.cjs} +1 -1
- package/dist/{SystemTabContent-C4azXKMs.js → SystemTabContent-CMyT7mDN.js} +2 -2
- package/dist/{TemplateDrive-XDRPkxIj.cjs → TemplateDrive-BJN-ReA_.cjs} +1 -1
- package/dist/{TemplateDrive-CfPXKMKX.js → TemplateDrive-DNBwL0oy.js} +10 -10
- package/dist/{ThemeAdmin-XLbC9fX7.js → ThemeAdmin-Cnqefrz6.js} +6 -6
- package/dist/ThemeAdmin-CoE_c5-P.cjs +1 -0
- package/dist/ThemeAdmin-DI7QaZ-0.js +2 -0
- package/dist/{ThemeAdmin-BrEozdpZ.cjs → ThemeAdmin-DkgmjW3g.cjs} +1 -1
- package/dist/TimeZoneField-Ckn1pKAL.cjs +11 -0
- package/dist/{TimeZoneField-Dv389mAe.js → TimeZoneField-oIMwb5_X.js} +119 -107
- package/dist/{TransactionsAdmin-X-NjI4NB.js → TransactionsAdmin-Brs-CEcG.js} +11 -11
- package/dist/{TransactionsAdmin-DgsG629u.cjs → TransactionsAdmin-C5wQRR1g.cjs} +1 -1
- package/dist/{Trouble-qjWYeKzC.js → Trouble-CtFq7tjk.js} +1 -1
- package/dist/{Trouble-DokPNHQZ.cjs → Trouble-KQZyf6aY.cjs} +1 -1
- package/dist/{Users-BEjl_Vjc.cjs → Users-B16L9cKI.cjs} +1 -1
- package/dist/{Users-BUGb7-Kz.js → Users-CbI4K_Le.js} +15 -15
- package/dist/{VideoPlayer-BVOkrJBR.cjs → VideoPlayer-CggwpVXH.cjs} +1 -1
- package/dist/{VideoPlayer-DB0oz6lM.js → VideoPlayer-QI1Jc3bS.js} +1 -1
- package/dist/appIcons-C90OKlV5.cjs +130 -0
- package/dist/{appIcons-CUXAX_gJ.js → appIcons-CCArfCDe.js} +761 -735
- package/dist/{arrivalRoads-BZk39p8Z.js → arrivalRoads-CGXm9Ntm.js} +0 -0
- package/dist/{arrivalRoads-CD7pt03E.cjs → arrivalRoads-Cc6AZM-d.cjs} +0 -0
- package/dist/{bookingPages-BxqkyZ-M.js → bookingPages-BFSY3Riv.js} +1 -1
- package/dist/{bookingPages-2fn9xPiA.cjs → bookingPages-Dx1ViiwW.cjs} +1 -1
- package/dist/{contentFallback-C6xLwXTs.js → contentFallback-BGGpI1Ts.js} +2 -2
- package/dist/{contentFallback-DLm_iHo9.cjs → contentFallback-DVCrIUvK.cjs} +1 -1
- package/dist/{email-DxxovRtf.js → email-PBHbXXgR.js} +1 -1
- package/dist/{email-DD48BP42.cjs → email-Sya6gl4F.cjs} +1 -1
- package/dist/lib/basket.d.ts +29 -9
- package/dist/lib/recordPrice.d.ts +1 -1
- package/dist/{notices-Cwon5Q0Y.cjs → notices-CKm9-Pqt.cjs} +1 -1
- package/dist/{notices-C4yqYzBw.js → notices-CysS7BLF.js} +1 -1
- package/dist/{ownerMail-CGmDk7aP.cjs → ownerMail-BS9SjJ2u.cjs} +1 -1
- package/dist/{ownerMail-Chzy5Ehy.js → ownerMail-DepG5-Qw.js} +2 -2
- package/dist/{pageFiles-BClshvXs.cjs → pageFiles-Cn0YQ4Ur.cjs} +1 -1
- package/dist/{pageFiles-D-GYqRgZ.js → pageFiles-ZFPSCDZz.js} +1 -1
- package/dist/{paidInFull-KuStok9_.cjs → paidInFull-CZywIs-V.cjs} +1 -1
- package/dist/{paidInFull-D14Eh0QV.js → paidInFull-mBOh9iwN.js} +1 -1
- package/dist/{paidSessions-Cr_93LGa.js → paidSessions-B8e5RHi4.js} +7 -7
- package/dist/{paidSessions-QXv7SHeb.cjs → paidSessions-D-zHC4oG.cjs} +1 -1
- package/dist/{people-D8nPPMlM.cjs → people-BwWVVLfy.cjs} +1 -1
- package/dist/{people-sk2DcHPi.js → people-Wk2opW4G.js} +1 -1
- package/dist/{publishSteps-DB1Hxr6H.js → publishSteps-Cf5pSB_H.js} +1 -1
- package/dist/{publishSteps-CaZRpC3C.cjs → publishSteps-DvWlF0p_.cjs} +1 -1
- package/dist/{recordLock-Dnz61J-_.js → recordLock-CMOiezNC.js} +1 -1
- package/dist/{recordLock-CLUp3QNh.cjs → recordLock-CiulizO1.cjs} +1 -1
- package/dist/{recordsKey-R5BjLoGQ.cjs → recordsKey-C4E2vOti.cjs} +1 -1
- package/dist/{recordsKey-DHJJWWOo.js → recordsKey-Cd216nq1.js} +2 -2
- package/dist/{registrationFields-COv8jW4n.cjs → registrationFields-DHHTptcl.cjs} +1 -1
- package/dist/{registrationFields-CeTZSerx.js → registrationFields-DdHoMPAQ.js} +1 -1
- package/dist/renderer.cjs.js +1 -1
- package/dist/renderer.es.js +1 -1
- package/dist/{roles-5juCr5sY.cjs → roles-BBDIJzox.cjs} +1 -1
- package/dist/{roles-hzcMnn_M.js → roles-DiwP6-WQ.js} +3 -3
- package/dist/{scheduleData-BpkfnBjP.cjs → scheduleData-BXjNXVHY.cjs} +1 -1
- package/dist/{scheduleData-BLCUm84s.js → scheduleData-DR6A-Q7Z.js} +1 -1
- package/dist/server.cjs.js +1 -1
- package/dist/server.es.js +1 -1
- package/dist/{serviceStatus-5sk8MPjW.js → serviceStatus-C9izcuQz.js} +2 -2
- package/dist/{serviceStatus-1pGLLilF.cjs → serviceStatus-Cde96_OO.cjs} +1 -1
- package/dist/{serviceSwitches-BWnZBooS.js → serviceSwitches-CZHwvVfP.js} +1 -1
- package/dist/{serviceSwitches-Do_pkFCu.cjs → serviceSwitches-mhJbQBrV.cjs} +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 +8 -8
- package/dist/your-ai-workflow-firebase-os.css +1 -1
- package/dist/your-ai-workflow-firebase-os.es.js +358 -316
- package/package.json +1 -1
- package/src/index.css +41 -6
- package/dist/PagesAdmin-B-XopEi9.js +0 -3
- package/dist/PagesAdmin-nL5ZltFn.cjs +0 -1
- package/dist/ThemeAdmin-CwCiTp2I.js +0 -2
- package/dist/ThemeAdmin-Db5edTYj.cjs +0 -1
- package/dist/TimeZoneField-zR8N2Fj0.cjs +0 -11
- package/dist/appIcons-BNovDw6_.cjs +0 -130
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { At as e, nt as t, rt as n } from "./TimeZoneField-
|
|
1
|
+
import { At as e, nt as t, rt as n } from "./TimeZoneField-oIMwb5_X.js";
|
|
2
2
|
import { n as r } from "./chevron-down--LwXEv9w.js";
|
|
3
3
|
import { useEffect as i, useState as a, useSyncExternalStore as o } from "react";
|
|
4
4
|
import { jsx as s, jsxs as c } from "react/jsx-runtime";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
require(`./chunk-CiTBaPhY.cjs`);const e=require(`./TimeZoneField-
|
|
1
|
+
require(`./chunk-CiTBaPhY.cjs`);const e=require(`./TimeZoneField-Ckn1pKAL.cjs`),t=require(`./chevron-down-lyDK1rfL.cjs`);let n=require(`react`),r=require(`react/jsx-runtime`),i=require(`react-dom`);var a={name:`shopping-bag`,size:24,node:[[`path`,{d:`M16 10a4 4 0 0 1-8 0`,key:`1ltviw`}],[`path`,{d:`M3.103 6.034h17.794`,key:`awc11p`}],[`path`,{d:`M3.4 5.467a2 2 0 0 0-.4 1.2V20a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6.667a2 2 0 0 0-.4-1.2l-2-2.667A2 2 0 0 0 17 2H7a2 2 0 0 0-1.6.8z`,key:`o988cm`}]]};a.node;var o=t.n(a),s=null,c=0,l=new Set,u=()=>l.forEach(e=>e()),d=e=>(l.add(e),()=>{l.delete(e)}),f=()=>s;function p(e,t={}){let n=String(e??``).trim();n&&(c+=1,s={id:c,text:n,...t},u())}function m(){s&&(s=null,u())}function h(){let t=(0,n.useSyncExternalStore)(d,f,()=>null),[a,o]=(0,n.useState)(!1);return(0,n.useEffect)(()=>{if(!t||a)return;let e=window.setTimeout(()=>{s&&s.id===t.id&&m()},Math.max(1500,t.for??3500));return()=>window.clearTimeout(e)},[t,a]),typeof document>`u`?null:(0,i.createPortal)((0,r.jsx)(`div`,{role:`status`,"aria-live":`polite`,className:`fixed inset-x-0 top-0 sm:top-auto sm:bottom-0 z-[10000] flex justify-center px-4 pt-[max(0.75rem,env(safe-area-inset-top))] sm:pt-0 sm:pb-[max(1.25rem,env(safe-area-inset-bottom))] pointer-events-none`,children:(0,r.jsx)(e.rt,{children:t&&(0,r.jsxs)(e.nt.div,{initial:{opacity:0,scale:.96},animate:{opacity:1,scale:1},exit:{opacity:0,scale:.98},transition:{duration:.22,ease:[.16,1,.3,1]},onMouseEnter:()=>o(!0),onMouseLeave:()=>o(!1),className:`pointer-events-auto max-w-full inline-flex items-center gap-3 pl-4 pr-2 py-2 rounded-full glass-popover border border-[var(--panel-border)] text-foreground`,children:[(0,r.jsx)(`span`,{className:`shrink-0 w-6 h-6 rounded-full bg-accent/15 text-accent inline-flex items-center justify-center`,children:(0,r.jsx)(e.At,{className:`w-3.5 h-3.5`,strokeWidth:3})}),(0,r.jsx)(e.nt.span,{initial:{opacity:0,y:4},animate:{opacity:1,y:0},transition:{duration:.18},className:`text-[13px] font-semibold leading-snug min-w-0 break-words py-1 pr-2`,children:t.text},t.id),t.action?(0,r.jsx)(`button`,{type:`button`,onClick:()=>{let e=t.action.onClick;m(),e()},className:`shrink-0 h-9 px-4 rounded-full bg-accent/10 hover:bg-accent/20 text-accent text-[13px] font-bold transition-colors cursor-pointer`,children:t.action.label}):null]},`said`)})}),document.body)}h.displayName=`Said`,Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return h}});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
require(`./chunk-CiTBaPhY.cjs`);const e=require(`./PageTitle-BWmE74WQ.cjs`),t=require(`./TimeZoneField-zR8N2Fj0.cjs`),n=require(`./DashboardNav-DOl9gJuu.cjs`),r=require(`./schedule-BAea6q8_.cjs`),i=require(`./chevron-down-lyDK1rfL.cjs`),a=require(`./scheduleData-BpkfnBjP.cjs`),o=require(`./BookingCalendar-DYsA71vl.cjs`),s=require(`./paidSessions-QXv7SHeb.cjs`),c=require(`./link-2-C7A-6PW6.cjs`),l=require(`./x-Ci8c5p6T.cjs`),u=require(`./plus-zsWFCu4F.cjs`),d=require(`./trash-D-CpYHCs.cjs`),f=require(`./Loader-p3eNQDUU.cjs`),p=require(`./email-DD48BP42.cjs`),m=require(`./notices-Cwon5Q0Y.cjs`),h=require(`./ConfirmModal-CQ73WYUg.cjs`),g=require(`./bookingPages-2fn9xPiA.cjs`),_=require(`./AccessNotice-BClqr7A9.cjs`),v=require(`./SystemTabContent-EegzTuLd.cjs`),y=require(`./serviceStatus-1pGLLilF.cjs`),b=require(`./NeedsService-DIF7mEHq.cjs`),x=require(`./CopyLink-BnYpVy6H.cjs`);let S=require(`react`),C=require(`react/jsx-runtime`),w=require(`firebase/firestore`),T=require(`react-router-dom`);var E=`w-[6.5rem] shrink-0`,D=`w-9 h-9 rounded-[var(--btn-radius,0.75rem)] border border-[var(--panel-border)] flex items-center justify-center shrink-0 text-foreground/45 hover:text-red-500 hover:border-red-500/40 hover:bg-red-500/[0.06] active:scale-[0.98] transition-all cursor-pointer`,O=`date-field h-9 w-[10.5rem] shrink-0 px-3 text-[13px] font-semibold bg-transparent border border-[var(--panel-border)] text-foreground focus:outline-none focus:border-accent transition-colors`,k={from:`09:00`,to:`13:00`};function A(e,t){return{upcoming:e.filter(e=>e.date>=t),past:e.filter(e=>e.date<t)}}function j({row:e,onChange:n,onRemove:i}){let a=e.windows.length===0,o=(t,r)=>n({...e,windows:e.windows.map((e,n)=>n===t?{...e,...r}:e)});return(0,C.jsxs)(`div`,{className:`flex flex-col gap-2 py-2.5`,children:[(0,C.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[(0,C.jsx)(`input`,{type:`date`,value:e.date,"aria-label":`The date`,onChange:t=>n({...e,date:t.target.value}),className:O,style:{borderRadius:`var(--input-radius, 0.75rem)`}}),(0,C.jsx)(`div`,{className:`w-[11rem] shrink-0`,children:(0,C.jsx)(t.Z,{ariaLabel:`${e.date} — how much of it`,value:a?`all`:`some`,options:[{value:`all`,label:`All day`},{value:`some`,label:`Only some hours`}],onChange:t=>n({...e,windows:t===`all`?[]:[k]}),className:`console-select`,compact:!0,dense:!0,portal:!0,direction:`auto`})}),(0,C.jsx)(`button`,{type:`button`,title:`Remove ${e.date||`this date`}`,"aria-label":`Remove ${e.date||`this date`}`,onClick:i,className:`${D} ml-auto`,children:(0,C.jsx)(l.t,{className:`w-3.5 h-3.5`})})]}),!a&&(0,C.jsxs)(`div`,{className:`flex flex-col gap-2 sm:pl-[0.125rem]`,children:[e.windows.map((i,a)=>(0,C.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,C.jsx)(`div`,{className:E,children:(0,C.jsx)(t.Z,{ariaLabel:`${e.date} from${a?` (${a+1})`:``}`,value:i.from,options:r.m,onChange:e=>o(a,{from:e}),className:`console-select`,compact:!0,portal:!0,direction:`auto`})}),(0,C.jsx)(`span`,{className:`w-3 text-center text-foreground/40 text-[13px] shrink-0 select-none`,children:`–`}),(0,C.jsx)(`div`,{className:E,children:(0,C.jsx)(t.Z,{ariaLabel:`${e.date} to${a?` (${a+1})`:``}`,value:i.to,options:r.d,onChange:e=>o(a,{to:e}),className:`console-select`,compact:!0,portal:!0,direction:`auto`})}),e.windows.length>1&&(0,C.jsx)(`button`,{type:`button`,title:`Remove these hours on ${e.date}`,"aria-label":`Remove ${e.date} hours ${a+1}`,onClick:()=>n({...e,windows:e.windows.filter((e,t)=>t!==a)}),className:D,children:(0,C.jsx)(l.t,{className:`w-3.5 h-3.5`})})]},a)),e.windows.length<2&&(0,C.jsx)(`button`,{type:`button`,onClick:()=>n({...e,windows:[...e.windows,{from:`14:00`,to:`18:00`}]}),className:`self-start h-6 px-1 text-[11.5px] font-semibold text-foreground/45 hover:text-accent transition-colors cursor-pointer`,children:`+ Add a second stretch`})]})]})}function M({blocked:e,onChange:n,now:i}){let a=r.rn(i?i():new Date),[o,s]=(0,S.useState)(!1),{upcoming:c,past:l}=A(e,a),d=o?[...l,...c]:c,f=(t,r)=>n(e.map(e=>e===t?r:e));return(0,C.jsx)(t.i,{label:`Days away`,hint:`Dates this week's hours do not apply to — a holiday, a flight, an afternoon out. Nobody can book them, on any link on these hours.`,children:(0,C.jsxs)(`div`,{className:`flex flex-col divide-y divide-[var(--panel-border)]/60 rounded-2xl border border-[var(--panel-border)]/60 px-4 py-1`,children:[d.length===0?(0,C.jsx)(`p`,{className:`${t.s} py-3`,children:`No days blocked out. Add one for a holiday or a day off.`}):d.map((t,r)=>(0,C.jsx)(j,{row:t,onChange:e=>f(t,e),onRemove:()=>n(e.filter(e=>e!==t))},`${t.date}-${r}`)),(0,C.jsxs)(`div`,{className:`flex items-center justify-between gap-3 py-2.5`,children:[(0,C.jsx)(t.o,{icon:u.t,compact:!0,title:`Add a day away`,onClick:()=>n([...e,{date:a,windows:[]}]),children:`Add a date`}),l.length>0&&(0,C.jsx)(`button`,{type:`button`,onClick:()=>s(e=>!e),className:`h-6 px-1 text-[11.5px] font-semibold text-foreground/45 hover:text-accent transition-colors cursor-pointer`,children:o?`Hide past dates`:`Show ${l.length} past date${l.length===1?``:`s`}`})]})]})})}var N=e=>r.s.find(t=>t.value===e)?.label||`Short text`;function P({options:e,onChange:n}){return(0,C.jsx)(t.i,{label:`Choices`,hint:`What people pick from.`,children:(0,C.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[e.length===0&&(0,C.jsx)(`span`,{className:`text-[11px] sm:text-[11.5px] text-foreground/40 font-medium leading-snug px-1`,children:`No choices yet — add the first one.`}),e.map((r,i)=>(0,C.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,C.jsx)(`input`,{type:`text`,value:r,"aria-label":`Choice ${i+1}`,placeholder:`e.g. At my place`,onChange:t=>n(e.map((e,n)=>n===i?t.target.value:e)),className:t.c}),(0,C.jsx)(t.o,{icon:l.t,tone:`danger`,compact:!0,title:`Remove choice ${i+1}`,onClick:()=>n(e.filter((e,t)=>t!==i)),children:`Remove`})]},i)),(0,C.jsx)(`div`,{children:(0,C.jsx)(t.o,{icon:u.t,onClick:()=>n([...e,``]),children:`Add choice`})})]})})}function F({question:e,index:n,count:a,siblings:o,fixed:s,onChange:c,onMove:l,onRemove:u}){let[f,p]=(0,S.useState)(!e.label.trim()),m=e.label.trim()||`A new question`;return(0,C.jsxs)(`div`,{className:`rounded-2xl border border-[var(--panel-border)]`,children:[(0,C.jsxs)(`div`,{className:`flex items-center gap-1.5 sm:gap-2.5 pr-2.5 sm:pr-3.5`,children:[(0,C.jsxs)(`button`,{type:`button`,onClick:()=>p(e=>!e),"aria-expanded":f,className:`flex-1 min-w-0 flex items-center justify-between gap-3 px-4 py-3.5 text-left cursor-pointer`,children:[(0,C.jsx)(`span`,{className:`text-[13px] font-semibold text-foreground/75 truncate`,children:m}),(0,C.jsxs)(`span`,{className:`flex items-center gap-2.5 shrink-0`,children:[(0,C.jsx)(`span`,{className:`${t.s} max-sm:hidden`,children:s?`Always asked`:`${N(e.type)}${e.required?` · must be answered`:``}`}),(0,C.jsx)(i.t,{className:`w-3.5 h-3.5 text-foreground/40 shrink-0 transition-transform ${f?`rotate-180`:``}`})]})]}),!s&&(0,C.jsxs)(`div`,{className:`flex items-center gap-1 sm:gap-1.5 shrink-0`,children:[(0,C.jsx)(t.o,{icon:t.jt,compact:!0,disabled:n===0,title:`Move ${m} up`,onClick:()=>l(-1),children:`Up`}),(0,C.jsx)(t.o,{icon:t.Mt,compact:!0,disabled:n===a-1,title:`Move ${m} down`,onClick:()=>l(1),children:`Down`}),(0,C.jsx)(`span`,{className:`max-sm:hidden w-px h-5 bg-[var(--panel-border)] mx-0.5`}),(0,C.jsx)(t.o,{icon:d.t,tone:`danger`,compact:!0,title:`Remove ${m}`,onClick:u,children:`Remove`})]})]}),f&&(0,C.jsxs)(`div`,{className:`px-4 pb-4 pt-4 border-t border-[var(--panel-border)]/60 flex flex-col gap-4`,children:[(0,C.jsx)(t.b,{label:`What are you asking?`,hint:s?`The words above the box. Every booking asks this one — you can only change how it is put.`:`The words above the box, as the person booking reads them.`,value:e.label,placeholder:s?`e.g. Who is coming?`:`e.g. What is your phone number?`,onChange:t=>c({...e,label:t,name:s?e.name:r.K(e,t,o)})}),!s&&(0,C.jsxs)(C.Fragment,{children:[(0,C.jsx)(t.g,{label:`Kind of answer`,hint:`Sets the box they type into. The example below follows what you pick.`,value:e.type,options:r.s,allowEmpty:!1,onChange:t=>c({...e,type:t,options:t===`select`?e.options:[],placeholder:r.W(e,t)})}),(0,C.jsx)(t.S,{label:`Must be answered`,hint:`On means they cannot book until it is filled in.`,hintWideOnly:!0,enabled:e.required,onChange:t=>c({...e,required:t})})]}),e.type===`select`&&(0,C.jsx)(P,{options:e.options,onChange:t=>c({...e,options:t})}),r.G(e.type)&&(0,C.jsx)(t.b,{label:`Example answer`,hint:e.type===`tel`?`Shown under the box — a phone box already starts with a dial code, so the example stands below it.`:`Faint grey words inside the empty box.`,value:e.placeholder,placeholder:r.o[e.type]||`e.g. +1 555 0123`,onChange:t=>c({...e,placeholder:t})})]})]})}function I({questions:e,onChange:n}){let i=e.filter(e=>r.ht(e.name)),a=e.filter(e=>!r.ht(e.name)),o=e=>n([...i,...e]);return(0,C.jsx)(t.i,{label:`What does a booking ask for?`,children:(0,C.jsxs)(`div`,{className:`flex flex-col gap-3.5`,children:[i.map(t=>(0,C.jsx)(F,{question:t,index:0,count:1,siblings:e,fixed:!0,onChange:r=>n(e.map(e=>e.name===t.name?r:e)),onMove:()=>{},onRemove:()=>{}},t.name)),a.map((t,n)=>(0,C.jsx)(F,{question:t,index:n,count:a.length,siblings:e,onChange:e=>o(a.map((t,r)=>r===n?e:t)),onMove:e=>{let t=n+e;if(t<0||t>=a.length)return;let r=[...a];[r[n],r[t]]=[r[t],r[n]],o(r)},onRemove:()=>o(a.filter((e,t)=>t!==n))},n)),(0,C.jsxs)(`div`,{className:`flex flex-col items-start sm:flex-row sm:items-center gap-3 rounded-2xl border border-dashed border-[var(--panel-border)] px-4 py-3.5`,children:[(0,C.jsx)(t.o,{icon:u.t,title:`Add a question`,onClick:()=>o([...a,r.j()]),children:`Add a question`}),a.length===0&&(0,C.jsx)(`p`,{className:`text-[11px] sm:text-[11.5px] text-foreground/40 font-medium leading-snug`,children:`Nothing else is asked — just a name and an email.`})]})]})})}var L=(e,t,n=72)=>e>=n&&e<=Math.max(n,t*.45);function R(e,t=340){if(!e)return null;let n=()=>{let t=e.getBoundingClientRect?.(),n=typeof window<`u`&&window.innerHeight||0;t&&n&&L(t.top,n)||e.scrollIntoView?.({behavior:`smooth`,block:`start`})};return typeof setTimeout==`function`?setTimeout(n,t):(n(),null)}function z(e,t,n){let r=(0,S.useRef)(new Set);(0,S.useEffect)(()=>{let i=new Set(e),a=[...r.current].filter(e=>!i.has(e)&&!n.current.has(e));e.forEach(e=>r.current.add(e)),a.length&&(a.forEach(e=>r.current.delete(e)),t(e=>{if(!a.some(t=>t in e))return e;let t={...e};for(let e of a)delete t[e];return t}))},[e.join(`\0`)])}var B=`__new_payment__`;function V(){let[e,n]=(0,S.useState)([]);return(0,S.useEffect)(()=>{let e=t.Zr(t.Qn,()=>(0,w.collection)(t.ui,t.Qn),e=>{let r=[];e.forEach(e=>{e.id!==`_settings`&&r.push(t.Dr(e.id,e.data()))}),n(r.filter(e=>e.kind===`once`).sort((e,t)=>(e.createdAt||0)-(t.createdAt||0)))},()=>n([]));return()=>e()},[]),e}function H({value:e,products:n,meetingName:r,canCreate:i,onChange:a,onCreate:o}){let[s,c]=(0,S.useState)(!1),[l,d]=(0,S.useState)(``),[f,p]=(0,S.useState)(``),[m,h]=(0,S.useState)(!1),g=[...n.map(e=>({value:e.id,label:`${t.xr(e)} — ${t.gr(e).map(e=>e.amount).filter(Boolean).join(` + `)||`no price yet`}`})),...i?[{value:B,label:`+ A new one-time payment`}]:[]],_=n.find(t=>t.id===e),v=l.trim()&&t.br(l)===null?`Just a number, like 25.`:void 0;return(0,C.jsxs)(`div`,{className:`flex flex-col gap-3`,children:[(0,C.jsx)(t.g,{label:`Payment for this meeting`,hint:_?`Taken on the booking page before the time is confirmed. Its price and its link are on the Payments screen.`:i?`Optional. A one-time payment taken on the booking page before the time is confirmed.`:n.length?`Optional. One of the payments your admin set up, taken on the booking page before the time is confirmed.`:`Your admin has not set up a payment to charge for a meeting yet.`,value:s?B:e,placeholder:`No payment`,options:g,onChange:e=>{if(e===`__new_payment__`){c(!0);return}c(!1),a(e)}}),s&&(0,C.jsxs)(`div`,{className:`rounded-2xl border border-[var(--panel-border)]/60 px-4 py-3.5 flex flex-col gap-3`,children:[(0,C.jsx)(t.b,{label:`The price`,hint:`Just the number — 25 charges 25 in your Stripe account's currency. The payment is called ${r} and appears on the Payments screen too.`,value:l,onChange:e=>{d(e),f&&p(``)},placeholder:`25`,error:f||v}),(0,C.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,C.jsx)(t.o,{icon:u.t,busy:m,onClick:async()=>{if(t.br(l)===null){p(`Just a number for the price, like 25.`);return}p(``),h(!0);let e=await o(r,l.trim());if(h(!1),e){p(e);return}c(!1),d(``)},children:`Create it`}),(0,C.jsx)(t.o,{onClick:()=>{c(!1),p(``),d(``)},children:`Never mind`})]})]})]})}function U({link:e,onChange:n}){return(0,C.jsx)(t.i,{label:`Emails about bookings`,hint:`Sent the moment a time is taken. Every booking is in your Inbox and on the calendar regardless.`,children:(0,C.jsxs)(`div`,{className:`flex flex-col gap-3 rounded-2xl border border-[var(--panel-border)]/60 px-4 py-3.5`,children:[(0,C.jsx)(t.S,{label:`Email me when someone books`,hint:`A note at your address — the sale alert, when they paid.`,hintWideOnly:!0,enabled:e.notifyOwner,onChange:e=>n({notifyOwner:e})}),(0,C.jsx)(t.S,{label:`Email them a confirmation`,hint:`Their receipt when they pay. For a free booking, a note that the time is theirs — to people who book signed in.`,hintWideOnly:!0,enabled:e.confirmBooker,onChange:e=>n({confirmBooker:e})})]})})}var ee=e=>{let t={...a.I(a.H(),e),createdAt:Date.now()};return{...t,name:r.O(t),description:r.D(t)}};function te({link:e,schedules:n,products:i,services:o,isAdmin:s=!0,onChange:c,onCreatePayment:l}){let u=n.find(t=>t.id===e.scheduleId),d=t=>c({...e,...t}),f=a.z(e,u),p=u?a.L(e,u):null,m=t=>{let n={...e,...t};return{...t,...e.name.trim()===r.O(e)?{name:r.O(n)}:{},...e.description.trim()===r.D(e)?{description:r.D(n)}:{}}};return(0,C.jsxs)(C.Fragment,{children:[(0,C.jsx)(t.g,{label:`Which hours is it booked in?`,hint:`Change the hours and every meeting booked in them changes with it — one holiday, entered once, closes them all.`,value:e.scheduleId,options:n.map(e=>({value:e.id,label:r.ut(e)})),allowEmpty:!1,onChange:t=>{let r=n.find(e=>e.id===t);if(!r)return;let i=!u||e.memberName.trim()===u.memberName.trim();d(m({scheduleId:r.id,memberId:r.memberId,...i?{memberName:r.memberName}:{}}))}}),(0,C.jsx)(t.b,{label:`What is it called?`,hint:`Visitors read this on the booking page. It starts named after its length — call it whatever you like. Left blank it goes back to ${r.O(e)}.`,value:e.name,onChange:e=>d({name:e}),placeholder:r.O(e)}),(0,C.jsx)(t.y,{label:`A line or two about it`,hint:`Visitors read it under the name — what it is for, what to bring, what happens after. Emptied, the booking page simply shows none.`,value:e.description,onChange:e=>d({description:e}),placeholder:`A first conversation about what you need and how I can help.`}),(0,C.jsx)(t.b,{label:`The name visitors see`,value:e.memberName,onChange:e=>d(m({memberName:e})),placeholder:`Anna`}),(0,C.jsx)(t.g,{label:`How long is one booking?`,value:String(e.slotMinutes),options:r.b,allowEmpty:!1,onChange:e=>d(m({slotMinutes:Number(e)}))}),(0,C.jsx)(t.g,{label:`How far ahead can people book?`,value:String(e.horizonDays),options:r.h,allowEmpty:!1,onChange:e=>d({horizonDays:Number(e)})}),(0,C.jsx)(t.g,{label:`How much notice do you need?`,value:String(e.noticeHours),options:r._,allowEmpty:!1,onChange:e=>d({noticeHours:Number(e)})}),(0,C.jsx)(I,{questions:e.questions,onChange:e=>d({questions:e})}),(0,C.jsx)(b.t,{service:`payments`,readiness:b.n(o.payments),children:(0,C.jsx)(H,{value:e.paymentId,products:i,meetingName:a.V(e),canCreate:s,onChange:e=>d({paymentId:e}),onCreate:async(e,t)=>{let n=await l(e,t);return n&&n.startsWith(`p_`)?(d({paymentId:n}),null):n||`The payment could not be made — make sure you are signed in as an admin and try again.`}})}),(0,C.jsx)(b.t,{service:`email`,readiness:b.n(o.email),children:(0,C.jsx)(U,{link:e,onChange:d})}),(0,C.jsx)(t.i,{label:`Booking link`,hint:p&&!f&&e.enabled?`Send it to anyone. They see the free times in their own time zone, pick one and book — and pay first, when a payment is attached.`:`The link opens once the meeting is complete and turned on.`,children:(0,C.jsx)(x.t,{title:a.V(e),path:r.U(e.id)})}),(0,C.jsx)(`div`,{className:`pt-1`,children:f?e.enabled?(0,C.jsxs)(`span`,{className:`text-[11.5px] font-semibold text-amber-500`,children:[`Turned on, but not bookable yet — `,f]}):(0,C.jsx)(`span`,{className:t.s,children:f}):e.enabled?(0,C.jsx)(`span`,{className:`text-[11.5px] font-semibold text-emerald-500`,children:`Bookable — send the link, pick it on a page under Booking on this page, or add a Pick-a-time question to a form.`}):(0,C.jsx)(`span`,{className:t.s,children:`Complete — flip the switch at the top of the row to offer it.`})})]})}function W({link:e,schedules:n,products:r,services:o,isAdmin:s=!0,open:c,fresh:l,error:u,onToggle:f,onChange:p,onRemove:m,onCreatePayment:g}){let _=n.find(t=>t.id===e.scheduleId),v=a.R(e,_),[y,b]=(0,S.useState)(!1),x=a.V(e),w=(0,S.useRef)(null);return(0,S.useEffect)(()=>{if(!l)return;let e=R(w.current);return()=>{e&&clearTimeout(e)}},[l]),(0,C.jsxs)(`div`,{ref:w,className:`scroll-mt-4 rounded-2xl border border-[var(--panel-border)]`,children:[(0,C.jsxs)(`div`,{className:`flex items-center gap-2 sm:gap-2.5 pr-3`,children:[(0,C.jsxs)(`button`,{type:`button`,onClick:f,"aria-expanded":c,className:`flex-1 min-w-0 flex items-center justify-between gap-3 px-4 py-3 text-left cursor-pointer`,children:[(0,C.jsx)(`span`,{className:`text-[13px] font-semibold text-foreground/75 truncate`,children:a.B(e,_)}),(0,C.jsxs)(`span`,{className:`flex items-center gap-2.5 shrink-0`,children:[(0,C.jsx)(`span`,{className:`max-sm:hidden`,children:(0,C.jsx)(t._,{state:v.state,label:v.label})}),(0,C.jsx)(i.t,{className:`w-3.5 h-3.5 text-foreground/40 shrink-0 transition-transform ${c?`rotate-180`:``}`})]})]}),(0,C.jsx)(t.x,{enabled:e.enabled,onChange:t=>p({...e,enabled:t}),label:`${x} — can be booked`}),(0,C.jsx)(t.o,{icon:d.t,tone:`danger`,compact:!0,title:`Remove ${x}`,onClick:()=>b(!0),children:`Remove`})]}),(0,C.jsx)(h.t,{isOpen:y,title:`Remove ${x}?`,message:`Its booking link stops working and it leaves every page and form it was picked on. The hours it was booked in stay, and so do the bookings already taken.`,confirmText:`Yes, remove`,cancelText:`Keep it`,onCancel:()=>b(!1),onConfirm:()=>{b(!1),m()}}),c&&(0,C.jsx)(`div`,{className:`px-4 pb-4 pt-4 border-t border-[var(--panel-border)]/60 flex flex-col gap-4`,children:(0,C.jsx)(te,{link:e,schedules:n,products:r,services:o,isAdmin:s,onChange:p,onCreatePayment:g})}),u&&(0,C.jsx)(`p`,{className:`text-[12px] font-semibold text-red-500 px-4 pb-3`,children:u})]})}function G({isAdmin:e=!0}={}){let{user:n}=t.Ft(),{loading:i,docs:o}=a.S(),s=V(),l={payments:y.r(`payments`),email:y.r(`email`)},[d,f]=(0,S.useState)({}),[p,m]=(0,S.useState)([]),[h,g]=(0,S.useState)(null),[_,v]=(0,S.useState)(null),[b,x]=(0,S.useState)({}),T=(0,S.useRef)(new Map);z(o.links.map(e=>e.id),f,T);let E=n?.uid||``,D=(0,S.useMemo)(()=>[...e?o.schedules:o.schedules.filter(e=>e.memberId===E)].sort((e,t)=>Number(t.memberId===E)-Number(e.memberId===E)),[o.schedules,e,E]),O=(0,S.useMemo)(()=>{let t=new Map(o.links.map(e=>[e.id,e]));for(let e of Object.values(d))t.set(e.id,e);for(let e of p)t.delete(e);return[...t.values()].filter(t=>e||t.memberId===E).sort((e,t)=>Number(t.memberId===E)-Number(e.memberId===E)||(e.createdAt||0)-(t.createdAt||0)||e.id.localeCompare(t.id))},[o.links,d,p,e,E]),k=e=>{let t=T.current.get(e.id);t&&clearTimeout(t),T.current.set(e.id,setTimeout(async()=>{T.current.delete(e.id);let t=await a.f(e);x(n=>{let r={...n};return t?r[e.id]=t:delete r[e.id],r})},600))},A=e=>{f(t=>({...t,[e.id]:e})),k(e)},j=()=>{let e=D.find(e=>e.memberId===E)||D[0];if(!e)return;let t=ee(e);f(e=>({...e,[t.id]:t})),g(t.id),v(t.id),k(t)},M=async e=>{let t=T.current.get(e);t&&(clearTimeout(t),T.current.delete(e)),f(t=>{let n={...t};return delete n[e],n}),m(t=>[...t,e]),h===e&&g(null);let n=await a.u(e);n&&(m(t=>t.filter(t=>t!==e)),x(t=>({...t,[e]:n})))},N=async(e,n)=>{let r={...t.cr(`p_${Date.now().toString(36)}`),kind:`once`,items:[{name:e,amount:n}]};try{let{id:e,...n}=r;return await(0,w.setDoc)((0,w.doc)(t.ui,t.Qn,e),n),e}catch(e){return console.error(`Could not make the payment`,e),null}};return(0,C.jsx)(t.m,{icon:c.t,title:`Booking links`,description:`One per kind of meeting — pick the hours it is booked in, say how long it lasts and what it asks, and send the link.`,actions:!i&&D.length>0?({open:e})=>(0,C.jsx)(t.o,{icon:u.t,compact:!0,title:`Add a booking link`,onClick:()=>{e(),j()},children:`Add a booking link`}):void 0,children:(0,C.jsx)(`div`,{className:`flex flex-col gap-3`,children:i?(0,C.jsx)(`p`,{className:t.s,children:`Loading your booking links…`}):D.length===0?(0,C.jsx)(`p`,{className:`${t.s} px-1`,children:`Add a schedule above first — a booking link is a meeting booked in somebody's hours, so there have to be hours to put it on.`}):O.length===0?(0,C.jsxs)(`p`,{className:`${t.s} px-1`,children:[`No booking link yet — press Add a booking link. It is what turns `,r.dt(D[0]),` into something people can book.`]}):O.map(t=>(0,C.jsx)(W,{link:t,schedules:D,products:s,services:l,isAdmin:e,open:h===t.id,fresh:_===t.id,error:b[t.id],onToggle:()=>g(h===t.id?null:t.id),onChange:A,onRemove:()=>M(t.id),onCreatePayment:N},t.id))})})}var K=`team`,ne=e=>`m:${e}`,re=`__nobody__`;function ie(e,t,n){return[{value:`me`,label:`My calendar`},{value:K,label:`My team's calendar`},...e.filter(e=>e.id!==n).map(e=>({value:ne(e.id),label:a.g(e)||e.email,disabled:!t.has(e.id)}))]}var q=e=>e.startsWith(`m:`)?e.slice(2):``;function J(e,t,n,i=``){if(!e.email)return Promise.resolve();let a=r.Zt(e,e.timeZone||n);return p.i(t,r.t,e.id,{when:`${a.day}, ${a.time}`,memberName:e.memberName,scheduleName:e.scheduleName,reason:i.trim()}).then(()=>{}).catch(()=>{})}function ae(e,t,n){let r=e=>[...new Set(e.map(e=>String(e||``).trim()))].filter(e=>e&&e!==n),i=r([e.memberId,...t.map(e=>e.memberId),...e.copyIds.map(e=>e.split(`__`)[0])]);return{members:i,bookers:r([e.uid,...t.map(e=>e.uid)]).filter(e=>e!==`guest`).filter(e=>!i.includes(e))}}async function oe(e,t,n,i){if(e.own||e.heldOnly)return;let a={title:`Meeting removed`,body:`${r.B(e)} · ${r.ot(new Date(e.start),i)}`};await J(e,`booking_cancelled`,i,`The meeting was removed from the calendar.`);let{members:o,bookers:s}=ae(e,t,n);await m.r(o,{...a,link:`/schedule`}),await m.r(s,{...a,link:`/my-bookings`})}var Y=e=>{try{return localStorage.getItem(`fbos_calendar_had_${e}`)===`1`}catch{return!1}};function se(){let{user:e}=t.Ft();return Y(e?.uid||``)?(0,C.jsx)(f.n,{className:`h-[420px] w-full`}):null}function X({isAdmin:e}){let{user:n}=t.Ft(),i=n?.uid||``,c=r.et(),[l,u]=(0,T.useSearchParams)(),d=l.get(`open`)||l.get(`booking`)||``,{schedules:p}=a.w(),{members:m}=a.T(),h=(0,S.useMemo)(()=>new Set(p.map(e=>e.memberId)),[p]),g=(0,S.useMemo)(()=>ie(m,h,i),[m,h,i]),[_,v]=(0,S.useState)(null);(0,S.useEffect)(()=>{d&&e&&v(e=>e??`team`)},[d,e]);let y=_??`me`,b=new Set(g.filter(e=>!e.disabled).map(e=>e.value)).has(y)?y:`me`,x=q(b),{loading:w,bookings:E,error:D}=a.v({members:b===`team`?void 0:[x||i||re],includePast:!0}),O=(0,S.useMemo)(()=>a.P(E),[E]),k=(0,S.useMemo)(()=>E.map(e=>{let t=O.get(e.id);return t?{...e,...t}:e}),[E,O]),{paid:A,checkouts:j}=s.t(k),M=a.C((0,S.useMemo)(()=>(b===`team`?m.map(e=>e.id):[x||i]).filter(Boolean),[b,m,x,i]),(0,S.useMemo)(()=>{let e=new Date;return new Date(Date.UTC(e.getUTCFullYear(),e.getUTCMonth()-1,1))},[]),{keepOpen:!0}),[N,P]=(0,S.useState)(()=>Date.now());(0,S.useEffect)(()=>{let e=setInterval(()=>P(Date.now()),6e4);return()=>clearInterval(e)},[]);let F=(0,S.useMemo)(()=>{let e=new Set(M.filter(e=>!e.open).map(e=>r.qt(e.memberId,e.start))),t=k.map(t=>a.M(t,j[t.id],e,N)),n=e=>{let t=m.find(t=>t.id===e);return p.find(t=>t.memberId===e)?.memberName||(t?a.g(t):``)},i=a.F(M,E,N).map(e=>a.N(e,n(e.memberId)));return i.length?[...t,...i]:t},[E,k,M,N,m,p,j]);(0,S.useEffect)(()=>{if(!(w||!i))try{localStorage.setItem(`fbos_calendar_had_${i}`,F.length?`1`:`0`)}catch{}},[w,i,F.length]);let I=x||i,L=m.find(e=>e.id===I),R=p.find(e=>e.memberId===I)?.memberName||(L?a.g(L):``)||(I===i?String(n?.displayName||``):``);return w&&F.length===0?Y(i)?(0,C.jsx)(f.n,{className:`h-[420px] w-full`}):null:F.length===0?null:(0,C.jsx)(t.m,{icon:o.d,title:`Calendar`,description:b===`team`?`Every booking made with your team, and the events they put on their own days — in your time, ${r.nn(c)}.`:x?`${R||`Their`} calendar, read as they read it — in your time, ${r.nn(c)}.`:`Every booking made with you, under every schedule of yours — in your time, ${r.nn(c)}.`,actions:e&&g.length>2?(0,C.jsx)(t.Z,{ariaLabel:`Whose calendar`,value:b,options:g,onChange:v,className:`console-select`,compact:!0,dense:!0,portal:!0,direction:`auto`}):void 0,children:w?(0,C.jsx)(`p`,{className:t.s,children:`Loading the calendar…`}):D?(0,C.jsx)(`p`,{className:`text-[12px] font-semibold text-red-500 px-1`,children:D}):(0,C.jsx)(s.n,{bookings:F,zone:c,paid:A,openBookingId:d||void 0,onOpened:d?()=>u(e=>(e.delete(`open`),e.delete(`booking`),e),{replace:!0}):void 0,withMember:b===K,me:i,onAccept:async e=>{let t=await a.t(e.id);return t||J(e,`booking_confirmed`,c),t},onCancel:async(e,t)=>{let r=await a.r(e.id,{ids:e.copyIds,reason:t,side:`host`,by:e.memberId===i?R||String(n?.displayName||``):e.memberName,byUid:i});return r||J(e,`booking_cancelled`,c,t),r},onDelete:async e=>(await oe(e,E,i,c),a.a(e.id,e.copyIds)),canDelete:t=>e||t.own&&t.memberId===i,onRelease:e=>a.c(e.memberId,e.start),onColor:a.m,onAdd:b===`team`?void 0:e=>a.n({...e,memberId:I,memberName:R,timeZone:c})})})}function ce(e,t){if(!e.enabled)return{state:`off`,label:`Off`};if(g.c(e,t))return{state:`error`,label:`Unfinished`};let n=e.schedules.length;return{state:`saved`,label:n===1?`1 meeting`:`${n} meetings`}}var le=e=>{let t=e.schedules.length;return`${g.s(e)} — ${t===0?`nothing on it yet`:t===1?`1 meeting`:`${t} meetings`}`};function Z({page:e,schedules:n,onChange:i}){return n.length?(0,C.jsx)(t.i,{label:`Meetings on this page`,hint:`They appear in the order you tick them. A meeting switched off above is kept off the page too.`,children:(0,C.jsx)(`div`,{className:`flex flex-col gap-1.5`,children:n.map(t=>{let n=e.schedules.includes(t.id);return(0,C.jsxs)(`button`,{type:`button`,role:`checkbox`,"aria-checked":n,onClick:()=>i(g.p(e,t.id)),className:`flex items-center gap-3 px-3 py-2.5 rounded-xl border text-left transition-all cursor-pointer active:scale-[0.995] ${n?`border-accent/45 bg-accent/[0.07]`:`border-[var(--panel-border)]/70 hover:border-accent/30 hover:bg-foreground/[0.03]`}`,children:[(0,C.jsx)(`span`,{"aria-hidden":!0,className:`w-[18px] h-[18px] rounded-[5px] border flex items-center justify-center shrink-0 transition-all ${n?`border-accent bg-accent`:`border-foreground/25`}`,children:n&&(0,C.jsx)(`span`,{className:`w-[7px] h-[7px] rounded-[2px] bg-[var(--button-fg,#fff)]`})}),(0,C.jsx)(`span`,{className:`flex-1 min-w-0 text-[13px] font-semibold text-foreground/80 truncate`,children:r.Bt(t)})]},t.id)})})}):(0,C.jsx)(t.i,{label:`Meetings on this page`,children:(0,C.jsx)(`p`,{className:`${t.s} px-1`,children:`Make a schedule above first — a page offers the meetings you have set up.`})})}function ue({page:e,taken:n,onRename:r}){let[i,a]=(0,S.useState)(e.id),o=g.f(i),s=!!o&&o!==e.id&&n.includes(o);return(0,C.jsx)(t.b,{label:`Its address`,prefix:`/meet/`,value:i,onChange:a,onBlur:()=>{if(!o||s||o===e.id){a(e.id);return}r(o)},placeholder:`anna-bell`,error:s?`Another page already has that address.`:void 0,hint:`Change it and the old link stops working, so change it before you send it out.`})}function de({page:n,schedules:r,taken:a,open:o,fresh:s,error:c,onToggle:l,onChange:u,onRename:f,onRemove:p}){let[m,_]=(0,S.useState)(!1),v=ce(n,r),y=g.s(n),b=g.c(n,r),w=(0,S.useRef)(null);return(0,S.useEffect)(()=>{if(!s)return;let e=R(w.current);return()=>{e&&clearTimeout(e)}},[s]),(0,C.jsxs)(`div`,{ref:w,className:`scroll-mt-4 rounded-2xl border border-[var(--panel-border)]`,children:[(0,C.jsxs)(`div`,{className:`flex items-center gap-2 sm:gap-2.5 pr-3`,children:[(0,C.jsxs)(`button`,{type:`button`,onClick:l,"aria-expanded":o,className:`flex-1 min-w-0 flex items-center justify-between gap-3 px-4 py-3 text-left cursor-pointer`,children:[(0,C.jsx)(`span`,{className:`text-[13px] font-semibold text-foreground/75 truncate`,children:le(n)}),(0,C.jsxs)(`span`,{className:`flex items-center gap-2.5 shrink-0`,children:[(0,C.jsx)(`span`,{className:`max-sm:hidden`,children:(0,C.jsx)(t._,{state:v.state,label:v.label})}),(0,C.jsx)(i.t,{className:`w-3.5 h-3.5 text-foreground/40 shrink-0 transition-transform ${o?`rotate-180`:``}`})]})]}),(0,C.jsx)(t.x,{enabled:n.enabled,onChange:e=>u({...n,enabled:e}),label:`${y} — page is live`}),(0,C.jsx)(t.o,{icon:d.t,tone:`danger`,compact:!0,title:`Remove ${y}`,onClick:()=>_(!0),children:`Remove`})]}),(0,C.jsx)(h.t,{isOpen:m,title:`Remove ${y}?`,message:`Its link stops working. The meetings on it are untouched and keep their own links, and bookings already taken are kept.`,confirmText:`Yes, remove`,cancelText:`Keep it`,onCancel:()=>_(!1),onConfirm:()=>{_(!1),p()}}),o&&(0,C.jsxs)(`div`,{className:`px-4 pb-4 pt-4 border-t border-[var(--panel-border)]/60 flex flex-col gap-4`,children:[(0,C.jsx)(t.b,{label:`Name on the page`,value:n.title,onChange:e=>u({...n,title:e}),placeholder:`Anna Bell`,hint:`Usually the name of whoever the page is for.`}),(0,C.jsx)(e.a,{label:`Photo`,hint:`Shown at the top of the page. A square picture of the person works best.`,value:n.photo,onChange:e=>u({...n,photo:e})}),(0,C.jsx)(t.y,{label:`About this page`,value:n.intro,onChange:e=>u({...n,intro:e}),rows:3,placeholder:`I help small studios get their bookkeeping straight. Pick a time below and tell me what you need.`}),(0,C.jsx)(Z,{page:n,schedules:r,onChange:u}),(0,C.jsx)(ue,{page:n,taken:a,onRename:f}),b?(0,C.jsx)(`p`,{className:`text-[12px] font-semibold text-amber-500 px-1`,children:b}):(0,C.jsx)(x.t,{title:y,path:g.l(n.id)})]}),c&&(0,C.jsx)(`p`,{className:`text-[12px] font-semibold text-red-500 px-4 pb-3`,children:c})]})}function fe({schedules:e,myName:n,isAdmin:r=!0,meId:i=``}){let{loading:a,pages:o}=g.i(),[s,l]=(0,S.useState)({}),[d,f]=(0,S.useState)([]),[p,m]=(0,S.useState)(null),[h,_]=(0,S.useState)(null),[v,y]=(0,S.useState)({}),b=(0,S.useRef)(new Map);z(o.map(e=>e.id),l,b);let x=new Map(o.map(e=>[e.id,e]));for(let e of Object.values(s))x.set(e.id,e);for(let e of d)x.delete(e);let w=[...x.values()].sort((e,t)=>(e.createdAt||0)-(t.createdAt||0)||e.id.localeCompare(t.id)),T=w.map(e=>e.id),E=g.u(w,i,r),D=r?e:e.filter(e=>e.memberId===i),O=e=>{let t=b.current.get(e.id);t&&clearTimeout(t),b.current.set(e.id,setTimeout(async()=>{b.current.delete(e.id);let t=await g.r(e);y(n=>{let r={...n};return t?r[e.id]=t:delete r[e.id],r})},600))},k=e=>{l(t=>({...t,[e.id]:e})),O(e)},A=()=>{let e=g.a(g.m(n||`my page`,T),n,i);l(t=>({...t,[e.id]:e})),f(t=>t.filter(t=>t!==e.id)),m(e.id),_(e.id),O(e)},j=async(e,t)=>{let n=b.current.get(e.id);n&&(clearTimeout(n),b.current.delete(e.id));let r={...e,id:t};l(n=>{let i={...n};return delete i[e.id],i[t]=r,i}),f(n=>[...n.filter(e=>e!==t),e.id]),p===e.id&&m(t);let i=await g.n(e.id,r);i&&y(e=>({...e,[t]:i}))},M=async e=>{let t=b.current.get(e);t&&(clearTimeout(t),b.current.delete(e)),l(t=>{let n={...t};return delete n[e],n}),f(t=>[...t,e]),p===e&&m(null);let n=await g.t(e);n&&(f(t=>t.filter(t=>t!==e)),y(t=>({...t,[e]:n})))};return(0,C.jsx)(t.m,{icon:c.t,title:`Your booking pages`,description:`One link with a photo, a line about you and every meeting you offer.`,actions:({open:e})=>(0,C.jsx)(t.o,{icon:u.t,compact:!0,title:`Create a page`,onClick:()=>{e(),A()},children:`Create a page`}),children:(0,C.jsx)(`div`,{className:`flex flex-col gap-3`,children:a?(0,C.jsx)(`p`,{className:`${t.s} px-1`,children:`Loading pages…`}):E.length===0?(0,C.jsx)(`p`,{className:`${t.s} px-1`,children:`No pages yet. Create one to hand out a single link — a visitor sees your photo, what you do and every meeting you offer, and picks the one they want.`}):E.map(e=>(0,C.jsx)(de,{page:e,schedules:D,taken:T,open:p===e.id,fresh:h===e.id,error:v[e.id],onToggle:()=>m(t=>t===e.id?null:e.id),onChange:k,onRename:t=>j(e,t),onRemove:()=>M(e.id)},e.id))})})}var pe={from:`09:00`,to:`17:00`},me=e=>r.pt(e)?{state:`saved`,label:`Ready`}:{state:`off`,label:`In progress`},he=e=>({...r.M(a.U(),e.id,a.g(e),r.et()),name:`Working hours`,enabled:!0,createdAt:Date.now()}),Q=`w-[6.5rem] shrink-0`,ge=`w-9 h-9 rounded-[var(--btn-radius,0.75rem)] border border-[var(--panel-border)] flex items-center justify-center shrink-0 text-foreground/45 hover:text-red-500 hover:border-red-500/40 hover:bg-red-500/[0.06] active:scale-[0.98] transition-all cursor-pointer`;function _e({day:e,windows:n,onChange:i}){let a=n.length>0,o=(e,t)=>i(n.map((n,r)=>r===e?{...n,...t}:n));return(0,C.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-[8.5rem_minmax(0,1fr)] items-start gap-x-4 gap-y-2 py-2.5`,children:[(0,C.jsxs)(`div`,{className:`flex items-center justify-between gap-3 h-9`,children:[(0,C.jsx)(`span`,{className:`text-[13px] font-medium ${a?`text-foreground/80`:`text-foreground/40`}`,children:r.u[e]}),(0,C.jsx)(t.x,{enabled:a,onChange:e=>i(e?[pe]:[]),label:`${r.u[e]} — bookable`})]}),a&&(0,C.jsxs)(`div`,{className:`flex flex-col gap-2 min-w-0`,children:[n.map((a,s)=>(0,C.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,C.jsx)(`div`,{className:Q,children:(0,C.jsx)(t.Z,{ariaLabel:`${r.u[e]} from${s?` (${s+1})`:``}`,value:a.from,options:r.m,onChange:e=>o(s,{from:e}),className:`console-select`,compact:!0,portal:!0,direction:`auto`})}),(0,C.jsx)(`span`,{className:`w-3 text-center text-foreground/40 text-[13px] shrink-0 select-none`,children:`–`}),(0,C.jsx)(`div`,{className:Q,children:(0,C.jsx)(t.Z,{ariaLabel:`${r.u[e]} to${s?` (${s+1})`:``}`,value:a.to,options:r.d,onChange:e=>o(s,{to:e}),className:`console-select`,compact:!0,portal:!0,direction:`auto`})}),n.length>1&&(0,C.jsx)(`button`,{type:`button`,title:`Remove these hours on ${r.u[e]}`,"aria-label":`Remove ${r.u[e]} hours ${s+1}`,onClick:()=>i(n.filter((e,t)=>t!==s)),className:ge,children:(0,C.jsx)(l.t,{className:`w-3.5 h-3.5`})})]},s)),n.length<2&&(0,C.jsx)(`button`,{type:`button`,onClick:()=>i([...n,{from:`18:00`,to:`20:00`}]),className:`self-start h-6 px-1 text-[11.5px] font-semibold text-foreground/45 hover:text-accent transition-colors cursor-pointer`,children:`+ Add a second stretch`})]})]})}function ve({schedule:e,onChange:n}){let i=t=>n({...e,...t}),a=r.ft(e);return(0,C.jsxs)(C.Fragment,{children:[(0,C.jsx)(t.b,{label:`What are these hours called?`,hint:`Only you and your team read this — it is how a booking link names the hours it is booked in. Working hours, Evenings, Studio days.`,value:e.name,onChange:e=>i({name:e}),placeholder:`Working hours`}),(0,C.jsx)(t.t,{value:e.timeZone,onChange:e=>i({timeZone:e})}),(0,C.jsx)(t.i,{label:`When`,hint:`The hours on each day, in this person's own time zone. Add a second stretch for a break in the middle. A time booked in any of their hours is taken here too.`,children:(0,C.jsx)(`div`,{className:`flex flex-col divide-y divide-[var(--panel-border)]/60 rounded-2xl border border-[var(--panel-border)]/60 px-4 py-1`,children:r.l.map(t=>(0,C.jsx)(_e,{day:t,windows:e.days[t]||[],onChange:n=>i({days:{...e.days,[t]:n}})},t))})}),(0,C.jsx)(M,{blocked:e.blocked,onChange:e=>i({blocked:e})}),(0,C.jsx)(`div`,{className:`pt-1`,children:a?(0,C.jsxs)(`span`,{className:`text-[11.5px] font-semibold text-amber-500`,children:[`Not usable yet — `,a]}):(0,C.jsx)(`span`,{className:`text-[11.5px] font-semibold text-emerald-500`,children:`Ready — add a booking link below to let people book these hours, or ask for a page built on them.`})})]})}function $({schedule:e,open:n,stale:a,fresh:o,error:s,onToggle:c,onChange:l,onRemove:u}){let f=me(e),[p,m]=(0,S.useState)(!1),g=r.dt(e),_=(0,S.useRef)(null);return(0,S.useEffect)(()=>{if(!o)return;let e=R(_.current);return()=>{e&&clearTimeout(e)}},[o]),(0,C.jsxs)(`div`,{ref:_,className:`scroll-mt-4 rounded-2xl border border-[var(--panel-border)] ${a?`opacity-60`:``}`,children:[(0,C.jsxs)(`div`,{className:`flex items-center gap-2 sm:gap-2.5 pr-3`,children:[(0,C.jsxs)(`button`,{type:`button`,onClick:c,"aria-expanded":n,className:`flex-1 min-w-0 flex items-center justify-between gap-3 px-4 py-3 text-left cursor-pointer`,children:[(0,C.jsx)(`span`,{className:`text-[13px] font-semibold text-foreground/75 truncate`,children:r.mt(e)}),(0,C.jsxs)(`span`,{className:`flex items-center gap-2.5 shrink-0`,children:[a?(0,C.jsx)(`span`,{className:`${t.s} max-sm:hidden`,children:`No longer on the team`}):(0,C.jsx)(`span`,{className:`max-sm:hidden`,children:(0,C.jsx)(t._,{state:f.state,label:f.label})}),(0,C.jsx)(i.t,{className:`w-3.5 h-3.5 text-foreground/40 shrink-0 transition-transform ${n?`rotate-180`:``}`})]})]}),(0,C.jsx)(t.o,{icon:d.t,tone:`danger`,compact:!0,title:`Remove ${g}`,onClick:()=>m(!0),children:`Remove`})]}),(0,C.jsx)(h.t,{isOpen:p,title:`Remove ${g}?`,message:a?`They are no longer on the team, so nobody can book them. Bookings already taken are kept.`:`Every booking link booked in these hours stops working, and they leave every page and form they were picked on. Bookings already taken are kept.`,confirmText:`Yes, remove`,cancelText:`Keep it`,onCancel:()=>m(!1),onConfirm:()=>{m(!1),u()}}),n&&(0,C.jsx)(`div`,{className:`px-4 pb-4 pt-4 border-t border-[var(--panel-border)]/60 flex flex-col gap-4`,children:(0,C.jsx)(ve,{schedule:e,onChange:l})}),s&&(0,C.jsx)(`p`,{className:`text-[12px] font-semibold text-red-500 px-4 pb-3`,children:s})]})}function ye({name:e,schedules:n,stale:r,open:a,onToggle:o,onAdd:s,openScheduleId:c,freshId:l,errors:d,onToggleSchedule:f,onChange:p,onRemove:m}){let h=r?`No longer on the team`:n.length===0?`No schedules yet`:`${n.length} schedule${n.length===1?``:`s`}`,g=(0,S.useRef)(null);return(0,S.useEffect)(()=>{if(!a)return;let e=R(g.current);return()=>{e&&clearTimeout(e)}},[a]),(0,C.jsxs)(`div`,{ref:g,className:`scroll-mt-4 rounded-2xl border border-[var(--panel-border)]`,children:[(0,C.jsxs)(`button`,{type:`button`,onClick:o,"aria-expanded":a,className:`w-full flex items-center justify-between gap-3 px-4 py-3 text-left cursor-pointer`,children:[(0,C.jsx)(`span`,{className:`text-[13px] font-semibold text-foreground/75 truncate`,children:e}),(0,C.jsxs)(`span`,{className:`flex items-center gap-2.5 shrink-0`,children:[(0,C.jsx)(`span`,{className:`${t.s} max-sm:hidden`,children:h}),(0,C.jsx)(i.t,{className:`w-3.5 h-3.5 text-foreground/40 shrink-0 transition-transform ${a?`rotate-180`:``}`})]})]}),a&&(0,C.jsxs)(`div`,{className:`px-4 pb-4 pt-4 border-t border-[var(--panel-border)]/60 flex flex-col gap-3`,children:[n.map(e=>(0,C.jsx)($,{schedule:e,stale:r,fresh:l===e.id,open:c===e.id,error:d[e.id],onToggle:()=>f(e.id),onChange:p,onRemove:()=>m(e.id)},e.id)),r?n.length===0&&(0,C.jsxs)(`p`,{className:`text-[11px] sm:text-[11.5px] text-foreground/40 font-medium leading-snug`,children:[`No schedule yet for `,e,`.`]}):(0,C.jsxs)(`div`,{className:`flex flex-col items-start sm:flex-row sm:items-center gap-3 rounded-2xl border border-dashed border-[var(--panel-border)] px-4 py-3`,children:[(0,C.jsx)(t.o,{icon:u.t,title:`Add a schedule for ${e}`,onClick:s,children:`Add a schedule`}),n.length===0&&(0,C.jsxs)(`p`,{className:`text-[11px] sm:text-[11.5px] text-foreground/40 font-medium leading-snug`,children:[`No schedule yet for `,e,`.`]})]})]})]})}var be=e=>({id:e.uid,name:String(e.displayName||``),email:String(e.email||``),role:`admin`});function xe({isAdmin:e=!0}={}){let{user:r}=t.Ft(),{loading:i,members:o}=a.T(),{loading:s,docs:c}=a.S(),l=c.schedules,[d,f]=(0,S.useState)({}),[p,m]=(0,S.useState)([]),[h,g]=(0,S.useState)(null),[_,v]=(0,S.useState)(null),[y,b]=(0,S.useState)(null),[x,w]=(0,S.useState)({}),E=(0,S.useRef)(new Map);z(l.map(e=>e.id),f,E);let D=(0,S.useMemo)(()=>{let e=new Map(l.map(e=>[e.id,e]));for(let t of Object.values(d))e.set(t.id,t);for(let t of p)e.delete(t);return[...e.values()].sort((e,t)=>(e.createdAt||0)-(t.createdAt||0)||e.id.localeCompare(t.id))},[l,d,p]),O=e=>{let t=E.current.get(e.id);t&&clearTimeout(t),E.current.set(e.id,setTimeout(async()=>{E.current.delete(e.id);let t=await a.p(e);w(n=>{let r={...n};return t?r[e.id]=t:delete r[e.id],r})},600))},k=e=>{f(t=>({...t,[e.id]:e})),O(e)},A=(0,S.useMemo)(()=>r?o.find(e=>e.id===r.uid)||be(r):null,[r,o]),j=(0,S.useMemo)(()=>A&&!o.some(e=>e.id===A.id)?[A,...o]:o,[A,o]),M=(0,S.useRef)(!1),[N,P]=(0,S.useState)(``),F=(0,S.useMemo)(()=>c.schedules.filter(t=>c.legacyIds.includes(t.id)&&(e||t.memberId===A?.id)),[c.schedules,c.legacyIds,e,A]);(0,S.useEffect)(()=>{M.current||F.length===0||(M.current=!0,a.h(F).then(e=>{e&&P(e)}))},[F]);let I=e=>{let t=he(e);f(e=>({...e,[t.id]:t})),g(t.id),v(t.id),A&&e.id!==A.id&&b(e.id),O(t)},L=()=>{A&&I(A)},R=async e=>{let t=E.current.get(e);t&&(clearTimeout(t),E.current.delete(e)),f(t=>{let n={...t};return delete n[e],n}),m(t=>[...t,e]),h===e&&g(null);let n=await a.d(e);n&&(m(t=>t.filter(t=>t!==e)),w(t=>({...t,[e]:n})))},B=i||s,V=new Set(j.map(e=>e.id)),H=A?D.filter(e=>e.memberId===A.id):[],U=(0,S.useMemo)(()=>{if(!A)return[];let e=new Map;for(let t of D){if(t.memberId===A.id)continue;let n=e.get(t.memberId);n?n.push(t):e.set(t.memberId,[t])}let t=[];for(let n of j)n.id!==A.id&&(t.push({id:n.id,name:a.g(n)||n.email,stale:!1,schedules:e.get(n.id)||[]}),e.delete(n.id));for(let[n,r]of e)t.push({id:n,name:r[0].memberName.trim()||`Someone no longer on the team`,stale:!0,schedules:r});return t},[D,j,A]);return(0,C.jsxs)(C.Fragment,{children:[(0,C.jsx)(t.m,{icon:n.C,title:`Your schedules`,description:`When you are free — a name, a time zone, the week's hours and the days you are away. The base for anything booked on them.`,actions:B?void 0:({open:e})=>(0,C.jsx)(t.o,{icon:u.t,compact:!0,title:`Add a schedule`,onClick:()=>{e(),L()},children:`Add a schedule`}),children:(0,C.jsxs)(`div`,{className:`flex flex-col gap-3`,children:[B?(0,C.jsx)(`p`,{className:t.s,children:`Loading your schedules…`}):H.length===0?(0,C.jsx)(`p`,{className:`${t.s} px-1`,children:`No hours of your own yet — press Add a schedule. Everything booked in them shares one availability, so a time taken once is gone from all of it.`}):H.map(e=>(0,C.jsx)($,{schedule:e,stale:!V.has(e.memberId),fresh:_===e.id,open:h===e.id,error:x[e.id],onToggle:()=>g(h===e.id?null:e.id),onChange:k,onRemove:()=>R(e.id)},e.id)),!!N&&(0,C.jsx)(`p`,{className:`text-[12px] font-semibold text-red-500 px-1`,children:N})]})}),e&&(0,C.jsx)(t.m,{icon:n.S,title:`Your team's schedules`,description:`When everyone else is free — one folded row per person; open a name to add their hours or see what they keep.`,children:(0,C.jsx)(`div`,{className:`flex flex-col gap-3`,children:B?(0,C.jsx)(`p`,{className:`text-[11px] sm:text-[11.5px] text-foreground/40 font-medium leading-snug`,children:`Loading your team's schedules…`}):U.length===0?(0,C.jsxs)(`p`,{className:`text-[11px] sm:text-[11.5px] text-foreground/40 font-medium leading-snug px-1`,children:[`Nobody else is marked Internal or Admin yet. Add them on the`,` `,(0,C.jsx)(T.Link,{to:`/users`,className:`text-accent font-bold hover:underline`,children:`Users screen`}),` and a folded row for them appears here.`]}):U.map(e=>(0,C.jsx)(ye,{name:e.name,schedules:e.schedules,stale:e.stale,open:y===e.id,onToggle:()=>{let t=y!==e.id;b(t?e.id:null),t&&e.schedules.length&&g(e.schedules[0].id)},onAdd:()=>{let t=j.find(t=>t.id===e.id);t&&I(t)},openScheduleId:h,freshId:_,errors:x,onToggleSchedule:e=>g(h===e?null:e),onChange:k,onRemove:R},e.id))})})]})}function Se(){let{ready:e}=t.Jn(`schedule`);return e?(0,C.jsx)(X,{isAdmin:!0}):(0,C.jsx)(se,{})}function Ce(){let{user:i,userRole:o}=t.Ft(),s=o===`admin`,{schedules:c}=a.y(),l=i&&(i.displayName||i.email?.split(`@`)[0])||``;return r.Sn(o)?(0,C.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,C.jsxs)(t.nt.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:`mb-6`,children:[(0,C.jsx)(e.t,{children:`Schedule`}),(0,C.jsxs)(`div`,{className:`flex items-center gap-2 text-foreground/40 font-bold uppercase tracking-[0.2em] text-[11px]`,children:[(0,C.jsx)(`span`,{className:`w-8 h-[1px] bg-foreground/10`}),`/schedule`]})]}),(0,C.jsxs)(`div`,{className:`flex flex-col gap-6 flex-1 pb-16`,children:[(0,C.jsx)(n.t,{}),(0,C.jsx)(v.n,{tab:`schedule`}),(0,C.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,C.jsxs)(`div`,{className:`flex flex-col gap-4`,children:[(0,C.jsx)(`div`,{className:`flex flex-col gap-1.5 px-1`,children:(0,C.jsx)(`p`,{className:`text-[13px] font-medium text-foreground/60 leading-relaxed`,children:s?`When you and your team are free, and everything built on it. A schedule is a week of hours in one person’s own time zone; a booking link turns those hours into a meeting people can book, with an address to send. The same hours are what a page you ask for is built on.`:`When you are free, and what people can book in it. Your schedule is your week of hours; a booking link turns it into a meeting, with an address of its own to send — they pick a free time and it lands on your calendar. A booking page gathers your meetings under one address to hand out.`})}),s?(0,C.jsx)(Se,{}):(0,C.jsx)(X,{isAdmin:!1}),(0,C.jsx)(xe,{isAdmin:s}),(0,C.jsx)(G,{isAdmin:s}),(0,C.jsx)(fe,{schedules:c,myName:l,isAdmin:s,meId:i?.uid||``})]})})]})]}):(0,C.jsx)(`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,C.jsx)(_.i,{})})}exports.ScheduleAdmin=Ce;
|
|
1
|
+
require(`./chunk-CiTBaPhY.cjs`);const e=require(`./PageTitle-DQkvCB11.cjs`),t=require(`./TimeZoneField-Ckn1pKAL.cjs`),n=require(`./DashboardNav-GgEUpyTa.cjs`),r=require(`./schedule-BAea6q8_.cjs`),i=require(`./chevron-down-lyDK1rfL.cjs`),a=require(`./scheduleData-BXjNXVHY.cjs`),o=require(`./BookingCalendar-BcvJiyaq.cjs`),s=require(`./paidSessions-D-zHC4oG.cjs`),c=require(`./link-2-C7A-6PW6.cjs`),l=require(`./x-Ci8c5p6T.cjs`),u=require(`./plus-zsWFCu4F.cjs`),d=require(`./trash-D-CpYHCs.cjs`),f=require(`./Loader-QHqQsXLr.cjs`),p=require(`./email-Sya6gl4F.cjs`),m=require(`./notices-CKm9-Pqt.cjs`),h=require(`./ConfirmModal-BUNtss4a.cjs`),g=require(`./bookingPages-Dx1ViiwW.cjs`),_=require(`./AccessNotice-BClqr7A9.cjs`),v=require(`./SystemTabContent-BWhRHoXx.cjs`),y=require(`./serviceStatus-Cde96_OO.cjs`),b=require(`./NeedsService-DIF7mEHq.cjs`),x=require(`./CopyLink-C5lKLyOU.cjs`);let S=require(`react`),C=require(`react/jsx-runtime`),w=require(`firebase/firestore`),T=require(`react-router-dom`);var E=`w-[6.5rem] shrink-0`,D=`w-9 h-9 rounded-[var(--btn-radius,0.75rem)] border border-[var(--panel-border)] flex items-center justify-center shrink-0 text-foreground/45 hover:text-red-500 hover:border-red-500/40 hover:bg-red-500/[0.06] active:scale-[0.98] transition-all cursor-pointer`,O=`date-field h-9 w-[10.5rem] shrink-0 px-3 text-[13px] font-semibold bg-transparent border border-[var(--panel-border)] text-foreground focus:outline-none focus:border-accent transition-colors`,k={from:`09:00`,to:`13:00`};function A(e,t){return{upcoming:e.filter(e=>e.date>=t),past:e.filter(e=>e.date<t)}}function j({row:e,onChange:n,onRemove:i}){let a=e.windows.length===0,o=(t,r)=>n({...e,windows:e.windows.map((e,n)=>n===t?{...e,...r}:e)});return(0,C.jsxs)(`div`,{className:`flex flex-col gap-2 py-2.5`,children:[(0,C.jsxs)(`div`,{className:`flex items-center gap-2 flex-wrap`,children:[(0,C.jsx)(`input`,{type:`date`,value:e.date,"aria-label":`The date`,onChange:t=>n({...e,date:t.target.value}),className:O,style:{borderRadius:`var(--input-radius, 0.75rem)`}}),(0,C.jsx)(`div`,{className:`w-[11rem] shrink-0`,children:(0,C.jsx)(t.Z,{ariaLabel:`${e.date} — how much of it`,value:a?`all`:`some`,options:[{value:`all`,label:`All day`},{value:`some`,label:`Only some hours`}],onChange:t=>n({...e,windows:t===`all`?[]:[k]}),className:`console-select`,compact:!0,dense:!0,portal:!0,direction:`auto`})}),(0,C.jsx)(`button`,{type:`button`,title:`Remove ${e.date||`this date`}`,"aria-label":`Remove ${e.date||`this date`}`,onClick:i,className:`${D} ml-auto`,children:(0,C.jsx)(l.t,{className:`w-3.5 h-3.5`})})]}),!a&&(0,C.jsxs)(`div`,{className:`flex flex-col gap-2 sm:pl-[0.125rem]`,children:[e.windows.map((i,a)=>(0,C.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,C.jsx)(`div`,{className:E,children:(0,C.jsx)(t.Z,{ariaLabel:`${e.date} from${a?` (${a+1})`:``}`,value:i.from,options:r.m,onChange:e=>o(a,{from:e}),className:`console-select`,compact:!0,portal:!0,direction:`auto`})}),(0,C.jsx)(`span`,{className:`w-3 text-center text-foreground/40 text-[13px] shrink-0 select-none`,children:`–`}),(0,C.jsx)(`div`,{className:E,children:(0,C.jsx)(t.Z,{ariaLabel:`${e.date} to${a?` (${a+1})`:``}`,value:i.to,options:r.d,onChange:e=>o(a,{to:e}),className:`console-select`,compact:!0,portal:!0,direction:`auto`})}),e.windows.length>1&&(0,C.jsx)(`button`,{type:`button`,title:`Remove these hours on ${e.date}`,"aria-label":`Remove ${e.date} hours ${a+1}`,onClick:()=>n({...e,windows:e.windows.filter((e,t)=>t!==a)}),className:D,children:(0,C.jsx)(l.t,{className:`w-3.5 h-3.5`})})]},a)),e.windows.length<2&&(0,C.jsx)(`button`,{type:`button`,onClick:()=>n({...e,windows:[...e.windows,{from:`14:00`,to:`18:00`}]}),className:`self-start h-6 px-1 text-[11.5px] font-semibold text-foreground/45 hover:text-accent transition-colors cursor-pointer`,children:`+ Add a second stretch`})]})]})}function M({blocked:e,onChange:n,now:i}){let a=r.rn(i?i():new Date),[o,s]=(0,S.useState)(!1),{upcoming:c,past:l}=A(e,a),d=o?[...l,...c]:c,f=(t,r)=>n(e.map(e=>e===t?r:e));return(0,C.jsx)(t.i,{label:`Days away`,hint:`Dates this week's hours do not apply to — a holiday, a flight, an afternoon out. Nobody can book them, on any link on these hours.`,children:(0,C.jsxs)(`div`,{className:`flex flex-col divide-y divide-[var(--panel-border)]/60 rounded-2xl border border-[var(--panel-border)]/60 px-4 py-1`,children:[d.length===0?(0,C.jsx)(`p`,{className:`${t.s} py-3`,children:`No days blocked out. Add one for a holiday or a day off.`}):d.map((t,r)=>(0,C.jsx)(j,{row:t,onChange:e=>f(t,e),onRemove:()=>n(e.filter(e=>e!==t))},`${t.date}-${r}`)),(0,C.jsxs)(`div`,{className:`flex items-center justify-between gap-3 py-2.5`,children:[(0,C.jsx)(t.o,{icon:u.t,compact:!0,title:`Add a day away`,onClick:()=>n([...e,{date:a,windows:[]}]),children:`Add a date`}),l.length>0&&(0,C.jsx)(`button`,{type:`button`,onClick:()=>s(e=>!e),className:`h-6 px-1 text-[11.5px] font-semibold text-foreground/45 hover:text-accent transition-colors cursor-pointer`,children:o?`Hide past dates`:`Show ${l.length} past date${l.length===1?``:`s`}`})]})]})})}var N=e=>r.s.find(t=>t.value===e)?.label||`Short text`;function P({options:e,onChange:n}){return(0,C.jsx)(t.i,{label:`Choices`,hint:`What people pick from.`,children:(0,C.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[e.length===0&&(0,C.jsx)(`span`,{className:`text-[11px] sm:text-[11.5px] text-foreground/40 font-medium leading-snug px-1`,children:`No choices yet — add the first one.`}),e.map((r,i)=>(0,C.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,C.jsx)(`input`,{type:`text`,value:r,"aria-label":`Choice ${i+1}`,placeholder:`e.g. At my place`,onChange:t=>n(e.map((e,n)=>n===i?t.target.value:e)),className:t.c}),(0,C.jsx)(t.o,{icon:l.t,tone:`danger`,compact:!0,title:`Remove choice ${i+1}`,onClick:()=>n(e.filter((e,t)=>t!==i)),children:`Remove`})]},i)),(0,C.jsx)(`div`,{children:(0,C.jsx)(t.o,{icon:u.t,onClick:()=>n([...e,``]),children:`Add choice`})})]})})}function F({question:e,index:n,count:a,siblings:o,fixed:s,onChange:c,onMove:l,onRemove:u}){let[f,p]=(0,S.useState)(!e.label.trim()),m=e.label.trim()||`A new question`;return(0,C.jsxs)(`div`,{className:`rounded-2xl border border-[var(--panel-border)]`,children:[(0,C.jsxs)(`div`,{className:`flex items-center gap-1.5 sm:gap-2.5 pr-2.5 sm:pr-3.5`,children:[(0,C.jsxs)(`button`,{type:`button`,onClick:()=>p(e=>!e),"aria-expanded":f,className:`flex-1 min-w-0 flex items-center justify-between gap-3 px-4 py-3.5 text-left cursor-pointer`,children:[(0,C.jsx)(`span`,{className:`text-[13px] font-semibold text-foreground/75 truncate`,children:m}),(0,C.jsxs)(`span`,{className:`flex items-center gap-2.5 shrink-0`,children:[(0,C.jsx)(`span`,{className:`${t.s} max-sm:hidden`,children:s?`Always asked`:`${N(e.type)}${e.required?` · must be answered`:``}`}),(0,C.jsx)(i.t,{className:`w-3.5 h-3.5 text-foreground/40 shrink-0 transition-transform ${f?`rotate-180`:``}`})]})]}),!s&&(0,C.jsxs)(`div`,{className:`flex items-center gap-1 sm:gap-1.5 shrink-0`,children:[(0,C.jsx)(t.o,{icon:t.jt,compact:!0,disabled:n===0,title:`Move ${m} up`,onClick:()=>l(-1),children:`Up`}),(0,C.jsx)(t.o,{icon:t.Mt,compact:!0,disabled:n===a-1,title:`Move ${m} down`,onClick:()=>l(1),children:`Down`}),(0,C.jsx)(`span`,{className:`max-sm:hidden w-px h-5 bg-[var(--panel-border)] mx-0.5`}),(0,C.jsx)(t.o,{icon:d.t,tone:`danger`,compact:!0,title:`Remove ${m}`,onClick:u,children:`Remove`})]})]}),f&&(0,C.jsxs)(`div`,{className:`px-4 pb-4 pt-4 border-t border-[var(--panel-border)]/60 flex flex-col gap-4`,children:[(0,C.jsx)(t.b,{label:`What are you asking?`,hint:s?`The words above the box. Every booking asks this one — you can only change how it is put.`:`The words above the box, as the person booking reads them.`,value:e.label,placeholder:s?`e.g. Who is coming?`:`e.g. What is your phone number?`,onChange:t=>c({...e,label:t,name:s?e.name:r.K(e,t,o)})}),!s&&(0,C.jsxs)(C.Fragment,{children:[(0,C.jsx)(t.g,{label:`Kind of answer`,hint:`Sets the box they type into. The example below follows what you pick.`,value:e.type,options:r.s,allowEmpty:!1,onChange:t=>c({...e,type:t,options:t===`select`?e.options:[],placeholder:r.W(e,t)})}),(0,C.jsx)(t.S,{label:`Must be answered`,hint:`On means they cannot book until it is filled in.`,hintWideOnly:!0,enabled:e.required,onChange:t=>c({...e,required:t})})]}),e.type===`select`&&(0,C.jsx)(P,{options:e.options,onChange:t=>c({...e,options:t})}),r.G(e.type)&&(0,C.jsx)(t.b,{label:`Example answer`,hint:e.type===`tel`?`Shown under the box — a phone box already starts with a dial code, so the example stands below it.`:`Faint grey words inside the empty box.`,value:e.placeholder,placeholder:r.o[e.type]||`e.g. +1 555 0123`,onChange:t=>c({...e,placeholder:t})})]})]})}function I({questions:e,onChange:n}){let i=e.filter(e=>r.ht(e.name)),a=e.filter(e=>!r.ht(e.name)),o=e=>n([...i,...e]);return(0,C.jsx)(t.i,{label:`What does a booking ask for?`,children:(0,C.jsxs)(`div`,{className:`flex flex-col gap-3.5`,children:[i.map(t=>(0,C.jsx)(F,{question:t,index:0,count:1,siblings:e,fixed:!0,onChange:r=>n(e.map(e=>e.name===t.name?r:e)),onMove:()=>{},onRemove:()=>{}},t.name)),a.map((t,n)=>(0,C.jsx)(F,{question:t,index:n,count:a.length,siblings:e,onChange:e=>o(a.map((t,r)=>r===n?e:t)),onMove:e=>{let t=n+e;if(t<0||t>=a.length)return;let r=[...a];[r[n],r[t]]=[r[t],r[n]],o(r)},onRemove:()=>o(a.filter((e,t)=>t!==n))},n)),(0,C.jsxs)(`div`,{className:`flex flex-col items-start sm:flex-row sm:items-center gap-3 rounded-2xl border border-dashed border-[var(--panel-border)] px-4 py-3.5`,children:[(0,C.jsx)(t.o,{icon:u.t,title:`Add a question`,onClick:()=>o([...a,r.j()]),children:`Add a question`}),a.length===0&&(0,C.jsx)(`p`,{className:`text-[11px] sm:text-[11.5px] text-foreground/40 font-medium leading-snug`,children:`Nothing else is asked — just a name and an email.`})]})]})})}var L=(e,t,n=72)=>e>=n&&e<=Math.max(n,t*.45);function R(e,t=340){if(!e)return null;let n=()=>{let t=e.getBoundingClientRect?.(),n=typeof window<`u`&&window.innerHeight||0;t&&n&&L(t.top,n)||e.scrollIntoView?.({behavior:`smooth`,block:`start`})};return typeof setTimeout==`function`?setTimeout(n,t):(n(),null)}function z(e,t,n){let r=(0,S.useRef)(new Set);(0,S.useEffect)(()=>{let i=new Set(e),a=[...r.current].filter(e=>!i.has(e)&&!n.current.has(e));e.forEach(e=>r.current.add(e)),a.length&&(a.forEach(e=>r.current.delete(e)),t(e=>{if(!a.some(t=>t in e))return e;let t={...e};for(let e of a)delete t[e];return t}))},[e.join(`\0`)])}var B=`__new_payment__`;function V(){let[e,n]=(0,S.useState)([]);return(0,S.useEffect)(()=>{let e=t.Zr(t.Qn,()=>(0,w.collection)(t.ui,t.Qn),e=>{let r=[];e.forEach(e=>{e.id!==`_settings`&&r.push(t.Dr(e.id,e.data()))}),n(r.filter(e=>e.kind===`once`).sort((e,t)=>(e.createdAt||0)-(t.createdAt||0)))},()=>n([]));return()=>e()},[]),e}function H({value:e,products:n,meetingName:r,canCreate:i,onChange:a,onCreate:o}){let[s,c]=(0,S.useState)(!1),[l,d]=(0,S.useState)(``),[f,p]=(0,S.useState)(``),[m,h]=(0,S.useState)(!1),g=[...n.map(e=>({value:e.id,label:`${t.xr(e)} — ${t.gr(e).map(e=>e.amount).filter(Boolean).join(` + `)||`no price yet`}`})),...i?[{value:B,label:`+ A new one-time payment`}]:[]],_=n.find(t=>t.id===e),v=l.trim()&&t.br(l)===null?`Just a number, like 25.`:void 0;return(0,C.jsxs)(`div`,{className:`flex flex-col gap-3`,children:[(0,C.jsx)(t.g,{label:`Payment for this meeting`,hint:_?`Taken on the booking page before the time is confirmed. Its price and its link are on the Payments screen.`:i?`Optional. A one-time payment taken on the booking page before the time is confirmed.`:n.length?`Optional. One of the payments your admin set up, taken on the booking page before the time is confirmed.`:`Your admin has not set up a payment to charge for a meeting yet.`,value:s?B:e,placeholder:`No payment`,options:g,onChange:e=>{if(e===`__new_payment__`){c(!0);return}c(!1),a(e)}}),s&&(0,C.jsxs)(`div`,{className:`rounded-2xl border border-[var(--panel-border)]/60 px-4 py-3.5 flex flex-col gap-3`,children:[(0,C.jsx)(t.b,{label:`The price`,hint:`Just the number — 25 charges 25 in your Stripe account's currency. The payment is called ${r} and appears on the Payments screen too.`,value:l,onChange:e=>{d(e),f&&p(``)},placeholder:`25`,error:f||v}),(0,C.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,C.jsx)(t.o,{icon:u.t,busy:m,onClick:async()=>{if(t.br(l)===null){p(`Just a number for the price, like 25.`);return}p(``),h(!0);let e=await o(r,l.trim());if(h(!1),e){p(e);return}c(!1),d(``)},children:`Create it`}),(0,C.jsx)(t.o,{onClick:()=>{c(!1),p(``),d(``)},children:`Never mind`})]})]})]})}function U({link:e,onChange:n}){return(0,C.jsx)(t.i,{label:`Emails about bookings`,hint:`Sent the moment a time is taken. Every booking is in your Inbox and on the calendar regardless.`,children:(0,C.jsxs)(`div`,{className:`flex flex-col gap-3 rounded-2xl border border-[var(--panel-border)]/60 px-4 py-3.5`,children:[(0,C.jsx)(t.S,{label:`Email me when someone books`,hint:`A note at your address — the sale alert, when they paid.`,hintWideOnly:!0,enabled:e.notifyOwner,onChange:e=>n({notifyOwner:e})}),(0,C.jsx)(t.S,{label:`Email them a confirmation`,hint:`Their receipt when they pay. For a free booking, a note that the time is theirs — to people who book signed in.`,hintWideOnly:!0,enabled:e.confirmBooker,onChange:e=>n({confirmBooker:e})})]})})}var ee=e=>{let t={...a.I(a.H(),e),createdAt:Date.now()};return{...t,name:r.O(t),description:r.D(t)}};function te({link:e,schedules:n,products:i,services:o,isAdmin:s=!0,onChange:c,onCreatePayment:l}){let u=n.find(t=>t.id===e.scheduleId),d=t=>c({...e,...t}),f=a.z(e,u),p=u?a.L(e,u):null,m=t=>{let n={...e,...t};return{...t,...e.name.trim()===r.O(e)?{name:r.O(n)}:{},...e.description.trim()===r.D(e)?{description:r.D(n)}:{}}};return(0,C.jsxs)(C.Fragment,{children:[(0,C.jsx)(t.g,{label:`Which hours is it booked in?`,hint:`Change the hours and every meeting booked in them changes with it — one holiday, entered once, closes them all.`,value:e.scheduleId,options:n.map(e=>({value:e.id,label:r.ut(e)})),allowEmpty:!1,onChange:t=>{let r=n.find(e=>e.id===t);if(!r)return;let i=!u||e.memberName.trim()===u.memberName.trim();d(m({scheduleId:r.id,memberId:r.memberId,...i?{memberName:r.memberName}:{}}))}}),(0,C.jsx)(t.b,{label:`What is it called?`,hint:`Visitors read this on the booking page. It starts named after its length — call it whatever you like. Left blank it goes back to ${r.O(e)}.`,value:e.name,onChange:e=>d({name:e}),placeholder:r.O(e)}),(0,C.jsx)(t.y,{label:`A line or two about it`,hint:`Visitors read it under the name — what it is for, what to bring, what happens after. Emptied, the booking page simply shows none.`,value:e.description,onChange:e=>d({description:e}),placeholder:`A first conversation about what you need and how I can help.`}),(0,C.jsx)(t.b,{label:`The name visitors see`,value:e.memberName,onChange:e=>d(m({memberName:e})),placeholder:`Anna`}),(0,C.jsx)(t.g,{label:`How long is one booking?`,value:String(e.slotMinutes),options:r.b,allowEmpty:!1,onChange:e=>d(m({slotMinutes:Number(e)}))}),(0,C.jsx)(t.g,{label:`How far ahead can people book?`,value:String(e.horizonDays),options:r.h,allowEmpty:!1,onChange:e=>d({horizonDays:Number(e)})}),(0,C.jsx)(t.g,{label:`How much notice do you need?`,value:String(e.noticeHours),options:r._,allowEmpty:!1,onChange:e=>d({noticeHours:Number(e)})}),(0,C.jsx)(I,{questions:e.questions,onChange:e=>d({questions:e})}),(0,C.jsx)(b.t,{service:`payments`,readiness:b.n(o.payments),children:(0,C.jsx)(H,{value:e.paymentId,products:i,meetingName:a.V(e),canCreate:s,onChange:e=>d({paymentId:e}),onCreate:async(e,t)=>{let n=await l(e,t);return n&&n.startsWith(`p_`)?(d({paymentId:n}),null):n||`The payment could not be made — make sure you are signed in as an admin and try again.`}})}),(0,C.jsx)(b.t,{service:`email`,readiness:b.n(o.email),children:(0,C.jsx)(U,{link:e,onChange:d})}),(0,C.jsx)(t.i,{label:`Booking link`,hint:p&&!f&&e.enabled?`Send it to anyone. They see the free times in their own time zone, pick one and book — and pay first, when a payment is attached.`:`The link opens once the meeting is complete and turned on.`,children:(0,C.jsx)(x.t,{title:a.V(e),path:r.U(e.id)})}),(0,C.jsx)(`div`,{className:`pt-1`,children:f?e.enabled?(0,C.jsxs)(`span`,{className:`text-[11.5px] font-semibold text-amber-500`,children:[`Turned on, but not bookable yet — `,f]}):(0,C.jsx)(`span`,{className:t.s,children:f}):e.enabled?(0,C.jsx)(`span`,{className:`text-[11.5px] font-semibold text-emerald-500`,children:`Bookable — send the link, pick it on a page under Booking on this page, or add a Pick-a-time question to a form.`}):(0,C.jsx)(`span`,{className:t.s,children:`Complete — flip the switch at the top of the row to offer it.`})})]})}function W({link:e,schedules:n,products:r,services:o,isAdmin:s=!0,open:c,fresh:l,error:u,onToggle:f,onChange:p,onRemove:m,onCreatePayment:g}){let _=n.find(t=>t.id===e.scheduleId),v=a.R(e,_),[y,b]=(0,S.useState)(!1),x=a.V(e),w=(0,S.useRef)(null);return(0,S.useEffect)(()=>{if(!l)return;let e=R(w.current);return()=>{e&&clearTimeout(e)}},[l]),(0,C.jsxs)(`div`,{ref:w,className:`scroll-mt-4 rounded-2xl border border-[var(--panel-border)]`,children:[(0,C.jsxs)(`div`,{className:`flex items-center gap-2 sm:gap-2.5 pr-3`,children:[(0,C.jsxs)(`button`,{type:`button`,onClick:f,"aria-expanded":c,className:`flex-1 min-w-0 flex items-center justify-between gap-3 px-4 py-3 text-left cursor-pointer`,children:[(0,C.jsx)(`span`,{className:`text-[13px] font-semibold text-foreground/75 truncate`,children:a.B(e,_)}),(0,C.jsxs)(`span`,{className:`flex items-center gap-2.5 shrink-0`,children:[(0,C.jsx)(`span`,{className:`max-sm:hidden`,children:(0,C.jsx)(t._,{state:v.state,label:v.label})}),(0,C.jsx)(i.t,{className:`w-3.5 h-3.5 text-foreground/40 shrink-0 transition-transform ${c?`rotate-180`:``}`})]})]}),(0,C.jsx)(t.x,{enabled:e.enabled,onChange:t=>p({...e,enabled:t}),label:`${x} — can be booked`}),(0,C.jsx)(t.o,{icon:d.t,tone:`danger`,compact:!0,title:`Remove ${x}`,onClick:()=>b(!0),children:`Remove`})]}),(0,C.jsx)(h.t,{isOpen:y,title:`Remove ${x}?`,message:`Its booking link stops working and it leaves every page and form it was picked on. The hours it was booked in stay, and so do the bookings already taken.`,confirmText:`Yes, remove`,cancelText:`Keep it`,onCancel:()=>b(!1),onConfirm:()=>{b(!1),m()}}),c&&(0,C.jsx)(`div`,{className:`px-4 pb-4 pt-4 border-t border-[var(--panel-border)]/60 flex flex-col gap-4`,children:(0,C.jsx)(te,{link:e,schedules:n,products:r,services:o,isAdmin:s,onChange:p,onCreatePayment:g})}),u&&(0,C.jsx)(`p`,{className:`text-[12px] font-semibold text-red-500 px-4 pb-3`,children:u})]})}function G({isAdmin:e=!0}={}){let{user:n}=t.Ft(),{loading:i,docs:o}=a.S(),s=V(),l={payments:y.r(`payments`),email:y.r(`email`)},[d,f]=(0,S.useState)({}),[p,m]=(0,S.useState)([]),[h,g]=(0,S.useState)(null),[_,v]=(0,S.useState)(null),[b,x]=(0,S.useState)({}),T=(0,S.useRef)(new Map);z(o.links.map(e=>e.id),f,T);let E=n?.uid||``,D=(0,S.useMemo)(()=>[...e?o.schedules:o.schedules.filter(e=>e.memberId===E)].sort((e,t)=>Number(t.memberId===E)-Number(e.memberId===E)),[o.schedules,e,E]),O=(0,S.useMemo)(()=>{let t=new Map(o.links.map(e=>[e.id,e]));for(let e of Object.values(d))t.set(e.id,e);for(let e of p)t.delete(e);return[...t.values()].filter(t=>e||t.memberId===E).sort((e,t)=>Number(t.memberId===E)-Number(e.memberId===E)||(e.createdAt||0)-(t.createdAt||0)||e.id.localeCompare(t.id))},[o.links,d,p,e,E]),k=e=>{let t=T.current.get(e.id);t&&clearTimeout(t),T.current.set(e.id,setTimeout(async()=>{T.current.delete(e.id);let t=await a.f(e);x(n=>{let r={...n};return t?r[e.id]=t:delete r[e.id],r})},600))},A=e=>{f(t=>({...t,[e.id]:e})),k(e)},j=()=>{let e=D.find(e=>e.memberId===E)||D[0];if(!e)return;let t=ee(e);f(e=>({...e,[t.id]:t})),g(t.id),v(t.id),k(t)},M=async e=>{let t=T.current.get(e);t&&(clearTimeout(t),T.current.delete(e)),f(t=>{let n={...t};return delete n[e],n}),m(t=>[...t,e]),h===e&&g(null);let n=await a.u(e);n&&(m(t=>t.filter(t=>t!==e)),x(t=>({...t,[e]:n})))},N=async(e,n)=>{let r={...t.cr(`p_${Date.now().toString(36)}`),kind:`once`,items:[{name:e,amount:n}]};try{let{id:e,...n}=r;return await(0,w.setDoc)((0,w.doc)(t.ui,t.Qn,e),n),e}catch(e){return console.error(`Could not make the payment`,e),null}};return(0,C.jsx)(t.m,{icon:c.t,title:`Booking links`,description:`One per kind of meeting — pick the hours it is booked in, say how long it lasts and what it asks, and send the link.`,actions:!i&&D.length>0?({open:e})=>(0,C.jsx)(t.o,{icon:u.t,compact:!0,title:`Add a booking link`,onClick:()=>{e(),j()},children:`Add a booking link`}):void 0,children:(0,C.jsx)(`div`,{className:`flex flex-col gap-3`,children:i?(0,C.jsx)(`p`,{className:t.s,children:`Loading your booking links…`}):D.length===0?(0,C.jsx)(`p`,{className:`${t.s} px-1`,children:`Add a schedule above first — a booking link is a meeting booked in somebody's hours, so there have to be hours to put it on.`}):O.length===0?(0,C.jsxs)(`p`,{className:`${t.s} px-1`,children:[`No booking link yet — press Add a booking link. It is what turns `,r.dt(D[0]),` into something people can book.`]}):O.map(t=>(0,C.jsx)(W,{link:t,schedules:D,products:s,services:l,isAdmin:e,open:h===t.id,fresh:_===t.id,error:b[t.id],onToggle:()=>g(h===t.id?null:t.id),onChange:A,onRemove:()=>M(t.id),onCreatePayment:N},t.id))})})}var K=`team`,ne=e=>`m:${e}`,re=`__nobody__`;function ie(e,t,n){return[{value:`me`,label:`My calendar`},{value:K,label:`My team's calendar`},...e.filter(e=>e.id!==n).map(e=>({value:ne(e.id),label:a.g(e)||e.email,disabled:!t.has(e.id)}))]}var q=e=>e.startsWith(`m:`)?e.slice(2):``;function J(e,t,n,i=``){if(!e.email)return Promise.resolve();let a=r.Zt(e,e.timeZone||n);return p.i(t,r.t,e.id,{when:`${a.day}, ${a.time}`,memberName:e.memberName,scheduleName:e.scheduleName,reason:i.trim()}).then(()=>{}).catch(()=>{})}function ae(e,t,n){let r=e=>[...new Set(e.map(e=>String(e||``).trim()))].filter(e=>e&&e!==n),i=r([e.memberId,...t.map(e=>e.memberId),...e.copyIds.map(e=>e.split(`__`)[0])]);return{members:i,bookers:r([e.uid,...t.map(e=>e.uid)]).filter(e=>e!==`guest`).filter(e=>!i.includes(e))}}async function oe(e,t,n,i){if(e.own||e.heldOnly)return;let a={title:`Meeting removed`,body:`${r.B(e)} · ${r.ot(new Date(e.start),i)}`};await J(e,`booking_cancelled`,i,`The meeting was removed from the calendar.`);let{members:o,bookers:s}=ae(e,t,n);await m.r(o,{...a,link:`/schedule`}),await m.r(s,{...a,link:`/my-bookings`})}var Y=e=>{try{return localStorage.getItem(`fbos_calendar_had_${e}`)===`1`}catch{return!1}};function se(){let{user:e}=t.Ft();return Y(e?.uid||``)?(0,C.jsx)(f.n,{className:`h-[420px] w-full`}):null}function X({isAdmin:e}){let{user:n}=t.Ft(),i=n?.uid||``,c=r.et(),[l,u]=(0,T.useSearchParams)(),d=l.get(`open`)||l.get(`booking`)||``,{schedules:p}=a.w(),{members:m}=a.T(),h=(0,S.useMemo)(()=>new Set(p.map(e=>e.memberId)),[p]),g=(0,S.useMemo)(()=>ie(m,h,i),[m,h,i]),[_,v]=(0,S.useState)(null);(0,S.useEffect)(()=>{d&&e&&v(e=>e??`team`)},[d,e]);let y=_??`me`,b=new Set(g.filter(e=>!e.disabled).map(e=>e.value)).has(y)?y:`me`,x=q(b),{loading:w,bookings:E,error:D}=a.v({members:b===`team`?void 0:[x||i||re],includePast:!0}),O=(0,S.useMemo)(()=>a.P(E),[E]),k=(0,S.useMemo)(()=>E.map(e=>{let t=O.get(e.id);return t?{...e,...t}:e}),[E,O]),{paid:A,checkouts:j}=s.t(k),M=a.C((0,S.useMemo)(()=>(b===`team`?m.map(e=>e.id):[x||i]).filter(Boolean),[b,m,x,i]),(0,S.useMemo)(()=>{let e=new Date;return new Date(Date.UTC(e.getUTCFullYear(),e.getUTCMonth()-1,1))},[]),{keepOpen:!0}),[N,P]=(0,S.useState)(()=>Date.now());(0,S.useEffect)(()=>{let e=setInterval(()=>P(Date.now()),6e4);return()=>clearInterval(e)},[]);let F=(0,S.useMemo)(()=>{let e=new Set(M.filter(e=>!e.open).map(e=>r.qt(e.memberId,e.start))),t=k.map(t=>a.M(t,j[t.id],e,N)),n=e=>{let t=m.find(t=>t.id===e);return p.find(t=>t.memberId===e)?.memberName||(t?a.g(t):``)},i=a.F(M,E,N).map(e=>a.N(e,n(e.memberId)));return i.length?[...t,...i]:t},[E,k,M,N,m,p,j]);(0,S.useEffect)(()=>{if(!(w||!i))try{localStorage.setItem(`fbos_calendar_had_${i}`,F.length?`1`:`0`)}catch{}},[w,i,F.length]);let I=x||i,L=m.find(e=>e.id===I),R=p.find(e=>e.memberId===I)?.memberName||(L?a.g(L):``)||(I===i?String(n?.displayName||``):``);return w&&F.length===0?Y(i)?(0,C.jsx)(f.n,{className:`h-[420px] w-full`}):null:F.length===0?null:(0,C.jsx)(t.m,{icon:o.d,title:`Calendar`,description:b===`team`?`Every booking made with your team, and the events they put on their own days — in your time, ${r.nn(c)}.`:x?`${R||`Their`} calendar, read as they read it — in your time, ${r.nn(c)}.`:`Every booking made with you, under every schedule of yours — in your time, ${r.nn(c)}.`,actions:e&&g.length>2?(0,C.jsx)(t.Z,{ariaLabel:`Whose calendar`,value:b,options:g,onChange:v,className:`console-select`,compact:!0,dense:!0,portal:!0,direction:`auto`}):void 0,children:w?(0,C.jsx)(`p`,{className:t.s,children:`Loading the calendar…`}):D?(0,C.jsx)(`p`,{className:`text-[12px] font-semibold text-red-500 px-1`,children:D}):(0,C.jsx)(s.n,{bookings:F,zone:c,paid:A,openBookingId:d||void 0,onOpened:d?()=>u(e=>(e.delete(`open`),e.delete(`booking`),e),{replace:!0}):void 0,withMember:b===K,me:i,onAccept:async e=>{let t=await a.t(e.id);return t||J(e,`booking_confirmed`,c),t},onCancel:async(e,t)=>{let r=await a.r(e.id,{ids:e.copyIds,reason:t,side:`host`,by:e.memberId===i?R||String(n?.displayName||``):e.memberName,byUid:i});return r||J(e,`booking_cancelled`,c,t),r},onDelete:async e=>(await oe(e,E,i,c),a.a(e.id,e.copyIds)),canDelete:t=>e||t.own&&t.memberId===i,onRelease:e=>a.c(e.memberId,e.start),onColor:a.m,onAdd:b===`team`?void 0:e=>a.n({...e,memberId:I,memberName:R,timeZone:c})})})}function ce(e,t){if(!e.enabled)return{state:`off`,label:`Off`};if(g.c(e,t))return{state:`error`,label:`Unfinished`};let n=e.schedules.length;return{state:`saved`,label:n===1?`1 meeting`:`${n} meetings`}}var le=e=>{let t=e.schedules.length;return`${g.s(e)} — ${t===0?`nothing on it yet`:t===1?`1 meeting`:`${t} meetings`}`};function Z({page:e,schedules:n,onChange:i}){return n.length?(0,C.jsx)(t.i,{label:`Meetings on this page`,hint:`They appear in the order you tick them. A meeting switched off above is kept off the page too.`,children:(0,C.jsx)(`div`,{className:`flex flex-col gap-1.5`,children:n.map(t=>{let n=e.schedules.includes(t.id);return(0,C.jsxs)(`button`,{type:`button`,role:`checkbox`,"aria-checked":n,onClick:()=>i(g.p(e,t.id)),className:`flex items-center gap-3 px-3 py-2.5 rounded-xl border text-left transition-all cursor-pointer active:scale-[0.995] ${n?`border-accent/45 bg-accent/[0.07]`:`border-[var(--panel-border)]/70 hover:border-accent/30 hover:bg-foreground/[0.03]`}`,children:[(0,C.jsx)(`span`,{"aria-hidden":!0,className:`w-[18px] h-[18px] rounded-[5px] border flex items-center justify-center shrink-0 transition-all ${n?`border-accent bg-accent`:`border-foreground/25`}`,children:n&&(0,C.jsx)(`span`,{className:`w-[7px] h-[7px] rounded-[2px] bg-[var(--button-fg,#fff)]`})}),(0,C.jsx)(`span`,{className:`flex-1 min-w-0 text-[13px] font-semibold text-foreground/80 truncate`,children:r.Bt(t)})]},t.id)})})}):(0,C.jsx)(t.i,{label:`Meetings on this page`,children:(0,C.jsx)(`p`,{className:`${t.s} px-1`,children:`Make a schedule above first — a page offers the meetings you have set up.`})})}function ue({page:e,taken:n,onRename:r}){let[i,a]=(0,S.useState)(e.id),o=g.f(i),s=!!o&&o!==e.id&&n.includes(o);return(0,C.jsx)(t.b,{label:`Its address`,prefix:`/meet/`,value:i,onChange:a,onBlur:()=>{if(!o||s||o===e.id){a(e.id);return}r(o)},placeholder:`anna-bell`,error:s?`Another page already has that address.`:void 0,hint:`Change it and the old link stops working, so change it before you send it out.`})}function de({page:n,schedules:r,taken:a,open:o,fresh:s,error:c,onToggle:l,onChange:u,onRename:f,onRemove:p}){let[m,_]=(0,S.useState)(!1),v=ce(n,r),y=g.s(n),b=g.c(n,r),w=(0,S.useRef)(null);return(0,S.useEffect)(()=>{if(!s)return;let e=R(w.current);return()=>{e&&clearTimeout(e)}},[s]),(0,C.jsxs)(`div`,{ref:w,className:`scroll-mt-4 rounded-2xl border border-[var(--panel-border)]`,children:[(0,C.jsxs)(`div`,{className:`flex items-center gap-2 sm:gap-2.5 pr-3`,children:[(0,C.jsxs)(`button`,{type:`button`,onClick:l,"aria-expanded":o,className:`flex-1 min-w-0 flex items-center justify-between gap-3 px-4 py-3 text-left cursor-pointer`,children:[(0,C.jsx)(`span`,{className:`text-[13px] font-semibold text-foreground/75 truncate`,children:le(n)}),(0,C.jsxs)(`span`,{className:`flex items-center gap-2.5 shrink-0`,children:[(0,C.jsx)(`span`,{className:`max-sm:hidden`,children:(0,C.jsx)(t._,{state:v.state,label:v.label})}),(0,C.jsx)(i.t,{className:`w-3.5 h-3.5 text-foreground/40 shrink-0 transition-transform ${o?`rotate-180`:``}`})]})]}),(0,C.jsx)(t.x,{enabled:n.enabled,onChange:e=>u({...n,enabled:e}),label:`${y} — page is live`}),(0,C.jsx)(t.o,{icon:d.t,tone:`danger`,compact:!0,title:`Remove ${y}`,onClick:()=>_(!0),children:`Remove`})]}),(0,C.jsx)(h.t,{isOpen:m,title:`Remove ${y}?`,message:`Its link stops working. The meetings on it are untouched and keep their own links, and bookings already taken are kept.`,confirmText:`Yes, remove`,cancelText:`Keep it`,onCancel:()=>_(!1),onConfirm:()=>{_(!1),p()}}),o&&(0,C.jsxs)(`div`,{className:`px-4 pb-4 pt-4 border-t border-[var(--panel-border)]/60 flex flex-col gap-4`,children:[(0,C.jsx)(t.b,{label:`Name on the page`,value:n.title,onChange:e=>u({...n,title:e}),placeholder:`Anna Bell`,hint:`Usually the name of whoever the page is for.`}),(0,C.jsx)(e.a,{label:`Photo`,hint:`Shown at the top of the page. A square picture of the person works best.`,value:n.photo,onChange:e=>u({...n,photo:e})}),(0,C.jsx)(t.y,{label:`About this page`,value:n.intro,onChange:e=>u({...n,intro:e}),rows:3,placeholder:`I help small studios get their bookkeeping straight. Pick a time below and tell me what you need.`}),(0,C.jsx)(Z,{page:n,schedules:r,onChange:u}),(0,C.jsx)(ue,{page:n,taken:a,onRename:f}),b?(0,C.jsx)(`p`,{className:`text-[12px] font-semibold text-amber-500 px-1`,children:b}):(0,C.jsx)(x.t,{title:y,path:g.l(n.id)})]}),c&&(0,C.jsx)(`p`,{className:`text-[12px] font-semibold text-red-500 px-4 pb-3`,children:c})]})}function fe({schedules:e,myName:n,isAdmin:r=!0,meId:i=``}){let{loading:a,pages:o}=g.i(),[s,l]=(0,S.useState)({}),[d,f]=(0,S.useState)([]),[p,m]=(0,S.useState)(null),[h,_]=(0,S.useState)(null),[v,y]=(0,S.useState)({}),b=(0,S.useRef)(new Map);z(o.map(e=>e.id),l,b);let x=new Map(o.map(e=>[e.id,e]));for(let e of Object.values(s))x.set(e.id,e);for(let e of d)x.delete(e);let w=[...x.values()].sort((e,t)=>(e.createdAt||0)-(t.createdAt||0)||e.id.localeCompare(t.id)),T=w.map(e=>e.id),E=g.u(w,i,r),D=r?e:e.filter(e=>e.memberId===i),O=e=>{let t=b.current.get(e.id);t&&clearTimeout(t),b.current.set(e.id,setTimeout(async()=>{b.current.delete(e.id);let t=await g.r(e);y(n=>{let r={...n};return t?r[e.id]=t:delete r[e.id],r})},600))},k=e=>{l(t=>({...t,[e.id]:e})),O(e)},A=()=>{let e=g.a(g.m(n||`my page`,T),n,i);l(t=>({...t,[e.id]:e})),f(t=>t.filter(t=>t!==e.id)),m(e.id),_(e.id),O(e)},j=async(e,t)=>{let n=b.current.get(e.id);n&&(clearTimeout(n),b.current.delete(e.id));let r={...e,id:t};l(n=>{let i={...n};return delete i[e.id],i[t]=r,i}),f(n=>[...n.filter(e=>e!==t),e.id]),p===e.id&&m(t);let i=await g.n(e.id,r);i&&y(e=>({...e,[t]:i}))},M=async e=>{let t=b.current.get(e);t&&(clearTimeout(t),b.current.delete(e)),l(t=>{let n={...t};return delete n[e],n}),f(t=>[...t,e]),p===e&&m(null);let n=await g.t(e);n&&(f(t=>t.filter(t=>t!==e)),y(t=>({...t,[e]:n})))};return(0,C.jsx)(t.m,{icon:c.t,title:`Your booking pages`,description:`One link with a photo, a line about you and every meeting you offer.`,actions:({open:e})=>(0,C.jsx)(t.o,{icon:u.t,compact:!0,title:`Create a page`,onClick:()=>{e(),A()},children:`Create a page`}),children:(0,C.jsx)(`div`,{className:`flex flex-col gap-3`,children:a?(0,C.jsx)(`p`,{className:`${t.s} px-1`,children:`Loading pages…`}):E.length===0?(0,C.jsx)(`p`,{className:`${t.s} px-1`,children:`No pages yet. Create one to hand out a single link — a visitor sees your photo, what you do and every meeting you offer, and picks the one they want.`}):E.map(e=>(0,C.jsx)(de,{page:e,schedules:D,taken:T,open:p===e.id,fresh:h===e.id,error:v[e.id],onToggle:()=>m(t=>t===e.id?null:e.id),onChange:k,onRename:t=>j(e,t),onRemove:()=>M(e.id)},e.id))})})}var pe={from:`09:00`,to:`17:00`},me=e=>r.pt(e)?{state:`saved`,label:`Ready`}:{state:`off`,label:`In progress`},he=e=>({...r.M(a.U(),e.id,a.g(e),r.et()),name:`Working hours`,enabled:!0,createdAt:Date.now()}),Q=`w-[6.5rem] shrink-0`,ge=`w-9 h-9 rounded-[var(--btn-radius,0.75rem)] border border-[var(--panel-border)] flex items-center justify-center shrink-0 text-foreground/45 hover:text-red-500 hover:border-red-500/40 hover:bg-red-500/[0.06] active:scale-[0.98] transition-all cursor-pointer`;function _e({day:e,windows:n,onChange:i}){let a=n.length>0,o=(e,t)=>i(n.map((n,r)=>r===e?{...n,...t}:n));return(0,C.jsxs)(`div`,{className:`grid grid-cols-1 sm:grid-cols-[8.5rem_minmax(0,1fr)] items-start gap-x-4 gap-y-2 py-2.5`,children:[(0,C.jsxs)(`div`,{className:`flex items-center justify-between gap-3 h-9`,children:[(0,C.jsx)(`span`,{className:`text-[13px] font-medium ${a?`text-foreground/80`:`text-foreground/40`}`,children:r.u[e]}),(0,C.jsx)(t.x,{enabled:a,onChange:e=>i(e?[pe]:[]),label:`${r.u[e]} — bookable`})]}),a&&(0,C.jsxs)(`div`,{className:`flex flex-col gap-2 min-w-0`,children:[n.map((a,s)=>(0,C.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,C.jsx)(`div`,{className:Q,children:(0,C.jsx)(t.Z,{ariaLabel:`${r.u[e]} from${s?` (${s+1})`:``}`,value:a.from,options:r.m,onChange:e=>o(s,{from:e}),className:`console-select`,compact:!0,portal:!0,direction:`auto`})}),(0,C.jsx)(`span`,{className:`w-3 text-center text-foreground/40 text-[13px] shrink-0 select-none`,children:`–`}),(0,C.jsx)(`div`,{className:Q,children:(0,C.jsx)(t.Z,{ariaLabel:`${r.u[e]} to${s?` (${s+1})`:``}`,value:a.to,options:r.d,onChange:e=>o(s,{to:e}),className:`console-select`,compact:!0,portal:!0,direction:`auto`})}),n.length>1&&(0,C.jsx)(`button`,{type:`button`,title:`Remove these hours on ${r.u[e]}`,"aria-label":`Remove ${r.u[e]} hours ${s+1}`,onClick:()=>i(n.filter((e,t)=>t!==s)),className:ge,children:(0,C.jsx)(l.t,{className:`w-3.5 h-3.5`})})]},s)),n.length<2&&(0,C.jsx)(`button`,{type:`button`,onClick:()=>i([...n,{from:`18:00`,to:`20:00`}]),className:`self-start h-6 px-1 text-[11.5px] font-semibold text-foreground/45 hover:text-accent transition-colors cursor-pointer`,children:`+ Add a second stretch`})]})]})}function ve({schedule:e,onChange:n}){let i=t=>n({...e,...t}),a=r.ft(e);return(0,C.jsxs)(C.Fragment,{children:[(0,C.jsx)(t.b,{label:`What are these hours called?`,hint:`Only you and your team read this — it is how a booking link names the hours it is booked in. Working hours, Evenings, Studio days.`,value:e.name,onChange:e=>i({name:e}),placeholder:`Working hours`}),(0,C.jsx)(t.t,{value:e.timeZone,onChange:e=>i({timeZone:e})}),(0,C.jsx)(t.i,{label:`When`,hint:`The hours on each day, in this person's own time zone. Add a second stretch for a break in the middle. A time booked in any of their hours is taken here too.`,children:(0,C.jsx)(`div`,{className:`flex flex-col divide-y divide-[var(--panel-border)]/60 rounded-2xl border border-[var(--panel-border)]/60 px-4 py-1`,children:r.l.map(t=>(0,C.jsx)(_e,{day:t,windows:e.days[t]||[],onChange:n=>i({days:{...e.days,[t]:n}})},t))})}),(0,C.jsx)(M,{blocked:e.blocked,onChange:e=>i({blocked:e})}),(0,C.jsx)(`div`,{className:`pt-1`,children:a?(0,C.jsxs)(`span`,{className:`text-[11.5px] font-semibold text-amber-500`,children:[`Not usable yet — `,a]}):(0,C.jsx)(`span`,{className:`text-[11.5px] font-semibold text-emerald-500`,children:`Ready — add a booking link below to let people book these hours, or ask for a page built on them.`})})]})}function $({schedule:e,open:n,stale:a,fresh:o,error:s,onToggle:c,onChange:l,onRemove:u}){let f=me(e),[p,m]=(0,S.useState)(!1),g=r.dt(e),_=(0,S.useRef)(null);return(0,S.useEffect)(()=>{if(!o)return;let e=R(_.current);return()=>{e&&clearTimeout(e)}},[o]),(0,C.jsxs)(`div`,{ref:_,className:`scroll-mt-4 rounded-2xl border border-[var(--panel-border)] ${a?`opacity-60`:``}`,children:[(0,C.jsxs)(`div`,{className:`flex items-center gap-2 sm:gap-2.5 pr-3`,children:[(0,C.jsxs)(`button`,{type:`button`,onClick:c,"aria-expanded":n,className:`flex-1 min-w-0 flex items-center justify-between gap-3 px-4 py-3 text-left cursor-pointer`,children:[(0,C.jsx)(`span`,{className:`text-[13px] font-semibold text-foreground/75 truncate`,children:r.mt(e)}),(0,C.jsxs)(`span`,{className:`flex items-center gap-2.5 shrink-0`,children:[a?(0,C.jsx)(`span`,{className:`${t.s} max-sm:hidden`,children:`No longer on the team`}):(0,C.jsx)(`span`,{className:`max-sm:hidden`,children:(0,C.jsx)(t._,{state:f.state,label:f.label})}),(0,C.jsx)(i.t,{className:`w-3.5 h-3.5 text-foreground/40 shrink-0 transition-transform ${n?`rotate-180`:``}`})]})]}),(0,C.jsx)(t.o,{icon:d.t,tone:`danger`,compact:!0,title:`Remove ${g}`,onClick:()=>m(!0),children:`Remove`})]}),(0,C.jsx)(h.t,{isOpen:p,title:`Remove ${g}?`,message:a?`They are no longer on the team, so nobody can book them. Bookings already taken are kept.`:`Every booking link booked in these hours stops working, and they leave every page and form they were picked on. Bookings already taken are kept.`,confirmText:`Yes, remove`,cancelText:`Keep it`,onCancel:()=>m(!1),onConfirm:()=>{m(!1),u()}}),n&&(0,C.jsx)(`div`,{className:`px-4 pb-4 pt-4 border-t border-[var(--panel-border)]/60 flex flex-col gap-4`,children:(0,C.jsx)(ve,{schedule:e,onChange:l})}),s&&(0,C.jsx)(`p`,{className:`text-[12px] font-semibold text-red-500 px-4 pb-3`,children:s})]})}function ye({name:e,schedules:n,stale:r,open:a,onToggle:o,onAdd:s,openScheduleId:c,freshId:l,errors:d,onToggleSchedule:f,onChange:p,onRemove:m}){let h=r?`No longer on the team`:n.length===0?`No schedules yet`:`${n.length} schedule${n.length===1?``:`s`}`,g=(0,S.useRef)(null);return(0,S.useEffect)(()=>{if(!a)return;let e=R(g.current);return()=>{e&&clearTimeout(e)}},[a]),(0,C.jsxs)(`div`,{ref:g,className:`scroll-mt-4 rounded-2xl border border-[var(--panel-border)]`,children:[(0,C.jsxs)(`button`,{type:`button`,onClick:o,"aria-expanded":a,className:`w-full flex items-center justify-between gap-3 px-4 py-3 text-left cursor-pointer`,children:[(0,C.jsx)(`span`,{className:`text-[13px] font-semibold text-foreground/75 truncate`,children:e}),(0,C.jsxs)(`span`,{className:`flex items-center gap-2.5 shrink-0`,children:[(0,C.jsx)(`span`,{className:`${t.s} max-sm:hidden`,children:h}),(0,C.jsx)(i.t,{className:`w-3.5 h-3.5 text-foreground/40 shrink-0 transition-transform ${a?`rotate-180`:``}`})]})]}),a&&(0,C.jsxs)(`div`,{className:`px-4 pb-4 pt-4 border-t border-[var(--panel-border)]/60 flex flex-col gap-3`,children:[n.map(e=>(0,C.jsx)($,{schedule:e,stale:r,fresh:l===e.id,open:c===e.id,error:d[e.id],onToggle:()=>f(e.id),onChange:p,onRemove:()=>m(e.id)},e.id)),r?n.length===0&&(0,C.jsxs)(`p`,{className:`text-[11px] sm:text-[11.5px] text-foreground/40 font-medium leading-snug`,children:[`No schedule yet for `,e,`.`]}):(0,C.jsxs)(`div`,{className:`flex flex-col items-start sm:flex-row sm:items-center gap-3 rounded-2xl border border-dashed border-[var(--panel-border)] px-4 py-3`,children:[(0,C.jsx)(t.o,{icon:u.t,title:`Add a schedule for ${e}`,onClick:s,children:`Add a schedule`}),n.length===0&&(0,C.jsxs)(`p`,{className:`text-[11px] sm:text-[11.5px] text-foreground/40 font-medium leading-snug`,children:[`No schedule yet for `,e,`.`]})]})]})]})}var be=e=>({id:e.uid,name:String(e.displayName||``),email:String(e.email||``),role:`admin`});function xe({isAdmin:e=!0}={}){let{user:r}=t.Ft(),{loading:i,members:o}=a.T(),{loading:s,docs:c}=a.S(),l=c.schedules,[d,f]=(0,S.useState)({}),[p,m]=(0,S.useState)([]),[h,g]=(0,S.useState)(null),[_,v]=(0,S.useState)(null),[y,b]=(0,S.useState)(null),[x,w]=(0,S.useState)({}),E=(0,S.useRef)(new Map);z(l.map(e=>e.id),f,E);let D=(0,S.useMemo)(()=>{let e=new Map(l.map(e=>[e.id,e]));for(let t of Object.values(d))e.set(t.id,t);for(let t of p)e.delete(t);return[...e.values()].sort((e,t)=>(e.createdAt||0)-(t.createdAt||0)||e.id.localeCompare(t.id))},[l,d,p]),O=e=>{let t=E.current.get(e.id);t&&clearTimeout(t),E.current.set(e.id,setTimeout(async()=>{E.current.delete(e.id);let t=await a.p(e);w(n=>{let r={...n};return t?r[e.id]=t:delete r[e.id],r})},600))},k=e=>{f(t=>({...t,[e.id]:e})),O(e)},A=(0,S.useMemo)(()=>r?o.find(e=>e.id===r.uid)||be(r):null,[r,o]),j=(0,S.useMemo)(()=>A&&!o.some(e=>e.id===A.id)?[A,...o]:o,[A,o]),M=(0,S.useRef)(!1),[N,P]=(0,S.useState)(``),F=(0,S.useMemo)(()=>c.schedules.filter(t=>c.legacyIds.includes(t.id)&&(e||t.memberId===A?.id)),[c.schedules,c.legacyIds,e,A]);(0,S.useEffect)(()=>{M.current||F.length===0||(M.current=!0,a.h(F).then(e=>{e&&P(e)}))},[F]);let I=e=>{let t=he(e);f(e=>({...e,[t.id]:t})),g(t.id),v(t.id),A&&e.id!==A.id&&b(e.id),O(t)},L=()=>{A&&I(A)},R=async e=>{let t=E.current.get(e);t&&(clearTimeout(t),E.current.delete(e)),f(t=>{let n={...t};return delete n[e],n}),m(t=>[...t,e]),h===e&&g(null);let n=await a.d(e);n&&(m(t=>t.filter(t=>t!==e)),w(t=>({...t,[e]:n})))},B=i||s,V=new Set(j.map(e=>e.id)),H=A?D.filter(e=>e.memberId===A.id):[],U=(0,S.useMemo)(()=>{if(!A)return[];let e=new Map;for(let t of D){if(t.memberId===A.id)continue;let n=e.get(t.memberId);n?n.push(t):e.set(t.memberId,[t])}let t=[];for(let n of j)n.id!==A.id&&(t.push({id:n.id,name:a.g(n)||n.email,stale:!1,schedules:e.get(n.id)||[]}),e.delete(n.id));for(let[n,r]of e)t.push({id:n,name:r[0].memberName.trim()||`Someone no longer on the team`,stale:!0,schedules:r});return t},[D,j,A]);return(0,C.jsxs)(C.Fragment,{children:[(0,C.jsx)(t.m,{icon:n.C,title:`Your schedules`,description:`When you are free — a name, a time zone, the week's hours and the days you are away. The base for anything booked on them.`,actions:B?void 0:({open:e})=>(0,C.jsx)(t.o,{icon:u.t,compact:!0,title:`Add a schedule`,onClick:()=>{e(),L()},children:`Add a schedule`}),children:(0,C.jsxs)(`div`,{className:`flex flex-col gap-3`,children:[B?(0,C.jsx)(`p`,{className:t.s,children:`Loading your schedules…`}):H.length===0?(0,C.jsx)(`p`,{className:`${t.s} px-1`,children:`No hours of your own yet — press Add a schedule. Everything booked in them shares one availability, so a time taken once is gone from all of it.`}):H.map(e=>(0,C.jsx)($,{schedule:e,stale:!V.has(e.memberId),fresh:_===e.id,open:h===e.id,error:x[e.id],onToggle:()=>g(h===e.id?null:e.id),onChange:k,onRemove:()=>R(e.id)},e.id)),!!N&&(0,C.jsx)(`p`,{className:`text-[12px] font-semibold text-red-500 px-1`,children:N})]})}),e&&(0,C.jsx)(t.m,{icon:n.S,title:`Your team's schedules`,description:`When everyone else is free — one folded row per person; open a name to add their hours or see what they keep.`,children:(0,C.jsx)(`div`,{className:`flex flex-col gap-3`,children:B?(0,C.jsx)(`p`,{className:`text-[11px] sm:text-[11.5px] text-foreground/40 font-medium leading-snug`,children:`Loading your team's schedules…`}):U.length===0?(0,C.jsxs)(`p`,{className:`text-[11px] sm:text-[11.5px] text-foreground/40 font-medium leading-snug px-1`,children:[`Nobody else is marked Internal or Admin yet. Add them on the`,` `,(0,C.jsx)(T.Link,{to:`/users`,className:`text-accent font-bold hover:underline`,children:`Users screen`}),` and a folded row for them appears here.`]}):U.map(e=>(0,C.jsx)(ye,{name:e.name,schedules:e.schedules,stale:e.stale,open:y===e.id,onToggle:()=>{let t=y!==e.id;b(t?e.id:null),t&&e.schedules.length&&g(e.schedules[0].id)},onAdd:()=>{let t=j.find(t=>t.id===e.id);t&&I(t)},openScheduleId:h,freshId:_,errors:x,onToggleSchedule:e=>g(h===e?null:e),onChange:k,onRemove:R},e.id))})})]})}function Se(){let{ready:e}=t.Jn(`schedule`);return e?(0,C.jsx)(X,{isAdmin:!0}):(0,C.jsx)(se,{})}function Ce(){let{user:i,userRole:o}=t.Ft(),s=o===`admin`,{schedules:c}=a.y(),l=i&&(i.displayName||i.email?.split(`@`)[0])||``;return r.Sn(o)?(0,C.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,C.jsxs)(t.nt.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:`mb-6`,children:[(0,C.jsx)(e.t,{children:`Schedule`}),(0,C.jsxs)(`div`,{className:`flex items-center gap-2 text-foreground/40 font-bold uppercase tracking-[0.2em] text-[11px]`,children:[(0,C.jsx)(`span`,{className:`w-8 h-[1px] bg-foreground/10`}),`/schedule`]})]}),(0,C.jsxs)(`div`,{className:`flex flex-col gap-6 flex-1 pb-16`,children:[(0,C.jsx)(n.t,{}),(0,C.jsx)(v.n,{tab:`schedule`}),(0,C.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,C.jsxs)(`div`,{className:`flex flex-col gap-4`,children:[(0,C.jsx)(`div`,{className:`flex flex-col gap-1.5 px-1`,children:(0,C.jsx)(`p`,{className:`text-[13px] font-medium text-foreground/60 leading-relaxed`,children:s?`When you and your team are free, and everything built on it. A schedule is a week of hours in one person’s own time zone; a booking link turns those hours into a meeting people can book, with an address to send. The same hours are what a page you ask for is built on.`:`When you are free, and what people can book in it. Your schedule is your week of hours; a booking link turns it into a meeting, with an address of its own to send — they pick a free time and it lands on your calendar. A booking page gathers your meetings under one address to hand out.`})}),s?(0,C.jsx)(Se,{}):(0,C.jsx)(X,{isAdmin:!1}),(0,C.jsx)(xe,{isAdmin:s}),(0,C.jsx)(G,{isAdmin:s}),(0,C.jsx)(fe,{schedules:c,myName:l,isAdmin:s,meId:i?.uid||``})]})})]})]}):(0,C.jsx)(`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,C.jsx)(_.i,{})})}exports.ScheduleAdmin=Ce;
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import { a as e, t } from "./PageTitle-
|
|
2
|
-
import { Dr as n, Ft as r, Jn as i, Mt as a, Qn as o, S as s, Z as c, Zr as l, _ as u, b as d, br as f, c as p, cr as m, g as h, gr as g, i as _, jt as v, m as y, nt as b, o as x, s as S, t as C, ui as w, x as T, xr as E, y as D } from "./TimeZoneField-
|
|
3
|
-
import { C as O, S as k, t as A } from "./DashboardNav-
|
|
1
|
+
import { a as e, t } from "./PageTitle-DCoUQWw6.js";
|
|
2
|
+
import { Dr as n, Ft as r, Jn as i, Mt as a, Qn as o, S as s, Z as c, Zr as l, _ as u, b as d, br as f, c as p, cr as m, g as h, gr as g, i as _, jt as v, m as y, nt as b, o as x, s as S, t as C, ui as w, x as T, xr as E, y as D } from "./TimeZoneField-oIMwb5_X.js";
|
|
3
|
+
import { C as O, S as k, t as A } from "./DashboardNav-CEd8gGPm.js";
|
|
4
4
|
import { B as j, Bt as M, D as N, G as P, K as F, M as ee, O as I, Sn as L, U as te, W as ne, Zt as re, _ as ie, b as ae, d as oe, dt as se, et as ce, ft as le, h as ue, ht as de, j as fe, l as pe, m as me, mt as he, nn as R, o as ge, ot as _e, pt as ve, qt as ye, rn as be, s as xe, t as Se, u as z, ut as Ce } from "./schedule-C13m_kiO.js";
|
|
5
5
|
import { t as B } from "./chevron-down--LwXEv9w.js";
|
|
6
|
-
import { B as we, C as Te, F as Ee, H as De, I as Oe, L as ke, M as Ae, N as je, P as Me, R as Ne, S as Pe, T as Fe, U as Ie, V, a as Le, c as Re, d as ze, f as Be, g as H, h as Ve, m as He, n as Ue, p as We, r as Ge, t as Ke, u as qe, v as Je, w as Ye, y as Xe, z as Ze } from "./scheduleData-
|
|
7
|
-
import { d as Qe } from "./BookingCalendar-
|
|
8
|
-
import { n as $e, t as et } from "./paidSessions-
|
|
6
|
+
import { B as we, C as Te, F as Ee, H as De, I as Oe, L as ke, M as Ae, N as je, P as Me, R as Ne, S as Pe, T as Fe, U as Ie, V, a as Le, c as Re, d as ze, f as Be, g as H, h as Ve, m as He, n as Ue, p as We, r as Ge, t as Ke, u as qe, v as Je, w as Ye, y as Xe, z as Ze } from "./scheduleData-DR6A-Q7Z.js";
|
|
7
|
+
import { d as Qe } from "./BookingCalendar-Bej__mIs.js";
|
|
8
|
+
import { n as $e, t as et } from "./paidSessions-B8e5RHi4.js";
|
|
9
9
|
import { t as tt } from "./link-2-CtDUJiNU.js";
|
|
10
10
|
import { t as U } from "./x-hax8aKt8.js";
|
|
11
11
|
import { t as W } from "./plus-BKrt0Qx5.js";
|
|
12
12
|
import { t as G } from "./trash-6Wj66gJi.js";
|
|
13
|
-
import { n as nt } from "./Loader-
|
|
14
|
-
import { i as rt } from "./email-
|
|
15
|
-
import { r as it } from "./notices-
|
|
16
|
-
import { t as at } from "./ConfirmModal-
|
|
17
|
-
import { a as ot, c as st, f as ct, i as lt, l as ut, m as dt, n as ft, p as pt, r as mt, s as ht, t as gt, u as _t } from "./bookingPages-
|
|
13
|
+
import { n as nt } from "./Loader-CVoz1Zf0.js";
|
|
14
|
+
import { i as rt } from "./email-PBHbXXgR.js";
|
|
15
|
+
import { r as it } from "./notices-CysS7BLF.js";
|
|
16
|
+
import { t as at } from "./ConfirmModal-BW9e6Y7d.js";
|
|
17
|
+
import { a as ot, c as st, f as ct, i as lt, l as ut, m as dt, n as ft, p as pt, r as mt, s as ht, t as gt, u as _t } from "./bookingPages-BFSY3Riv.js";
|
|
18
18
|
import { i as vt } from "./AccessNotice-DGsp8Xfl.js";
|
|
19
|
-
import { n as yt } from "./SystemTabContent-
|
|
20
|
-
import { r as bt } from "./serviceStatus-
|
|
19
|
+
import { n as yt } from "./SystemTabContent-CMyT7mDN.js";
|
|
20
|
+
import { r as bt } from "./serviceStatus-C9izcuQz.js";
|
|
21
21
|
import { n as xt, t as St } from "./NeedsService-SxEZO5Fa.js";
|
|
22
|
-
import { t as Ct } from "./CopyLink-
|
|
22
|
+
import { t as Ct } from "./CopyLink-CNjDLzOl.js";
|
|
23
23
|
import { useEffect as K, useMemo as q, useRef as J, useState as Y } from "react";
|
|
24
24
|
import { Fragment as X, jsx as Z, jsxs as Q } from "react/jsx-runtime";
|
|
25
25
|
import { collection as wt, doc as Tt, setDoc as Et } from "firebase/firestore";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
require(`./chunk-CiTBaPhY.cjs`),require(`./PageTitle-
|
|
1
|
+
require(`./chunk-CiTBaPhY.cjs`),require(`./PageTitle-DQkvCB11.cjs`);const e=require(`./TimeZoneField-Ckn1pKAL.cjs`),t=require(`./schedule-BAea6q8_.cjs`),n=require(`./chevron-down-lyDK1rfL.cjs`),r=require(`./x-Ci8c5p6T.cjs`);let i=require(`react`),a=require(`react/jsx-runtime`),o=require(`react-router-dom`);var s=()=>{if(typeof window>`u`||!window.getSelection)return!1;try{let e=window.getSelection();return!!e&&!e.isCollapsed&&e.toString().trim().length>0}catch{return!1}},c=(e,t)=>t&&(Math.abs(e.clientX-t.x)>4||Math.abs(e.clientY-t.y)>4)?!1:!s(),l=e=>`${t.Vt(e)} · ${t.Yt(e.slotMinutes)}`,u=e=>{let n=t.X(e);return n?`${t.ut(e)} · ${n}`:t.ut(e)};function d({schedules:s,selected:c,onPick:d,placeholder:f=`Pick a schedule`,mode:p=`meetings`}){let[m,h]=(0,i.useState)(!1),g=p===`hours`,_=e=>g?t.ut(e):t.Vt(e),v=e=>g?u(e):l(e),y=e=>g?t.pt(e):t.P(e),b=e=>g?t.ft(e)?`Unfinished on the Schedule screen`:``:e.enabled?t.Rt(e)?`Unfinished on the Schedule screen`:``:`Turned off on the Schedule screen`;if(s.length===0)return(0,a.jsxs)(`p`,{className:e.s,children:[g?`No hours yet`:`No schedule yet`,` — add `,g?`a week`:`one`,` on the`,` `,(0,a.jsx)(o.Link,{to:`/schedule`,className:`text-accent font-bold hover:underline`,children:`Schedule screen`}),` first.`]});let x=c.map(e=>s.find(t=>t.id===e)).filter(e=>!!e);return(0,a.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,a.jsxs)(`div`,{className:`w-full min-h-11 flex items-center gap-2 px-3 py-1.5 rounded-[var(--input-radius,0.75rem)] border bg-[var(--panel-bg)] transition-all duration-300 console-field ${m?`border-accent`:`border-[var(--panel-border)] hover:border-accent/40`}`,children:[(0,a.jsxs)(`div`,{className:`flex-1 min-w-0 flex flex-wrap items-center gap-1.5`,children:[x.length===0&&(0,a.jsx)(`button`,{type:`button`,onClick:()=>h(e=>!e),className:`text-[14px] text-foreground/35 text-left cursor-pointer`,children:f}),x.map(e=>(0,a.jsxs)(`span`,{className:`inline-flex items-center gap-1.5 h-7 pl-2.5 pr-1.5 rounded-lg bg-accent/10 border border-accent/20 text-[12.5px] font-semibold text-foreground max-w-full`,children:[(0,a.jsx)(`span`,{className:`truncate`,children:_(e)}),(0,a.jsx)(`button`,{type:`button`,"aria-label":`Remove ${_(e)}`,onClick:()=>d(e.id),className:`w-4 h-4 rounded-md flex items-center justify-center text-foreground/50 hover:text-red-500 hover:bg-red-500/10 transition-colors cursor-pointer`,children:(0,a.jsx)(r.t,{className:`w-3 h-3`})})]},e.id))]}),(0,a.jsx)(`button`,{type:`button`,"aria-label":m?`Close the list of schedules`:`Open the list of schedules`,"aria-expanded":m,onClick:()=>h(e=>!e),className:`w-8 h-8 shrink-0 rounded-lg flex items-center justify-center text-foreground/40 hover:text-foreground hover:bg-foreground/[0.05] transition-colors cursor-pointer`,children:(0,a.jsx)(n.t,{className:`w-4 h-4 transition-transform ${m?`rotate-180`:``}`})})]}),m&&(0,a.jsx)(`div`,{className:`flex flex-col rounded-2xl border border-[var(--panel-border)]/60 px-2 py-1.5`,role:`listbox`,"aria-label":`Schedules`,"aria-multiselectable":!0,children:s.map(t=>{let n=c.includes(t.id),r=b(t);return(0,a.jsxs)(`button`,{type:`button`,role:`option`,"aria-selected":n,"aria-label":_(t),onClick:()=>d(t.id),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 ${y(t)?``:`opacity-70`}`,children:[(0,a.jsx)(`span`,{"aria-hidden":!0,className:`w-[18px] h-[18px] rounded-md border flex items-center justify-center shrink-0 transition-colors ${n?`bg-accent border-accent`:`border-[var(--panel-border)]`}`,children:n&&(0,a.jsx)(e.At,{className:`w-3 h-3 text-[var(--button-fg,#fff)]`})}),(0,a.jsx)(`span`,{className:`text-[13px] font-medium text-foreground/80 truncate min-w-0`,children:v(t)}),r&&(0,a.jsx)(`span`,{className:`text-[11px] font-semibold text-foreground/40 whitespace-nowrap shrink-0 max-sm:hidden`,children:r})]},t.id)})}),(0,a.jsx)(`span`,{className:e.s,children:g?`One person’s hours each — picking a second week of theirs replaces the first.`:`One schedule per person — picking a second one of theirs replaces the first.`})]})}Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return d}});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "./PageTitle-
|
|
2
|
-
import { At as e, s as t } from "./TimeZoneField-
|
|
1
|
+
import "./PageTitle-DCoUQWw6.js";
|
|
2
|
+
import { At as e, s as t } from "./TimeZoneField-oIMwb5_X.js";
|
|
3
3
|
import { P as n, Rt as r, Vt as i, X as a, Yt as o, ft as s, pt as c, ut as l } from "./schedule-C13m_kiO.js";
|
|
4
4
|
import { t as u } from "./chevron-down--LwXEv9w.js";
|
|
5
5
|
import { t as d } from "./x-hax8aKt8.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const e=require(`./chunk-CiTBaPhY.cjs`),t=require(`./PageTitle-
|
|
1
|
+
const e=require(`./chunk-CiTBaPhY.cjs`),t=require(`./PageTitle-DQkvCB11.cjs`),n=require(`./TimeZoneField-Ckn1pKAL.cjs`),r=require(`./arrow-right-CGvbxks5.cjs`),i=require(`./SupportBar-DLWruzQb.cjs`),a=require(`./eye-off-zYG7T389.cjs`),o=require(`./x-Ci8c5p6T.cjs`),s=require(`./shield-check-Bsd5oaif.cjs`);let c=require(`react`);c=e.a(c,1);let l=require(`react/jsx-runtime`);require(`firebase/firestore`);var u=`aistudio`;function d(){return u}function f(){let[e,t]=(0,c.useState)(d);return[e,(0,c.useCallback)(e=>{t(e)},[])]}var p=`Set this project up for Your AI Firebase, and do only what is listed here.
|
|
2
2
|
|
|
3
3
|
1. If there is no app in this folder yet, create a Vite + React + TypeScript app in it.
|
|
4
4
|
2. Delete the starter demo — the counter, the logos, App.css, the sample markup. None of the template's own content stays.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { _ as e, b as t, t as n } from "./PageTitle-
|
|
2
|
-
import { At as r, It as i, Lt as a, Rt as o, mi as s, nt as c } from "./TimeZoneField-
|
|
1
|
+
import { _ as e, b as t, t as n } from "./PageTitle-DCoUQWw6.js";
|
|
2
|
+
import { At as r, It as i, Lt as a, Rt as o, mi as s, nt as c } from "./TimeZoneField-oIMwb5_X.js";
|
|
3
3
|
import { t as l } from "./arrow-right-C6OLl8Zh.js";
|
|
4
|
-
import { t as u } from "./SupportBar-
|
|
4
|
+
import { t as u } from "./SupportBar-DI_XbEsG.js";
|
|
5
5
|
import { t as d } from "./eye-off-CgKkn1b3.js";
|
|
6
6
|
import { r as f } from "./x-hax8aKt8.js";
|
|
7
7
|
import { t as p } from "./shield-check-DRQNdYcW.js";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import "./PageTitle-
|
|
2
|
-
import { At as e, _ as t, h as n, m as r, n as i, o as a, s as o } from "./TimeZoneField-
|
|
1
|
+
import "./PageTitle-DCoUQWw6.js";
|
|
2
|
+
import { At as e, _ as t, h as n, m as r, n as i, o as a, s as o } from "./TimeZoneField-oIMwb5_X.js";
|
|
3
3
|
import { t as s } from "./arrow-right-C6OLl8Zh.js";
|
|
4
|
-
import { t as c } from "./SupportBar-
|
|
5
|
-
import { a as l, n as u } from "./Setup-
|
|
6
|
-
import { i as d, n as f, t as p } from "./serviceStatus-
|
|
4
|
+
import { t as c } from "./SupportBar-DI_XbEsG.js";
|
|
5
|
+
import { a as l, n as u } from "./Setup-_G-s5y5Q.js";
|
|
6
|
+
import { i as d, n as f, t as p } from "./serviceStatus-C9izcuQz.js";
|
|
7
7
|
import "react";
|
|
8
8
|
import { Fragment as m, jsx as h, jsxs as g } from "react/jsx-runtime";
|
|
9
9
|
import { Navigate as _ } from "react-router-dom";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=require(`./chunk-CiTBaPhY.cjs`);require(`./PageTitle-
|
|
1
|
+
const e=require(`./chunk-CiTBaPhY.cjs`);require(`./PageTitle-DQkvCB11.cjs`);const t=require(`./TimeZoneField-Ckn1pKAL.cjs`),n=require(`./arrow-right-CGvbxks5.cjs`),r=require(`./SupportBar-DLWruzQb.cjs`),i=require(`./Setup-R4r6_tbV.cjs`),a=require(`./serviceStatus-Cde96_OO.cjs`);let o=require(`react`);o=e.a(o,1);let s=require(`react/jsx-runtime`),c=require(`react-router-dom`);var l={configured:!1,mode:null,webhookConfigured:!1};function u(e=5e3){let{status:t,error:n}=a.i(e);return{...t??l,checked:t!==null||!!n}}function d(e,t){if(!t.checked)return{state:`saving`,label:`Checking`};switch(e){case 1:case 2:return t.configured?{state:`saved`,label:`Done`}:{state:`off`,label:`Not yet`};case 3:return t.configured?{state:`saved`,label:t.mode===`live`?`Key found — live`:`Key found — test mode`}:{state:`off`,label:`No key yet`}}}var f=a.t({});function p(e=5e3){let{status:t,error:n}=a.n(e);return{...t??f,checked:t!==null||!!n}}function m(e){return e.checked?e.configured?e.key===`refused`?{state:`error`,label:`Key refused`}:e.key===`sending-only`?{state:`off`,label:`Needs Full access`}:{state:`saved`,label:`Key found`}:{state:`off`,label:`Not yet`}:{state:`saving`,label:`Checking`}}var h=`text-accent underline underline-offset-2 font-semibold hover:text-accent-deep transition-colors`;function g({href:e,children:t}){return(0,s.jsx)(`a`,{href:e,target:`_blank`,rel:`noopener noreferrer`,className:h,children:t})}function _({number:e,title:t,aside:n,children:r}){return(0,s.jsxs)(`div`,{className:`flex flex-col gap-3 pb-5 mb-5 border-b border-[var(--panel-border)]/50 last:border-0 last:pb-0 last:mb-0`,children:[(0,s.jsxs)(`div`,{className:`flex items-center gap-2.5`,children:[(0,s.jsx)(`span`,{className:`w-7 h-7 shrink-0 rounded-full bg-accent/10 border border-accent/20 text-accent flex items-center justify-center text-[12.5px] font-extrabold`,children:e}),(0,s.jsx)(`h4`,{className:`text-[14px] font-bold text-foreground tracking-tight flex-1 min-w-0`,children:t}),n]}),(0,s.jsx)(`div`,{className:`text-[13px] text-foreground/70 leading-relaxed space-y-3 sm:pl-[2.375rem]`,children:r})]})}var v=`space-y-1.5 list-decimal list-inside text-foreground/75`,y=`glass-panel border border-[var(--panel-border)] rounded-2xl overflow-hidden bg-background`;function b({onConfirm:e,hint:n,label:r}){let[a]=i.a();return(0,s.jsxs)(`div`,{className:`flex flex-col gap-2 pt-1`,children:[(0,s.jsx)(t.o,{icon:t.At,onClick:e,className:`self-start`,children:r||`I have added the variables`}),(0,s.jsx)(`p`,{className:t.s,children:n||(a===`local`?`Start the app again first — a value added to .env while it is running is not read until then. If the chips have not turned green a minute later, reload this page.`:`Press Apply in AI Studio’s Secrets tab first — the app can only read a secret once it has been applied. If the chips have not turned green a minute later, reload this page.`)})]})}function x({icon:e,title:a,description:o,stepsDescription:c,button:l,secret:u,open:d,onOpen:f,confirmed:p,steps:m,children:h}){let[g]=i.a();return(0,s.jsxs)(t.m,{icon:e,title:a,description:d?c:o,collapsible:!1,children:[(d||p)&&(0,s.jsx)(r.t,{}),d?m:(0,s.jsxs)(s.Fragment,{children:[h,p&&(0,s.jsxs)(t.h,{tone:`error`,children:[`The app cannot see the key yet.`,` `,g===`local`?(0,s.jsxs)(s.Fragment,{children:[`Make sure `,u,` has a value in your .env file, start the app again, then reload this page`]}):(0,s.jsxs)(s.Fragment,{children:[`In AI Studio’s Secrets tab make sure `,u,` is there and press Apply, then reload this page`]}),` `,`— or open the steps again to check them.`]}),(0,s.jsxs)(`button`,{type:`button`,onClick:f,className:`inline-flex items-center gap-1.5 w-fit h-9 px-4 rounded-[var(--btn-radius,0.75rem)] text-[12.5px] font-bold border border-accent/40 bg-accent/10 text-accent hover:bg-accent/15 transition-all active:scale-[0.98] cursor-pointer`,children:[l,(0,s.jsx)(n.t,{className:`w-3.5 h-3.5`})]})]})]})}function S({onConfirm:e}){let n=u(),[r]=i.a(),a=r===`local`;return(0,s.jsxs)(`div`,{className:`flex flex-col`,children:[(0,s.jsx)(_,{number:1,title:`Make a Stripe account`,aside:(0,s.jsx)(t._,{...d(1,n)}),children:(0,s.jsxs)(`ol`,{className:v,children:[(0,s.jsxs)(`li`,{children:[`Open `,(0,s.jsx)(g,{href:`https://dashboard.stripe.com`,children:`dashboard.stripe.com`}),` and create an account. It asks about your business — answer what you can and skip what you can't; none of it blocks the next steps.`]}),(0,s.jsxs)(`li`,{children:[`Click your account name in the `,(0,s.jsx)(`strong`,{children:`top left`}),` corner, choose`,` `,(0,s.jsx)(`strong`,{children:`Switch to sandbox`}),`, and make a sandbox for testing. A sandbox is a practice copy of Stripe: every card in it is pretend and every payment is practice, so nothing you do here can cost anyone real money.`]})]})}),(0,s.jsx)(_,{number:2,title:`Copy the test secret key`,aside:(0,s.jsx)(t._,{...d(2,n)}),children:(0,s.jsxs)(`ol`,{className:v,children:[(0,s.jsxs)(`li`,{children:[`Along the very bottom of the Stripe page is a dark bar that says `,(0,s.jsx)(`strong`,{children:`Developers`}),`. Click the arrow on it to unfold the panel.`]}),(0,s.jsxs)(`li`,{children:[`On the right of that panel, under `,(0,s.jsx)(`strong`,{children:`Testing tools`}),`, is your`,` `,(0,s.jsx)(`strong`,{children:`secret key`}),` — it starts with `,(0,s.jsx)(`strong`,{children:`sk_test_`}),`. Copy it.`]})]})}),(0,s.jsxs)(_,{number:3,title:a?`Put it in your .env and start the app again`:`Paste it into Secrets and press Apply`,aside:(0,s.jsx)(t._,{...d(3,n)}),children:[a?(0,s.jsxs)(`p`,{children:[`Open your `,(0,s.jsx)(`strong`,{children:`.env`}),` file — or ask your assistant to. The line below is already in it: paste the sk_test_… key between its quotes. One line, and that is the whole step — then `,(0,s.jsx)(`strong`,{children:`start the app again`}),` so it is read.`]}):(0,s.jsxs)(`ol`,{className:v,children:[(0,s.jsxs)(`li`,{children:[`Click the `,(0,s.jsx)(t.n,{}),` icon in the top right corner of your app in Google AI Studio.`]}),(0,s.jsxs)(`li`,{children:[`In the menu along the top, scroll across to `,(0,s.jsx)(`strong`,{children:`Secrets`}),`, then click`,` `,(0,s.jsx)(`strong`,{children:`+ Add secret`}),`.`]}),(0,s.jsxs)(`li`,{children:[`Copy the name below into `,(0,s.jsx)(`strong`,{children:`Secret name`}),`, and paste the sk_test_… key you just copied as the value.`]}),(0,s.jsxs)(`li`,{children:[`Click `,(0,s.jsx)(`strong`,{children:`Apply`}),`, then refresh the page. You are all set.`]})]}),(0,s.jsx)(`div`,{className:y,children:(0,s.jsx)(i.n,{name:`STRIPE_SECRET_KEY`,hint:`the sk_test_… key you copied in step 2`})}),(0,s.jsxs)(`p`,{children:[`Now you can test a payment with the pretend card `,(0,s.jsx)(`strong`,{children:`4242 4242 4242 4242`}),` and any other details you like, or by paying with Google Pay or Apple Pay. Nothing is ever charged — a sandbox is all practice.`]})]}),(0,s.jsx)(b,{onConfirm:e})]})}function C({onConfirm:e}){let n=p(),[r]=i.a(),a=r===`local`;return(0,s.jsxs)(`div`,{className:`flex flex-col`,children:[(0,s.jsx)(_,{number:1,title:`Make a Resend account and a key`,aside:(0,s.jsx)(t._,{...m(n)}),children:(0,s.jsxs)(`ol`,{className:v,children:[(0,s.jsxs)(`li`,{children:[`Open `,(0,s.jsx)(g,{href:`https://resend.com`,children:`resend.com`}),` and create a free account. It is the service that delivers email for you. Sign up with the address you sign in to this app with: until your domain is verified, that is the only address your app's mail can reach.`]}),(0,s.jsxs)(`li`,{children:[`In Resend, open `,(0,s.jsx)(`strong`,{children:`API Keys`}),` and click `,(0,s.jsx)(`strong`,{children:`Create API key`}),`. Give it any name, and under `,(0,s.jsx)(`strong`,{children:`Permission`}),` choose `,(0,s.jsx)(`strong`,{children:`Full access`}),`: that is what lets your app add your domain for you.`]}),(0,s.jsxs)(`li`,{children:[`Copy the key it shows. It starts with `,(0,s.jsx)(`strong`,{children:`re_`}),`.`]})]})}),(0,s.jsxs)(_,{number:2,title:a?`Put it in your .env and start the app again`:`Paste it into Secrets and press Apply`,aside:(0,s.jsx)(t._,{...m(n)}),children:[a?(0,s.jsxs)(`p`,{children:[`Open your `,(0,s.jsx)(`strong`,{children:`.env`}),` file, or ask your assistant to. The line below is already in it: paste the re_… key between its quotes, then `,(0,s.jsx)(`strong`,{children:`start the app again`}),` so it is read.`]}):(0,s.jsxs)(`ol`,{className:v,children:[(0,s.jsxs)(`li`,{children:[`Click the `,(0,s.jsx)(t.n,{}),` icon in the top right corner of your app in Google AI Studio.`]}),(0,s.jsxs)(`li`,{children:[`In the menu along the top, scroll across to `,(0,s.jsx)(`strong`,{children:`Secrets`}),`, then click`,` `,(0,s.jsx)(`strong`,{children:`+ Add secret`}),`.`]}),(0,s.jsxs)(`li`,{children:[`Copy the name below into `,(0,s.jsx)(`strong`,{children:`Secret name`}),`, and paste the re_… key as the value.`]}),(0,s.jsxs)(`li`,{children:[`Click `,(0,s.jsx)(`strong`,{children:`Apply`}),`, then refresh the page.`]})]}),(0,s.jsx)(`div`,{className:y,children:(0,s.jsx)(i.n,{name:`RESEND_KEY`,hint:`the re_… key you just made, with Full access`})}),(0,s.jsx)(`p`,{children:`That is the only secret. Your domain comes next, on this screen: you type it, and the app shows you exactly what to copy.`})]}),(0,s.jsx)(b,{onConfirm:e,label:`I have added the key`})]})}function w(){return(0,s.jsx)(c.Navigate,{to:`/setup`,replace:!0})}exports.ConnectCard=x,exports.EmailSetupSteps=C,exports.SetupPayments=w,exports.StripeSetupSteps=S;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const e=require(`./chunk-CiTBaPhY.cjs`),t=require(`./PageTitle-
|
|
1
|
+
const e=require(`./chunk-CiTBaPhY.cjs`),t=require(`./PageTitle-DQkvCB11.cjs`),n=require(`./TimeZoneField-Ckn1pKAL.cjs`),r=require(`./DashboardNav-GgEUpyTa.cjs`),i=require(`./Trouble-KQZyf6aY.cjs`),a=require(`./chevron-down-lyDK1rfL.cjs`),o=require(`./SupportBar-DLWruzQb.cjs`),s=require(`./ProviderMark--adeeajP.cjs`),c=require(`./x-Ci8c5p6T.cjs`),l=require(`./plus-zsWFCu4F.cjs`),u=require(`./shield-check-Bsd5oaif.cjs`),d=require(`./Button-Ccy4wFZ1.cjs`),f=require(`./registrationFields-DHHTptcl.cjs`),p=require(`./roles-BBDIJzox.cjs`);let m=require(`react`);m=e.a(m,1);let h=require(`react/jsx-runtime`),g=require(`firebase/firestore`);var _={name:`square-pen`,size:24,node:[[`path`,{d:`M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7`,key:`1m0v6g`}],[`path`,{d:`M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z`,key:`ohrbg2`}]],aliases:[`pen-box`,`edit`,`pen-square`]};_.node;var v=a.n(_),y={name:`user-plus`,size:24,node:[[`path`,{d:`M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2`,key:`1yyitq`}],[`circle`,{cx:`9`,cy:`7`,r:`4`,key:`nufk8`}],[`line`,{x1:`19`,x2:`19`,y1:`8`,y2:`14`,key:`1bvyxn`}],[`line`,{x1:`22`,x2:`16`,y1:`11`,y2:`11`,key:`1shjgl`}]]};y.node;var b=a.n(y);function x({roles:e,onCreated:t,placeholder:r=`Client`,onPending:i}){let[a,o]=(0,m.useState)(!1),[s,u]=(0,m.useState)(``),[d,f]=(0,m.useState)(``),[g,_]=(0,m.useState)(!1),v=()=>{o(!1),u(``),f(``)},y=async()=>{let r=p.o(s,e);if(r){f(r);return}let a=s.trim();_(!0),i?.(a);try{t(await p.n(a)),v()}catch(e){f(n.ii(e,`The role could not be saved. Try again.`))}_(!1),i?.(``)},b=`flex items-center gap-2 px-3 py-2.5 text-[13px]`,x={borderRadius:`calc(var(--input-radius, 0.75rem) - 0.25rem)`},S=`shrink-0 w-7 h-7 flex items-center justify-center rounded-md transition-colors cursor-pointer hover:bg-foreground/[0.07]`;return(0,h.jsx)(`div`,{className:`mt-1 pt-1 border-t border-[var(--panel-border)]/60`,children:g?(0,h.jsxs)(`div`,{className:`${b} justify-between font-medium text-foreground/55`,style:x,children:[(0,h.jsxs)(`span`,{className:`truncate`,children:[`Adding `,s.trim(),`…`]}),(0,h.jsx)(c.r,{className:`w-3.5 h-3.5 shrink-0 animate-spin text-accent`})]}):a?(0,h.jsxs)(`div`,{className:`flex flex-col gap-1 p-1`,children:[(0,h.jsxs)(`div`,{className:`flex items-center gap-1`,children:[(0,h.jsx)(`input`,{autoFocus:!0,value:s,placeholder:r,"aria-label":`Name the role`,onChange:e=>{u(e.target.value),d&&f(``)},onKeyDown:e=>{e.key===`Enter`&&(e.preventDefault(),y()),e.key===`Escape`&&(e.preventDefault(),v())},className:`flex-1 min-w-0 h-8 px-2.5 rounded-md border border-[var(--panel-border)] bg-[var(--panel-bg)] text-[13px] font-medium text-foreground placeholder:text-foreground/35 outline-none focus:border-accent transition-colors`}),(0,h.jsx)(`button`,{type:`button`,onClick:y,title:`Add role`,"aria-label":`Add role`,className:`${S} text-accent`,children:(0,h.jsx)(n.At,{className:`w-3.5 h-3.5`})}),(0,h.jsx)(`button`,{type:`button`,onClick:v,title:`Cancel`,"aria-label":`Cancel the new role`,className:`${S} text-foreground/45 hover:text-foreground`,children:(0,h.jsx)(c.t,{className:`w-3.5 h-3.5`})})]}),d&&(0,h.jsx)(`span`,{className:`text-[11.5px] font-semibold text-red-500 leading-snug px-1.5`,children:d})]}):(0,h.jsxs)(`div`,{role:`option`,"aria-selected":!1,onClick:()=>o(!0),className:`${b} font-semibold text-accent hover:bg-foreground/5 cursor-pointer`,style:x,children:[(0,h.jsx)(l.t,{className:`w-3.5 h-3.5 shrink-0`}),`Custom role…`]})})}var S={collection:`sys_configs`,doc:`registration_briefs`},C=`What do you want to ask people after they register?`,w=(e,t)=>e===`member`?C:`${C.slice(0,-1)} as ${n.xn(e,t).replace(`one of our team`,`one of your team`)}?`,T=`What would you like changed about these questions?`,E=`Their company name, and for business customers a VAT number — the VAT number must not be editable afterwards.`,D=`Which office they work from, and their job title.`,O=`Make the VAT number optional, and ask which country they are in.`,k=`Anything I have not decided — how a question is worded, what kind of box it is, what order they come in — decide yourself and write it finished; do not stop to ask me.`,A=`Each question is { key, label, type, required, editable } — editable: false for an answer that must never be changed after it is first given.`;function j(e,t,n){let r=`src/your-ai-workflow-firebase-os/configs/${f.x(e)}`,i=String(n?.words||``).trim();return n?.sent?[`The questions my app asks ${f.w(e,t)} on its Finish registration screen are one file: ${r}.`,`Change that file, and leave the questions I have not mentioned exactly as they are; decide anything I have not said yourself. If it is not there, write it: one const named ${f.b(e)} with a fields list.`,A,`Here is what I would like changed: ${i||`___`}`].join(`
|
|
2
2
|
`):[`My app shows people a Finish registration screen after they register — a few questions on top of a name and an email address, kept on the person's own profile. This is what I ask ${f.w(e,t)}.`,`Write one file: ${r}, exporting one const named ${f.b(e)} with a fields list. Do not build a registration page or a form of your own, do not touch any other file, and do not add a question I have not asked for.`,A,k,`Here is what I want to know: ${i||`___`}`].join(`
|
|
3
3
|
`)}function M(e,t){return[`My app shows people a Finish registration screen after they register — a few questions on top of a name and an email address, kept on the person's own profile. It asks different questions depending on how somebody registers, one file per role below. Do not build a registration page or a form of your own, do not touch a file I have not named here, and do not add a question I have not asked for.`,...e.filter(e=>String(t[e.id]?.words||``).trim()).map(e=>{let n=`src/your-ai-workflow-firebase-os/configs/${f.x(e.id)}`,r=String(t[e.id]?.words||``).trim(),i=!!t[e.id]?.sent;return[`For ${f.w(e.id,e.name)}:`,i?`change ${n}, leaving any question I have not mentioned exactly as it is — if it is not there, write it, one const named ${f.b(e.id)} with a fields list.`:`write ${n}, exporting one const named ${f.b(e.id)} with a fields list.`,`Here is what I ${i?`would like changed`:`want to know`}: ${r}`].join(` `)}),A,k].join(`
|
|
4
4
|
`)}var N=`fbos_swr_registration_briefs`,P=()=>{try{let e=localStorage.getItem(N);return e?JSON.parse(e):{}}catch{return{}}};function F(e,t){let r={id:f.t,name:n.qr(`user`,t)};return e.finishRegistration.perRole?[r,...n.bn(e,t).map(e=>({id:e.id,name:e.name}))]:[r]}function I({list:e,answer:r,words:i,onType:a,onSave:o,onCopied:s,showPrompt:c=!0}){let l=!!r?.sent;return(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(n.y,{label:l?T:w(e.id,e.name),value:i,placeholder:l?O:e.id===`internal`?D:E,onChange:a,onBlur:o}),c&&(0,h.jsx)(t.o,{compact:!0,title:l?`Change what you ask`:`Ask for these details`,prompt:j(e.id,e.name,{...r,words:i}),locked:!i.trim(),onCopied:s})]})}function L({settings:e}){let r=p.l(),[i,o]=(0,m.useState)(P),[s,c]=(0,m.useState)({}),[l,u]=(0,m.useState)(null),[d,f]=(0,m.useState)(``);(0,m.useEffect)(()=>(0,g.onSnapshot)((0,g.doc)(n.ui,S.collection,S.doc),e=>{let t=e.exists()?e.data():{};o(t);try{localStorage.setItem(N,JSON.stringify(t))}catch{}},e=>{console.warn(`registration_briefs snapshot error:`,e)}),[]);let _=(e,t)=>{let r={...i[e],...t};o(t=>({...t,[e]:r})),(0,g.setDoc)((0,g.doc)(n.ui,S.collection,S.doc),{[e]:r},{merge:!0}).catch(e=>console.warn(`registration_briefs write failed:`,e))},v=(0,m.useCallback)(e=>{c(t=>({...t,[e]:``})),_(e,{words:``,sent:Date.now()})},[i]),y=(0,m.useCallback)(e=>{c(t=>{let n={...t};for(let t of e)n[t]=``;return n});let t=Date.now();for(let n of e)_(n,{words:``,sent:t})},[i]),{skippable:b,perRole:x}=e.finishRegistration,C=n.bn(e,r).length>0,w=async t=>f(await e.setFinishRegistration(t)||``),T=F(e,r),E=e=>s[e]??i[e]?.words??``,D=e=>({list:e,answer:i[e.id],words:E(e.id),onType:t=>c(n=>({...n,[e.id]:t})),onSave:()=>{E(e.id)!==(i[e.id]?.words??``)&&_(e.id,{words:E(e.id)})}}),O=T.filter(e=>E(e.id).trim()).map(e=>e.id),k={};for(let e of T)k[e.id]={...i[e.id],words:E(e.id)};let A=O.some(e=>i[e]?.sent);return(0,h.jsxs)(n.m,{title:`Finish registration`,description:`A screen people see once, after they register, for anything you want to know on top of a name and an email address. It only appears when you have asked for something.`,children:[(0,h.jsx)(n.h,{children:`Some of it is there already: somebody who came in with a phone number or an emailed link is asked for a name or an email address first, and then for your questions. People can change their own answers on their Profile, and you can read them on the Users screen.`}),(0,h.jsx)(n.S,{label:`People can skip it`,hint:b?`Skippable — the screen has a Skip for now, and anything you marked as needed is asked again next time they sign in.`:`Required — nobody goes on until it is filled in. You and your admins are never held.`,hintWideOnly:!0,enabled:b,onChange:e=>w({skippable:e}),disabled:e.loading}),C&&(0,h.jsx)(n.S,{label:`Different questions for different roles`,hint:x?`One set of questions per role below. A role with none of its own is asked everybody's.`:`One set of questions, asked of everybody whatever they registered as.`,hintWideOnly:!0,enabled:x,onChange:e=>w({perRole:e}),disabled:e.loading}),d?(0,h.jsx)(n.h,{tone:`error`,children:d}):null,T.length===1?(0,h.jsx)(`div`,{className:`flex flex-col gap-4`,children:(0,h.jsx)(I,{...D(T[0]),onCopied:()=>v(T[0].id)})}):(0,h.jsx)(`div`,{className:`flex flex-col gap-3`,children:T.map(e=>{let t=l===e.id,r=!!i[e.id]?.sent;return(0,h.jsxs)(`div`,{onClick:()=>u(t?null:e.id),className:`group flex flex-col p-3.5 sm:py-4 sm:px-5 glass-panel border border-transparent hover:border-accent/40 transition-all rounded-2xl hover:shadow-sm cursor-pointer`,children:[(0,h.jsxs)(`div`,{className:`flex items-center justify-between w-full gap-2 sm:gap-3`,children:[(0,h.jsxs)(`div`,{className:`flex items-center gap-2.5 flex-1 min-w-0`,children:[(0,h.jsx)(`h3`,{className:`text-[14.5px] font-semibold text-foreground tracking-tight truncate`,children:e.id===`member`?`${e.name} — everybody else`:e.name}),(0,h.jsx)(`span`,{className:`max-sm:hidden text-[12px] font-medium text-foreground/45 truncate`,children:r?`Asked for`:`Nothing asked yet`})]}),(0,h.jsx)(`div`,{className:`p-1.5 transition-transform duration-300 text-foreground/40 shrink-0 ${t?`rotate-180`:``}`,children:(0,h.jsx)(a.t,{className:`w-3.5 h-3.5`})})]}),(0,h.jsx)(n.rt,{children:t&&(0,h.jsx)(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:(0,h.jsx)(I,{...D(e),showPrompt:!1})})})]},e.id)})}),T.length>1&&(0,h.jsx)(t.o,{compact:!0,title:A?`Change what you ask`:`Ask for these details`,prompt:M(T,k),locked:!O.length,onCopied:()=>y(O)})]})}var R=[{id:`login`,title:`The sign-in page`,description:`Where somebody who already has an account comes back in.`,to:`/login?preview=1`,icon:i.o},{id:`register`,title:`The registration page`,description:`Where somebody new makes an account for the first time.`,to:`/register?preview=1`,icon:b}],z=/\b((?:[a-z0-9-]+\.)+(?:com|org|net|io|dev|app|ai))(\/[a-z0-9\-._~:/?#@!$&'()*+,;=%]*)?/gi;function B({text:e}){let t=[],n=0;for(let r of e.matchAll(z)){let i=r[0],a=r.index??0;a>n&&t.push(e.slice(n,a)),t.push((0,h.jsx)(`a`,{href:`https://${i}`,target:`_blank`,rel:`noreferrer`,className:`font-bold text-accent hover:underline break-all`,children:i},`${i}-${a}`)),n=a+i.length}return n===0?(0,h.jsx)(h.Fragment,{children:e}):(n<e.length&&t.push(e.slice(n)),(0,h.jsx)(h.Fragment,{children:t}))}function V({title:e,steps:t,addresses:n,missing:r,children:i}){return(0,h.jsxs)(`div`,{className:`rounded-2xl border border-[var(--panel-border)]/60 bg-foreground/[0.02] p-4`,children:[(0,h.jsx)(`p`,{className:`text-[11px] font-bold uppercase tracking-[0.16em] text-foreground/40 mb-2.5`,children:e}),(0,h.jsx)(`ol`,{className:`space-y-2.5 list-decimal pl-[1.15rem] text-[13px] text-foreground/75 font-medium leading-relaxed marker:font-bold marker:text-foreground/35`,children:t.map(e=>{let{text:t,copy:i}=typeof e==`string`?{text:e,copy:void 0}:e,a=i&&n?n[i.address]:``;return(0,h.jsxs)(`li`,{children:[(0,h.jsx)(B,{text:t}),i&&(a?(0,h.jsx)(H,{label:i.label,value:a,note:i.note}):r?.(i))]},t)})}),i]})}function H({label:e,value:r,note:i}){let[a,o]=(0,m.useState)(!1);return(0,h.jsxs)(`div`,{className:`mt-2 mb-1 rounded-xl border border-accent/25 bg-accent/[0.06] p-3`,children:[(0,h.jsxs)(`div`,{className:`flex items-center justify-between gap-2 mb-1.5`,children:[(0,h.jsxs)(`span`,{className:`text-[11.5px] font-bold text-foreground/60 leading-tight`,children:[`Paste into “`,e,`”`]}),(0,h.jsx)(n.o,{icon:a?n.At:t._,title:`Copy ${r}`,onClick:()=>{try{navigator.clipboard?.writeText(r)?.catch(()=>{})}catch{}o(!0),setTimeout(()=>o(!1),1500)},children:a?`Copied`:`Copy`})]}),(0,h.jsx)(`code`,{className:`block text-[12px] font-mono text-foreground/80 break-all leading-relaxed`,children:r}),i&&(0,h.jsx)(`p`,{className:`mt-2 text-[11.5px] font-medium text-foreground/50 leading-relaxed`,children:i})]})}function U({method:e,onClose:t}){let r=e?s.t[e.id]:null,i=e?.setup,a={callback:n.pn(n.gn()),home:n.dn()};return(0,h.jsx)(n.rt,{children:e&&(0,h.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center p-4`,children:[(0,h.jsx)(n.nt.div,{onClick:t,initial:{opacity:0},animate:{opacity:1},exit:{opacity:0},className:`absolute inset-0 bg-background/80 backdrop-blur-xl cursor-pointer`}),(0,h.jsxs)(n.nt.div,{role:`dialog`,"aria-modal":`true`,"aria-label":`Set up ${e.label} in Firebase`,initial:{opacity:0,scale:.95,y:10},animate:{opacity:1,scale:1,y:0},exit:{opacity:0,scale:.95,y:10},className:`w-full max-w-[520px] max-h-[86vh] flex flex-col rounded-3xl glass-popover border border-[var(--panel-border)] shadow-2xl relative z-10`,children:[(0,h.jsxs)(`div`,{className:`flex-1 min-h-0 overflow-y-auto p-6 pb-2`,children:[(0,h.jsxs)(`div`,{className:`grid grid-cols-[auto_minmax(0,1fr)] gap-x-3 gap-y-1 mb-4`,children:[(0,h.jsx)(`div`,{className:`row-start-1 col-start-1 w-10 h-10 rounded-2xl flex items-center justify-center shrink-0 border border-[var(--panel-border)]/50 bg-accent/10 text-accent`,children:r&&(0,h.jsx)(r,{className:`w-5 h-5`})}),(0,h.jsx)(`h3`,{className:`row-start-1 col-start-2 self-center min-w-0 text-[17px] font-bold text-foreground tracking-tight leading-tight`,children:e.setupTitle||`Set up ${e.label} in Firebase first`}),(0,h.jsx)(`p`,{className:`row-start-2 col-start-2 min-w-0 text-[13.5px] font-medium text-foreground/60 leading-relaxed`,children:i?(0,h.jsxs)(h.Fragment,{children:[`This one takes two consoles. Firebase asks `,e.label,` who you are, and `,i.where,` wants an address back. Both halves are below — it is about five minutes.`]}):(0,h.jsx)(h.Fragment,{children:`This one is switched on in your Firebase project, not here. Firebase walks you through it — these are the clicks that get you to the right screen.`})})]}),(0,h.jsxs)(`div`,{className:`flex flex-col gap-3 mb-4`,children:[(0,h.jsx)(V,{title:`In Firebase`,steps:[...n.cn,...e.steps],addresses:a,children:i&&(0,h.jsxs)(`div`,{className:`mt-3 flex flex-wrap items-center gap-1.5`,children:[(0,h.jsx)(`span`,{className:`text-[11.5px] font-semibold text-foreground/45`,children:`It asks you for`}),i.asksFor.map(e=>(0,h.jsx)(`span`,{className:`px-2 py-0.5 rounded-lg border border-[var(--panel-border)] bg-foreground/[0.04] text-[11.5px] font-bold text-foreground/70`,children:e},e))]})}),i&&(0,h.jsx)(V,{title:`In ${i.where} — where those come from`,steps:i.steps,addresses:a,missing:t=>t.address===`home`?null:(0,h.jsxs)(`p`,{className:`mt-2 mb-1 text-[12.5px] font-medium text-foreground/55 leading-relaxed`,children:[`The address for “`,t.label,`” is the one Firebase prints at the bottom of its own `,e.label,` panel. Copy it from there.`]})}),i?.warning&&(0,h.jsx)(`p`,{className:`text-[12.5px] font-medium text-amber-600 dark:text-amber-400 leading-relaxed px-1`,children:i.warning})]}),(0,h.jsxs)(`div`,{className:`flex flex-wrap items-center gap-x-5 gap-y-2 mb-5`,children:[(0,h.jsxs)(`a`,{href:`https://console.firebase.google.com/`,target:`_blank`,rel:`noreferrer`,className:`inline-flex items-center gap-1.5 text-[13px] font-bold text-accent hover:underline`,children:[`Open the Firebase console`,(0,h.jsx)(n.Ot,{className:`w-3.5 h-3.5`})]}),i&&(0,h.jsxs)(`a`,{href:i.url,target:`_blank`,rel:`noreferrer`,className:`inline-flex items-center gap-1.5 text-[13px] font-bold text-accent hover:underline`,children:[`Open `,i.where,(0,h.jsx)(n.Ot,{className:`w-3.5 h-3.5`})]})]})]}),(0,h.jsx)(`div`,{className:`shrink-0 px-6 pb-6 pt-4 border-t border-[var(--panel-border)]/50 flex items-center gap-3 w-full`,children:(0,h.jsx)(d.t,{type:`button`,variant:`secondary`,onClick:t,className:`flex-1 py-2.5 text-[13px] font-bold rounded-xl`,children:`Close`})})]})]})})}function W({method:e,settings:t,problem:r,onFlip:i,onSteps:a}){let o=s.t[e.id],c=t.on[e.id];return(0,h.jsxs)(`div`,{className:`grid grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-x-3 sm:gap-x-3.5 gap-y-0.5 px-4 py-3`,children:[(0,h.jsx)(`div`,{className:`row-start-1 row-span-2 col-start-1 self-center w-9 h-9 rounded-xl flex items-center justify-center shrink-0 border border-[var(--panel-border)]/50 bg-accent/10 text-accent`,children:(0,h.jsx)(o,{className:`w-4 h-4`})}),(0,h.jsx)(`span`,{className:`row-start-1 col-start-2 min-w-0 text-[13px] font-bold text-foreground leading-tight self-end truncate`,children:e.label}),(0,h.jsx)(`span`,{className:`${r?``:`max-sm:hidden `}row-start-2 col-start-2 min-w-0 text-[12px] leading-snug self-start truncate ${r?`text-red-500 font-medium`:`text-foreground/50 font-normal`}`,children:r||e.description}),(0,h.jsxs)(`div`,{className:`row-start-1 row-span-2 col-start-3 self-center justify-self-end flex items-center gap-2 sm:gap-3 shrink-0`,children:[e.needsSetup&&(0,h.jsx)(`button`,{type:`button`,onClick:a,className:`max-sm:hidden text-[11.5px] font-semibold text-foreground/45 hover:text-accent transition-colors cursor-pointer`,children:`How to set it up`}),t.loading?(0,h.jsx)(`span`,{"aria-hidden":!0,className:`w-10 h-6 rounded-full bg-foreground/10 animate-pulse shrink-0`}):(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(`span`,{className:`max-sm:hidden`,children:(0,h.jsx)(n._,{state:c?`saved`:`off`,label:c?`On`:`Off`})}),(0,h.jsx)(n.x,{enabled:c,onChange:i,label:e.label})]})]})]})}function G({settings:e}){let t=p.l(),[r,i]=(0,m.useState)(``),[a,o]=(0,m.useState)(``),{on:c,roles:l}=e.registerAs,u=[{value:`internal`,label:n.qr(`internal`,t)},...t.filter(e=>!a||e.name.trim().toLowerCase()!==a.trim().toLowerCase()).map(e=>({value:e.id,label:e.name}))],d=n.bn(e,t),f=async t=>i(await e.setRegisterAs({on:t})||``),g=async t=>{let n=l.includes(t)?l.filter(e=>e!==t):[...l,t];i(await e.setRegisterAs({roles:n})||``)},_=d.length?n.vn(d):`Tick at least one, or the registration page stays the one form it is.`;return(0,h.jsxs)(n.m,{icon:s.n,title:`Registering as a role`,description:`Let people say what they are when they sign up. You approve each one on the Users screen.`,children:[(0,h.jsx)(n.S,{label:`Let people register as…`,hint:c?`On — the registration page opens on a choice: the roles below, or an ordinary account.`:`Off — the registration page is one form, and everybody who signs up is a member.`,hintWideOnly:!0,enabled:c,onChange:f,disabled:e.loading}),c&&(0,h.jsxs)(h.Fragment,{children:[(0,h.jsx)(n.i,{label:`Which roles`,hint:_,children:(0,h.jsx)(n.Z,{multiple:!0,dense:!0,portal:!0,direction:`auto`,className:`console-select`,ariaLabel:`Roles people can register as`,placeholder:`Pick the roles`,values:l.filter(e=>u.some(t=>t.value===e)),options:u,onChange:g,footer:(0,h.jsx)(x,{roles:t,onPending:o,onCreated:e=>{g(e.id)}}),disabled:e.loading})}),(0,h.jsx)(n.h,{children:`Registering as a role makes an ordinary account with a request on it — nobody becomes anything by asking. You approve or decline each request on the Users screen, and until you do they are a member like anybody else. Admins are never offered here: an admin is made on the Users screen only. Signing in does not change.`})]}),r?(0,h.jsx)(n.h,{tone:`error`,children:r}):null]})}function K(){let e=n.Cn(),[i,a]=(0,m.useState)(``),[s,c]=(0,m.useState)({}),[l,d]=(0,m.useState)(null),f=async(t,n)=>{a(``),c(e=>({...e,[t.id]:``}));let r=await e.set(t.id,n);r&&c(e=>({...e,[t.id]:r}))},p=n.sn.filter(e=>e.kind===`security`);return(0,h.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,h.jsxs)(n.nt.div,{initial:{opacity:0,y:20},animate:{opacity:1,y:0},className:`mb-6`,children:[(0,h.jsx)(t.t,{children:`Sign in`}),(0,h.jsxs)(`div`,{className:`flex items-center gap-2 text-foreground/40 font-bold uppercase tracking-[0.2em] text-[11px]`,children:[(0,h.jsx)(`span`,{className:`w-8 h-[1px] bg-foreground/10`}),`/sign-in`]})]}),(0,h.jsxs)(`div`,{className:`flex flex-col gap-6 flex-1 pb-16`,children:[(0,h.jsx)(r.t,{}),(0,h.jsxs)(`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 gap-4 min-h-[600px]`,children:[(0,h.jsxs)(n.m,{icon:v,title:`Your two pages`,description:`Right now people can sign in with ${n.Sn(e)}.`,children:[(0,h.jsx)(`div`,{className:`flex flex-col divide-y divide-[var(--panel-border)]/60 rounded-2xl border border-[var(--panel-border)]/60`,children:R.map(e=>{let t=e.icon;return(0,h.jsxs)(`div`,{className:`grid grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-x-3 sm:gap-x-3.5 gap-y-0.5 px-4 py-3`,children:[(0,h.jsx)(`div`,{className:`row-start-1 row-span-2 col-start-1 self-center w-9 h-9 rounded-xl flex items-center justify-center shrink-0 border border-[var(--panel-border)]/50 bg-accent/10 text-accent`,children:(0,h.jsx)(t,{className:`w-4 h-4`})}),(0,h.jsx)(`span`,{className:`row-start-1 col-start-2 min-w-0 text-[13px] font-bold text-foreground leading-tight self-end truncate`,children:e.title}),(0,h.jsx)(`span`,{className:`max-sm:hidden row-start-2 col-start-2 min-w-0 text-[12px] text-foreground/50 font-normal leading-snug self-start truncate`,children:e.description}),(0,h.jsx)(n.C,{to:e.to,title:`View ${e.title.charAt(0).toLowerCase()}${e.title.slice(1)}`,className:`row-start-1 row-span-2 col-start-3 self-center justify-self-end`,children:`View page`})]},e.id)})}),(0,h.jsx)(`p`,{className:n.s,children:`Both pages draw themselves from the switches below: every way you switch on appears on them, and every way you switch off leaves. There is nothing to rebuild in between.`})]}),(0,h.jsxs)(n.m,{icon:r.A,title:`Ways in`,description:`What people can use to sign in and to register.`,children:[(0,h.jsx)(n.h,{children:`A way of signing in also has to be switched on in your Firebase project before it works, and most of them already are. Switch one on here and it appears on both pages straight away; if Firebase has not got it, the person who presses that button is told so in plain words, and “How to set it up” on the row shows you exactly where to go.`}),(0,h.jsx)(`div`,{className:`flex flex-col divide-y divide-[var(--panel-border)]/60 rounded-2xl border border-[var(--panel-border)]/60`,children:n.un.map(t=>(0,h.jsx)(W,{method:t,settings:e,problem:s[t.id]||``,onFlip:e=>f(t,e),onSteps:()=>d(t)},t.id))}),i?(0,h.jsx)(n.h,{tone:`error`,children:i}):null]}),(0,h.jsxs)(n.m,{icon:u.t,title:`One more step`,description:`A code by text after the password, for an app that holds something worth protecting.`,children:[(0,h.jsx)(n.h,{children:`With this on, everybody with a password is asked for a phone number the first time they sign in, and for a texted code every time after. People who sign in with Google, GitHub or X are already covered by that company's own checks.`}),(0,h.jsx)(`div`,{className:`flex flex-col divide-y divide-[var(--panel-border)]/60 rounded-2xl border border-[var(--panel-border)]/60`,children:p.map(t=>(0,h.jsx)(W,{method:t,settings:e,problem:s[t.id]||``,onFlip:e=>f(t,e),onSteps:()=>d(t)},t.id))}),e.on.sms2fa&&(0,h.jsx)(n.S,{label:`People can skip it`,hint:e.twoStepOptional?`Optional — the setup screen has a "Not now" on it, and they are asked again the next time they sign in.`:`Required — nobody gets past the setup screen until they have given a number.`,hintWideOnly:!0,enabled:e.twoStepOptional,onChange:async t=>a(await e.setTwoStepOptional(t)||``),disabled:e.loading}),(0,h.jsx)(n.h,{children:`A phone number can only be set up on one account. Somebody typing a number that is already somebody else's two-step code is told so before the text is sent — so the code really does say which person is signing in, which is the whole reason to ask for one. Signing in WITH a phone number is one account per number too; that part is Firebase's own doing.`})]}),(0,h.jsx)(G,{settings:e}),(0,h.jsx)(L,{settings:e})]})]}),(0,h.jsx)(o.t,{video:`signin`}),(0,h.jsx)(U,{method:l,onClose:()=>d(null)})]})}exports.SignInAdmin=K;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { _ as e, o as t, t as n } from "./PageTitle-
|
|
2
|
-
import { At as r, C as i, Cn as a, Ot as o, S as s, Sn as c, Z as l, _ as u, bn as d, cn as f, dn as p, gn as m, h, i as g, ii as _, m as v, nt as y, o as b, pn as x, qr as S, rt as C, s as w, sn as T, ui as E, un as D, vn as O, w as ee, x as k, xn as A, y as te } from "./TimeZoneField-
|
|
3
|
-
import { A as ne, t as re } from "./DashboardNav-
|
|
4
|
-
import { o as ie } from "./Trouble-
|
|
1
|
+
import { _ as e, o as t, t as n } from "./PageTitle-DCoUQWw6.js";
|
|
2
|
+
import { At as r, C as i, Cn as a, Ot as o, S as s, Sn as c, Z as l, _ as u, bn as d, cn as f, dn as p, gn as m, h, i as g, ii as _, m as v, nt as y, o as b, pn as x, qr as S, rt as C, s as w, sn as T, ui as E, un as D, vn as O, w as ee, x as k, xn as A, y as te } from "./TimeZoneField-oIMwb5_X.js";
|
|
3
|
+
import { A as ne, t as re } from "./DashboardNav-CEd8gGPm.js";
|
|
4
|
+
import { o as ie } from "./Trouble-CtFq7tjk.js";
|
|
5
5
|
import { n as j, t as ae } from "./chevron-down--LwXEv9w.js";
|
|
6
|
-
import { t as oe } from "./SupportBar-
|
|
7
|
-
import { n as se, t as M } from "./ProviderMark-
|
|
6
|
+
import { t as oe } from "./SupportBar-DI_XbEsG.js";
|
|
7
|
+
import { n as se, t as M } from "./ProviderMark-BvEMlZAm.js";
|
|
8
8
|
import { r as ce, t as le } from "./x-hax8aKt8.js";
|
|
9
9
|
import { t as ue } from "./plus-BKrt0Qx5.js";
|
|
10
10
|
import { t as de } from "./shield-check-DRQNdYcW.js";
|
|
11
|
-
import { t as fe } from "./Button-
|
|
12
|
-
import { b as N, t as pe, w as P, x as F } from "./registrationFields-
|
|
13
|
-
import { l as I, n as me, o as he } from "./roles-
|
|
11
|
+
import { t as fe } from "./Button-BGN6q7lY.js";
|
|
12
|
+
import { b as N, t as pe, w as P, x as F } from "./registrationFields-DdHoMPAQ.js";
|
|
13
|
+
import { l as I, n as me, o as he } from "./roles-DiwP6-WQ.js";
|
|
14
14
|
import { useCallback as L, useEffect as ge, useState as R } from "react";
|
|
15
15
|
import { Fragment as z, jsx as B, jsxs as V } from "react/jsx-runtime";
|
|
16
16
|
import { doc as H, onSnapshot as _e, setDoc as ve } from "firebase/firestore";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { a as e, u as t } from "./mediaKind-BtaMpGy8.js";
|
|
2
|
-
import { h as n, y as r } from "./PageTitle-
|
|
3
|
-
import { i } from "./Trouble-
|
|
2
|
+
import { h as n, y as r } from "./PageTitle-DCoUQWw6.js";
|
|
3
|
+
import { i } from "./Trouble-CtFq7tjk.js";
|
|
4
4
|
import { n as a, t as o } from "./chevron-down--LwXEv9w.js";
|
|
5
|
-
import { r as s, t as c } from "./VideoPlayer-
|
|
6
|
-
import { t as l } from "./Popup-
|
|
5
|
+
import { r as s, t as c } from "./VideoPlayer-QI1Jc3bS.js";
|
|
6
|
+
import { t as l } from "./Popup-Bi63lzoS.js";
|
|
7
7
|
import { useEffect as u, useLayoutEffect as d, useRef as f, useState as p, useSyncExternalStore as m } from "react";
|
|
8
8
|
import { Fragment as h, jsx as g, jsxs as _ } from "react/jsx-runtime";
|
|
9
9
|
import { createPortal as v } from "react-dom";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
require(`./chunk-CiTBaPhY.cjs`);const e=require(`./PageTitle-
|
|
1
|
+
require(`./chunk-CiTBaPhY.cjs`);const e=require(`./PageTitle-DQkvCB11.cjs`),t=require(`./Trouble-KQZyf6aY.cjs`),n=require(`./chevron-down-lyDK1rfL.cjs`),r=require(`./VideoPlayer-CggwpVXH.cjs`),i=require(`./Popup-COnHpbrY.cjs`),a=require(`./mediaKind-ButDya5f.cjs`);let o=require(`react`),s=require(`react/jsx-runtime`),c=require(`react-dom`);var l={name:`chevron-up`,size:24,node:[[`path`,{d:`m18 15-6-6-6 6`,key:`153udz`}]]};l.node;var u=n.n(l),d={name:`headset`,size:24,node:[[`path`,{d:`M3 11h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-5Zm0 0a9 9 0 1 1 18 0m0 0v5a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3Z`,key:`12oyoe`}],[`path`,{d:`M21 16v2a4 4 0 0 1-4 4h-5`,key:`1x7m43`}]]};d.node;var f=n.n(d),p={setup:``,publish:``,payments:``,users:``,signin:``},m=e=>{let t=String(e||``).trim();return/^\d+(?::\d{1,2}){1,2}$/.test(t)?t.split(`:`).map(Number).reduce((e,t)=>e*60+t,0):/^\d+$/.test(t)?Number(t.slice(0,-4)||0)*3600+Number(t.slice(-4,-2)||0)*60+Number(t.slice(-2)):0},h=e=>e&&!/^[a-z][a-z0-9+.-]*:/i.test(e)&&/^[\w.-]+\.[a-z]{2,}(?:[/?#]|$)/i.test(e)?`https://${e}`:e,g=(e,t)=>{if(!e||!(t>0))return e;try{let n=new URL(e),r=n.hostname.replace(/^(?:www|m|music|player)\./,``);return r===`youtu.be`||/(?:^|\.)youtube(?:-nocookie)?\.com$/.test(r)?n.searchParams.set(`t`,`${t}s`):/(?:^|\.)vimeo\.com$/.test(r)?n.hash=`t=${t}s`:/(?:^|\.)loom\.com$/.test(r)?n.searchParams.set(`t`,String(t)):n.hash=`t=${t}`,n.toString()}catch{return e}},_=e=>{let[t=``,n=``]=String(e||``).trim().split(/\s+/);return g(h(t),m(n))},v=e=>_(p[e]),y=`https://www.youraiworkflow.co/tutorials.json`,b=5e3,x=`fbos_tutorials`,S=!0,C=null,w=null,T=0,E=e=>!!e&&typeof e==`object`&&!Array.isArray(e),D=()=>{try{let e=JSON.parse(localStorage.getItem(x)||`null`);return E(e)?e:{}}catch{return{}}},O=e=>{try{localStorage.setItem(x,JSON.stringify(e))}catch{}};function k(){if(w)return Promise.resolve(w);if(C)return C;if(!S||typeof fetch!=`function`||Date.now()-T<3e5)return Promise.resolve(D());let e=typeof AbortController==`function`?new AbortController:null,t=e?setTimeout(()=>e.abort(),b):null;return C=fetch(y,{signal:e?.signal}).then(e=>e.ok?e.json():Promise.reject(Error(`tutorials.json: ${e.status}`))).then(e=>{if(!E(e))throw Error(`tutorials.json: not the file`);return w=e,O(e),e}).catch(()=>(T=Date.now(),D())).finally(()=>{C=null,t&&clearTimeout(t)}),C}function A(e){let[t,n]=(0,o.useState)(w);return(0,o.useEffect)(()=>{if(!e)return;let t=!0;return k().then(e=>{t&&n(e)}),()=>{t=!1}},[e]),e?_(String(t?.[e]||``)):``}var j=`Video not available`,M=e=>{let t=(e||``).trim();return/^https?:\/\//i.test(t)&&a.a(t)!==null?!0:/^https:\/\//i.test(t)&&a.u(t)===`video`};function N({children:e}){let t=(0,o.useRef)(null),[n,r]=(0,o.useState)(0);return(0,o.useLayoutEffect)(()=>{let e=t.current;if(!e)return;let n=()=>{let t=Math.min((typeof window>`u`?900:window.innerHeight)*.92-112,760);r(Math.min(e.clientWidth,16/9*Math.max(0,t)))};if(n(),window.addEventListener(`resize`,n),typeof ResizeObserver>`u`)return()=>window.removeEventListener(`resize`,n);let i=new ResizeObserver(n);return i.observe(e),()=>{i.disconnect(),window.removeEventListener(`resize`,n)}},[]),(0,s.jsx)(`div`,{ref:t,className:`flex items-center justify-center`,style:{maxHeight:`min(calc(92dvh - 112px), 760px)`},children:(0,s.jsx)(`div`,{className:`w-full`,style:n?{width:n}:void 0,children:e})})}function P({open:e,href:t,onClose:n}){let a=(t||``).trim();return(0,s.jsx)(i.t,{open:e,onClose:n,size:`xl`,title:`Tutorial`,children:(0,s.jsx)(N,{children:M(a)?(0,s.jsx)(r.t,{src:a}):(0,s.jsx)(`div`,{className:`relative w-full aspect-video overflow-hidden rounded-2xl border border-[var(--panel-border)] bg-foreground/[0.04]`,children:(0,s.jsx)(`p`,{className:`absolute inset-0 flex items-center justify-center text-[13px] font-semibold text-foreground/40`,children:j})})})})}var F=`https://youraiworkflow.co`,I=`antonina@youraiworkflow.co`,L=(t=e.y)=>t&&t!==`dev`?`${F}/report?v=${encodeURIComponent(t)}`:`${F}/report`,R={target:`_blank`,rel:`noopener noreferrer`},z=`h-9 flex items-center justify-center rounded-xl btn-secondary cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-accent`,B=`text-[13px] font-semibold text-foreground/50 hover:text-accent transition-colors whitespace-nowrap outline-none focus-visible:text-accent`,V=`pointer-events-auto max-w-full glass-popover rounded-2xl`,H=[],U=new Set,W=()=>U.forEach(e=>e()),G=e=>(U.add(e),()=>{U.delete(e)}),K=()=>H[0]?.token,q=()=>H.find(e=>e.video)?.video,J=()=>document.querySelector(`[aria-modal="true"]`)!==null,Y=e=>{let t=new MutationObserver(e);return t.observe(document.body,{childList:!0,subtree:!0,attributes:!0,attributeFilter:[`aria-modal`]}),()=>t.disconnect()};function X({video:i}={}){let a=t.i(),[l,d]=(0,o.useState)(!0),[p,m]=(0,o.useState)(!1),h=(0,o.useRef)(null);h.current===null&&(h.current=Symbol(`support-bar`));let g=(0,o.useSyncExternalStore)(G,K,()=>void 0),_=(0,o.useSyncExternalStore)(G,q,()=>void 0),y=A(_),b=(0,o.useSyncExternalStore)(Y,J,()=>!1);if((0,o.useEffect)(()=>{let e=h.current;return H=[...H,{token:e,video:i}],W(),()=>{H=H.filter(t=>t.token!==e),W()}},[i]),g!==void 0&&g!==h.current)return null;let x=l?(0,s.jsxs)(`button`,{type:`button`,onClick:()=>d(!1),"aria-expanded":!1,"aria-label":`Show help`,className:`${V} h-10 pl-3.5 pr-3 flex items-center gap-2 text-[13px] font-semibold text-foreground/60 hover:text-accent hover:border-accent/40 transition-colors cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-accent`,children:[(0,s.jsx)(f,{className:`w-4 h-4 shrink-0`}),`Help`,(0,s.jsx)(u,{className:`w-4 h-4 shrink-0 text-foreground/35`})]}):(0,s.jsxs)(`nav`,{"aria-label":`Help`,className:`${V} p-1.5 flex items-center gap-3`,children:[(0,s.jsxs)(`div`,{className:`flex items-center gap-1.5 shrink-0`,children:[(0,s.jsx)(`a`,{href:`mailto:${I}`,title:I,"aria-label":`Email me`,className:`${z} w-9`,children:(0,s.jsx)(e.h,{className:`w-4 h-4 text-foreground/80`})}),(0,s.jsxs)(`a`,{href:`${F}/book`,...R,className:`${z} gap-2 px-3.5 text-[13px] font-semibold text-foreground/80 whitespace-nowrap`,children:[(0,s.jsx)(f,{className:`w-4 h-4 shrink-0`}),(0,s.jsx)(`span`,{className:`max-sm:hidden`,children:`Book a session`}),(0,s.jsx)(`span`,{className:`sm:hidden`,children:`Book`})]})]}),(0,s.jsx)(`span`,{"aria-hidden":`true`,className:`w-px h-5 shrink-0 bg-[var(--panel-border)]`}),(0,s.jsxs)(`a`,{href:`${F}/quote`,...R,className:B,children:[(0,s.jsx)(`span`,{className:`max-sm:hidden`,children:`Request a quote`}),(0,s.jsx)(`span`,{className:`sm:hidden`,children:`Quote`})]}),(0,s.jsxs)(`a`,{href:L(),...R,className:B,children:[(0,s.jsx)(`span`,{className:`max-sm:hidden`,children:`Report an issue`}),(0,s.jsx)(`span`,{className:`sm:hidden`,children:`Report`})]}),(0,s.jsx)(`button`,{type:`button`,onClick:()=>d(!0),"aria-expanded":!0,"aria-label":`Fold help away`,title:`Fold away`,className:`w-8 h-9 -ml-1 shrink-0 flex items-center justify-center rounded-xl text-foreground/35 hover:text-foreground/70 transition-colors cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-accent`,children:(0,s.jsx)(n.t,{className:`w-4 h-4`})})]}),S=_&&l?(0,s.jsxs)(`button`,{type:`button`,onClick:()=>m(!0),className:`${V} h-10 pl-3.5 pr-4 flex items-center gap-2 text-[13px] font-semibold text-foreground/60 hover:text-accent hover:border-accent/40 transition-colors whitespace-nowrap cursor-pointer outline-none focus-visible:ring-2 focus-visible:ring-accent`,children:[(0,s.jsx)(r.r,{className:`w-4 h-4 shrink-0`}),`Tutorial`]}):null;return(0,s.jsxs)(s.Fragment,{children:[b?null:(0,c.createPortal)((0,s.jsxs)(`div`,{className:`fixed inset-x-0 z-30 px-4 flex justify-center gap-2 pointer-events-none transition-[bottom] duration-300 ${a?`bottom-24`:`bottom-4`}`,children:[x,S]}),document.body),_?(0,s.jsx)(P,{open:p,href:y||v(_),onClose:()=>m(!1)}):null]})}Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return X}});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
require(`./chunk-CiTBaPhY.cjs`);const e=require(`./TimeZoneField-
|
|
1
|
+
require(`./chunk-CiTBaPhY.cjs`);const e=require(`./TimeZoneField-Ckn1pKAL.cjs`),t=require(`./contentFallback-DVCrIUvK.cjs`);let n=require(`react`),r=require(`react/jsx-runtime`);var i={inbox:`inbox_tab`,users:`users_tab`,schedule:`schedule_tab`,mybookings:`my_bookings_tab`,assets:`assets_tab`};function a({tab:a}){let o=i[a],s=e.mi();e.Rr();let[c,l]=(0,n.useState)(null);(0,n.useEffect)(()=>{let e={contentKey:o};if(t.r(e))return;let n=!1;return t.n(e).then(e=>{!n&&e&&l(()=>e)}),()=>{n=!0}},[o]);let u=s.microcomponents?.[o]||(typeof window<`u`?window.__FBOS_MICROCOMPONENTS__?.[o]:void 0)||c||void 0;return u?(0,r.jsx)(`div`,{className:`fbos-content-slot relative w-full`,children:(0,r.jsx)(t.p,{size:`part`,children:(0,r.jsx)(u,{})})}):null}Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return i}});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Rr as e, mi as t } from "./TimeZoneField-
|
|
2
|
-
import { n, p as r, r as i } from "./contentFallback-
|
|
1
|
+
import { Rr as e, mi as t } from "./TimeZoneField-oIMwb5_X.js";
|
|
2
|
+
import { n, p as r, r as i } from "./contentFallback-BGGpI1Ts.js";
|
|
3
3
|
import { useEffect as a, useState as o } from "react";
|
|
4
4
|
import { jsx as s } from "react/jsx-runtime";
|
|
5
5
|
//#region src/components/SystemTabContent.tsx
|