PageSourceSearch

https://healthserve.ae/assets/AdminForms-oRGc1CW3.js

js healthserve.ae collected 2026-10-04 02:40:09 UTC 14,862 bytes, 9 lines download raw bytes

1import{e as J,r as n,j as e,y as p,aO as f,b2 as I}from"./index-CzMEFmtw.js";import{C as y,P as M,a as U}from"./ui-BklIU2Vp.js";import{S as V}from"./save-Bu384Y2v.js";import{P as G}from"./plus-DZqQktxt.js";import{G as H}from"./grip-vertical-BONnPuEz.js";import{A as W,a as z,W as K}from"./wrench-BM7oAc0k.js";import{T as D}from"./trash-2-gzkfqCHP.js";import{I as O}from"./inbox-DX1wze4V.js";import{D as q}from"./download-D1O7GOuA.js";/**
2 * @license lucide-react v0.462.0 - ISC
3 *
4 * This source code is licensed under the ISC license.
5 * See the LICENSE file in the root directory of this source tree.
6 */const Q=J("Settings2",[["path",{d:"M20 7h-9",key:"3s1dr2"}],["path",{d:"M14 17H5",key:"gfn3mx"}],["circle",{cx:"17",cy:"17",r:"3",key:"18b49y"}],["circle",{cx:"7",cy:"7",r:"3",key:"dfmy0x"}]]),Y=[{value:"text",label:"Text"},{value:"email",label:"Email"},{value:"tel",label:"Phone"},{value:"textarea",label:"Long Text"},{value:"select",label:"Dropdown"},{value:"radio",label:"Radio buttons"},{value:"checkbox",label:"Checkbox"}],g="w-full h-9 px-3 border border-gray-200 rounded-lg text-sm text-gray-900 bg-white focus:outline-none focus:ring-2 focus:ring-[#F9A01B]/40 focus:border-[#F9A01B]",h="block text-xs font-semibold uppercase tracking-wider text-gray-600 mb-1";function Z(){const[i,b]=n.useState([]),[o,c]=n.useState(null),[t,d]=n.useState(null),[j,w]=n.useState(!0),[u,k]=n.useState(!1);async function x(){w(!0);const{data:a,error:s}=await p.from("form_definitions").select("slug,name,description,submit_label,success_message,fields").order("name");s&&f.error(s.message);const l=(a??[]).map(r=>({...r,fields:r.fields??[]}));b(l),l.length&&!o&&c(l[0].slug),w(!1)}n.useEffect(()=>{x()},[]),n.useEffect(()=>{const a=i.find(s=>s.slug===o);d(a?JSON.parse(JSON.stringify(a)):null)},[o,i]);const _=n.useMemo(()=>{const a=i.find(s=>s.slug===o);return t&&a&&JSON.stringify(t)!==JSON.stringify(a)},[t,i,o]);function m(a,s){if(!t)return;const l=t.fields.slice();l[a]={...l[a],...s},d({...t,fields:l})}function S(a,s){if(!t)return;const l=a+s;if(l<0||l>=t.fields.length)return;const r=t.fields.slice();[r[a],r[l]]=[r[l],r[a]],d({...t,fields:r})}function v(a){t&&confirm("Remove this field?")&&d({...t,fields:t.fields.filter((s,l)=>l!==a)})}function F(){if(!t)return;const a=`field_${t.fields.length+1}`;d({...t,fields:[...t.fields,{key:a,type:"text",label:"New field",placeholder:"",required:!1}]})}async function N(){if(!t)return;k(!0);const{error:a}=await p.from("form_definitions").update({name:t.name,description:t.description,submit_label:t.submit_label,success_message:t.success_message,fields:t.fields}).eq("slug",t.slug);if(k(!1),a)return f.error(a.message);f.success("Form saved"),I(t.slug),x()}return e.jsxs("div",{className:"grid md:grid-cols-[260px_1fr] gap-4",children:[e.jsxs(y,{className:"p-2 h-fit",children:[e.jsx("div",{className:"text-xs font-bold uppercase tracking-wider text-gray-500 px-2 py-2",children:"Public Forms"}),j&&e.jsx("div",{className:"text-sm text-gray-500 px-2 py-4",children:"Loading…"}),i.map(a=>e.jsxs("button",{onClick:()=>c(a.slug),className:`w-full text-left px-3 py-2 rounded-lg text-sm font-medium mb-0.5 flex items-center gap-2 ${o===a.slug?"bg-[#F9A01B]/10 text-[#B26800]":"text-gray-700 hover:bg-gray-50"}`,children:[e.jsx(Q,{className:"w-4 h-4 opacity-70"}),e.jsx("span",{className:"min-w-0 truncate",children:a.name})]},a.slug))]}),t?e.jsxs(y,{className:"p-5",children:[e.jsxs("div",{className:"flex items-start justify-between gap-4 mb-5",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"text-xs font-mono text-gray-500 mb-1",children:["/",t.slug]}),e.jsx("input",{className:"text-xl font-bold text-gray-900 w-full bg-transparent border-b border-transparent focus:border-gray-300 focus:outline-none",value:t.name,onChange:a=>d({...t,name:a.target.value})}),t.description&&e.jsx("div",{className:"text-sm text-gray-500 mt-1",children:t.description})]}),e.jsxs("button",{disabled:!_||u,onClick:N,className:"inline-flex items-center gap-2 h-10 px-4 rounded-lg bg-[#F9A01B] text-white text-sm font-semibold disabled:opacity-50",children:[e.jsx(V,{className:"w-4 h-4"}),u?"Saving…":"Save changes"]})]}),e.jsxs("div",{className:"grid md:grid-cols-2 gap-4 mb-6",children:[e.jsxs("div",{children:[e.jsx("label",{className:h,children:"Submit button label"}),e.jsx("input",{className:g,value:t.submit_label,onChange:a=>d({...t,submit_label:a.target.value})})]}),e.jsxs("div",{children:[e.jsx("label",{className:h,children:"Success message"}),e.jsx("input",{className:g,value:t.success_message,onChange:a=>d({...t,success_message:a.target.value})})]})]}),e.jsxs("div",{className:"flex items-center justify-between mb-3",children:[e.jsxs("div",{className:"text-sm font-bold text-gray-900",children:["Fields (",t.fields.length,")"]}),e.jsxs("button",{onClick:F,className:"inline-flex items-center gap-1.5 h-8 px-3 rounded-lg border border-gray-200 text-sm font-semibold text-gray-700 hover:bg-gray-50",children:[e.jsx(G,{className:"w-4 h-4"})," Add field"]})]}),e.jsxs("div",{className:"space-y-3",children:[t.fields.map((a,s)=>e.jsxs("div",{className:"border border-gray-200 rounded-xl p-4 bg-gray-50/50",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3",children:[e.jsx(H,{className:"w-4 h-4 text-gray-400"}),e.jsxs("div",{className:"flex-1 text-xs font-mono text-gray-500",children:["field key: ",e.jsx("span",{className:"text-gray-800",children:a.key})]}),e.jsx("button",{onClick:()=>S(s,-1),className:"p-1.5 rounded hover:bg-white text-gray-500 disabled:opacity-30",disabled:s===0,children:e.jsx(W,{className:"w-4 h-4"})}),e.jsx("button",{onClick:()=>S(s,1),className:"p-1.5 rounded hover:bg-white text-gray-500 disabled:opacity-30",disabled:s===t.fields.length-1,children:e.jsx(z,{className:"w-4 h-4"})}),e.jsx("button",{onClick:()=>v(s),className:"p-1.5 rounded hover:bg-red-50 text-red-500",children:e.jsx(D,{className:"w-4 h-4"})})]}),e.jsxs("div",{className:"grid md:grid-cols-4 gap-3",children:[e.jsxs("div",{className:"md:col-span-2",children:[e.jsx("label",{className:h,children:"Label"}),e.jsx("input",{className:g,value:a.label,onChange:l=>m(s,{label:l.target.value})})]}),e.jsxs("div",{children:[e.jsx("label",{className:h,children:"Type"}
6),e.jsx("select",{className:g,value:a.type,onChange:l=>m(s,{type:l.target.value}),children:Y.map(l=>e.jsx("option",{value:l.value,children:l.label},l.value))})]}),e.jsx("div",{className:"flex items-end",children:e.jsxs("label",{className:"inline-flex items-center gap-2 text-sm text-gray-700 h-9",children:[e.jsx("input",{type:"checkbox",checked:!!a.required,onChange:l=>m(s,{required:l.target.checked})}),"Required"]})}),e.jsxs("div",{className:"md:col-span-2",children:[e.jsx("label",{className:h,children:"Placeholder"}),e.jsx("input",{className:g,value:a.placeholder??"",onChange:l=>m(s,{placeholder:l.target.value})})]}),e.jsxs("div",{className:"md:col-span-2",children:[e.jsx("label",{className:h,children:"Field key (identifier)"}),e.jsx("input",{className:`${g} font-mono`,value:a.key,onChange:l=>m(s,{key:l.target.value.replace(/[^a-zA-Z0-9_]/g,"_")})})]}),(a.type==="select"||a.type==="radio"||a.type==="checkbox")&&e.jsxs("div",{className:"md:col-span-4",children:[e.jsx("label",{className:h,children:"Options (one per line)"}),e.jsx("textarea",{rows:4,className:`${g} h-auto py-2`,value:(a.options??[]).join(`
7`),onChange:l=>m(s,{options:l.target.value.split(`
8`).map(r=>r.trim()).filter(Boolean)})})]})]})]},s)),t.fields.length===0&&e.jsx("div",{className:"text-sm text-gray-500 text-center py-8 border border-dashed border-gray-200 rounded-xl",children:'No fields yet. Click "Add field" to start.'})]}),e.jsxs("div",{className:"mt-6 text-xs text-gray-500 bg-blue-50 border border-blue-100 rounded-lg p-3",children:[e.jsx("strong",{children:"How this works:"})," Labels, placeholders, dropdown options, required toggle, submit button label, and success message are applied to the live site immediately after saving. Field keys must match what the underlying form component expects — for main lead forms (Contact, Book Consultation, German Nursing), changing keys or adding new fields requires a code change; other fields work fully."]})]}):e.jsx(y,{className:"p-8 text-center text-gray-500 text-sm",children:"Select a form on the left to edit it."})]})}function ce(){const[i,b]=n.useState("builder"),[o,c]=n.useState([]),[t,d]=n.useState([]),[j,w]=n.useState([]),[u,k]=n.useState(""),[x,_]=n.useState("all");async function m(){const[s,l,r]=await Promise.all([p.from("form_submissions").select("*").order("created_at",{ascending:!1}),p.from("contact_messages").select("*").order("created_at",{ascending:!1}),p.from("consultation_requests").select("*").order("created_at",{ascending:!1})]);s.error&&f.error(s.error.message),c(s.data??[]),d(l.data??[]),w(r.data??[])}n.useEffect(()=>{m()},[]);const S=n.useMemo(()=>Array.from(new Set(o.map(s=>s.form_key))).sort(),[o]),v=n.useMemo(()=>o.filter(s=>x!=="all"&&s.form_key!==x?!1:u?(JSON.stringify(s.data).toLowerCase()+" "+s.form_key.toLowerCase()).includes(u.toLowerCase()):!0),[o,u,x]);async function F(s,l){const{error:r}=await p.from("form_submissions").update({status:l}).eq("id",s);if(r)return f.error(r.message);m()}async function N(s,l){if(!confirm("Delete this submission?"))return;const{error:r}=await p.from(s).delete().eq("id",l);if(r)return f.error(r.message);m()}function a(s,l){if(!l.length)return f.error("Nothing to export");const r=new Set;l.forEach(B=>Object.keys(B).forEach(L=>r.add(L)));const E=Array.from(r),T=[E.join(","),...l.map(B=>E.map(L=>{const C=B[L];return`"${(C==null?"":typeof C=="object"?JSON.stringify(C):String(C)).replace(/"/g,'""')}"`}).join(","))].join(`
9`),$=new Blob([T],{type:"text/csv"}),P=URL.createObjectURL($),A=document.createElement("a");A.href=P,A.download=`${s}-${new Date().toISOString().slice(0,10)}.csv`,A.click(),URL.revokeObjectURL(P)}return e.jsxs(M,{children:[e.jsx(U,{title:"Forms",description:"Build and edit every public form, and review submissions."}),e.jsx("div",{className:"flex gap-2 mb-4 flex-wrap",children:[{key:"builder",label:"Builder",icon:K},{key:"submissions",label:"Submissions",icon:O},{key:"contacts",label:"Contacts",icon:O},{key:"consultations",label:"Consultations",icon:O}].map(s=>{const l=s.icon,r=s.key==="submissions"?o.length:s.key==="contacts"?t.length:s.key==="consultations"?j.length:null;return e.jsxs("button",{onClick:()=>b(s.key),className:`inline-flex items-center gap-1.5 h-9 px-3 rounded-lg text-sm font-semibold ${i===s.key?"bg-gray-900 text-white":"bg-white border border-gray-200 text-gray-700"}`,children:[e.jsx(l,{className:"w-4 h-4"}),s.label,r!=null&&e.jsxs("span",{className:"ml-1 text-xs opacity-70",children:["(",r,")"]})]},s.key)})}),i==="builder"&&e.jsx(Z,{}),i==="submissions"&&e.jsxs(y,{className:"p-4",children:[e.jsxs("div",{className:"flex gap-2 mb-3",children:[e.jsx("input",{placeholder:"Search…",value:u,onChange:s=>k(s.target.value),className:"flex-1 h-9 px-3 border border-gray-200 rounded-lg text-sm"}),e.jsxs("select",{value:x,onChange:s=>_(s.target.value),className:"h-9 px-3 border border-gray-200 rounded-lg text-sm bg-white",children:[e.jsx("option",{value:"all",children:"All forms"}),S.map(s=>e.jsx("option",{value:s,children:s},s))]}),e.jsxs("button",{onClick:()=>a("submissions",v),className:"inline-flex items-center gap-1.5 h-9 px-3 rounded-lg bg-[#F9A01B] text-white text-sm font-semibold",children:[e.jsx(q,{className:"w-4 h-4"})," CSV"]})]}),e.jsxs("div",{className:"space-y-2 max-h-[65vh] overflow-y-auto",children:[v.length===0&&e.jsx("div",{className:"text-sm text-gray-500 text-center py-8",children:"No submissions yet."}),v.map(s=>e.jsx("div",{className:"border border-gray-200 rounded-lg p-3",children:e.jsxs("div",{className:"flex items-start justify-between gap-3",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[e.jsx("span",{className:"text-[11px] font-bold uppercase tracking-wider px-2 py-0.5 rounded bg-[#F9A01B]/10 text-[#B26800]",children:s.form_key}),e.jsx("span",{className:"text-xs text-gray-500",children:new Date(s.created_at).toLocaleStr
9ing()}),e.jsxs("select",{value:s.status,onChange:l=>F(s.id,l.target.value),className:"text-xs h-6 px-2 border border-gray-200 rounded bg-white",children:[e.jsx("option",{value:"new",children:"new"}),e.jsx("option",{value:"in_progress",children:"in progress"}),e.jsx("option",{value:"resolved",children:"resolved"}),e.jsx("option",{value:"archived",children:"archived"})]})]}),e.jsx("pre",{className:"text-xs bg-gray-50 text-gray-900 rounded p-2 overflow-x-auto whitespace-pre-wrap break-words",children:JSON.stringify(s.data,null,2)}),s.source_url&&e.jsxs("div",{className:"text-[11px] text-gray-500 mt-1",children:["from ",s.source_url]})]}),e.jsx("button",{onClick:()=>N("form_submissions",s.id),className:"text-red-500 hover:bg-red-50 p-2 rounded-lg",children:e.jsx(D,{className:"w-4 h-4"})})]})},s.id))]})]}),i==="contacts"&&e.jsxs(y,{className:"p-4",children:[e.jsx("div",{className:"flex justify-end mb-3",children:e.jsxs("button",{onClick:()=>a("contacts",t),className:"inline-flex items-center gap-1.5 h-9 px-3 rounded-lg bg-[#F9A01B] text-white text-sm font-semibold",children:[e.jsx(q,{className:"w-4 h-4"})," CSV"]})}),e.jsx(R,{rows:t,cols:["created_at","name","email","whatsapp","service","message"],onDelete:s=>N("contact_messages",s)})]}),i==="consultations"&&e.jsxs(y,{className:"p-4",children:[e.jsx("div",{className:"flex justify-end mb-3",children:e.jsxs("button",{onClick:()=>a("consultations",j),className:"inline-flex items-center gap-1.5 h-9 px-3 rounded-lg bg-[#F9A01B] text-white text-sm font-semibold",children:[e.jsx(q,{className:"w-4 h-4"})," CSV"]})}),e.jsx(R,{rows:j,cols:["created_at","name","email","whatsapp","country","profession","experience","goals","status"],onDelete:s=>N("consultation_requests",s)})]})]})}function R({rows:i,cols:b,onDelete:o}){return i.length?e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"text-left text-xs uppercase text-gray-500 border-b border-gray-200",children:[b.map(c=>e.jsx("th",{className:"py-2 pr-3 font-semibold",children:c},c)),e.jsx("th",{})]})}),e.jsx("tbody",{children:i.map(c=>e.jsxs("tr",{className:"border-b border-gray-100 align-top text-gray-800",children:[b.map(t=>e.jsx("td",{className:"py-2 pr-3 max-w-[240px] truncate",children:t==="created_at"?new Date(c[t]).toLocaleString():c[t]==null?"—":String(c[t])},t)),e.jsx("td",{className:"py-2",children:e.jsx("button",{onClick:()=>o(c.id),className:"text-red-500 hover:bg-red-50 p-1.5 rounded",children:e.jsx(D,{className:"w-4 h-4"})})})]},c.id))})]})}):e.jsx("div",{className:"text-sm text-gray-500 text-center py-8",children:"No records."})}export{ce 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.