1import{b3 as V,bX as H,bZ as Z,bM as W,bU as X,bq as D,bn as t,bP as E,bK as x,bh as e,a9 as J,C as S,k,j as C,bl as ee,i as F,t as K,a3 as A,m as se,n as te,Y as ae,q as I,aT as u,am as re}from"./index-c8i37G0q.js";import{S as oe,c as ie,d as ne,a as ce,b as le}from"./select-CKt0zyZn.js";import{P as de}from"./PageBreadcrumb-DTtorG_s.js";import{A as ue,h as me,c as pe,f as he,g as ge,d as xe,e as ye,b as fe,a as je}from"./alert-dialog-BgSlcY5r.js";import{L as we}from"./lock-DQ3XXYGK.js";import{E as z}from"./external-link-DgnF2ZPo.js";import{S as ve}from"./search-QMyz0oJD.js";import{M as be}from"./mail-BjNokB-S.js";import"./index-WhM0agtj.js";const Ne=V("Unplug",[["path",{d:"m19 5 3-3",key:"yk6iyv"}],["path",{d:"m2 22 3-3",key:"19mgm9"}],["path",{d:"M6.3 20.3a2.4 2.4 0 0 0 3.4 0L12 18l-6-6-2.3 2.3a2.4 2.4 0 0 0 0 3.4Z",key:"goz73y"}],["path",{d:"M7.5 13.5 10 11",key:"7xgeeb"}],["path",{d:"M10.5 16.5 13 14",key:"10btkg"}],["path",{d:"m12 6 6 6 2.3-2.3a2.4 2.4 0 0 0 0-3.4l-2.6-2.6a2.4 2.4 0 0 0-3.4 0Z",key:"1snsnr"}]]);function Se({done:a,active:n,number:i}){return e.jsx("div",{className:`h-7 w-7 rounded-full flex items-center justify-center shrink-0 text-xs font-bold transition-colors 2 ${a?"bg-emerald-500 text-white":n?"bg-primary text-primary-foreground":"bg-muted text-muted-foreground"}`,children:a?e.jsx(K,{className:"h-4 w-4"}):i})}function ke({email:a,onDisconnect:n,onSwitch:i,disconnecting:m,switching:c}){return e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[e.jsxs("div",{className:"flex items-center gap-2 px-3 py-1.5 rounded-lg bg-primary/5 border border-primary/15 text-sm","data-testid":"text-google-email",children:[e.jsx(be,{className:"h-3.5 w-3.5 text-primary shrink-0"}),e.jsxs("span",{className:"text-muted-foreground text-xs",children:["Signed in as ",e.jsx("strong",{className:"text-foreground",children:a})]})]}),e.jsxs(C,{variant:"ghost",size:"sm",className:"text-muted-foreground hover:text-foreground h-7 px-2 text-xs",disabled:c||m,onClick:i,"data-testid":"button-switch-google-account",children:[c?e.jsx(A,{className:"h-3 w-3 animate-spin mr-1"}):e.jsx(re,{className:"h-3 w-3 mr-1"}),"Switch account"]}),e.jsxs(ue,{children:[e.jsx(me,{asChild:!0,children:e.jsxs(C,{variant:"ghost",size:"sm",className:"text-muted-foreground hover:text-destructive h-7 px-2 text-xs",disabled:m||c,children:[m?e.jsx(A,{className:"h-3 w-3 animate-spin mr-1"}):e.jsx(Ne,{className:"h-3 w-3 mr-1"}),"Disconnect"]})}),e.jsxs(pe,{children:[e.jsxs(he,{children:[e.jsx(ge,{children:"Disconnect this account?"}),e.jsx(xe,{children:"This will remove access for this service. Your other Google connection (if any) will remain active. You can reconnect with any Google account at any time."})]}),e.jsxs(ye,{children:[e.jsx(fe,{children:"Cancel"}),e.jsx(je,{onClick:n,children:"Disconnect"})]})]})]})]})}function Le(){const{toast:a}=H(),{data:n}=Z(),{activeProjectId:i,projects:m}=W(),c=X(),[p,y]=D.useState(null),h=D.useRef(null);D.useEffect(()=>{const s=new URLSearchParams(c),r=s.get("gsc_connected"),o=s.get("gsc_error");if(!!(window.opener&&!window.opener.closed)){try{const N=r?{type:"ghostd_oauth",success:!0,service:r}:{type:"ghostd_oauth",success:!1,error:o||"unknown"};window.opener.postMessage(N,window.location.origin)}catch{}window.close();return}r==="gsc"?(t.invalidateQueries({queryKey:["/api/oauth/google/status"]}),t.invalidateQueries({queryKey:["/api/gsc/sites"]}),a({title:"Search Console connected",description:"Your Google Search Console account is linked. Select your property below."}),window.history.replaceState({},"","/app/settings/connectors")):r==="ga4"?(t.invalidateQueries({queryKey:["/api/oauth/google/status"]}),t.invalidateQueries({queryKey:["/api/ga4/properties"]}),a({title:"Analytics connected",description:"Your Google Analytics account is linked. Select your GA4 property below."}),window.history.replaceState({},"","/app/settings/connectors")):r==="true"?(t.invalidateQueries({queryKey:["/api/oauth/google/status"]}),a({title:"Google account connected"}),window.history.replaceState({},"","/app/settings/connectors")):o&&(a({title:"Failed to connect",description:{missing_params:"The authorization response was incomplete. Please try again.",invalid_state:"The authorization session expired or was invali
2d. Please try again.",state_expired:"The authorization session timed out. Please try again.",not_configured:"Google OAuth is not configured on the server.",token_exchange_failed:"Could not complete the authorization with Google. Please try again."}[o]||o,variant:"destructive"}),window.history.replaceState({},"","/app/settings/connectors"))},[c]);const{data:f}=E({queryKey:["/api/oauth/google/status"]}),P=(!n?.plan||n.plan==="free")&&!n?.isAdmin,l=!!f?.gsc?.connected,U=!!f?.ga4?.connected,M=f?.gsc?.email||null;f?.ga4?.email;const{data:j,isLoading:R}=E({queryKey:["/api/gsc/sites"],enabled:l&&!P,staleTime:0}),{data:Ce}=E({queryKey:["/api/ga4/properties"],enabled:U&&!P}),d=m.find(s=>s.id===i),G=!!d?.gscSiteUrl;d?.ga4PropertyId;const T=async s=>{if(p){h.current?.focus();return}const o=await(await u("GET",`/api/oauth/google?service=${s}`)).json(),b=window.open(o.url,"google_oauth","width=540,height=660,scrollbars=yes,resizable=yes,toolbar=no,menubar=no");if(!b){window.location.href=o.url;return}h.current=b,y(s);const L={missing_params:"The authorization response was incomplete. Please try again.",invalid_state:"The authorization session expired or was invali
2d. Please try again.",state_expired:"The authorization session timed out. Please try again.",not_configured:"Google OAuth is not configured on the server.",token_exchange_failed:"Could not complete the authorization with Google. Please try again."};let N=!1;const q=g=>{if(g.origin===window.location.origin&&g.data?.type==="ghostd_oauth")if(N=!0,window.removeEventListener("message",q),h.current=null,y(null),t.invalidateQueries({queryKey:["/api/oauth/google/status"]}),t.invalidateQueries({queryKey:["/api/gsc/sites"]}),t.invalidateQueries({queryKey:["/api/ga4/properties"]}),g.data.success){const _=g.data.service;a({title:_==="gsc"?"Search Console connected":"Analytics connected",description:_==="gsc"?"Your Google Search Console account is linked. Select your property below.":"Your Google Analytics account is linked. Select your GA4 property below."})}else a({title:"Failed to connect",description:L[g.data.error]||"Something went wrong. Please try again.",variant:"destructive"})};window.addEventListener("message",q);const O=setInterval(()=>{b.closed&&(clearInterval(O),window.removeEventListener("message",q),h.current=null,y(null),N||t.invalidateQueries({queryKey:["/api/oauth/google/status"]}))},500)},$=x({mutationFn:T,onError:s=>{y(null),h.current=null,a({title:"Failed to start connection",description:s.message,variant:"destructive"})}}),Y=async s=>{await u("DELETE",`/api/oauth/google?service=${s}`),t.invalidateQueries({queryKey:["/api/oauth/google/status"]}),t.invalidateQueries({queryKey:["/api/gsc/sites"]}),await T(s)},Q=x({mutationFn:async()=>{await u("DELETE","/api/oauth/google?service=gsc")},onSuccess:()=>{t.invalidateQueries({queryKey:["/api/oauth/google/status"]}),t.invalidateQueries({queryKey:["/api/gsc/sites"]}),a({title:"Search Console account disconnected"})}});x({mutationFn:async()=>{await u("DELETE","/api/oauth/google?service=ga4")},onSuccess:()=>{t.invalidateQueries({queryKey:["/api/oauth/google/status"]}),t.invalidateQueries({queryKey:["/api/ga4/properties"]}),a({title:"Analytics account disconnected"})}});const B=x({mutationFn:async s=>{const r=await u("POST",`/api/projects/${i}/gsc-site`,{gscSiteUrl:s});if(!r.ok){const o=await r.json().catch(()=>({}));throw new Error(o.message||"Failed to link property")}return r.json()},onSuccess:()=>{t.invalidateQueries({queryKey:["/api/projects"]}),a({title:"Search Console property linked"})},onError:s=>{a({title:"Could not link property",description:s.message,variant:"destructive"})}});x({mutationFn:async s=>{const r=await u("POST",`/api/projects/${i}/ga4-property`,{ga4PropertyId:s});if(!r.ok){const o=await r.json().catch(()=>({}));throw new Error(o.message||"Failed to link property")}return r.json()},onSuccess:()=>{t.invalidateQueries({queryKey:["/api/projects"]}),t.invalidateQueries({queryKey:["/api/projects",i,"ga4-data"]}),a({title:"Analytics property linked"})},onError:s=>{a({title:"Could not link property",description:s.message,variant:"destructive"})}});const w=[l,G].filter(Boolean).length,v=2;return e.jsx("div",{className:"h-full overflow-y-auto",children:e.jsxs("div",{className:"container mx-auto px-6 py-6 max-w-4xl",children:[e.jsxs("div",{className:"mb-8",children:[e.jsx("div",{className:"mb-3",children:e.jsx(de,{items:[{label:"Settings",href:"/app/settings/account"},{label:"Connectors"}]})}),e.jsxs("h1",{className:"text-3xl font-bold font-display flex items-center gap-3","data-testid":"text-connectors-title",children:[e.jsx(J,{className:"h-8 w-8 text-primary"}),"Data Connectors"]}),e.jsx("p",{className:"text-muted-foreground mt-2",children:"Connect your Google Search Console account to pull in search performance data alongside your AI visibility metrics."})]}),P?e.jsx(S,{className:"border-dashed border-2",children:e.jsxs(k,{className:"flex flex-col items-center justify-center py-12 gap-4",children:[e.jsx("div",{className:"h-14 w-14 rounded-2xl bg-muted flex items-center justify-center",children:e.jsx(we,{className:"h-7 w-7 text-muted-foreground"})}),e.jsxs("div",{className:"text-center",children:[e.jsx("p",{className:"font-semibold",children:"Pro Feature"}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1 max-w-sm",children:"Connect Google Analytics and Search Console on Pro and Agency plans to see AI referral traffic, site metrics, and search performance."})]}),e.jsxs(C,{variant:"outline",disabled:!0,children:[e.jsx(z,{className:"h-4 w-4 mr-2"}),"Connect Google Account"]})]})}):e.jsxs("div",{className:"space-y-5",children:[e.jsx(S,{className:`border ${w===v?"border-emerald-200 dark:border-emerald-800/50 bg-emerald-50/30 dark:bg-emerald-950/10":"border-primary/20 bg-primary/5"}`,children:e.jsxs(k,{className:"pt-5 pb-5",children:[e.jsxs("div",{className:"flex items-center justify-between mb-3",children:[e.jsx("p",{className:"text-sm font-semibold",children:"Setup Progress"}),e.jsxs("span",{className:"text-xs text-muted-foreground",children:[w," of ",v," steps done"]})]}),e.jsx("div",{className:"w-full bg-muted rounded-full h-1.5 mb-4",children:e.jsx(ee.div,{className:`h-1.5 rounded-full ${w===v?"bg-emerald-500":"bg-primary"}`,initial:{width:0},animate:{width:`${w/v*100}%`},transition:{duration:.7,ease:"easeOut"}})}),e.jsx("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-3",children:[{label:"Connect Search Console account",done:l},{label:"Link a Search Console property",done:G}].map((s,r)=>e.jsxs("div",{className:`flex items-center gap-2 ${s.done?"":"op
2acity-50"}`,children:[e.jsx(Se,{done:s.done,active:!0,number:r+1}),e.jsx("span",{className:`text-sm ${s.done?"line-through text-muted-foreground":""}`,children:s.label})]},r))})]})}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-2 mb-3",children:[e.jsx("div",{className:"h-7 w-7 rounded-lg bg-[#4285F4]/10 flex items-center justify-center",children:e.jsx(ve,{className:"h-4 w-4 text-[#4285F4]"})}),e.jsx("h2",{className:"text-base font-semibold font-display",children:"Google Search Console"}),l&&G&&e.jsxs(F,{className:"ml-auto bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400 border-0 text-xs",children:[e.jsx(K,{className:"h-3 w-3 mr-1"})," Ready"]})]}),e.jsx(S,{"data-testid":"card-gsc",children:e.jsxs(k,{className:"pt-5 space-y-4",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm font-medium mb-2",children:"Google account"}),l?e.jsx(ke,{email:M,onDisconnect:()=>Q.mutate(),disconnecting:Q.isPending,onSwitch:()=>Y("gsc"),switching:p==="gsc"}):e.jsxs("div",{className:"space-y-2",children:[e.jsxs(C,{onClick:()=>$.mutate("gsc"),disabled:!!p,size:"sm","data-testid":"button-connect-gsc",children:[p==="gsc"?e.jsx(A,{className:"h-4 w-4 animate-spin mr-2"}):e.jsx(z,{className:"h-4 w-4 mr-2"}),p==="gsc"?"Waiting for Google...":"Connect Google Account for Search Console"]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Read-only access to your Search Console properties."})]})]}),l&&e.jsxs("div",{className:"border-t border-border/50 pt-4",children:[e.jsxs("p",{className:"text-sm font-medium mb-2",children:["Property for ",e.jsx("span",{className:"text-primary",children:d?.name||"this project"})]}),R?e.jsxs("p",{className:"text-sm text-muted-foreground flex items-center gap-2",children:[e.jsx(A,{className:"h-3.5 w-3.5 animate-spin"})," Loading propertiesâ¦"]}):j?.sites?.length>0?e.jsxs("div",{className:"space-y-1.5",children:[e.jsxs(oe,{value:d?.gscSiteUrl||"",onValueChange:s=>B.mutate(s),children:[e.jsx(ie,{className:"w-full max-w-md","data-testid":"select-gsc-site",children:e.jsx(ne,{placeholder:"Select a Search Console property..."})}),e.jsx(ce,{children:j.sites.map(s=>e.jsx(le,{value:s.siteUrl,children:s.siteUrl},s.siteUrl))})]}),d?.gscSiteUrl&&e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Linked: ",e.jsx("span",{className:"font-medium text-foreground",children:d.gscSiteUrl})," ",e.jsxs(F,{className:"bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400 border-0 text-xs",children:[e.jsx(K,{className:"h-2.5 w-2.5 mr-0.5"})," active"]})]})]}):e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-sm text-muted-foreground",children:"No Search Console properties found on this account. Make sure your Google account has access to at least one verified property in Search Console."}),j?.error&&e.jsx("p",{className:"text-xs text-amber-600 dark:text-amber-400",children:j.error}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["If you just connected, try ",e.jsx("button",{className:"underline underline-offset-2 hover:text-foreground transition-colors",onClick:()=>t.invalidateQueries({queryKey:["/api/gsc/sites"]}),children:"refreshing"}),"."]})]})]}),e.jsx("p",{className:"text-xs text-muted-foreground border-t border-border/40 pt-3",children:"Pulls clicks, impressions, and top keyword rankings for the last 90 days. Shows in Brand Visibility alongside your AI visibility score."})]})})]}),!1]}),e.jsxs(S,{className:"mt-8",children:[e.jsx(se,{children:e.jsxs(te,{className:"flex items-center gap-2",children:[e.jsx(ae,{className:"h-4 w-4 text-primary"}),"How Connectors Work"]})}),e.jsx(k,{children:e.jsxs("div",{className:"space-y-4 text-sm text-muted-foreground",children:[e.jsx("p",{children:"Ghostd uses two types of data connections: your Google accounts for live traffic and search data, and hardcoded backend integrations for AI analysis."}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex gap-3",children:[e.jsx(I,{className:"h-4 w-4 text-primary shrink-0 mt-0.5"}),e.jsxs("div",{children:[e.jsx("p",{className:"font-medium text-foreground",children:"Google Search Console"}),e.jsx("p",{children:"Pulls clicks, impressions, and top-performing keywords for the last 90 days. Shows in Brand Visibility alongside your AI visibility scores."})]})]}),e.jsxs("div",{className:"flex gap-3",children:[e.jsx(I,{className:"h-4 w-4 text-primary shrink-0 mt-0.5"}),e.jsxs("div",{children:[e.jsx("p",{className:"font-medium text-foreground",children:"Authority and backlink data"}),e.jsx("p",{children:"Domain authority and backlink signals are fetched automatically during scans â no setup needed."})]})]})]}),e.jsx("p",{className:"text-xs border-t border-border/60 pt-3",children:"Connectors never block a scan. If any data source is unavailable, the scan continues with the remaining signals."})]})})]})]})})}export{Le 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.