PageSourceSearch

https://rentamaids247.com/assets/AdminWallets-IpnsflvS.js

js rentamaids247.com collected 2026-10-02 01:41:31 UTC 17,765 bytes, 6 lines download raw bytes

1import{f as ae,at as re,b as ne,j as e,ai as le,a as H,bk as oe,bV as ie,bW as de,bX as ce}from"./index-ldhLsBZg.js";import{r as a}from"./react-vendor-D2UoAUYf.js";import{M as Q}from"./Modal-DVtu92k7.js";import{T as me}from"./Toast-B41YKfWe.js";import{u as ue}from"./useToast-DvLUY4kv.js";import{W as q}from"./wallet-Bx4uc7FY.js";import{T as xe}from"./trending-up-C4kFmxra.js";import{G as he}from"./gift-Dcstlmar.js";import{I as G}from"./indian-rupee-D59XQuK9.js";import{S as ge}from"./save-ISkGn3na.js";import{S as be}from"./search-Foj3p9Ir.js";import{R as F}from"./refresh-cw-B9pE92pq.js";import{A as pe}from"./alert-triangle-D7VO6MDR.js";import{P as ye}from"./plus-vNdJdMI3.js";import{H as fe}from"./history-B9FuKkYZ.js";import{A as Ne,a as je}from"./arrow-up-right-DeUd4kg8.js";import"./supabase-DnPY-mAy.js";import"./alert-circle-DLHnu5gf.js";/**
2 * @license lucide-react v0.344.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 ve=ae("Minus",[["path",{d:"M5 12h14",key:"1ays0h"}]]),we=[100,200,500,1e3],Se={signup_bonus:"Signup Bonus",admin_credit:"Added by Admin",admin_debit:"Deducted by Admin",booking_payment:"Booking Payment",refund:"Refund"};function Qe(){const[i,w]=a.useState([]),[z,S]=a.useState(!0),[g,V]=a.useState(""),[b,k]=a.useState("0"),[_,A]=a.useState(0),[L,C]=a.useState(!1),[u,T]=a.useState(null),[I,B]=a.useState(!1),[r,x]=a.useState(null),[o,X]=a.useState("credit"),[d,p]=a.use
6State(""),[E,$]=a.useState(""),[R,M]=a.useState(!1),[y,U]=a.useState(null),[D,J]=a.useState([]),[K,W]=a.useState(!1),{toast:f,showToast:n,hideToast:Y}=ue();a.useEffect(()=>{h()},[]);const h=async()=>{S(!0);const[s,t]=await Promise.all([re(),ne()]);if(s.error){const l=s.error?.message||"Unknown database error";T(l),n("Could not load wallets — see the details below","error")}else T(null),w(s.data);if(t.data){const c=t.data.find(j=>j.key==="new_account_bonus"),m=c&&Number(c.value)||0;k(String(m)),A(m)}S(!1)},Z=async()=>{B(!0);const{data:s,error:t}=await ie();if(B(!1),t){n(`Could not run bootstrap: ${t?.message||""}. Run the fix_is_admin migration first.`,"error");return}s?.ok?(n(`Your account (${s.email}) is now an admin ✓`,"success"),h()):s?.reason==="admins_exist"?n("Other admins already exist — ask one to add you, or use the SQL below.","error"):n(`Could not set admin (${s?.reason||"unknown"}).`,"error")},N=a.useMemo(()=>({users:i.length,totalBalance:i.reduce((s,t)=>s+Number(t.balance||0),0),funded:i.filter(s=>Number(s.balance)>0).length}),[i]),O=a.useMemo(()=>{const s=g.toLowerCase();return s?i.filter(t=>t.email.toLowerCase().includes(s)||(t.name||"").toLowerCase().includes(s)||(t.phone||"").includes(s)):i},[i,g]),ee=async()=>{const s=Number(b);if(Number.isNaN(s)||s<0){n("Bonus must be 0 or a positive amount","error");return}C(!0);try{const{error:t}=await oe("new_account_bonus",s);if(t)throw t;A(s),n(`New users will now receive ₹${s.toLocaleString("en-IN")} on signup`,"success")}catch(t){console.error("Error saving bonus:",t),n("Error saving bonus setting","error")}finally{C(!1)}},P=(s,t)=>{x(s),X(t),p(""),$("")},se=async s=>{if(s.preventDefault(),!r)return;const t=Number(d);if(Number.isNaN(t)||t<=0){n("Enter a valid amount greater than 0","error");return}if(o==="debit"&&t>Number(r.balance)){n("Cannot deduct more than the current balance","error");return}M(!0);try{const l=o==="credit"?t:-t,{data:c,error:m}=await ce(r.user_id,l,E);if(m)throw m;n(o==="credit"?`₹${t.toLocaleString("en-IN")} added to ${r.email}`:`₹${t.toLocaleString("en-IN")} deducted from ${r.email}`,"success"),c&&w(j=>j.map(v=>v.user_id===r.user_id?{...v,balance:c.balance}:v)),x(null)}catch(l){console.error("Error adjusting wallet:",l),n(l?.message||"Error updating wallet","error")}finally{M(!1)}},te=async s=>{U(s),W(!0);const{data:t,error:l}=await de(s.user_id);l&&n("Error loading transactions","error"),J(t||[]),W(!1)};return z?e.jsx("div",{className:"flex items-center justify-center h-64",children:e.jsx("div",{className:"animate-spin rounded-full h-10 w-10 border-b-2 border-blue-600"})}):e.jsxs("div",{className:"space-y-6",children:[f&&e.jsx(me,{message:f.message,type:f.type,onClose:Y}),e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-3 gap-4",children:[e.jsx("div",{className:"grid grid-cols-2 gap-4 lg:col-span-2",children:[{label:"Registered Users",value:N.users.toLocaleString("en-IN"),icon:le,color:"text-blue-600 bg-blue-50"},{label:"Total Wallet Balance",value:`₹${N.totalBalance.toLocaleString("en-IN")}`,icon:q,color:"text-emerald-600 bg-emerald-50"},{label:"Funded Wallets",value:N.funded.toLocaleString("en-IN"),icon:xe,color:"text-indigo-600 bg-indigo-50"},{label:"Current Signup Bonus",value:`₹${_.toLocaleString("en-IN")}`,icon:he,color:"text-pink-600 bg-pink-50"}].map(s=>e.jsxs("div",{className:"bg-white rounded-xl border border-gray-200 p-4 flex items-center gap-3",children:[e.jsx("div",{className:`p-2.5 rounded-lg ${s.color}`,children:e.jsx(s.icon,{className:"h-5 w-5"})}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"text-xl font-bold text-gray-900 leading-none truncate",children:s.value}),e.jsx("div",{className:"text-xs text-gray-500 mt-1",children:s.label})]})]},s.label))}),e.jsxs("div",{className:"bg-gradient-to-br from-pink-50 via-white to-indigo-50 rounded-xl border border-pink-100 p-5",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[e.jsx(H,{className:"h-4 w-4 text-pink-500"}),e.jsx("h3",{className:"font-bold text-gray-900 text-sm",children:"New Account Bonus"})]}),e.jsx("p",{className:"text-xs text-gray-500 mb-3",children:"Every new user automatically gets this amount in their wallet when they create an account."}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs("div",{className:"relative flex-1",children:[e.jsx(G,{className:"h-4 w-4 text-gray-400 absolute left-3 top-1/2 -translate-y-1/2"}),e.jsx("input",{type:"number",min:0,value:b,onChange:s=>k(s.target.value),className:"w-full pl-9 pr-3 py-2 border border-gray-300 rounded-lg text-sm font-semibold focus:outline-none focus:ring-2 focus:ring-pink-400"})]}),e.jsxs("button",{onClick:ee,disabled:L||Number(b)===_,className:"flex items-center gap-1.5 px-4 py-2 bg-pink-600 hover:bg-pink-700 text-white rounded-lg text-sm font-semibold disabled:opacity-40 transition-colors",children:[e.jsx(ge,{className:"h-4 w-4"})," ",L?"Saving...":"Save"]})]})]})]}),e.jsxs("div",{className:"bg-white rounded-xl border border-gray-200 p-4 flex flex-col sm:flex-row gap-3 sm:items-center",children:[e.jsxs("div",{className:"relative flex-1",children:[e.jsx(be,{className:"h-4 w-4 text-gray-400 absolute left-3 top-1/2 -translate-y-1/2"}),e.jsx("input",{type:"text",value:g,onChange:s=>V(s.target.value),placeholder:"Search users by email, name or phone...",className:"w-full pl-9 pr-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"})]}),e.jsxs("button",{onClick:h,className:"flex items-center justify-center gap-2 px-4 py-2 border border-gray-300 rounded-lg text-sm font-semibold text-gray-700 hover:bg-gray-50 transition-colors",children:[e.jsx(F,{className:"h-4 w-4"})," Refresh"]})]}),u&&e.jsx("div",{className:"bg-red-50 border border-red-200 rounded-xl p-5",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:"p-2 rounded-lg bg-red-100 text-red-600 shrink-0",children:e.jsx(pe,{className:"h-5 w-5"})}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("h3",{className:"font-bold text-red-800",children:"Could not load wallets"}),e.jsx("p",{className:"text-sm text-red-700 mt-1",children:"The database returned:"}),e.jsx("code",{className:"block mt-1 text-xs bg-white/70 border border-red-100 rounded px-2 py-1.5 text-red-700 break-words",children:u}),e.jsxs("div",{className:"text-sm text-gray-600 mt-3 space-y-1",children:[e.jsx("p",{className:"font-semibold text-gray-700",children:"How to fix:"}),/function|schema cache|does not exist|PGRST202/i.test(u)?e.jsxs("p",{children:["The wallet functions aren’t in the database yet. Open the Supabase ",e.jsx("b",{children:"SQL Editor"})," and run the migration ",e.jsx("code",{className:"bg-gray-100 px-1 rounded",children:"supabase/migrations/20260719100000_wallets_repair.sql"}),". It re-creates the wallet tables + RPCs and reloads the schema cache."]}):/access denied|permission/i.test(u)?e.jsxs("div",{className:"space-y-2",children:[e.jsxs("p",{children:["The database doesn’t recognise your account as an admin — even though the app UI let you in. (The DB’s ",e.jsx("code",{className:"bg-gray-100 px-1 rounded",children:"is_admin()"})," only checked the ",e.jsx("code",{className:"bg-gray-100 px-1 rounded",children:"admin_users"})," table, which starts empty.)"]}),e.jsxs("p",{className:"font-semibold text-gray-700",children:["Step 1 — run the migration once (adds the fix + a one-click bootstrap):",e.jsx("br",{}),e.jsx("code",{className:"bg-gray-100 px-1 rounded",children:"supabase/migrations/20260719200000_fix_is_admin.sql"})," in the Supabase SQL Editor."]}),e.jsx("p",{className:"font-semibold text-gray-700",children:"Step 2 — click below to make your signed-in account the admin:"}),e.jsxs("button",{onClick:Z,disabled:I,className:"inline-flex items-center gap-2 px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-white rounded-lg text-sm font-bold disabled:opacity-50",children:[e.jsx(H,{className:"h-4 w-4"})," ",I?"Setting up…":"Make my account the admin"]}),e.jsxs("p",{className:"text-xs text-gray-500 pt-1",children:["Advanced / other admins already exist — add yourself with SQL:",e.jsx("br",{}),e.jsx("code",{className:"block bg-gray-100 px-2 py-1 rounded mt-1 text-xs break-words",children:"INSERT INTO admin_users (email, full_name, role, is_active) VALUES ('[email protected]','Owner','super_admin',true) ON CONFLICT (email) DO UPDATE SET is_active = true;"})]})]}):e.jsxs("p",{children:["Run ",e.jsx("code",{className:"bg-gray-100 px-1 rounded",children:"supabase/migrations/20260719100000_wallets_repair.sql"})," in the Supabase SQL Editor, then retry. If it persists, share this exact message."]})]}),e.jsxs("button",{onClick:h,className:"mt-3 inline-flex items-center gap-1.5 px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg text-sm font-semibold",children:[e.jsx(F,{className:"h-4 w-4"})," Retry"]})]})]})}),e.jsx("div",{className:"bg-white rounded-xl border border-gray-200 overflow-hidden",children:O.length===0?e.jsxs("div",{className:"p-12 text-center",children:[e.jsx(q,{className:"h-12 w-12 text-gray-300 mx-auto mb-3"}),e.jsx("h3",{className:"text-gray-900 font-semibold mb-1",children:"No users found"}),e.jsx("p",{className:"text-sm text-gray-500",children:"Users appear here after they sign up on the customer app."})]}):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:"bg-gray-50 text-left text-xs text-gray-500 uppercase tracking-wider",children:[e.jsx("th",{className:"px-4 py-3 font-semibold",children:"User"}),e.jsx("th",{className:"px-4 py-3 font-semibold hidden md:table-cell",children:"Joined"}),e.jsx("th",{className:"px-4 py-3 font-semibold text-right",children:"Balance"}),e.jsx("th",{className:"px-4 py-3 font-semibold text-right",children:"Actions"})]})}),e.jsx("tbody",{className:"divide-y divide-gray-100",children:O.map(s=>e.jsxs("tr",{className:"hover:bg-gray-50/60 transition-colors",children:[e.jsx("td",{className:"px-4 py-3",children:e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("div",{className:"h-9 w-9 rounded-full bg-gradient-to-br from-blue-500 to-indigo-600 flex items-center justify-center text-white font-bold text-xs shrink-0 uppercase",children:(s.name||s.email).slice(0,2)}),e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"font-semibold text-gray-900 truncate",children:s.name||s.email.split("@")[0]}),e.jsxs("div",{className:"text-xs text-gray-500 truncate",children:[s.email,s.phone?` • ${s.phone}`:""]})]})]})}),e.jsx("td",{className:"px-4 py-3 text-gray-500 hidden md:table-cell",children:new Date(s.created_at).toLocaleDateString("en-IN",{day:"numeric",month:"short",year:"numeric"})}),e.jsx("td",{className:"px-4 py-3 text-right",children:e.jsxs("span",{className:`font-bold ${Number(s.balance)>0?"text-emerald-600":"text-gray-400"}
6`,children:["₹",Number(s.balance).toLocaleString("en-IN")]})}),e.jsx("td",{className:"px-4 py-3",children:e.jsxs("div",{className:"flex items-center justify-end gap-1.5",children:[e.jsxs("button",{onClick:()=>P(s,"credit"),className:"flex items-center gap-1 px-2.5 py-1.5 bg-emerald-50 text-emerald-700 rounded-lg text-xs font-bold hover:bg-emerald-100 transition-colors",title:"Add money",children:[e.jsx(ye,{className:"h-3.5 w-3.5"})," Add"]}),e.jsxs("button",{onClick:()=>P(s,"debit"),className:"flex items-center gap-1 px-2.5 py-1.5 bg-red-50 text-red-600 rounded-lg text-xs font-bold hover:bg-red-100 transition-colors",title:"Deduct money",children:[e.jsx(ve,{className:"h-3.5 w-3.5"})," Deduct"]}),e.jsx("button",{onClick:()=>te(s),className:"p-1.5 text-gray-400 hover:text-blue-600 hover:bg-blue-50 rounded-lg transition-colors",title:"Transaction history",children:e.jsx(fe,{className:"h-4 w-4"})})]})})]},s.user_id))})]})})}),e.jsx(Q,{isOpen:!!r,onClose:()=>x(null),title:o==="credit"?"Add Money to Wallet":"Deduct Money from Wallet",size:"sm",children:r&&e.jsxs("form",{onSubmit:se,className:"space-y-4",children:[e.jsxs("div",{className:"bg-gray-50 rounded-xl p-4 flex items-center justify-between",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"font-semibold text-gray-900 truncate",children:r.name||r.email.split("@")[0]}),e.jsx("div",{className:"text-xs text-gray-500 truncate",children:r.email})]}),e.jsxs("div",{className:"text-right shrink-0 ml-3",children:[e.jsx("div",{className:"text-xs text-gray-400",children:"Current"}),e.jsxs("div",{className:"font-bold text-gray-900",children:["₹",Number(r.balance).toLocaleString("en-IN")]})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium text-gray-700 mb-1",children:"Amount (₹) *"}),e.jsxs("div",{className:"relative",children:[e.jsx(G,{className:"h-4 w-4 text-gray-400 absolute left-3 top-1/2 -translate-y-1/2"}),e.jsx("input",{type:"number",min:1,step:"1",autoFocus:!0,value:d,onChange:s=>p(s.target.value),className:"w-full pl-9 pr-3 py-2.5 border border-gray-300 rounded-lg text-lg font-bold focus:outline-none focus:ring-2 focus:ring-blue-500",placeholder:"0",required:!0})]}),e.jsx("div",{className:"flex gap-2 mt-2",children:we.map(s=>e.jsxs("button",{type:"button",onClick:()=>p(String(s)),className:"px-3 py-1 bg-gray-100 hover:bg-gray-200 rounded-full text-xs font-semibold text-gray-700 transition-colors",children:["₹",s]},s))})]}),e.jsxs("div",{children:[e.jsx("label",{className:"block text-sm font-medium text-gray-700 mb-1",children:"Note (optional)"}),e.jsx("input",{type:"text",value:E,onChange:s=>$(s.target.value),className:"w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500",placeholder:o==="credit"?"e.g. Referral reward":"e.g. Adjustment for booking #123"})]}),d&&Number(d)>0&&e.jsxs("div",{className:"text-sm text-gray-600 bg-blue-50 rounded-lg px-3 py-2",children:["New balance will be"," ",e.jsxs("span",{className:"font-bold text-gray-900",children:["₹",(Number(r.balance)+(o==="credit"?1:-1)*Number(d)).toLocaleString("en-IN")]})]}),e.jsxs("div",{className:"flex justify-end gap-3 pt-2",children:[e.jsx("button",{type:"button",onClick:()=>x(null),className:"px-4 py-2 border border-gray-300 rounded-lg text-sm font-semibold text-gray-700 hover:bg-gray-50",children:"Cancel"}),e.jsx("button",{type:"submit",disabled:R,className:`px-6 py-2 text-white rounded-lg text-sm font-semibold disabled:opacity-50 transition-colors ${o==="credit"?"bg-emerald-600 hover:bg-emerald-700":"bg-red-600 hover:bg-red-700"}`,children:R?"Processing...":o==="credit"?"Add Money":"Deduct Money"})]})]})}),e.jsx(Q,{isOpen:!!y,onClose:()=>U(null),title:`Transactions — ${y?.name||y?.email||""}`,size:"md",children:K?e.jsx("div",{className:"flex items-center justify-center py-12",children:e.jsx("div",{className:"animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"})}):D.length===0?e.jsx("div",{className:"text-center py-10 text-gray-500 text-sm",children:"No transactions yet for this user."}):e.jsx("div",{className:"divide-y divide-gray-100",children:D.map(s=>e.jsxs("div",{className:"py-3 flex items-center gap-3",children:[e.jsx("div",{className:`p-2 rounded-full shrink-0 ${Number(s.amount)>=0?"bg-emerald-50 text-emerald-600":"bg-red-50 text-red-500"}`,children:Number(s.amount)>=0?e.jsx(Ne,{className:"h-4 w-4"}):e.jsx(je,{className:"h-4 w-4"})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("div",{className:"text-sm font-semibold text-gray-900",children:Se[s.type]||s.type}),e.jsxs("div",{className:"text-xs text-gray-500 truncate",children:[s.description||"—",s.created_by?` • by ${s.created_by}`:""]}),e.jsx("div",{className:"text-[11px] text-gray-400",children:new Date(s.created_at).toLocaleStr
6ing("en-IN",{day:"numeric",month:"short",year:"numeric",hour:"2-digit",minute:"2-digit"})})]}),e.jsxs("div",{className:"text-right shrink-0",children:[e.jsxs("div",{className:`font-bold text-sm ${Number(s.amount)>=0?"text-emerald-600":"text-red-500"}`,children:[Number(s.amount)>=0?"+":"","₹",Math.abs(Number(s.amount)).toLocaleString("en-IN")]}),e.jsxs("div",{className:"text-[11px] text-gray-400",children:["Bal ₹",Number(s.balance_after).toLocaleString("en-IN")]})]})]},s.id))})})]})}export{Qe as AdminWallets};

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.