UNPKG

@tebuto/react-booking-widget

Version:

React Component for the Tebuto Booking Widget

3 lines (2 loc) 30.1 kB
import{jsxs as e,jsx as t,Fragment as n}from"react/jsx-runtime";import{createContext as r,useMemo as o,useContext as i,useState as a,useEffect as l,useCallback as s,useRef as d}from"react";function c({noScriptText:n="Widget konnte nicht geladen werden. Möglicherweise ist Skripting im Browser deaktiviert.",...r}){return e("div",{id:"tebuto-booking-widget","data-testid":"tebuto-booking-widget-container",children:[t(g,{config:r}),t("noscript",{"data-testid":"tebuto-booking-widget-noscript",children:n})]})}function g({config:e}){const n=function(e){const t={"data-therapist-uuid":e.therapistUUID},n=e.backgroundColor??e.theme?.backgroundColor;return n&&(t["data-background-color"]=n),e.categories&&e.categories.length>0&&(t["data-categories"]=e.categories.join(",")),function(e,t){void 0!==t.border&&(e["data-border"]=t.border?"true":"false"),void 0!==t.includeSubusers&&(e["data-include-subusers"]=t.includeSubusers?"true":"false"),void 0!==t.showQuickFilters&&(e["data-show-quick-filters"]=t.showQuickFilters?"true":"false");const n=t.inheritFont??t.theme?.inheritFont;void 0!==n&&(e["data-inherit-font"]=n?"true":"false")}(t,e),e.theme&&function(e,t){t.primaryColor&&(e["data-primary-color"]=t.primaryColor),t.textPrimary&&(e["data-text-primary"]=t.textPrimary),t.textSecondary&&(e["data-text-secondary"]=t.textSecondary),t.borderColor&&(e["data-border-color"]=t.borderColor),t.fontFamily&&(e["data-font-family"]=t.fontFamily)}(t,e.theme),t}(e);return t("script",{src:"https://widget.tebuto.de/booking.js",...n,"data-testid":"tebuto-booking-widget-script"})}const u="tebuto-fingerprint",b=r(null);function p({therapistUUID:e,apiBaseUrl:n="https://api.tebuto.de",categories:r,includeSubusers:i,children:s}){const d=function(){const[e,t]=a("");return l(()=>{if(void 0===globalThis.window)return;const e=sessionStorage.getItem(u);if(e)t(e);else{const e=crypto.randomUUID();sessionStorage.setItem(u,e),t(e)}},[]),e}(),c=o(()=>({therapistUUID:e,apiBaseUrl:n,categories:r,includeSubusers:i,buildUrl:e=>`${n}${e}`,fingerprint:d}),[e,n,r,i,d]);return t(b.Provider,{value:c,children:s})}function m(){const e=i(b);if(!e)throw new Error("useTebutoContext must be used within a TebutoProvider");return e}function h(){const{therapistUUID:e,buildUrl:t}=m(),[n,r]=a({data:null,isLoading:!0,error:null}),o=s(async()=>{r(e=>({...e,isLoading:!0,error:null}));try{const n=await fetch(t(`/therapists/uuid/${e}`));if(!n.ok)throw new Error(`Failed to fetch therapist: ${n.statusText}`);const o=await n.json();r({data:o,isLoading:!1,error:null})}catch(e){const t=e instanceof Error?e:new Error("Unknown error occurred");r({data:null,isLoading:!1,error:t})}},[e,t]);return l(()=>{o().catch(()=>{})},[o]),{...n,refetch:o}}function f(e){return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,"0")}-${String(e.getDate()).padStart(2,"0")}`}function y(e){const t=new Date(e.start),n=new Date(e.end),r=new Date,o=new Date(r.getFullYear(),r.getMonth(),r.getDate()),i=new Date(t.getFullYear(),t.getMonth(),t.getDate()),a=Math.round((n.getTime()-t.getTime())/6e4);return{...e,dateKey:f(t),timeString:t.toLocaleTimeString("de-DE",{hour:"2-digit",minute:"2-digit"}),durationMinutes:a,formattedPrice:new Intl.NumberFormat("de-DE",{style:"currency",currency:"EUR"}).format(Number.parseFloat(e.price)),isToday:i.getTime()===o.getTime(),isPast:t<r}}function v(e={}){const{autoFetch:t=!0,categories:n}=e,{therapistUUID:r,buildUrl:i,categories:d,includeSubusers:c,fingerprint:g}=m(),[u,b]=a({data:null,isLoading:t,error:null}),p=n??d,h=p?.join(",")??"",v=s(async()=>{if(g){b(e=>({...e,isLoading:!0,error:null}));try{const e=new URL(i(`/events/${r}`));e.searchParams.set("fingerprint",g),h&&e.searchParams.set("categories",h),c&&e.searchParams.set("includeSubusers","true");const t=await fetch(e.toString());if(!t.ok)throw new Error(`Failed to fetch slots: ${t.statusText}`);const n=await t.json(),o=Array.isArray(n)?n:n.events;b({data:o,isLoading:!1,error:null})}catch(e){const t=e instanceof Error?e:new Error("Unknown error occurred");b({data:null,isLoading:!1,error:t})}}},[r,i,h,c,g]);l(()=>{t&&g&&v().catch(()=>{})},[t,v,g]);const k=o(()=>{if(!u.data)return{};const e={},t=new Date;for(const n of u.data){const r=new Date(n.start);if(r<=t)continue;const o=f(r);e[o]||(e[o]=[]),e[o].push(n)}for(const t in e)e[t].sort((e,t)=>new Date(e.start).getTime()-new Date(t.start).getTime());return e},[u.data]),x=o(()=>Object.keys(k).map(e=>{const[t,n,r]=e.split("-").map(Number);return new Date(t,n-1,r)}).sort((e,t)=>e.getTime()-t.getTime()),[k]),S=s(e=>{const t=f(e);return(k[t]??[]).map(y)},[k]),w=o(()=>{if(!u.data)return[];const e=new Map;for(const t of u.data)e.has(t.eventCategoryId)||e.set(t.eventCategoryId,{id:t.eventCategoryId,name:t.title,color:t.color});return Array.from(e.values())},[u.data]);return{...u,refetch:v,slotsByDate:k,availableDates:x,getSlotsForDate:S,categories:w,totalSlots:u.data?.length??0}}function k(){const{therapistUUID:e,buildUrl:t,fingerprint:n}=m(),[r,o]=a({claimedSlot:null,claimResponse:null,isLoading:!1,error:null}),i=d(null),l=s(async()=>{if(r.claimedSlot&&i.current)try{await fetch(t(`/events/${e}/unclaim`),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({fingerprint:n,start:r.claimedSlot.start,end:r.claimedSlot.end,eventRuleId:r.claimedSlot.eventRuleId})})}catch{}finally{i.current=null,o(e=>({...e,claimedSlot:null,claimResponse:null}))}else o(e=>({...e,claimedSlot:null,claimResponse:null}))},[r.claimedSlot,e,t,n]),c=s(async a=>{const s=`${a.start}-${a.eventRuleId}`;if(i.current===s&&r.claimResponse)return r.claimResponse;i.current&&i.current!==s&&await l(),o(e=>({...e,isLoading:!0,error:null}));try{const r=await fetch(t(`/events/${e}/claim`),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({fingerprint:n,start:a.start,end:a.end,eventRuleId:a.eventRuleId})});if(!r.ok)throw new Error(`Failed to claim slot: ${r.statusText}`);const l=await r.json();return l.isAvailable?(i.current=s,o({claimedSlot:a,claimResponse:l,isLoading:!1,error:null}),l):(o(e=>({...e,isLoading:!1,error:new Error("This time slot is no longer available")})),null)}catch(e){const t=e instanceof Error?e:new Error("Unknown error occurred");return o(e=>({...e,isLoading:!1,error:t})),null}},[e,t,l,r.claimResponse,n]),g=s(e=>!!r.claimedSlot&&(r.claimedSlot.start===e.start&&r.claimedSlot.eventRuleId===e.eventRuleId),[r.claimedSlot]),u=s(()=>{o(e=>({...e,error:null}))},[]);return{...r,claim:c,unclaim:l,isClaimed:g,clearError:u}}function x(){const{therapistUUID:e,buildUrl:t,fingerprint:n}=m(),[r,o]=a({isLoading:!1,error:null,isSuccess:!1});return{...r,book:s(async r=>{const{slot:i,client:a,locationSelection:l}=r;o({isLoading:!0,error:null,isSuccess:!1});try{const r=await fetch(t(`/events/${e}/book`),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({fingerprint:n,start:i.start,end:i.end,eventRuleId:i.eventRuleId,locationSelection:l??i.location,...a})});if(!r.ok)throw new Error(`Booking failed: ${r.statusText}`);return o({isLoading:!1,error:null,isSuccess:!0}),!0}catch(e){const t=e instanceof Error?e:new Error("Unknown error occurred");return o({isLoading:!1,error:t,isSuccess:!1}),!1}},[e,t,n]),reset:s(()=>{o({isLoading:!1,error:null,isSuccess:!1})},[])}}function S(e={}){const{onBookingComplete:t,onError:n}=e,[r,i]=a("loading"),[l,d]=a(null),[c,g]=a(null),[u,b]=a(null),p=h(),m=v({categories:e.categories}),f=k(),y=x();o(()=>{"loading"!==r||p.isLoading||m.isLoading||(p.error||m.error?i("error"):i("date-selection"))},[r,p.isLoading,m.isLoading,p.error,m.error]);const S=o(()=>l?m.getSlotsForDate(l):[],[l,m]),w=s(e=>{d(e),g(null),b(null),e&&i("time-selection")},[d,g,b,i]),D=s(async e=>{if(!e)return await f.unclaim(),g(null),b(null),!0;return await f.claim(e)?(g(e),"not-fixed"!==e.location&&b(e.location),i("booking-form"),!0):(f.error&&n?.(f.error),!1)},[f,n]),I=s(async e=>{if(!c)return!1;return await y.book({slot:c,client:e,locationSelection:u??c.location})?(t?.(),i("confirmation"),!0):(y.error&&n?.(y.error),!1)},[c,u,y,t,n]),T=s(()=>{i("loading"),d(null),g(null),b(null),y.reset(),f.unclaim(),m.refetch()},[y,f,m]),R=s(e=>{i(e)},[]),C=s(e=>{b(e)},[]),L=p.isLoading||m.isLoading||f.isLoading||y.isLoading,z=p.error??m.error??f.error??y.error;return{step:r,goToStep:R,therapist:p,slots:m,selectedDate:l,selectDate:w,selectedDateSlots:S,selectedSlot:c,selectSlot:D,selectedLocation:u,setLocation:C,claim:f,booking:y,submitBooking:I,reset:T,isLoading:L,error:z}}const w={"--booking-bg":"#0f0f10","--booking-surface":"#18181b","--booking-surface-elevated":"#1f1f23","--booking-surface-hover":"#27272a","--booking-border":"#2d2d30","--booking-border-subtle":"#232326","--booking-text":"#fafafa","--booking-text-secondary":"#d4d4d8","--booking-text-muted":"#a1a1aa","--booking-text-subtle":"#71717a","--booking-accent":"#10b981","--booking-accent-hover":"#34d399","--booking-accent-muted":"rgba(16, 185, 129, 0.12)","--booking-accent-glow":"rgba(16, 185, 129, 0.25)","--booking-error":"#ef4444","--booking-error-bg":"rgba(239, 68, 68, 0.1)","--booking-radius":"10px","--booking-radius-sm":"6px","--booking-radius-lg":"14px","--booking-shadow":"0 4px 24px rgba(0, 0, 0, 0.4)","--booking-transition":"0.15s ease","--booking-font":'"Inter", -apple-system, BlinkMacSystemFont, sans-serif'};function D(){return t("div",{style:{width:32,height:32,border:"2px solid var(--booking-border)",borderTopColor:"var(--booking-accent)",borderRadius:"50%",animation:"spin 0.6s linear infinite"}})}function I(){return e("div",{style:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",padding:80,gap:16},children:[t(D,{}),t("span",{style:{color:"var(--booking-text-muted)",fontSize:14},children:"Verfügbare Termine werden geladen..."})]})}function T({current:e,total:n}){return t("div",{style:{display:"flex",alignItems:"center",justifyContent:"center",gap:8,marginBottom:32},children:Array.from({length:n},(n,r)=>t("div",{style:{display:"flex",alignItems:"center",gap:8},children:t("div",{style:{width:r===e?28:10,height:10,borderRadius:5,background:r<=e?"var(--booking-accent)":"var(--booking-border)",transition:"all 0.2s ease",boxShadow:r===e?"0 0 12px var(--booking-accent-glow)":"none"}})},r))})}function R({availableDates:n,selectedDate:r,onSelectDate:i}){const[l,s]=a(()=>n.length>0?new Date(n[0]):new Date),d=o(()=>new Set(n.map(e=>e.toDateString())),[n]),{year:c,month:g,weeks:u}=o(()=>{const e=l.getFullYear(),t=l.getMonth(),n=new Date(e,t,1),r=new Date(e,t+1,0).getDate(),o=(n.getDay()+6)%7,i=[];let a=[];for(let e=0;e<o;e++)a.push(null);for(let e=1;e<=r;e++)a.push(e),7===a.length&&(i.push(a),a=[]);if(a.length>0){for(;a.length<7;)a.push(null);i.push(a)}return{year:e,month:t,daysInMonth:r,firstDayOfWeek:o,weeks:i}},[l]),b=e=>{const t=new Date(c,g,e);return d.has(t.toDateString())},p=new Date,m=c>p.getFullYear()||c===p.getFullYear()&&g>p.getMonth();return e("div",{children:[e("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:20,padding:"0 4px"},children:[t("button",{type:"button",onClick:()=>{s(new Date(c,g-1,1))},disabled:!m,style:{width:36,height:36,border:"1px solid var(--booking-border)",borderRadius:"var(--booking-radius-sm)",background:"var(--booking-surface)",color:m?"var(--booking-text)":"var(--booking-text-subtle)",cursor:m?"pointer":"not-allowed",display:"flex",alignItems:"center",justifyContent:"center",fontSize:16,transition:"var(--booking-transition)",opacity:m?1:.4},children:"‹"}),e("span",{style:{fontSize:16,fontWeight:600,color:"var(--booking-text)"},children:[["Januar","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"][g]," ",c]}),t("button",{type:"button",onClick:()=>{s(new Date(c,g+1,1))},style:{width:36,height:36,border:"1px solid var(--booking-border)",borderRadius:"var(--booking-radius-sm)",background:"var(--booking-surface)",color:"var(--booking-text)",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",fontSize:16,transition:"var(--booking-transition)"},children:"›"})]}),t("div",{style:{display:"grid",gridTemplateColumns:"repeat(7, 1fr)",gap:4,marginBottom:8},children:["Mo","Di","Mi","Do","Fr","Sa","So"].map(e=>t("div",{style:{textAlign:"center",fontSize:12,fontWeight:500,color:"var(--booking-text-subtle)",padding:"8px 0",textTransform:"uppercase",letterSpacing:"0.05em"},children:e},e))}),t("div",{style:{display:"flex",flexDirection:"column",gap:4},children:u.map(n=>{const o=n.find(e=>null!==e)??0,a=`${c}-${g}-w${o}`;return t("div",{style:{display:"grid",gridTemplateColumns:"repeat(7, 1fr)",gap:4},children:n.map((n,o)=>{if(null===n)return t("div",{style:{aspectRatio:"1",minHeight:44}},`${a}-empty-${o}`);const l=b(n),s=(e=>!!r&&new Date(c,g,e).toDateString()===r.toDateString())(n),d=(e=>{const t=new Date;return e===t.getDate()&&g===t.getMonth()&&c===t.getFullYear()})(n);let u="1px solid transparent";s?u="2px solid var(--booking-accent)":d&&(u="1px solid var(--booking-accent)");let p="transparent";s?p="var(--booking-accent)":l&&(p="var(--booking-surface-elevated)");let m="var(--booking-text-subtle)";s?m="#000":l&&(m="var(--booking-text)");let h=400;return s?h=600:l&&(h=500),e("button",{type:"button",onClick:()=>(e=>{b(e)&&i(new Date(c,g,e))})(n),disabled:!l,style:{aspectRatio:"1",minHeight:44,border:u,borderRadius:"var(--booking-radius-sm)",background:p,color:m,cursor:l?"pointer":"default",fontSize:14,fontWeight:h,fontFamily:"inherit",display:"flex",alignItems:"center",justifyContent:"center",transition:"var(--booking-transition)",opacity:l?1:.35,position:"relative"},children:[n,l&&!s&&t("span",{style:{position:"absolute",bottom:6,width:4,height:4,borderRadius:"50%",background:"var(--booking-accent)"}})]},`${c}-${g}-${n}`)})},a)})}),e("div",{style:{display:"flex",alignItems:"center",gap:20,marginTop:20,paddingTop:16,borderTop:"1px solid var(--booking-border-subtle)",fontSize:12,color:"var(--booking-text-muted)"},children:[e("div",{style:{display:"flex",alignItems:"center",gap:8},children:[t("span",{style:{width:8,height:8,borderRadius:"50%",background:"var(--booking-accent)"}}),t("span",{children:"Termine verfügbar"})]}),e("div",{style:{display:"flex",alignItems:"center",gap:8},children:[t("span",{style:{width:8,height:8,borderRadius:"50%",background:"var(--booking-text-subtle)",opacity:.35}}),t("span",{children:"Keine Termine"})]})]})]})}function C({slots:n,selectedSlot:r,onSelectSlot:o,selectedDate:i,onBack:a}){const l=e=>{switch(e){case"virtual":return"🎥";case"onsite":return"📍";case"not-fixed":return"🔄"}},s=e=>{switch(e){case"virtual":return"Online";case"onsite":return"Vor Ort";case"not-fixed":return"Flexibel"}},d=n.reduce((e,t)=>{const n=t.title;return e[n]||(e[n]=[]),e[n].push(t),e},{});return e("div",{children:[e("div",{style:{marginBottom:24},children:[t("button",{type:"button",onClick:a,style:{display:"flex",alignItems:"center",gap:6,background:"none",border:"none",color:"var(--booking-text-muted)",fontSize:13,cursor:"pointer",padding:"4px 0",marginBottom:12,fontFamily:"inherit",transition:"var(--booking-transition)"},children:"← Zurück zum Kalender"}),e("h3",{style:{fontSize:18,fontWeight:600,color:"var(--booking-text)",margin:0,display:"flex",alignItems:"center",gap:12},children:[t("span",{style:{width:40,height:40,borderRadius:"var(--booking-radius-sm)",background:"var(--booking-accent-muted)",display:"flex",alignItems:"center",justifyContent:"center",fontSize:18},children:"🕐"}),(c=i,c.toLocaleDateString("de-DE",{weekday:"long",day:"numeric",month:"long",year:"numeric"}))]})]}),t("div",{style:{display:"flex",flexDirection:"column",gap:28},children:Object.entries(d).map(([n,i])=>e("div",{children:[e("h4",{style:{fontSize:14,fontWeight:600,color:"var(--booking-text-secondary)",margin:"0 0 12px 0",display:"flex",alignItems:"center",gap:8},children:[t("span",{style:{width:3,height:14,borderRadius:2,background:i[0]?.color||"var(--booking-accent)"}}),n]}),t("div",{style:{display:"grid",gridTemplateColumns:"repeat(auto-fill, minmax(240px, 1fr))",gap:12},children:i.map(n=>{const i=r?.start===n.start&&r?.eventRuleId===n.eventRuleId;return e("button",{type:"button",onClick:()=>o(n),style:{padding:"14px 16px",border:i?"2px solid var(--booking-accent)":"1px solid var(--booking-border)",borderRadius:"var(--booking-radius)",background:i?"var(--booking-accent-muted)":"var(--booking-surface-elevated)",cursor:"pointer",textAlign:"left",fontFamily:"inherit",transition:"var(--booking-transition)",display:"flex",alignItems:"center",justifyContent:"space-between",gap:12},children:[e("div",{style:{display:"flex",alignItems:"center",gap:12},children:[t("span",{style:{fontSize:17,fontWeight:600,color:"var(--booking-text)",fontVariantNumeric:"tabular-nums"},children:n.timeString}),e("span",{style:{fontSize:11,color:"var(--booking-text-subtle)",background:"var(--booking-surface)",padding:"4px 8px",borderRadius:4,display:"inline-flex",alignItems:"center",gap:4,whiteSpace:"nowrap",flexShrink:0},children:[l(n.location)," ",s(n.location)]})]}),t("span",{style:{fontSize:14,fontWeight:600,color:"var(--booking-accent)"},children:n.formattedPrice})]},`${n.start}-${n.eventRuleId}`)})})]},n))}),0===n.length&&t("div",{style:{textAlign:"center",padding:40,color:"var(--booking-text-muted)"},children:"Keine Termine an diesem Tag verfügbar."})]});var c}function L({slot:r,showLocationSelector:o,selectedLocation:i,onLocationChange:l,onSubmit:s,onBack:d,isLoading:c,error:g}){const[u,b]=a({firstName:"",lastName:"",email:"",phone:"",notes:""}),p={width:"100%",padding:"14px 16px",border:"1px solid var(--booking-border)",borderRadius:"var(--booking-radius-sm)",background:"var(--booking-bg)",color:"var(--booking-text)",fontSize:15,fontFamily:"inherit",outline:"none",transition:"var(--booking-transition)",boxSizing:"border-box"},m={display:"block",fontSize:13,fontWeight:600,color:"var(--booking-text-secondary)",marginBottom:8,textTransform:"uppercase",letterSpacing:"0.03em"};return e("div",{children:[t("button",{type:"button",onClick:d,style:{display:"inline-flex",alignItems:"center",gap:6,background:"var(--booking-surface-elevated)",border:"1px solid var(--booking-border)",borderRadius:"var(--booking-radius-sm)",color:"var(--booking-text-muted)",fontSize:13,cursor:"pointer",padding:"8px 14px",marginBottom:24,fontFamily:"inherit",transition:"var(--booking-transition)"},children:"← Zurück"}),e("div",{style:{background:"linear-gradient(135deg, var(--booking-accent-muted) 0%, var(--booking-surface-elevated) 100%)",borderRadius:"var(--booking-radius-lg)",padding:24,marginBottom:28,border:"1px solid var(--booking-accent)",position:"relative",overflow:"hidden"},children:[t("div",{style:{position:"absolute",top:0,left:0,width:6,height:"100%",background:r.color||"var(--booking-accent)"}}),e("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",flexWrap:"wrap",gap:16},children:[e("div",{style:{display:"flex",alignItems:"center",gap:20},children:[t("div",{style:{width:56,height:56,borderRadius:"var(--booking-radius)",background:"var(--booking-surface)",display:"flex",alignItems:"center",justifyContent:"center",fontSize:24,border:"1px solid var(--booking-border)"},children:"📅"}),e("div",{children:[t("div",{style:{fontSize:18,fontWeight:700,color:"var(--booking-text)",marginBottom:6},children:r.title}),e("div",{style:{display:"flex",alignItems:"center",gap:16,fontSize:14,color:"var(--booking-text-muted)"},children:[e("span",{style:{display:"flex",alignItems:"center",gap:6},children:[t("span",{style:{opacity:.7},children:"📆"})," ",(h=r.start,new Date(h).toLocaleDateString("de-DE",{weekday:"short",day:"numeric",month:"short"}))]}),e("span",{style:{display:"flex",alignItems:"center",gap:6},children:[t("span",{style:{opacity:.7},children:"🕐"})," ",r.timeString," Uhr"]}),e("span",{style:{display:"flex",alignItems:"center",gap:6},children:[t("span",{style:{opacity:.7},children:"⏱"})," ",r.durationMinutes," Min."]})]})]})]}),e("div",{style:{textAlign:"right"},children:[t("div",{style:{fontSize:12,color:"var(--booking-text-muted)",marginBottom:2},children:"Preis"}),t("div",{style:{fontSize:28,fontWeight:700,color:"var(--booking-accent)"},children:r.formattedPrice})]})]})]}),o&&e("div",{style:{background:"var(--booking-surface-elevated)",borderRadius:"var(--booking-radius)",padding:20,marginBottom:28,border:"1px solid var(--booking-border)"},children:[t("div",{style:{fontSize:14,fontWeight:600,color:"var(--booking-text)",marginBottom:14},children:"Wo soll der Termin stattfinden?"}),t("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:12},children:["virtual","onsite"].map(n=>e("button",{type:"button",onClick:()=>l(n),style:{padding:"16px 20px",border:i===n?"2px solid var(--booking-accent)":"1px solid var(--booking-border)",borderRadius:"var(--booking-radius)",background:i===n?"var(--booking-accent-muted)":"var(--booking-surface)",color:"var(--booking-text)",cursor:"pointer",fontFamily:"inherit",fontSize:15,fontWeight:600,display:"flex",alignItems:"center",justifyContent:"center",gap:10,transition:"var(--booking-transition)"},children:[t("span",{style:{fontSize:20},children:"virtual"===n?"🎥":"📍"}),"virtual"===n?"Online-Termin":"Vor Ort"]},n))})]}),e("div",{style:{background:"var(--booking-surface-elevated)",borderRadius:"var(--booking-radius-lg)",padding:28,border:"1px solid var(--booking-border)"},children:[e("div",{style:{display:"flex",alignItems:"center",gap:14,marginBottom:24,paddingBottom:20,borderBottom:"1px solid var(--booking-border)"},children:[t("div",{style:{width:44,height:44,borderRadius:"var(--booking-radius-sm)",background:"var(--booking-accent-muted)",display:"flex",alignItems:"center",justifyContent:"center",fontSize:20},children:"👤"}),e("div",{children:[t("h3",{style:{fontSize:17,fontWeight:700,color:"var(--booking-text)",margin:0},children:"Ihre Kontaktdaten"}),t("p",{style:{fontSize:13,color:"var(--booking-text-muted)",margin:"4px 0 0 0"},children:"Wir benötigen diese Angaben für Ihre Terminbestätigung"})]})]}),g&&e("div",{style:{background:"var(--booking-error-bg)",border:"1px solid var(--booking-error)",borderRadius:"var(--booking-radius-sm)",padding:"14px 16px",marginBottom:20,color:"var(--booking-error)",fontSize:14,display:"flex",alignItems:"center",gap:10},children:[t("span",{children:"⚠️"})," ",g.message]}),e("form",{onSubmit:e=>{e.preventDefault(),s({firstName:u.firstName,lastName:u.lastName,email:u.email,phone:u.phone||void 0,notes:u.notes||void 0})},style:{display:"flex",flexDirection:"column",gap:20},children:[e("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr",gap:16},children:[e("div",{children:[t("label",{htmlFor:"booking-firstName",style:m,children:"Vorname"}),t("input",{id:"booking-firstName",type:"text",required:!0,value:u.firstName,onChange:e=>b(t=>({...t,firstName:e.target.value})),style:p,placeholder:"Max"})]}),e("div",{children:[t("label",{htmlFor:"booking-lastName",style:m,children:"Nachname"}),t("input",{id:"booking-lastName",type:"text",required:!0,value:u.lastName,onChange:e=>b(t=>({...t,lastName:e.target.value})),style:p,placeholder:"Mustermann"})]})]}),e("div",{children:[t("label",{htmlFor:"booking-email",style:m,children:"E-Mail-Adresse"}),t("input",{id:"booking-email",type:"email",required:!0,value:u.email,onChange:e=>b(t=>({...t,email:e.target.value})),style:p,placeholder:"max@beispiel.de"})]}),e("div",{children:[e("label",{htmlFor:"booking-phone",style:{...m,color:"var(--booking-text-muted)"},children:["Telefonnummer ",t("span",{style:{fontWeight:400,textTransform:"none"},children:"(optional)"})]}),t("input",{id:"booking-phone",type:"tel",value:u.phone,onChange:e=>b(t=>({...t,phone:e.target.value})),style:p,placeholder:"+49 123 456789"})]}),e("div",{children:[e("label",{htmlFor:"booking-notes",style:{...m,color:"var(--booking-text-muted)"},children:["Nachricht ",t("span",{style:{fontWeight:400,textTransform:"none"},children:"(optional)"})]}),t("textarea",{id:"booking-notes",value:u.notes,onChange:e=>b(t=>({...t,notes:e.target.value})),style:{...p,minHeight:100,resize:"vertical"},placeholder:"Gibt es etwas, das wir vorab wissen sollten?"})]}),t("button",{type:"submit",disabled:c||o&&!i,style:{marginTop:8,padding:"18px 32px",border:"none",borderRadius:"var(--booking-radius)",background:"var(--booking-accent)",color:"#000",fontSize:16,fontWeight:700,cursor:c||o&&!i?"not-allowed":"pointer",fontFamily:"inherit",transition:"var(--booking-transition)",opacity:c||o&&!i?.5:1,display:"flex",alignItems:"center",justifyContent:"center",gap:10,boxShadow:c||o&&!i?"none":"0 4px 14px var(--booking-accent-glow)"},children:c?e(n,{children:[t(D,{})," Wird gebucht..."]}):t(n,{children:"Termin verbindlich buchen"})})]})]})]});var h}function z({slot:n,onReset:r}){return e("div",{style:{textAlign:"center",padding:"48px 24px"},children:[t("div",{style:{width:72,height:72,borderRadius:"50%",background:"var(--booking-accent-muted)",display:"flex",alignItems:"center",justifyContent:"center",margin:"0 auto 24px",fontSize:32,border:"2px solid var(--booking-accent)"},children:"✓"}),t("h2",{style:{fontSize:24,fontWeight:700,color:"var(--booking-text)",margin:"0 0 12px 0"},children:"Terminanfrage eingegangen!"}),e("p",{style:{fontSize:15,color:"var(--booking-text-muted)",maxWidth:400,margin:"0 auto 32px",lineHeight:1.6},children:["Ihre Anfrage für ",e("strong",{style:{color:"var(--booking-text)"},children:['"',n.title,'"']})," am"," ",t("strong",{style:{color:"var(--booking-text)"},children:(o=n.start,new Date(o).toLocaleDateString("de-DE",{weekday:"long",day:"numeric",month:"long",year:"numeric"}))})," um"," ",e("strong",{style:{color:"var(--booking-text)"},children:[n.timeString," Uhr"]})," ist eingegangen. Bitte bestätigen Sie den Termin über den Link in der E-Mail, die wir Ihnen gerade gesendet haben."]}),t("div",{style:{display:"flex",gap:12,justifyContent:"center",flexWrap:"wrap"},children:t("button",{type:"button",onClick:r,style:{padding:"12px 20px",border:"1px solid var(--booking-border)",borderRadius:"var(--booking-radius-sm)",background:"transparent",color:"var(--booking-text)",fontSize:14,fontWeight:500,cursor:"pointer",fontFamily:"inherit"},children:"Weiteren Termin buchen"})})]});var o}function F(){const{step:n,goToStep:r,therapist:o,slots:i,selectedDate:a,selectDate:l,selectedDateSlots:s,selectedSlot:d,selectSlot:c,selectedLocation:g,setLocation:u,submitBooking:b,reset:p,isLoading:m,error:h}=S(),f=d?{...d,dateKey:new Date(d.start).toISOString().split("T")[0],timeString:new Date(d.start).toLocaleTimeString("de-DE",{hour:"2-digit",minute:"2-digit"}),durationMinutes:Math.round((new Date(d.end).getTime()-new Date(d.start).getTime())/6e4),formattedPrice:new Intl.NumberFormat("de-DE",{style:"currency",currency:"EUR"}).format(Number.parseFloat(d.price)),isToday:!1,isPast:!1}:null;return e("div",{style:{...w,fontFamily:"var(--booking-font)",background:"var(--booking-bg)",color:"var(--booking-text)",minHeight:"100vh",padding:"40px 24px"},children:[t("style",{children:"\n@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');\n@keyframes spin { to { transform: rotate(360deg); } }\n@keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }\n"}),e("div",{style:{maxWidth:880,margin:"0 auto"},children:[e("header",{style:{textAlign:"center",marginBottom:40},children:[e("h1",{style:{fontSize:28,fontWeight:700,margin:"0 0 8px 0",color:"var(--booking-text)"},children:["Termin buchen",o.data?` bei ${o.data.name}`:""]}),t("p",{style:{fontSize:15,color:"var(--booking-text-muted)",margin:0},children:"Wählen Sie einen passenden Termin für Ihr Anliegen"})]}),"loading"!==n&&"error"!==n&&"confirmation"!==n&&t(T,{current:(()=>{switch(n){case"date-selection":default:return 0;case"time-selection":return 1;case"booking-form":return 2;case"confirmation":return 3}})(),total:3}),t("div",{style:{background:"var(--booking-surface)",borderRadius:"var(--booking-radius-lg)",border:"1px solid var(--booking-border)",boxShadow:"var(--booking-shadow)",overflow:"hidden",animation:"fadeIn 0.3s ease"},children:e("div",{style:{padding:28},children:["loading"===n&&t(I,{}),"error"===n&&e("div",{style:{textAlign:"center",padding:40},children:[t("div",{style:{background:"var(--booking-error-bg)",border:"1px solid var(--booking-error)",borderRadius:"var(--booking-radius)",padding:16,marginBottom:20,color:"var(--booking-error)"},children:h?.message??"Ein Fehler ist aufgetreten"}),t("button",{type:"button",onClick:p,style:{padding:"12px 24px",border:"none",borderRadius:"var(--booking-radius-sm)",background:"var(--booking-accent)",color:"#000",fontSize:14,fontWeight:600,cursor:"pointer",fontFamily:"inherit"},children:"Erneut versuchen"})]}),"date-selection"===n&&e("div",{children:[e("h3",{style:{fontSize:18,fontWeight:600,color:"var(--booking-text)",margin:"0 0 20px 0",display:"flex",alignItems:"center",gap:12},children:[t("span",{style:{width:40,height:40,borderRadius:"var(--booking-radius-sm)",background:"var(--booking-accent-muted)",display:"flex",alignItems:"center",justifyContent:"center",fontSize:18},children:"📅"}),t("span",{children:"Datum wählen"})]}),t(R,{availableDates:i.availableDates,selectedDate:a,onSelectDate:l})]}),"time-selection"===n&&a&&t(C,{slots:s,selectedSlot:d?{...d,dateKey:"",timeString:"",durationMinutes:0,formattedPrice:"",isToday:!1,isPast:!1}:null,onSelectSlot:async e=>{await c(e)},selectedDate:a,onBack:()=>r("date-selection")}),"booking-form"===n&&f&&t(L,{slot:f,showLocationSelector:"not-fixed"===f.location,selectedLocation:g,onLocationChange:u,onSubmit:b,onBack:()=>r("time-selection"),isLoading:m,error:h}),"confirmation"===n&&f&&t(z,{slot:f,onReset:p})]})})]})]})}function U({therapistUUID:e,categories:n}){return t(p,{therapistUUID:e,categories:n,children:t(F,{})})}export{U as CustomBookingExample,c as TebutoBookingWidget,p as TebutoProvider,v as useAvailableSlots,x as useBookAppointment,S as useBookingFlow,k as useClaimSlot,m as useTebutoContext,h as useTherapist}; //# sourceMappingURL=index.js.map