PageSourceSearch

https://resoflow-prod.web.app/assets/ReviewsPage-CzKVTJSk.js

js resoflow-prod.web.app collected 2026-10-03 12:36:03 UTC 19,162 bytes, 8 lines download raw bytes

1!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{};e.SENTRY_RELEASE={id:"1.0.0"};var s=(new e.Error).stack;s&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[s]="71ea94b0-ba60-4ea5-9342-060691f90445",e._sentryDebugIdIdentifier="sentry-dbid-71ea94b0-ba60-4ea5-9342-060691f90445")}catch(t){}}();import{G as e,j as s,bX as t,E as r,a4 as a,A as i}from"./index-CJ0eVksD.js";import{R as o,L as l,b as n,r as d}from"./vendor-react-Cg5IBgwO.js";import{q as c,f as m,c as p,o as u}from"./vendor-firebase-db-BWYKWqg8.js";import{db as h}from"./firebase-DvHzvjpo.js";import{u as x}from"./DashboardContext-CecwK-yo.js";import{c as f}from"./apiClient--m1UJa-S.js";import{h as v}from"./settingsService-DWNbfFyj.js";import{r as j,R as b}from"./reviewsVenueGate-DD8Z-9jC.js";import{n as w}from"./notify-DLhs2xBD.js";import{friendlyErrorMessage as y}from"./errorMessages-DM6_MVJz.js";import{D as g}from"./DashboardPageHeader-DaImy8ER.js";import{I as k}from"./IntroCard-BbVLhQ7_.js";import{C as N}from"./check-BWVn7Uwa.js";import{C as R}from"./copy-CTf-EqRx.js";import{E as S}from"./external-link-V1YUMAgj.js";import{D as C}from"./DefaultChip-jDW45DA1.js";import{D as T,a as z,b as D,c as E}from"./dialog-BCSGQg7_.js";import"./OverflowRow-BuyPqomT.js";import"./useEscapeLayer-BYkrVTo8.js";import"./layoutOverlayHost--rgM4dhW.js";import{u as A}from"./useEntityLinks-vchY6mwM.js";import{E as L}from"./EmptyState-CfE3HFLj.js";import{T as I}from"./ToggleSwitch-B1alh_UU.js";import{A as M}from"./ActionButton-CE1Zg744.js";import{F as $}from"./FilterPill-CslfQf7S.js";import{r as F,a as P,R as O,b as q}from"./PublicReviewBits-B5KqCue-.js";import{f as B}from"./formatMediumDate-DrTRR0Rb.js";import{S as H}from"./star-B912nPW0.js";import{L as Y}from"./lock-DOPcn-g5.js";import{F as _}from"./flag-BjmdiTg9.js";import"./vendor-firebase-auth-Dw-tYyLh.js";import"./turnstileScript-Nso5-LFr.js";import"./helpers-DlcxdMGb.js";import"./cycleWindow-BHn3tM_i.js";import"./subDays-DeC4Dhpo.js";import"./en-US-DSTBSzO8.js";import"./format-Cqu3RLcn.js";import"./isWalkInSource-GMcf3upj.js";import"./postSignOutError-BXWQuBO0.js";import"./reportListenerDeath-Dlr7Syko.js";import"./publicBookingSource-CE6_PvFq.js";import"./eventService-Cq61G-nh.js";import"./useListenerRedial-Dy6lpSEx.js";import"./waitlist-BBTyHysC.js";import"./specialDateRules-BSvcUCYt.js";import"./staffTableJoining-D_MbVaX2.js";import"./userDocNameCache-7DB8l2eC.js";import"./bookingTypesModel-Dj3kT6QP.js";import"./noShowTableHold-Bu7QzwNJ.js";import"./waitlistRules-Bs9wu54o.js";import"./staffService-Dn6Yer-g.js";import"./themeWriteRegister-CY0ImIDj.js";import"./scopedLocalStorage-C63pQoBG.js";import"./offlineActionPolicy-Djb7n2Z2.js";import"./menuDealsModel-3su4us9K.js";import"./menuDietary-zYYOBkf9.js";import"./sha256Sync-21y9jCIc.js";import"./planService-RCjdxSEx.js";import"./themeSync-BN6IDfTv.js";import"./timelineColourDefaults-DmyWhyHT.js";import"./popover-CCJTvFZr.js";import"./utils-DruVD-uI.js";import"./composite-DSWmIJ4G.js";import"./useButton-Dv-sk77p.js";import"./useBaseUiId-D49M12hI.js";import"./useRole-BY-HprSY.js";import"./ToolbarRootContext-BSjCopqj.js";import"./HelpBubble-BANzJ5lJ.js";import"./LazyMountBoundary-BrLkzM1_.js";import"./circle-question-mark-B2AzTWoo.js";import"./wifi-off-Q64yAg_D.js";import"./x-C3OBs_Zs.js";import"./useViewportQuery-vHNKbmrR.js";import"./topbarTitleStore-nyK4uHxE.js";import"./ellipsis-UW_yNHBe.js";import"./button-Duwog9Kr.js";import"./index-C30fg99R.js";import"./chevron-left-Bp7EXqvH.js";import"./chevron-right-Gtu9w0j0.js";import"./useEffectivePermissions-DeR9iY_g.js";import"./defaults-sFNQu5fI.js";import"./navVisibility-DeWB5MK3.js";import"./screenModes-DOVe14Vw.js";
2/**
3 * @license lucide-react v0.546.0 - ISC
4 *
5 * This source code is licensed under the ISC license.
6 * See the LICENSE file in the root directory of this source tree.
7 */const V=e("message-square-reply",[["path",{d:"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z",key:"18887p"}],["path",{d:"m10 8-3 3 3 3",key:"fp6dz7"}],["path",{d:"M17 14v-1a2 2 0 0 0-2-2H7",key:"1tkjnz"}]]);function W({title:e,description:i,url:n,closed:d=!1,closedLabel:c,closedActionLabel:m,onOpenSettings:p,qrHubAllowed:u,shellPrefix:h,qrNote:x}){const[f,v]=o.useState(!1);return s.jsxs("div",{className:"rounded-dash-xl border border-v4-line bg-v4-surface px-4 sm:px-5 py-4 space-y-3",children:[s.jsxs("div",{className:"flex items-start justify-between gap-3 flex-wrap",children:[s.jsxs("div",{className:"min-w-0",children:[s.jsx("h2",{className:"text-sm font-bold text-v4-ink",children:e}),s.jsx("p",{className:"text-xs text-v4-ink-3 mt-0.5",children:d?c??i:i})]}),d&&p&&s.jsx("button",{type:"button",onClick:p,className:"touch-hitslop shrink-0 inline-flex items-center gap-1.5 h-9 pointer-coarse:min-h-11 px-3 rounded-dash-lg bg-primary text-white text-xs font-bold hover:bg-primary/90 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary",children:m??"Open settings"})]}),s.jsxs("div",{className:"flex items-stretch gap-2",children:[s.jsxs("div",{className:"flex min-w-0 flex-1 items-center gap-2 rounded-dash-lg border border-v4-line bg-v4-surface-2 px-3 py-2.5",children:[s.jsx(t,{size:15,className:"shrink-0 text-v4-ink-3"}),s.jsx("span",{className:"truncate text-sm font-medium text-v4-ink-2",title:n,children:n.replace(/^https?:\/\//,"")})]}),s.jsxs("button",{type:"button",onClick:async()=>{try{await navigator.clipboard.writeText(n),v(!0),w.success("Link copied"),setTimeout(()=>v(!1),1800)}catch{w.error("Couldn't copy the link — please copy it manually.")}},className:r("touch-hitslop shrink-0 inline-flex items-center gap-1.5 rounded-dash-lg px-3.5 text-sm font-bold text-white transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary",f?"bg-green-600":"bg-primary hover:bg-primary/90"),children:[f?s.jsx(N,{size:15}):s.jsx(R,{size:15}),f?"Copied":"Copy link"]}),s.jsxs("a",{href:n,target:"_blank",rel:"noopener noreferrer",className:"touch-hitslop shrink-0 inline-flex items-center gap-1.5 rounded-dash-lg border border-v4-line bg-v4-surface px-3.5 text-sm font-bold text-v4-ink-2 hover:bg-v4-surface-2 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary",children:[s.jsx(S,{size:15}),"Open"]})]}),s.jsxs("p",{className:"text-xs text-v4-ink-3 leading-relaxed",children:[s.jsx(a,{size:13,className:"inline-block mr-1 -mt-0.5"}),"Want it on the wall? The"," ",u?s.jsx(l,{to:`${h}/settings/qrcodes`,className:"text-primary font-semibold hover:underline",children:"QR codes page"}):s.jsx("span",{className:"font-semibold text-v4-ink-2",children:"QR codes page"})," ","turns this same link into a printable code",x?`, ${x}`:"."]})]})}function Q(e){if("ticket"===(null==e?void 0:e.kind))return"event";if("order"===(null==e?void 0:e.kind)){if("collection"===e.fulfilment)return"collection";if("delivery"===e.fulfilment)return"delivery"}return"dined_in"}function U({stars:e,size:t=14}){return s.jsx("span",{className:"inline-flex items-center gap-0.5",role:"img","aria-label":`${e} out of 5 stars`,children:[1,2,3,4,5].map(r=>s.jsx(H,{size:t,"aria-hidden":"true",className:r<=e?"text-amber-400 fill-amber-400":"text-slate-200 fill-slate-200 dark:text-slate-700 dark:fill-slate-700"},r))})}function G(e){try{return B(new Date(e))}catch{return""}}function J(){var e;const{tenantId:t,settings:r,planState:a}=x(),{pathname:o}
7=n(),N=o.startsWith("/portal"),R=N?"/portal":"/dashboard",S=!1!==(null==a?void 0:a.loading),B=j(null==a?void 0:a.plan,(null==(e=null==a?void 0:a.tenantPlan)?void 0:e.products)??null),[J,K]=d.useState(null),[X,Z]=d.useState(!1),[ee,se]=d.useState(!1),[te,re]=d.useState(null),[ae,ie]=d.useState(""),[oe,le]=d.useState(null),[ne,de]=d.useState(""),[ce,me]=d.useState(!1),[pe,ue]=d.useState("all"),[he,xe]=d.useState(0);d.useEffect(()=>{if(!t)return;const e=c(p(h,"tenants",t,"reviews"),m("createdAt","desc"));return u(e,e=>{K(e.docs.map(e=>({id:e.id,...e.data()}))),Z(!1)},e=>{console.warn("[ReviewsPage] listener failed:",e),Z(!0),K([])})},[t,he]);const fe=d.useMemo(()=>(J??[]).filter(e=>"live"===e.status||"reported"===e.status),[J]),ve=d.useMemo(()=>F((J??[]).map(e=>({badge:Q(e.source)}))),[J]),je=d.useMemo(()=>{const e=J??[];return"all"===pe?e:e.filter(e=>P(Q(e.source))===pe)},[J,pe]),be=d.useMemo(()=>0===fe.length?null:Math.round(fe.reduce((e,s)=>e+(s.stars||0),0)/fe.length*10)/10,[fe]),we=!0===(null==r?void 0:r.reviewsEnabled),ye=A(t||""),ge=`${"undefined"!=typeof window?`${window.location.protocol}//${window.location.host}`:"https://resoflow.co.uk"}/venue/${t??""}#reviews`,ke=null===J?"Loading your reviews…":0===fe.length?"No reviews yet":`${fe.length} review${1===fe.length?"":"s"}${null!==be?` · ${be.toFixed(1)} out of 5`:""}`;return S||B?s.jsxs("div",{className:"p-4 sm:p-6 space-y-5 max-w-5xl",children:[s.jsx(g,{icon:H,title:"Reviews",subtitle:ke}),s.jsx(k,{lead:"Customers who have completed an order, a booking or an event ticket can leave a star rating and a few words — for 30 days after their visit, and they can edit it for 30 days (your reply stays). Reviews show on your venue page — and on your website's reviews section if you have one — while the display switch is on.",sub:N?"You can reply publicly to any review. Reporting an abusive review — and the display switch — live on the owner dashboard.":"You can reply publicly to any review. If one is abusive, report it — ResoFlow will look at it and can remove it. Reviews cannot be deleted by the venue."}),!N&&s.jsxs("div",{className:"rounded-dash-xl border border-v4-line bg-v4-surface shadow-sm p-4 flex items-center justify-between gap-4",children:[s.jsxs("div",{className:"min-w-0",children:[s.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[s.jsx("p",{className:"font-bold text-sm text-slate-900 dark:text-slate-100 m-0",children:"Show reviews to customers"}),s.jsx(C,{value:"off",changed:we})]}),s.jsx("p",{className:"text-xs text-slate-500 dark:text-slate-400 m-0 mt-0.5",children:we?"On — customers can leave reviews, and they show on your venue page.":"Off — nothing shows publicly and new reviews cannot be left."})]}),s.jsx(I,{value:we,onChange:e=>{(async e=>{if(t&&!ee){se(!0);try{await v(t,{reviewsEnabled:e}),w.success(e?"Reviews switched on":"Reviews switched off")}catch(s){w.error(y(s))}finally{se(!1)}}})(e)},initialLoadComplete:null!==r,disabled:ee,ariaLabel:"Show reviews to customers"})]}),s.jsx(W,{title:"Your reviews page",description:"Share this anywhere you ask for reviews — a card with the bill, your email footer, your social bios. Customers who have completed an order, booking or event can leave one.",url:ge,closed:null!==r&&!we,closedLabel:N?"This is where your reviews page will live. It’s closed to customers until the owner switches reviews on.":"This is where your reviews page will live. It’s closed to customers until you switch reviews on above.",qrHubAllowed:ye.settingsAllowed("qrcodes"),shellPrefix:R,qrNote:"ready for a card by the door or the bill."}),s.jsxs("p",{className:"text-xs text-slate-500 dark:text-slate-400 m-0",children:["Looking for the email that asks customers to review you on Google or Tripadvisor? That’s the review request, set up in"," ",s.jsx(l,{to:`${R}/marketing/automations#automation-review`,className:"font-semibold text-primary underline",children:"Marketing → Automations"})," ","— it can also point customers at this page."]}),null===J?s.jsx("div",{className:"space-y-3","aria-hidden":"true",children:[0,1,2].map(e=>
7s.jsx("div",{className:"h-24 rounded-dash-xl bg-slate-100 dark:bg-slate-800/60 animate-pulse"},e))}):X?s.jsx(L,{icon:H,title:"We couldn't load your reviews",description:"Please check your connection and try again.",actionLabel:"Try again",onAction:()=>xe(e=>e+1)}):0===J.length?s.jsx(L,{icon:H,size:"md",iconTone:"primary",title:"No reviews yet",description:we?"Once a customer completes an order, a booking or an event, they can leave a review from their confirmation page — reviews will appear here.":"Switch reviews on above and customers can start leaving them after a completed order, booking or event."}):s.jsxs("div",{className:"space-y-3",children:[ve.length>0&&s.jsx("div",{className:"flex items-center gap-2 flex-wrap",role:"group","aria-label":"Filter reviews by source",children:["all",...ve].map(e=>s.jsx($,{active:pe===e,tone:"primary",onClick:()=>ue(e),children:"all"===e?"All":O[e]},e))}),0===je.length&&s.jsx("p",{className:"text-sm text-slate-400 m-0",children:"No reviews of this kind yet."}),je.map(e=>{var t,r,a;return s.jsx("div",{className:"rounded-dash-xl border border-v4-line bg-v4-surface shadow-sm p-4 space-y-2",children:"removed"===e.status?s.jsxs("p",{className:"text-sm text-slate-500 dark:text-slate-400 italic m-0",children:["Removed by ResoFlow",(null==(t=e.reported)?void 0:t.reason)?` — reported: ${e.reported.reason}`:""]}):s.jsxs(s.Fragment,{children:[s.jsxs("div",{className:"flex items-center justify-between gap-3 flex-wrap",children:[s.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[s.jsx(U,{stars:e.stars}),s.jsx("span",{className:"text-sm font-bold text-slate-900 dark:text-slate-100 truncate",children:e.displayName}),s.jsx("span",{className:"inline-flex items-center px-2 py-0.5 rounded-dash-md bg-slate-100 dark:bg-slate-800 text-slate-500 dark:text-slate-400 text-[10px] font-bold shrink-0",children:q[Q(e.source)]}),s.jsx("span",{className:"text-xs text-slate-400",children:G(e.updatedAt??e.createdAt)})]}),s.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:["reported"===e.status&&s.jsxs("span",{className:"inline-flex items-center gap-1 px-2 py-0.5 rounded-dash-md bg-amber-50 dark:bg-amber-900/20 text-amber-700 dark:text-amber-400 text-xs font-bold",children:[s.jsx(_,{size:12,"aria-hidden":"true"})," Hidden — reported to ResoFlow"]}),s.jsxs(M,{tone:"blue",size:"sm",onClick:()=>{var s;re(e),ie((null==(s=e.reply)?void 0:s.text)??"")},children:[s.jsx(V,{size:14,"aria-hidden":"true"}),e.reply?"Edit reply":"Reply"]}),"reported"!==e.status&&!N&&s.jsxs(M,{tone:"amber",size:"sm",onClick:()=>{le(e),de("")},children:[s.jsx(_,{size:14,"aria-hidden":"true"}),"Report"]})]})]}),e.text&&s.jsx("p",{className:"text-sm text-slate-700 dark:text-slate-300 whitespace-pre-wrap leading-relaxed m-0",children:e.text}),(null==(r=e.reply)?void 0:r.text)&&s.jsxs("div",{className:"rounded-xl bg-slate-50 dark:bg-slate-800/60 border border-slate-100 dark:border-slate-800 p-3",children:[s.jsxs("p",{className:"text-[11px] font-black uppercase tracking-wide text-slate-400 m-0",children:["Your reply",(null==(a=e.reply.by)?void 0:a.name)?` · ${e.reply.by.name}`:""]}),s.jsx("p",{className:"text-xs text-slate-600 dark:text-slate-300 whitespace-pre-wrap m-0 mt-1",children:e.reply.text})]})]})},e.id)})]}),s.jsx(T,{open:null!==te,onOpenChange:e=>{e||re(null)},children:s.jsxs(z,{className:"sm:max-w-lg",children:[s.jsx(D,{children:s.jsx(E,{children:(null==te?void 0:te.reply)?"Edit your reply":"Reply to this review"})}),s.jsx("p",{className:"text-xs text-slate-500 dark:text-slate-400 m-0",children:"Your reply is shown publicly under the review, as the venue."}),s.jsx("textarea",{value:ae,onChange:e=>ie(e.target.value.slice(0,1e3)),rows:4,placeholder:"Thanks for coming in…",className:"w-full rounded-dash-lg border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 p-3 text-sm text-slate-900 dark:text-slate-100 focus:outline-none focus:ring-2 focus:ring-primary/30 resize-none"}),s.jsxs("div",{className:"flex justify-end gap-2",children:[s.jsx(M,{tone:"slate",onClick:()=>re(null),children:"Cancel"}),s.jsxs(M,{tone:"primary",onClick:()=>{(async()=>
7{if(t&&te&&!ce)if(ae.trim()){me(!0);try{const e=f("replyToVenueReview");await e({tenantId:t,reviewId:te.id,text:ae.trim()}),w.success("Reply posted"),re(null),ie("")}catch(e){w.error(y(e))}finally{me(!1)}}else w.error("Please write a reply first.")})()},disabled:ce,children:[ce&&s.jsx(i,{size:14,className:"animate-spin","aria-hidden":"true"}),"Post reply"]})]})]})}),s.jsx(T,{open:null!==oe,onOpenChange:e=>{e||le(null)},children:s.jsxs(z,{className:"sm:max-w-lg",children:[s.jsx(D,{children:s.jsx(E,{children:"Report this review to ResoFlow"})}),s.jsx("p",{className:"text-xs text-slate-500 dark:text-slate-400 m-0",children:"Use this for abusive, fake or offensive reviews. The review comes off your public page and out of your rating straight away while ResoFlow looks at it. You'll get an email with the outcome either way — removed, or back on your page if it stands."}),s.jsx("textarea",{value:ne,onChange:e=>de(e.target.value.slice(0,500)),rows:3,placeholder:"Tell us what's wrong with it",className:"w-full rounded-dash-lg border border-slate-200 dark:border-slate-700 bg-white dark:bg-slate-900 p-3 text-sm text-slate-900 dark:text-slate-100 focus:outline-none focus:ring-2 focus:ring-primary/30 resize-none"}),s.jsxs("div",{className:"flex justify-end gap-2",children:[s.jsx(M,{tone:"slate",onClick:()=>le(null),children:"Cancel"}),s.jsxs(M,{tone:"amber",onClick:()=>{(async()=>{if(t&&oe&&!ce)if(ne.trim()){me(!0);try{const e=f("reportVenueReview");await e({tenantId:t,reviewId:oe.id,reason:ne.trim()}),w.success("Reported to ResoFlow — the review is hidden from your page while we look into it"),le(null),de("")}catch(e){w.error(y(e))}finally{me(!1)}}else w.error("Please say why this review is being reported.")})()},disabled:ce,children:[ce&&s.jsx(i,{size:14,className:"animate-spin","aria-hidden":"true"}),"Report review"]})]})]})})]}):s.jsxs("div",{className:"p-4 sm:p-6 space-y-5 max-w-5xl",children:[s.jsx(g,{icon:H,title:"Reviews",subtitle:"Not included on your current setup"}),s.jsx(k,{lead:"Customer reviews let verified customers — people with a completed order, booking or event ticket — leave a star rating and a few words that show on your venue page.",sub:`${b} Any reviews you already collected are kept safely and come back the moment a paid plan or product is active again.`}),s.jsxs("div",{className:"rounded-dash-xl border border-v4-line bg-v4-surface shadow-sm p-5 space-y-3",children:[s.jsxs("div",{className:"flex items-center gap-2 t-caption text-slate-600 dark:text-slate-400 bg-slate-100 dark:bg-slate-800 px-3 h-10 rounded-dash-lg border border-slate-200 dark:border-slate-700 w-fit",children:[s.jsx(Y,{size:14,className:"text-slate-600 dark:text-slate-400"}),"Included with any paid plan or any paid product"]}),N?s.jsx("p",{className:"text-sm text-slate-600 dark:text-slate-300 m-0",children:"The venue owner can unlock reviews by choosing a plan or product in Billing."}):s.jsxs("p",{className:"text-sm text-slate-600 dark:text-slate-300 m-0",children:["Choose a plan or add a product in"," ",s.jsx(l,{to:"/dashboard/account/plan",className:"font-semibold text-primary underline",children:"Billing"})," ","and reviews unlock straight away — nothing else to set up."]})]})]})}export{J as default};
8//# sourceMappingURL=ReviewsPage-CzKVTJSk.js.map

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.