1import{c as F,_ as ne,i as ie,h as le,r as g,k as ee,l as ce,j as e,av as k,aq as D,ay as T,aw as U,a3 as C,B as x,az as oe,C as de,f as me,a9 as xe,aa as ue,aA as he,g as pe,ad as M,O as je,Q as fe,S as ge,V as ve,W as Ne,Y as be,d as ye,m as we}from"./index-DeAJFg0-.js";import{B as W}from"./badge-BArgkDG0.js";import{T as Ce,a as Se,b as S,c,d as Le,e as l}from"./table-D7cAjHSf.js";import{S as _,a as $,b as J,c as K,d as b}from"./select-DT1_cda6.js";import{A as Y}from"./arrow-left-kJnOqUyJ.js";import{C as Re,S as Ae}from"./sliders-horizontal-CEtXHTW5.js";import{C as Ee}from"./clipboard-list-DOYLXObM.js";import{B as ke}from"./brain-circuit-BHoLO8-d.js";import{S as De}from"./search-COsumyqS.js";import{R as Te}from"./refresh-cw-B-N0oVtT.js";import"./index-BdQq_4o_.js";import"./index-DtIbnU2d.js";import"./check-0SD3cnfC.js";/** 2 * @license lucide-react v0.453.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 Ue=F("Activity",[["path",{d:"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2",key:"169zse"}]]);/** 7 * @license lucide-react v0.453.0 - ISC 8 * 9 * This source code is licensed under the ISC license. 10 * See the LICENSE file in the root directory of this source tree. 11 */const Me=F("History",[["path",{d:"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8",key:"1357e3"}],["path",{d:"M3 3v5h5",key:"1xhq8a"}],["path",{d:"M12 7v5l4 2",key:"1fdv2h"}]]);/** 12 * @license lucide-react v0.453.0 - ISC 13 * 14 * This source code is licensed under the ISC license. 15 * See the LICENSE file in the root directory of this source tree. 16 */const Fe=F("Pen",[["path",{d:"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",key:"1a8usu"}]]);function X(t){switch(t){case"premium":return null;case"influencer":return 50;default:return 5}}function Ie(t){switch(t){case"premium":return null;case"influencer":return 10;default:return 0}}function Z({value:t,max:u,size:r=44,strokeWidth:h=3}){const o=r/2-h,p=2*Math.PI*o,n=u<=0?1:u,d=Math.min(t,n)/n*100,v=p-d/100*p;return e.jsxs("div",{className:"relative inline-flex items-center justify-center",children:[e.jsxs("svg",{width:r,height:r,className:"-rotate-90","aria-hidden":!0,children:[e.jsx("circle",{cx:r/2,cy:r/2,r:o,fill:"none",stroke:"currentColor",strokeWidth:h,className:"text-slate-200"}),e.jsx("circle",{cx:r/2,cy:r/2,r:o,fill:"none",stroke:"currentColor",strokeWidth:h,strokeDasharray:p,strokeDashoffset:v,strokeLinecap:"round",className:ye("transition-all duration-500",d>=100?"text-amber-600":"text-emerald-600")})]}),e.jsxs("span",{className:"absolute text-[10px] font-medium text-slate-700 tabular-nums",children:[t,"/",u]})]})}function y({value:t}){return e.jsx("span",{className:"inline-flex items-center rounded-full bg-slate-100 px-2.5 py-0.5 text-xs font-medium text-slate-700",children:t})}const Pe=["free","influencer","premium"],He=[{href:"/admin/billing",label:"Billing",icon:de},{href:"/admin/usage",label:"Usage",icon:Re},{href:"/admin/realtime",label:"Realtime",icon:Ue},{href:"/admin/history",label:"History",icon:Me},{href:"/admin/logs",label:"Logs",icon:Ee},{href:"/admin/model-test",label:"AI Model Test",icon:ke},{href:"/admin/recency-rules",label:"Resume Rules",icon:Ae}];function se(t){if(!t)return"â";try{return new Date(t).toLocaleDateString(void 0,{month:"short",day:"numeric",year:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return"â"}}function qe(t,u){const r=new Date(t);return r.setDate(r.getDate()+u),r}function es(){const{user:t,isAuthenticated:u}=ne(),r=ie(),{toast:h}=le(),[o,p]=g.useState("all"),[n,j]=g.useState(""),[d,v]=g.useState(null),[I,P]=g.useState(""),[H,L]=g.useState(""),[q,B]=g.useState("0"),[O,ae]=g.useState(null),z=u&&(t==null?void 0:t.isAdmin)===!0,w=ee({queryKey:["/api/admin/users",o],queryFn:async({queryKey:s})=>{const[,a]=s,i=a&&a!=="all"?`/api/admin/users?accountLevel=${encodeURIComponent(a)}`:"/api/admin/users",N=await fetch(i,{credentials:"include"}),m=await N.text();if(N.status===401)throw new Error("Unauthorized");if(!N.ok){if(m.startsWith("<")||m.startsWith("<!"))throw new Error("Server returned HTML instead of JSON. The admin API may not be reachable, or your session may have expired. Try refreshing or logging in again.");try{const f=JSON.parse(m);throw new Error((f==null?void 0:f.message)||m||"Failed to fetch users")}catch(f){throw f instanceof SyntaxError?new Error(m||"Failed to fetch users"):f}}try{return JSON.parse(m)}catch{throw new Error("Invalid response from server")}},enabled:z}),R=ce({mutationFn:async({userId:s,accountLevel:a,usageTimeLeft:i,freeRagUsesRemaining:N})=>{const m={};
16return a!==void 0&&(m.accountLevel=a),i!==void 0&&(m.usageTimeLeft=i||null),m.freeRagUsesRemaining=N,(await we("PATCH",`/api/admin/users/${s}`,m)).json()},onSuccess:s=>{r.setQueryData(["/api/admin/users",o],a=>a&&a.map(i=>i.id===s.id?{...i,...s,pdfUploadCount:i.pdfUploadCount,libraryResumeCount:i.libraryResumeCount,errorCount:i.errorCount}:i)),r.invalidateQueries({queryKey:["/api/admin/users"]}),v(null),h({title:"User updated",description:"Changes saved successfully."})},onError:s=>{h({title:"Save failed",description:s instanceof Error?s.message:"Could not update user.",variant:"destructive"})}}),G=w.data??[],Q=n.trim()?G.filter(s=>s.email.toLowerCase().includes(n.trim().toLowerCase())):G,A=w.isLoading,E=w.error,te=s=>{v(s),P(s.accountLevel),L(s.usageTimeLeft?s.usageTimeLeft.split("T")[0]:""),B(String(s.freeRagUsesRemaining??0))},re=()=>{if(!d)return;const s=String(q).trim(),a=s===""?NaN:Number.parseInt(s,10),i=Number.isFinite(a)&&a>=0?Math.trunc(a):0;R.mutate({userId:d.id,accountLevel:I,usageTimeLeft:H||null,freeRagUsesRemaining:i})},V=s=>{if(!d)return;const a=qe(new Date,s);L(a.toISOString().split("T")[0])};return u?z?e.jsxs("div",{className:"min-h-screen bg-slate-50 py-8 px-4",children:[e.jsxs("div",{className:"container mx-auto max-w-7xl",children:[e.jsx("div",{className:"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4 mb-8",children:e.jsxs("div",{children:[e.jsx(C,{href:"/",children:e.jsxs(x,{variant:"ghost",size:"sm",className:"mb-2 -ml-2",children:[e.jsx(Y,{className:"mr-2 h-4 w-4"}),"Back to App"]})}),e.jsxs("h1",{className:"text-2xl font-bold text-slate-900 flex items-center gap-2",children:[e.jsx(oe,{className:"h-7 w-7"}),"Admin Dashboard"]}),e.jsx("p",{className:"text-slate-600 mt-1",children:"Manage users, view usage stats, and set usage windows"}),e.jsx("div",{className:"mt-4 flex flex-wrap gap-2",children:He.map(({href:s,label:a,icon:i})=>e.jsx(C,{href:s,children:e.jsxs(x,{variant:"outline",size:"sm",className:"bg-white",children:[e.jsx(i,{className:"mr-2 h-4 w-4"}),a]})},s))})]})}),e.jsxs(me,{className:"mb-6",children:[e.jsxs(xe,{children:[e.jsx(ue,{children:"Users"}),e.jsx(he,{children:"Filter by tier (free, influencer/coupon, premium). View and edit account levels and usage windows."})]}),e.jsxs(pe,{className:"space-y-4",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-4",children:[e.jsxs("div",{className:"relative flex-1 min-w-[200px] max-w-sm",children:[e.jsx(De,{className:"absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-slate-400"}),e.jsx(M,{placeholder:"Search by email...",value:n,onChange:s=>j(s.target.value),className:"pl-9"})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-sm font-medium text-slate-700",children:"Filter by tier:"}),e.jsxs(_,{value:o,onValueChange:p,children:[e.jsx($,{className:"w-[180px]",children:e.jsx(J,{})}),e.jsxs(K,{children:[e.jsx(b,{value:"all",children:"All tiers"}),e.jsx(b,{value:"free",children:"Free"}),e.jsx(b,{value:"influencer",children:"Influencer (coupon)"}),e.jsx(b,{value:"premium",children:"Premium"})]})]})]}),e.jsxs(x,{variant:"outline",size:"sm",onClick:()=>w.refetch(),disabled:A,children:[e.jsx(Te,{className:`h-4 w-4 mr-2 ${A?"animate-spin":""}`}),"Refresh"]})]}),E&&e.jsxs(k,{variant:"destructive",children:[e.jsx(D,{className:"h-4 w-4"}),e.jsx(T,{children:"Error loading users"}),e.jsx(U,{children:E instanceof Error?E.message:"Unknown error"})]}),e.jsx("div",{className:"rounded-md border overflow-x-auto",children:e.jsxs(Ce,{children:[e.jsx(Se,{children:e.jsxs(S,{className:"bg-slate-100 text-slate-700 font-medium text-md",children:[e.jsx(c,{children:"Email"}),e.jsx(c,{children:"Tier"}),e.jsx(c,{children:"Coupon"}),e.jsx(c,{className:"text-center",children:e.jsx("span",{title:"Resume generations",children:"Resumes Generated"})}),e.jsx(c,{className:"text-center",children:e.jsx("span",{title:"Total saved resumes in this user's library",children:"Library Resumes"})}),e.jsx(c,{className:"text-center",children:e.jsx("span",{title:"PDF uploads",children:"Uploaded PDFs"})}),e.jsx(c,{className:"text-center",children:e.jsx("span",{title:"Skill map clicks",children:"Skill Map"})}),e.jsx(c,{className:"text-center",children:e.jsx("span",{title:"Free RAG uses remaining",children:"RAG Trial Left"})}),e.jsx(c,{className:"text-center",children:"Onboarding"}),e.jsx(c,{children:"Usage Expires"}),e.jsx(c,{className:"text-center",children:"Errors"}),e.jsx(c,{className:"w-[100px]",children:"Actions"})]})}),e.jsx(Le,{children:A?e.jsx(S,{children:e.jsx(l,{colSpan:12,className:"text-center py-8 text-slate-500",children:"Loading users..."})}):Q.length===0?e.jsx(S,{children:e.jsx(l,{colSpan:12,className:"text-center py-8 text-slate-500",children:"No users found"})}):Q.map(s=>e.jsxs(S,{children:[e.jsx(l,{children:e.jsx("span",{className:"font-medium text-slate-900",children:s.email})}),e.jsx(l,{children:e.jsx(W,{variant:s.accountLevel==="premium"?"default":s.accountLevel==="influencer"?"secondary":"outline",children:s.accountLevel})}),e.jsx(l,{className:"text-slate-600",children:s.couponCode||"â"}),e.jsx(l,{className:"text-center",children:X(s.accountLevel)!==null?e.jsx(Z,{value:s.resumeGenCount,max:X(s.accountLevel)}):e.jsx(y,{value:s.resumeGenCount})}),e.jsx(l,{className:"text-center",children:e.jsx(y,{value:s.libraryResumeCount??0})}),e.jsx(l,{className:"text-center",children:e.jsx(y,{value:s.pdfUploadCount})}),e.jsx(l,{className:"text-center",children:(()=>{const a=Ie(s.accountLevel);return a!==null&&a>0?e.jsx(Z,{value:s.skillMapCount,max:a}):e.jsx(y,{value:s.skillMapCount})})()}),e.jsx(l,{className:"text-center",children:e.jsx("span",{className:"font-semibold tabular-nums text-blue-600",children:s.freeRagUsesRemaining??0})}),e.jsx(l,{className:"text-center",children:e.jsx(W,{variant:"outline",className:s.onboardingCompletedAt?"border-emerald-200 bg-emerald-50 text-emerald-700":"border-slate-200 bg-slate-50 text-slate-500",children:s.onboardingCompletedAt?"Complete":"Incomplete"})}),e.jsx(l,{className:"text-slate-600 text-sm",children:se(s.usageTimeLeft)}),e.jsx(l,{className:"text-center",children:s.errorCount>0?e.jsx(Be,{userId:s.id,count:s.errorCount,expanded:O===s.id,onToggle:()=>ae(O===s.id?null:s.id)}):e.jsx(y,{value:0})}),e.jsx(l,{children:e.jsx(x,{variant:"ghost",size:"sm",onClick:()=>te(s),children:e.jsx(Fe,{className:"h-4 w-4"})})})]},s.id))})]})})]})]}),e.jsx("p",{className:"text-xs text-slate-500 mt-2",children:"Page visits are not currently tracked. Resumes Generated = usage-window counter; Library Resumes = total saved resumes in the user's library; PDFs = resume/PDF uploads; Skill Map = skill mapping analysis clicks."})]}),e.jsx(je,{open:!!d,onOpenChange:s=>!s&&v(null),children:e.jsxs(fe,{children:[e.jsxs(ge,{children:[e.jsx(ve,{children:"Edit User"}),e.jsxs(Ne,{children:["Change account level or set usage window expiration for ",d==null?void 0:d.email]})]}),d&&e.jsxs("div",{className:"space-y-4 py-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium text-slate-700",children:"Account Level"}),e.jsxs(_,{value:I,onValueChange:P,children:[e.jsx($,{className:"mt-1",children:e.jsx(J,{})}),e.jsx(K,{children:Pe.map(s=>e.jsx(b,{value:s,children:s},s))})]})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium text-slate-700",children:"Free RAG Uses Remaining"}),e.jsx("p",{className:"text-xs text-slate-500 mb-1",children:"Set trial RAG clicks remaining for this user."}
16),e.jsx(M,{type:"number",min:0,step:1,value:q,onChange:s=>B(s.target.value)})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-sm font-medium text-slate-700",children:"Usage Window Expiration"}),e.jsx("p",{className:"text-xs text-slate-500 mb-1",children:"When the rolling usage window resets. Leave empty for no limit."}),e.jsxs("div",{className:"flex gap-2 mt-1",children:[e.jsx(M,{type:"date",value:H,onChange:s=>L(s.target.value)}),e.jsx(x,{variant:"outline",size:"sm",onClick:()=>V(14),children:"2 weeks"}),e.jsx(x,{variant:"outline",size:"sm",onClick:()=>V(30),children:"30 days"})]})]})]}),e.jsxs(be,{children:[e.jsx(x,{variant:"outline",onClick:()=>v(null),children:"Cancel"}),e.jsx(x,{onClick:re,disabled:R.isPending,children:R.isPending?"Saving...":"Save"})]})]})})]}):e.jsx("div",{className:"min-h-screen flex items-center justify-center bg-slate-50",children:e.jsxs(k,{variant:"destructive",className:"max-w-md",children:[e.jsx(D,{className:"h-4 w-4"}),e.jsx(T,{children:"Access Denied"}),e.jsx(U,{children:"The admin dashboard access is restricted. Your account does not have access."}),e.jsx(C,{href:"/",children:e.jsxs(x,{className:"mt-4",variant:"outline",children:[e.jsx(Y,{className:"mr-2 h-4 w-4"}),"Return to App"]})})]})}):e.jsx("div",{className:"min-h-screen flex items-center justify-center bg-slate-50",children:e.jsxs(k,{variant:"destructive",className:"max-w-md",children:[e.jsx(D,{className:"h-4 w-4"}),e.jsx(T,{children:"Authentication Required"}),e.jsx(U,{children:"Please sign in to access the admin dashboard. Only authorized admin emails can access this page."}),e.jsx(C,{href:"/auth",children:e.jsx(x,{className:"mt-4",children:"Sign In"})})]})})}function Be({userId:t,count:u,expanded:r,onToggle:h}){const{data:o,isLoading:p}=ee({queryKey:[`/api/admin/users/${t}/errors`],queryFn:async({queryKey:n})=>{const j=await fetch(n[0],{credentials:"include"});if(j.status===401)throw new Error("Unauthorized");if(!j.ok)throw new Error(await j.text());return j.json()},enabled:r});return e.jsxs("div",{className:"flex flex-col items-center",children:[e.jsx(x,{variant:"ghost",size:"sm",className:"h-auto p-0 font-medium",onClick:h,children:e.jsxs("span",{className:"inline-flex items-center rounded-full bg-amber-100 px-2.5 py-0.5 text-xs font-medium text-amber-800 hover:bg-amber-200",children:[u," ",r?"â²":"â¼"]})}),r&&e.jsx("div",{className:"mt-2 w-full max-w-md text-left",children:p?e.jsx("span",{className:"text-xs text-slate-500",children:"Loading..."}):o&&o.length>0?e.jsx("div",{className:"space-y-2 max-h-48 overflow-y-auto rounded border bg-slate-50 p-2",children:o.map(n=>e.jsxs("div",{className:"text-xs border-l-2 border-amber-400 pl-2 py-1",children:[e.jsx("span",{className:"font-medium",children:n.errorType}),e.jsx("p",{className:"text-slate-600 truncate",title:n.errorMessage,children:n.errorMessage}),e.jsxs("span",{className:"text-slate-400",children:[se(n.timestamp),n.resolved&&" (resolved)"]})]},n.id))}):e.jsx("span",{className:"text-xs text-slate-500",children:"No error logs"})})]})}export{es 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.