PageSourceSearch

https://adrianboysel.com/assets/DashboardInbox-DQcwJ3p9.js

js adrianboysel.com collected 2026-10-08 16:35:52 UTC 14,186 bytes, 6 lines download raw bytes

1import{c as se,W as ae,a as te,r as i,s as g,j as e,_ as w,B as f,Y as H,a0 as re,Z as x}from"./index-BWLWF2Sb.js";import{A as L}from"./AppShell-kp35rZRf.js";import{I}from"./input-BjDNHiyc.js";import{M as ie}from"./mail-CwQ9hpMT.js";import{C as U}from"./circle-alert-BkdfXj0P.js";import{C as ne}from"./circle-x-D2Ozl5tJ.js";import{C as le}from"./circle-check-CCkAZ-KA.js";import{o as oe,s as Y}from"./types-Crpao7PO.js";import"./useRole-lwHDbRT8.js";import"./square-check-big-DU1S-nXz.js";import"./calendar-bseSL4Nh.js";import"./bot-CkpuzE1_.js";import"./users-C5Eq47Fd.js";import"./shield-check-DYSZ3BCp.js";import"./globe-DGbc2JOW.js";import"./rocket-CAgkhHEE.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 ce=se("MailOpen",[["path",{d:"M21.2 8.4c.5.38.8.97.8 1.6v10a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V10a2 2 0 0 1 .8-1.6l8-6a2 2 0 0 1 2.4 0l8 6Z",key:"1jhwl8"}],["path",{d:"m22 10-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 10",key:"1qfld7"}]]),de=oe({label:Y().trim().min(2,{message:"Label must be at least 2 characters"}).max(80,{message:"Label must be less than 80 characters"}),email_address:Y().trim().toLowerCase().email({message:"Enter a valid email address"}).max(255,{message:"Email must be less than 255 characters"})}),me=c=>c?new Date(c).toLocaleString():"—",Z=c=>{if(!c)return"—";const b=Date.now()-new Date(c).getTime(),u=Math.floor(b/6e4);if(u<1)return"just now";if(u<60)return`${u}m ago`;const m=Math.floor(u/60);return m<24?`${m}h ago`:`${Math.floor(m/24)}d ago`},Ae=()=>{const{user:c,loading:b}=ae(),u=te(),[m,J]=i.useState(null),[v,K]=i.useState([]),[E,V]=i.useState([]),[O,G]=i.useState(!0),[N,M]=i.useState(null),[X,k]=i.useState(!1),[$,z]=i.useState(""),[T,P]=i.useState(""),[p,j]=i.useState({}),[h,D]=i.useState(!1),[l,_]=i.useState({mailboxId:"all",unreadOnly:!1,actionItemsOnly:!1,search:""}),[o,Q]=i.useState(null);i.useEffect(()=>{!b&&!c&&u("/dashboard/login",{replace:!0})},[c,b,u]),i.useEffect(()=>{c&&(async()=>{const{data:s}=await g.rpc("has_role",{_user_id:c.id,_role:"admin"});J(!!s)})()},[c]);const y=async()=>{G(!0);const[s,a]=await Promise.all([g.from("mailboxes").select("*").order("created_at",{ascending:!0}),g.from("communications").select("*").in("kind",["email_in","email_out"]).eq("source_system","gmail").order("occurred_at",{ascending:!1}).limit(200)]);K(s.data||[]),V(a.data||[]),G(!1)};i.useEffect(()=>{m&&y()},[m]);const q=i.useMemo(()=>E.filter(s=>{var a,t;if(l.mailboxId!=="all"&&((a=s.sync_state)==null?void 0:a.mailbox_id)!==l.mailboxId||l.unreadOnly&&!((t=s.sync_state)!=null&&t.unread))return!1;if(l.actionItemsOnly){const r=s.ai_action_items;if(!(Array.isArray(r)?r.length>0:!1))return!1}if(l.search){const r=l.search.toLowerCase();if(!`${s.subject||""} ${s.from_address||""} ${s.summary||""}`.toLowerCase().includes(r))return!1}return!0}),[E,l]),S=async s=>{const{data:a,error:t}=await g.functions.invoke("gmail-oauth-start",{body:{mailbox_id:s}});if(t||!(a!=null&&a.url)){x.error((t==null?void 0:t.message)||"Failed to start OAuth");return}window.open(a.url,"gmail-oauth","width=520,height=640,menubar=no,toolbar=no")||x.error("Popup blocked — allow popups and try again")};i.useEffect(()=>{const s=async a=>{const t=a.data;!t||t.source!=="gmail-oauth"||(t.status==="ok"?(x.success("Gmail connected — starting first sync"),await y(),t.mailboxId&&await A(t.mailboxId)):(x.error(t.message||"Gmail connection failed"),await y()))};return window.addEventListener("message",s),()=>window.removeEventListener("message",s)},[]);const ee=async()=>{j({});const s=de.safeParse({label:$,email_address:T});if(!s.success){const r={};for(const n of s.error.issues)n.path[0]==="label"&&(r.label=n.message),n.path[0]==="email_address"&&(r.email=n.message);j(r);return}const{label:a,email_address:t}=s.data;if(v.some(r=>r.email_address.toLowerCase()===t)){j({email:"A mailbox with this email already exists"});return}D(!0);try{const{data:r,error:n}=await g.from("mailboxes").insert({label:a,email_address:t,connection_secret_name:"GOOGLE_MAIL_API_KEY",auth_method:"oauth",connection_status:"pending"}).select("id").single();if(n)throw n;x.success("Mailbox saved — authorize it with Google"),P(""),z(""),k(!1),await y(),r!=null&&r.id&&await S(r.i
6d)}catch(r){const n=(r==null?void 0:r.message)||"Failed to add mailbox";/duplicate|unique/i.test(n)?j({email:"A mailbox with this email already exists"}):x.error(n)}finally{D(!1)}},A=async s=>{M(s||"all");try{const{data:a,error:t}=await g.functions.invoke("gmail-sync",{body:s?{mailbox_id:s}:{}});if(t)throw t;const n=((a==null?void 0:a.results)||[]).reduce((d,C)=>d+(C.synced||0),0);x.success(`Synced ${n} new emails`),y()}catch(a){x.error((a==null?void 0:a.message)||"Sync failed")}finally{M(null)}};return b||m===null?e.jsx(L,{title:"Inbox",children:e.jsx("div",{className:"flex items-center justify-center min-h-[60vh]",children:e.jsx(w,{className:"h-6 w-6 animate-spin text-primary"})})}):m?e.jsx(L,{title:"Inbox",children:e.jsxs("div",{className:"max-w-7xl mx-auto px-4 py-8 space-y-8",children:[e.jsxs("header",{className:"flex items-center justify-between flex-wrap gap-4",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-3xl font-bold tracking-tight",children:"Inbox"}),e.jsx("p",{className:"text-muted-foreground text-sm",children:"Unified Gmail sync across your business mailboxes."})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(f,{onClick:()=>A(),disabled:!!N,variant:"outline",children:[N==="all"?e.jsx(w,{className:"h-4 w-4 mr-2 animate-spin"}):e.jsx(H,{className:"h-4 w-4 mr-2"}),"Sync all"]}),e.jsxs(f,{onClick:()=>k(s=>!s),children:[e.jsx(re,{className:"h-4 w-4 mr-2"})," Add mailbox"]})]})]}),X&&e.jsxs("form",{onSubmit:s=>{s.preventDefault(),h||ee()},className:"rounded-xl border border-border bg-card p-4 space-y-3",children:[e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(I,{placeholder:"Label (e.g. Adrian — Personal)",value:$,onChange:s=>z(s.target.value),maxLength:80,"aria-invalid":!!p.label,disabled:h}),p.label&&e.jsx("p",{className:"text-xs text-red-400",children:p.label})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx(I,{type:"email",placeholder:"[email protected]",value:T,onChange:s=>P(s.target.value),maxLength:255,"aria-invalid":!!p.email,disabled:h}),p.email&&e.jsx("p",{className:"text-xs text-red-400",children:p.email})]})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(f,{type:"submit",disabled:h,children:[h&&e.jsx(w,{className:"h-4 w-4 mr-2 animate-spin"}),h?"Saving...":"Save & connect Gmail"]}),e.jsx(f,{type:"button",variant:"ghost",onClick:()=>{k(!1),j({})},disabled:h,children:"Cancel"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"After saving, a Google consent popup opens so this inbox can authorize itself. Sign in with the same Google account as the email above — we verify they match before connecting."})]}),e.jsxs("section",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-3",children:[v.length===0&&e.jsxs("div",{className:"col-span-full rounded-xl border border-dashed border-border p-8 text-center text-sm text-muted-foreground",children:["No mailboxes yet. Click ",e.jsx("strong",{children:"Add mailbox"})," to register your first inbox."]}),v.map(s=>{var C,F,R,B,W;const a=s.auth_method==="oauth",t=a&&s.connection_status!=="connected",r=a&&s.connection_status==="connected"&&(((C=s.last_error)==null?void 0:C.toLowerCase().includes("token"))||((F=s.last_error)==null?void 0:F.toLowerCase().includes("expired"))||((R=s.last_error)==null?void 0:R.toLowerCase().includes("refresh"))||((B=s.last_error)==null?void 0:B.toLowerCase().includes("unauthorized"))||((W=s.last_error)==null?void 0:W.toLowerCase().includes("401"))),n=s.last_sync_status==="error"&&!r;let d;return t?d={label:"Pending",color:"bg-amber-500/10 text-amber-400 border-amber-500/20",icon:e.jsx(U,{className:"h-3 w-3"}),help:"Awaiting Google authorization. Click Connect Gmail to finish setup."}:r?d={label:"Token Expired",color:"bg-red-500/10 text-red-400 border-red-500/20",icon:e.jsx(ne,{className:"h-3 w-3"}),help:"Google authorization expired. Click Reconnect to restore access."}:n?d={label:"Sync Error",color:"bg-red-500/10 text-red-400 border-red-500/20",icon:e.jsx(U,{className:"h-3 w-3"}),help:"Last sync failed. Click Sync now to retry or check the error below."}:d={label:"Connected",color:"bg-emerald-500/10 text-emerald-400 border-emerald-500/20",icon:e.jsx(le,{className:"h-3 w-3"}),help:"Authorized and ready. Click Sync now to refresh emails."},e.jsxs("div",{className:"rounded-xl border border-border bg-card p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"font-semibold truncate",children:s.label}),e.jsx("div",{className:"text-xs text-muted-foreground truncate",children:s.email_address})]}),e.jsxs("span",{className:`inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs font-medium whitespace-nowrap shrink-0 ${d.color}`,children:[d.icon,d.label]})]}),e.jsx("p",{className:"text-xs text-muted-foreground leading-relaxed",children:d.help}),e.jsxs("div",{className:"text-xs text-muted-foreground space-y-0.5",children:[e.jsxs("div",{children:["Auth method: ",a?"OAuth (Google)":"Workspace connector"]}),e.jsxs("div",{children:["Last sync: ",Z(s.last_synced_at)]}),e.jsxs("div",{children:["Total synced: ",s.total_messages_synced.toLocaleStr
6ing()]}),s.last_error&&e.jsx("div",{className:"text-red-400 truncate",title:s.last_error,children:s.last_error})]}),e.jsxs("div",{className:"flex gap-2 flex-wrap",children:[t?e.jsx(f,{size:"sm",onClick:()=>S(s.id),children:"Connect Gmail"}):e.jsxs(f,{size:"sm",variant:"outline",onClick:()=>A(s.id),disabled:N===s.id,children:[N===s.id?e.jsx(w,{className:"h-3 w-3 mr-2 animate-spin"}):e.jsx(H,{className:"h-3 w-3 mr-2"}),"Sync now"]}),a&&(s.connection_status==="connected"||r)&&e.jsx(f,{size:"sm",variant:"ghost",onClick:()=>S(s.id),children:"Reconnect"})]})]},s.id)})]}),e.jsxs("section",{className:"flex flex-wrap items-center gap-2 border-y border-border py-3",children:[e.jsxs("select",{value:l.mailboxId,onChange:s=>_({...l,mailboxId:s.target.value}),className:"bg-background border border-border rounded-md px-3 py-1.5 text-sm",children:[e.jsx("option",{value:"all",children:"All mailboxes"}),v.map(s=>e.jsx("option",{value:s.id,children:s.label},s.id))]}),e.jsxs("label",{className:"flex items-center gap-2 text-sm",children:[e.jsx("input",{type:"checkbox",checked:l.unreadOnly,onChange:s=>_({...l,unreadOnly:s.target.checked})}),"Unread only"]}),e.jsxs("label",{className:"flex items-center gap-2 text-sm",children:[e.jsx("input",{type:"checkbox",checked:l.actionItemsOnly,onChange:s=>_({...l,actionItemsOnly:s.target.checked})}),"Has action items"]}),e.jsx(I,{placeholder:"Search subject, sender, summary...",value:l.search,onChange:s=>_({...l,search:s.target.value}),className:"max-w-xs ml-auto"})]}),e.jsxs("section",{className:"grid grid-cols-1 lg:grid-cols-[1fr_1.2fr] gap-4",children:[e.jsxs("div",{className:"rounded-xl border border-border bg-card divide-y divide-border max-h-[70vh] overflow-y-auto",children:[O&&e.jsxs("div",{className:"p-8 text-center text-sm text-muted-foreground",children:[e.jsx(w,{className:"h-5 w-5 animate-spin inline mr-2"})," Loading..."]}),!O&&q.length===0&&e.jsx("div",{className:"p-8 text-center text-sm text-muted-foreground",children:"No emails match these filters."}),q.map(s=>{var t;const a=(t=s.sync_state)==null?void 0:t.unread;return e.jsxs("button",{onClick:()=>Q(s),className:`w-full text-left p-3 hover:bg-muted/30 transition ${(o==null?void 0:o.id)===s.id?"bg-muted/40":""}`,children:[e.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[a?e.jsx(ie,{className:"h-3.5 w-3.5 text-primary"}):e.jsx(ce,{className:"h-3.5 w-3.5 text-muted-foreground"}),e.jsx("span",{className:`text-sm truncate ${a?"font-semibold":""}`,children:s.from_address||"(unknown)"}),e.jsx("span",{className:"text-xs text-muted-foreground ml-auto whitespace-nowrap",children:Z(s.occurred_at)})]}),e.jsx("div",{className:`text-sm truncate ${a?"font-medium":"text-muted-foreground"}`,children:s.subject||"(no subject)"}),s.summary&&e.jsx("div",{className:"text-xs text-muted-foreground truncate mt-0.5",children:s.summary})]},s.id)})]}),e.jsx("div",{className:"rounded-xl border border-border bg-card p-5 max-h-[70vh] overflow-y-auto",children:o?e.jsxs("article",{className:"space-y-3",children:[e.jsx("h2",{className:"text-xl font-semibold",children:o.subject||"(no subject)"}),e.jsxs("div",{className:"text-xs text-muted-foreground",children:[e.jsxs("div",{children:[e.jsx("strong",{children:"From:"})," ",o.from_address]}),e.jsxs("div",{children:[e.jsx("strong",{children:"To:"})," ",(o.to_addresses||[]).join(", ")]}),e.jsxs("div",{children:[e.jsx("strong",{children:"When:"})," ",me(o.occurred_at)]}),o.thread_id&&e.jsxs("div",{children:[e.jsx("strong",{children:"Thread:"})," ",e.jsx("code",{className:"text-[10px]",children:o.thread_id})]})]}),Array.isArray(o.ai_action_items)&&o.ai_action_items.length>0&&e.jsxs("div",{className:"rounded-md border border-primary/40 bg-primary/5 p-3",children:[e.jsx("div",{className:"text-xs uppercase tracking-wider text-primary mb-2",children:"AI action items"}),e.jsx("ul",{className:"list-disc pl-5 text-sm space-y-1",children:o.ai_action_items.map((s,a)=>e.jsx("li",{children:typeof s=="string"?s:JSON.stringify(s)},a))})]}),e.jsx("div",{className:"prose prose-invert prose-sm max-w-none whitespace-pre-wrap break-words text-foreground
6/90",children:o.body||o.summary||"(empty body)"})]}):e.jsx("div",{className:"text-sm text-muted-foreground text-center py-20",children:"Select an email to read it."})})]})]})}):e.jsx(L,{title:"Inbox",children:e.jsxs("div",{className:"max-w-2xl mx-auto py-20 text-center",children:[e.jsx("h1",{className:"text-2xl font-bold mb-2",children:"Access denied"}),e.jsx("p",{className:"text-muted-foreground",children:"Admin only."})]})})};export{Ae 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.