1import{a2 as U,c as G,r as o,j as e,a3 as K,s as J,a4 as Q,a5 as Z,a6 as w,A as X,a7 as ee}from"./index-CL_TZ6iC.js";import{u as Y}from"./adminStaff-C_42Hcnk.js";import{b as f,c as H,S as se,d as ne,e as ae,g as te,h as ie,j as re,v as le,k as ce,l as de}from"./serviceProducts-YklqEqla.js";const q=1,z=1e5;function oe(r,d){if(![r,d].every(x=>Number.isFinite(x)&&x>0))return null;const u=Math.round(r*d);return Number.isFinite(u)&&u>0?u:null}function W(r,d="price"){const u=r.trim();if(u==="")return{error:`Enter the new ${d} in US dollars.`};if(!/^\d{1,8}(\.\d{1,2})?$/.test(u))return{error:"Enter a dollar amount with at most two decimals â 180 or 179.50, no symbol."};const x=Number(u);return!Number.isFinite(x)||x<q||x>z?{error:`Enter an amount between ${f(q)} and ${f(z)}.`}:{usd:x}}function ue(r){return{invalid_body:"That request was malformed. Reload the page and try again.",invalid_slug:"That package cannot be priced from this screen.",invalid_usd:`Enter a USD amount between ${f(q)} and ${f(z)}, with at most two decimals.`,invalid_africa_usd:`Enter an Africa price between ${f(q)} and ${f(z)} in US dollars, with at most two decimals.`,nothing_to_change:"Nothing was changed â fill in a new price first.",package_not_found:"That package no longer exists. Reload the page.",pricing_table_missing:"Consultation price storage is not set up on this site yet, so nothing was saved. It has to be switched on before these prices can be changed here.",forbidden:"You do not have permission to change prices.",unauthorized:"Your session has expired â sign in again to change prices.",length_required:"The request was missing a Content-Length header.",payload_too_large:"That request was too large to send.",rate_limited:"Too many changes in the last minute. Wait a moment and try again."}[r]??"Could not save the price. Try again in a moment."}function he(r,d,u){const x=[];if(typeof d.usd=="number"&&x.push(`${r.name} will cost ${f(r.usd)} â ${f(d.usd)} for buyers outside Africa.`),typeof d.africaUsd=="number"){const L=oe(d.africaUsd,u);x.push(`Buyers in Africa will pay ${f(r.africaUsd)} â ${f(d.africaUsd)}`+(L!==null?`, about ${U(L)} at today's rate (now ${U(r.ngn)}).`:"."))}return x.join(" ")}function me(r,d){if(r.source==="default"||!r.updatedAt)return d?"Default â never changed":"Using the built-in price";const u=new Date(r.updatedAt).toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"});return r.updatedBy?`by ${r.updatedBy} on ${u}`:`Changed on ${u}`}function Ne(){const{apiFetch:r}=G(),{data:d,state:u}=Y("/admin/pricing/ngn"),[x,L]=o.useState(null),l=x??d??null,b=(l==null?void 0:l.prices)??[],[k,M]=o.useState({}),[R,T]=o.useState(null),[F,$]=o.useState(null),[I,y]=o.useState(null),[S,_]=o.useState(null),E=o.useId(),N=(l==null?void 0:l.tableMissing)===!0;function j(t){if(R)return;$(null),y(null);const g=Q(k[t.tier]??"");if("error"in g){y(g.error);return}if(g.amount===t.amount){y(`${K[t.tier]} already costs ${U(t.amount)} a month.`);return}_({row:t,amount:g.amount})}async function C(t,g){var D,A;T(t.tier),$(null),y(null);try{const n=await r("/admin/pricing/ngn",{method:"PUT",body:JSON.stringify({tier:t.tier,amount:g})}),h=(n==null?void 0:n.prices)??[];L({prices:h,tableMissing:(n==null?void 0:n.tableMissing)===!0}),M(s=>({...s,[t.tier]:""})),Z(w(h));const v=((D=h.find(s=>s.tier===t.tier))==null?void 0:D.amount)??g;$(`â ${K[t.tier]} now costs ${U(v)} a month for African buyers`)}catch(n){const h=n instanceof X?(A=n.body)==null?void 0:A.error:void 0;y(ee(h??""))}finally{T(null),_(null)}}return u==="forbidden"?e.jsx("div",{className:"admin-state",children:"Not authorized â admin access is required to see prices."}):u==="loading"&&b.length===0?e.jsx("div",{className:"admin-state",children:"Loadingâ¦"}):u==="error"&&b.length===0?e.jsx("div",{className:"admin-state",children:"Could not load the prices. Reload the page to try again."}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"admin-head-row",children:e.jsx("h2",{children:"Naira plan prices"})}),e.jsx("p",{className:"admin-note is-strong",children:"These prices apply only to buyers in Africa, who pay in Naira through Payaza. The amount here is what their card is actually charged â there is no separate product list behind it. USD prices are set in Stripe and are not edited here. A new price applies to new checkouts within about a minute; pages people already have open update when they come back to them or reload. A checkout someone already has open keeps the price it opened with."}),N&&e.jsx("div",{className:"admin-error",children:"Price storage is not switched on for this site yet, so s
1aving a price will fail. The figures below are the built-in ones customers are being charged right now. Ask whoever handles deployments to apply the pricing setup step (migration 0031), then reload this page."}),e.jsx("div",{className:"admin-table-wrap",children:e.jsxs("table",{className:"admin-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Plan"}),e.jsx("th",{className:"r",children:"Price now"}),e.jsx("th",{children:"Last changed"}),e.jsx("th",{className:"r",children:"New price (â¦)"}),e.jsx("th",{children:"Actions"})]})}),e.jsx("tbody",{children:b.map(t=>{const g=K[t.tier]??t.tier,D=`${E}-${t.tier}`,A=k[t.tier]??"";return e.jsxs("tr",{children:[e.jsx("td",{children:g}),e.jsx("td",{className:"r",children:U(t.amount)}),e.jsx("td",{className:"muted",children:me(t,N)}),e.jsx("td",{className:"r",children:e.jsx("input",{id:D,type:"number",min:100,max:1e7,step:1,inputMode:"numeric",className:"rate-input","aria-label":`New monthly price for ${g}, in naira`,placeholder:String(t.amount),value:A,disabled:R!==null,onChange:n=>M(h=>({...h,[t.tier]:n.target.value})),onKeyDown:n=>{n.key==="Enter"&&j(t)}})}),e.jsx("td",{children:e.jsx("button",{type:"button",className:"ingest-btn","aria-label":`Save the new ${g} price`,disabled:R!==null||A.trim()==="",onClick:()=>j(t),children:R===t.tier?"Savingâ¦":"Save"})})]},t.tier)})})]})}),e.jsxs("div",{className:"ingest-actions",children:[I&&e.jsx("span",{className:"ingest-result err",children:I}),!I&&F&&e.jsx("span",{className:"ingest-result",children:F})]}),S&&e.jsx(J,{title:`Change the ${K[S.row.tier]} price?`,lead:`${K[S.row.tier]} will cost ${U(S.row.amount)} â ${U(S.amount)} a month for African buyers. Checkouts already open keep their old price.`,confirmLabel:"Change price",busy:R!==null,onCancel:()=>_(null),onConfirm:()=>void C(S.row,S.amount)}),e.jsx(pe,{}),e.jsx(xe,{})]})}function ge(r){return r.updatedAt?`Changed on ${new Date(r.updatedAt).toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"})}`:"Never changed"}function pe(){const{apiFetch:r}=G(),{data:d,state:u}=Y("/admin/pricing/consultations"),[x,L]=o.useState(null),l=x??d??null,b=(l==null?void 0:l.packages)??[],k=typeof(l==null?void 0:l.fxRate)=="number"?l.fxRate:0,[M,R]=o.useState({}),[T,F]=o.useState({}),[$,I]=o.useState(null),[y,S]=o.useState(null),[_,E]=o.useState(null),[N,j]=o.useState(null),C=o.useId(),t=()=>{S(null),E(null)};function g(n){if($)return;t();const h=(M[n.slug]??"").trim(),v=(T[n.slug]??"").trim();if(h===""&&v===""){E({slug:n.slug,field:"row",text:"Enter a new price first."});return}const s={};if(h!==""){const i=W(h);if("error"in i){E({slug:n.slug,field:"usd",text:i.error});return}if(i.usd===n.usd){E({slug:n.slug,field:"usd",text:`${n.name} already costs ${f(n.usd)}.`});return}s.usd=i.usd}if(v!==""){const i=W(v,"Africa price");if("error"in i){E({slug:n.slug,field:"africa",text:i.error});return}if(i.usd===n.africaUsd){E({slug:n.slug,field:"africa",text:`The Africa price is already ${f(n.africaUsd)}.`});return}s.africaUsd=i.usd}j({row:n,change:s})}async function D(n,h){var v;I(n.slug),t();try{const s=await r("/admin/pricing/consultations",{method:"PUT",body:JSON.stringify({slug:n.slug,...h})}),i=Array.isArray(s==null?void 0:s.packages)?s.packages:b;L({packages:i,fxRate:typeof(s==null?void 0:s.fxRate)=="number"?s.fxRate:k}),h.usd!==void 0&&R(a=>({...a,[n.slug]:""})),h.africaUsd!==void 0&&F(a=>({...a,[n.slug]:""}));const p=i.find(a=>a.slug===n.slug);S(p?`â ${p.name} now costs ${f(p.usd)} by card and ${U(p.ngn)} in Africa`:`â ${n.name} saved`)}catch(s){const i=s instanceof X?(v=s.body)==null?void 0:v.error:void 0;E({slug:n.slug,field:"row",text:ue(i??"")})}finally{I(null),j(null)}}const A=(n,h)=>_&&_.slug===n&&_.field===h?_.text:null;return u==="loading"&&b.length===0?e.jsxs("section",{className:"admin-section",children:[e.jsx("div",{className:"admin-head-row",children:e.jsx("h2",{children:"Consultation prices"})}),e.jsx("div",{className:"admin-state",children:"Loadingâ¦"})]}):u==="error"&&b.length===0?e.jsxs("section",{className:"admin-section",children:[e.jsx("div",{className:"admin-head-row",children:e.jsx("h2",{children:"Consultation prices"})}),e.jsx("div",{className:"admin-error",children:"Could not load the consultation prices. Reload the page to try again."})]}):e.jsxs("section",{className:"admin-section",children:[e.jsx("div",{className:"admin-head-row",children:e.jsx("h2",{children:"Consultation prices"})}),e.jsxs("p",{className:"admin-note is-strong",children:["These are the sessions sold on Speak with an advisor. Both prices are in US dollars. Buyers outside Africa pay the first one by card (Stripe). Buyers in Africa pay the second one in naira through Payaza, converted at todayâs rate (",H(k)," to $1), so the naira figure moves with the exchange rate and the dollar figure does not. A new price applies to new checkouts straight away; a checkout someone already has open keeps the price it opened with."]}),b.length===0?e.jsx("p",{className:"admin-empty",children:"No consultation packages to price yet."}):e.jsx("div",{className:"admin-table-wrap",children:e.jsxs("table",{className:"admin-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Package"}),e.jsx("th",{className:"r",children:"Card price now"}),e.jsx("th",{className:"r",children:"Africa now"}),e.jsx("th",{children:"Last changed"}),e.jsx("th",{className:"r",children:"New $"}),e.jsx("th",{className:"r",children:"New Africa $"}),e.jsx("th",{children:"Actions"})]})}),e.jsx("tbody",{children:b.map(n=>{const h=M[n.slug]??"",v=T[n.slug]??"",s=A(n.slug,"usd"),i=A(n.slug,"africa"),p=A(n.slug,"row"),a=`${C}-${n.slug}-usd`,c=`${C}-${n.slug}-africa`,P=m=>Number.isInteger(m)?String(m):m.toFixed(2);return e.jsxs("tr",{children:[e.jsxs("td",{children:[n.name," ",!n.active&&e.jsx("span",{className:"sbadge sbadge-never",children:"inactive"})]}),e.jsx("td",{className:"r mono",children:f(n.usd)}),e.jsxs("td",{className:"r",children:[e.jsx("div",{className:"mono",children:f(n.africaUsd)}),e.jsxs("div",{className:"muted",children:["â ",U(n.ngn)]})]}),e.jsx("td",{className:"muted",children:ge(n)}),e.jsxs("td",{className:"r",children:[e.jsx("input",{id:a,type:"number",min:q,max:z,step:.01,inputMode:"decimal",className:"rate-input","aria-label":`New card price for ${n.name}, in US dollars`,"aria-invalid":s?!0:void 0,"aria-describedby":s?`${a}-err`:void 0,placeholder:P(n.usd),value:h,disabled:$!==null,onChange:m=>{R(B=>({...B,[n.slug]:m.target.value})),t()},onKeyDown:m=>{m.key==="Enter"&&g(n)}}),s&&e.jsx("span",{className:"price-field-error",id:`${a}-err`,role:"alert",children:s})]}
1),e.jsxs("td",{className:"r",children:[e.jsx("input",{id:c,type:"number",min:q,max:z,step:.01,inputMode:"decimal",className:"rate-input","aria-label":`New Africa price for ${n.name}, in US dollars`,"aria-invalid":i?!0:void 0,"aria-describedby":i?`${c}-err`:void 0,placeholder:P(n.africaUsd),value:v,disabled:$!==null,onChange:m=>{F(B=>({...B,[n.slug]:m.target.value})),t()},onKeyDown:m=>{m.key==="Enter"&&g(n)}}),i&&e.jsx("span",{className:"price-field-error",id:`${c}-err`,role:"alert",children:i})]}),e.jsxs("td",{children:[e.jsx("button",{type:"button",className:"ingest-btn","aria-label":`Save the new ${n.name} price`,"aria-describedby":p?`${C}-${n.slug}-err`:void 0,disabled:$!==null||h.trim()===""&&v.trim()==="",onClick:()=>g(n),children:$===n.slug?"Savingâ¦":"Save"}),p&&e.jsx("span",{className:"price-field-error",id:`${C}-${n.slug}-err`,role:"alert",children:p})]})]},n.slug)})})]})}),y&&e.jsx("div",{className:"ingest-actions",role:"status","aria-live":"polite",children:e.jsx("span",{className:"ingest-result",children:y})}),N&&e.jsx(J,{title:`Change the ${N.row.name} price?`,lead:he(N.row,N.change,k),confirmLabel:"Change price",busy:$!==null,onCancel:()=>j(null),onConfirm:()=>void D(N.row,N.change)})]})}function fe(r){if(!r.updatedAt)return"Using the default price";const d=new Date(r.updatedAt).toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"});return r.updatedBy?`by ${r.updatedBy} on ${d}`:`Changed on ${d}`}function xe(){const{apiFetch:r}=G(),{data:d,state:u}=Y("/admin/pricing/products"),[x,L]=o.useState(null),l=x??d??null,b=(l==null?void 0:l.products)??[],k=typeof(l==null?void 0:l.africaPercent)=="number"?l.africaPercent:se,M=typeof(l==null?void 0:l.fxRate)=="number"?l.fxRate:0,R=(l==null?void 0:l.tableMissing)===!0,[T,F]=o.useState({}),[$,I]=o.useState({}),[y,S]=o.useState(null),[_,E]=o.useState(null),[N,j]=o.useState(null),[C,t]=o.useState(null),g=o.useId(),D=()=>{E(null),j(null)};function A(s){if(y)return;D();const i=(T[s.slug]??"").trim(),p=($[s.slug]??"").trim();if(i===""&&p===""){j({slug:s.slug,field:"row",text:"Enter a new price first."});return}const a={};if(i!==""){const c=le(i);if("error"in c){j({slug:s.slug,field:"usd",text:c.error});return}if(c.usd===s.usd){j({slug:s.slug,field:"usd",text:`${s.name} already costs ${f(s.usd)}.`});return}a.usd=c.usd}if(p!==""){const c=ce(p);if("error"in c){j({slug:s.slug,field:"ngn",text:c.error});return}if(c.ngn===s.ngnOverride){j({slug:s.slug,field:"ngn",text:`The Africa price is already fixed at ${U(c.ngn)}.`});return}a.ngnOverride=c.ngn}t({row:s,change:a})}function n(s){y||(D(),t({row:s,change:{ngnOverride:null}}))}async function h(s,i){var p;S(s.slug),D();try{const a=await r("/admin/pricing/products",{method:"PUT",body:JSON.stringify({slug:s.slug,...i})}),c=Array.isArray(a==null?void 0:a.products)?a.products:[];L({products:c,africaPercent:typeof(a==null?void 0:a.africaPercent)=="number"?a.africaPercent:k,fxRate:typeof(a==null?void 0:a.fxRate)=="number"?a.fxRate:M,tableMissing:(a==null?void 0:a.tableMissing)===!0}),i.usd!==void 0&&F(m=>({...m,[s.slug]:""})),i.ngnOverride!==void 0&&I(m=>({...m,[s.slug]:""}));const P=c.find(m=>m.slug===s.slug);E(P?`â ${P.name} now costs ${f(P.usd)} by card and ${U(P.ngn)} in Africa`:`â ${s.name} saved`)}catch(a){const c=a instanceof X?(p=a.body)==null?void 0:p.error:void 0;j({slug:s.slug,field:"row",text:de(c??"")})}finally{S(null),t(null)}}const v=(s,i)=>N&&N.slug===s&&N.field===i?N.text:null;return u==="loading"&&b.length===0?e.jsxs("section",{className:"admin-section",children:[e.jsx("div",{className:"admin-head-row",children:e.jsx("h2",{children:"Service prices"})}),e.jsx("div",{className:"admin-state",children:"Loadingâ¦"})]}):u==="error"&&b.length===0?e.jsxs("section",{className:"admin-section",children:[e.jsx("div",{className:"admin-head-row",children:e.jsx("h2",{children:"Service prices"})}),e.jsx("div",{className:"admin-error",children:"Could not load the service prices. Reload the page to try again."})]}):e.jsxs("section",{className:"admin-section",children:[e.jsx("div",{className:"admin-head-row",children:e.jsx("h2",{children:"Service prices"})}),e.jsxs("p",{className:"admin-note is-strong",children:["Buyers outside Africa pay the USD price by card (Stripe). Buyers in Africa pay in naira (Payaza): by default ",k,"% of the USD price at todayâs rate (",H(M)," to $1), rounded to the nearest â¦100. Set a fixed naira price to stop it moving with the exchange rate."]}),R&&e.jsx("div",{className:"admin-error",children:"Service price storage is not switched on for this site yet, so s
1aving a price will fail. Ask whoever handles deployments to apply the service-products setup step (migration 0035), then reload this page."}),b.length===0?e.jsx("p",{className:"admin-empty",children:"No service products to price yet."}):e.jsx("div",{className:"admin-table-wrap",children:e.jsxs("table",{className:"admin-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Product"}),e.jsx("th",{className:"r",children:"USD now"}),e.jsx("th",{className:"r",children:"Africa now"}),e.jsx("th",{children:"Last changed"}),e.jsx("th",{className:"r",children:"New $"}),e.jsx("th",{className:"r",children:"New fixed â¦"}),e.jsx("th",{children:"Actions"})]})}),e.jsx("tbody",{children:b.map(s=>{const i=T[s.slug]??"",p=$[s.slug]??"",a=v(s.slug,"usd"),c=v(s.slug,"ngn"),P=v(s.slug,"row"),m=`${g}-${s.slug}-usd`,B=`${g}-${s.slug}-ngn`;return e.jsxs("tr",{children:[e.jsxs("td",{children:[s.name," ",!s.active&&e.jsx("span",{className:"sbadge sbadge-never",children:"inactive"})]}),e.jsx("td",{className:"r mono",children:f(s.usd)}),e.jsxs("td",{className:"r",children:[e.jsx("div",{className:"mono",children:U(s.ngn)}),e.jsx("div",{className:"muted",children:s.ngnOverride===null?`default (${k}%)`:"fixed"})]}),e.jsx("td",{className:"muted",children:fe(s)}),e.jsxs("td",{className:"r",children:[e.jsx("input",{id:m,type:"number",min:ae,max:ne,step:.01,inputMode:"decimal",className:"rate-input","aria-label":`New USD price for ${s.name}`,"aria-invalid":a?!0:void 0,"aria-describedby":a?`${m}-err`:void 0,placeholder:Number.isInteger(s.usd)?String(s.usd):s.usd.toFixed(2),value:i,disabled:y!==null,onChange:O=>{F(V=>({...V,[s.slug]:O.target.value})),D()},onKeyDown:O=>{O.key==="Enter"&&A(s)}}),a&&e.jsx("span",{className:"price-field-error",id:`${m}-err`,role:"alert",children:a})]}),e.jsxs("td",{className:"r",children:[e.jsx("input",{id:B,type:"number",min:ie,max:te,step:1,inputMode:"numeric",className:"rate-input rate-input-wide","aria-label":`New fixed naira price for ${s.name}`,"aria-invalid":c?!0:void 0,"aria-describedby":c?`${B}-err`:void 0,placeholder:String(s.ngnOverride??s.ngnDefault),value:p,disabled:y!==null,onChange:O=>{I(V=>({...V,[s.slug]:O.target.value})),D()},onKeyDown:O=>{O.key==="Enter"&&A(s)}}),c&&e.jsx("span",{className:"price-field-error",id:`${B}-err`,role:"alert",children:c})]}),e.jsxs("td",{children:[e.jsxs("div",{className:"price-actions",children:[e.jsx("button",{type:"button",className:"ingest-btn","aria-label":`Save the new ${s.name} price`,"aria-describedby":P?`${g}-${s.slug}-err`:void 0,disabled:y!==null||i.trim()===""&&p.trim()==="",onClick:()=>A(s),children:y===s.slug?"Savingâ¦":"Save"}),s.ngnOverride!==null&&e.jsx("button",{type:"button",className:"admin-refresh","aria-label":`Use the default naira price for ${s.name}`,disabled:y!==null,onClick:()=>n(s),children:"Use default"})]}),P&&e.jsx("span",{className:"price-field-error",id:`${g}-${s.slug}-err`,role:"alert",children:P})]})]},s.slug)})})]})}),_&&e.jsx("div",{className:"ingest-actions",role:"status","aria-live":"polite",children:e.jsx("span",{className:"ingest-result",children:_})}),C&&e.jsx(J,{title:`Change the ${C.row.name} price?`,lead:re(C.row,C.change,k,M),confirmLabel:"Change price",busy:y!==null,onCancel:()=>t(null),onConfirm:()=>void h(C.row,C.change)})]})}export{Ne as default};
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.