PageSourceSearch

https://42flows.com/_nuxt/eSGcr0ES.js

js 42flows.com collected 2026-09-25 23:07:22 UTC 13,334 bytes, 1 lines download raw bytes

1import{_ as rt}from"./AraIXkfJ.js";import{e as nt,h as ot,Q as dt,G as it,i as lt,s as ct,c as r,a as e,b as gt,w as ut,u as a,d as g,t as d,g as k,F as w,r as $,p as m,I as yt,q as u,o as n,k as mt,K as xt,m as ht,n as bt,z}from"./CC8EkxHD.js";import{u as kt}from"./Cf89m91Z.js";import"./crG6u2v1.js";import"./BbVOUWSb.js";import"./Da5Cl52y.js";const pt={class:"max-w-5xl mx-auto"},vt={class:"mb-6"},ft={key:0,class:"mb-4 rounded border border-red-300 bg-red-50 p-3 text-sm text-red-900 dark:bg-red-950 dark:border-red-800 dark:text-red-100"},_t={key:1,class:"mb-6 rounded border border-gray-200 bg-white p-4 dark:bg-gray-900 dark:border-gray-800"},wt={class:"text-sm text-gray-500 mt-1 dark:text-gray-400"},It={class:"text-xs"},Ct={key:0,class:"mt-3 text-sm text-red-700 dark:text-red-300"},St={class:"mt-3 space-y-2"},Pt=["value"],$t={class:"font-mono text-gray-900 dark:text-gray-100"},At={class:"text-xs text-gray-500 dark:text-gray-400"},Tt={key:0,class:"text-xs rounded bg-amber-100 px-1.5 py-0.5 text-amber-900 dark:bg-amber-950 dark:text-amber-100"},Ut=["disabled"],Mt={key:2,class:"mb-6 rounded border border-amber-300 bg-amber-50 p-4 text-sm text-amber-900 dark:bg-amber-950 dark:border-amber-800 dark:text-amber-100"},Nt={key:3,class:"mb-6 rounded border border-gray-200 bg-white p-6 dark:bg-gray-900 dark:border-gray-800"},Ft={key:1,class:"mt-4 text-sm text-amber-900 bg-amber-50 border border-amber-300 rounded p-3 dark:bg-amber-950 dark:border-amber-800 dark:text-amber-100"},Rt={class:"mb-6 rounded border border-gray-200 bg-white p-4 dark:bg-gray-900 dark:border-gray-800"},Bt={class:"flex items-start justify-between gap-4"},Dt={class:"font-semibold text-gray-900 dark:text-gray-100"},Lt={class:"ml-2 text-sm font-normal text-gray-500 dark:text-gray-400"},Ot={class:"text-xs text-gray-500 mt-1 dark:text-gray-400"},qt={key:0,class:"text-xs text-red-700 mt-1 dark:text-red-300"},Vt={key:1,class:"text-xs text-red-700 mt-1 dark:text-red-300"},zt={class:"flex gap-2 shrink-0"},Et=["disabled"],Ht={class:"mb-6"},Wt={key:0,class:"mt-3 grid grid-cols-1 md:grid-cols-3 gap-4"},jt={class:"text-xs text-gray-500 dark:text-gray-400"},Gt={class:"mt-1 flex items-baseline gap-2"},Kt={class:"text-2xl font-bold text-gray-900 dark:text-gray-100 tabular-nums"},Qt=["viewBox"],Xt=["points"],Jt={key:1,class:"mt-3 text-xs text-gray-500 dark:text-gray-400"},Yt={key:1,class:"mt-3 rounded border border-gray-200 bg-white p-6 text-sm text-gray-500 dark:bg-gray-900 dark:border-gray-800 dark:text-gray-400"},Zt={class:"mb-6 rounded border border-gray-200 bg-white p-4 dark:bg-gray-900 dark:border-gray-800"},te={key:0,class:"mt-3 space-y-1.5"},ee={class:"w-40 shrink-0 truncate text-gray-900 dark:text-gray-100"},ae={class:"flex-1 bg-gray-100 rounded h-4 dark:bg-gray-800"},se={class:"w-16 shrink-0 text-right text-gray-900 dark:text-gray-100 tabular-nums"},re={key:1,class:"mt-3 text-sm text-gray-500 dark:text-gray-400"},ne={class:"mb-6 rounded border border-gray-200 bg-white p-4 dark:bg-gray-900 dark:border-gray-800"},oe={key:0,class:"mt-3 divide-y divide-gray-100 dark:divide-gray-800"},de=["href"],ie=["src"],le={key:1,class:"w-12 h-12 rounded bg-gray-100 dark:bg-gray-800 shrink-0"},ce={class:"min-w-0 flex-1"},ge={class:"text-sm text-gray-900 dark:text-gray-100 truncate"},ue={class:"text-xs text-gray-500 dark:text-gray-400"},ye={class:"text-xs text-gray-900 dark:text-gray-100 tabular-nums shrink-0 text-right"},me={key:1,class:"mt-3 text-sm text-gray-500 dark:text-gray-400"},E=300,A=56,_e=nt({__name:"instagram",async setup(xe){let I,R;const C=ot(),H=dt(),c=m(()=>C.params.siteId),T=m(()=>String(C.query.instagram||"")),S=m(()=>String(C.query.connectionId||"")),W=m(()=>String(C.query.message||"")),{data:i,pending:j,refresh:U}=([I,R]=it(()=>kt(()=>`/api/sites/${c.value}/instagram/status`,{lazy:!0},"$W2vbIiuPI-")),I=await I,R(),I),v=u([]),B=u(null),D=u(""),M=u(!1),p=u(null),x=u(""),P=u(!1);async function G(o){M.value=!0,p.value=null;try{const t=await $fetch(`/api/sites/${c.value}/instagram/accounts`,{query:{connectionId:o}});v.value=t.accounts,B.value=t.suggestedIgUserId,D.value=t.metaUserName||"",x.value=t.suggestedIgUserId||t.accounts[0]?.igUserId||""}catch(t){p.value=t?.data?.statusMessage||t?.message||"Failed to load Instagram accounts"}finally{M.value=!1}}async function K(){if(!(!x.value||!S.value)){P.value=!0;try{await $fetch(`/api/sites/${c.value}/instagram/select`,{method:"POST",body:{connectionId:S.value,igUserId:x.value}}),await H.replace({path:`/dashboard/sites/${c.value}/instagram`}),await U(),v.value=[]}catch(o){p.value=o?.data?.statusMessage||o?.message||"Failed to bind account"}finally{P.value=!1}}}function Q(){yt().trackOAuthStarted("meta",{surface:"instagram",site_id:c.value}),window.location.href=`/api/auth/meta/start?siteId=${c.value}`}const y=u(null),L=u(!1);async function O(){if(i.value?.connected){L.value=!0;try{y.value=await $fetch(`/api/sites/${c.value}/instagram/trends`)}catch{y.value=null}finally{L.value=!1}}}const f=u(!1);async function X(){f.value=!0;try{await $fetch(`/api/sites/${c.value}/instagram/sync-now`,{method:"POST",body:{}})}catch(o){alert(o?.data?.statusMessage||o?.message||"Sync failed to queue"),f.value=!1;return}setTimeout(async()=>{await U(),await O(),f.value=!1},8e3)}async function J(){confirm("Disconnect Instagram from this site? The history archive is preserved.")&&(await $fetch(`/api/sites/${c.value}/instagram/disconnect`,{method:"POST",body:{}}),await U(),y.value=null)}lt(async()=>{T.value==="consent_done"&&S.value&&await G(S.value)}),ct(i,async o=>{o?.connected&&await O()},{immediate:!0});
1function q(o){return o?(typeof o=="string"?new Date(o):o).toLocaleString():"—"}function h(o){return o==null?"—":o.toLocaleString()}function Y(o){if(!o||o.length<2)return"";const t=o.map(_=>_.value),b=Math.min(...t),l=Math.max(...t)-b||1,F=E/(o.length-1);return o.map((_,et)=>{const at=et*F,st=A-(_.value-b)/l*A;return`${at.toFixed(1)},${st.toFixed(1)}`}).join(" ")}const V=m(()=>{const o=y.value?.trends;return[{key:"follower_count",label:"Followers"},{key:"reach",label:"Reach"},{key:"profile_views",label:"Profile views"}].map(({key:b,label:s})=>{const l=o?.[b]??[],F=l.length?l[l.length-1].value:null,_=l.length>=2?l[l.length-1].value-l[0].value:null;return{key:b,label:s,series:l,latest:F,delta:_}})}),Z=m(()=>V.value.some(o=>o.series.length>0)),N=m(()=>(y.value?.demographics?.city??[]).slice(0,10)),tt=m(()=>Math.max(1,...N.value.map(o=>o.value)));return(o,t)=>{const b=rt;return n(),r("div",pt,[e("div",vt,[gt(b,{to:`/dashboard/sites/${a(c)}`,class:"text-sm text-gray-500 hover:text-gray-700 dark:hover:text-gray-200 dark:text-gray-400"},{default:ut(()=>[...t[1]||(t[1]=[g("← Site hub",-1)])]),_:1},8,["to"]),t[2]||(t[2]=e("h1",{class:"mt-2 text-2xl font-bold text-gray-900 dark:text-gray-100"},"Instagram Insights",-1)),t[3]||(t[3]=e("p",{class:"text-sm text-gray-500 mt-1 dark:text-gray-400"}," The customer's own Instagram account, via the Meta Graph API. We snapshot reach, follower growth, audience, and per-post performance daily — the permanent history Instagram itself discards. ",-1))]),a(T)==="error"?(n(),r("div",ft,[t[4]||(t[4]=e("strong",null,"Instagram connection failed.",-1)),g(" "+d(a(W)||"Unknown error."),1)])):k("",!0),a(v).length>0?(n(),r("div",_t,[t[7]||(t[7]=e("h2",{class:"font-semibold text-gray-900 dark:text-gray-100"},"Pick an Instagram account",-1)),e("p",wt,[t[5]||(t[5]=g(" Signed in to Meta as ",-1)),e("code",It,d(a(D)||"your account"),1),t[6]||(t[6]=g(". Choose the Instagram Business/Creator account for this site. ",-1))]),a(p)?(n(),r("div",Ct,d(a(p)),1)):k("",!0),e("div",St,[(n(!0),r(w,null,$(a(v),s=>(n(),r("label",{key:s.igUserId,class:"flex items-center gap-2 text-sm"},[mt(e("input",{"onUpdate:modelValue":t[0]||(t[0]=l=>ht(x)?x.value=l:null),type:"radio",value:s.igUserId},null,8,Pt),[[xt,a(x)]]),e("span",$t,"@"+d(s.igUsername||s.igUserId),1),e("span",At,d(h(s.followerCount))+" followers · "+d(s.fbPageName||"Page"),1),s.igUserId===a(B)?(n(),r("span",Tt,"best match")):k("",!0)]))),128))]),e("button",{class:"mt-4 rounded bg-gray-900 text-white text-sm px-3 py-1.5 hover:bg-gray-800 disabled:opacity-50 dark:bg-gray-100 dark:text-gray-900 dark:hover:bg-white",disabled:!a(x)||a(P),onClick:K},d(a(P)?"Binding…":"Use this account"),9,Ut)])):!a(M)&&a(T)==="consent_done"&&a(v).length===0&&!a(p)?(n(),r("div",Mt,[...t[8]||(t[8]=[e("strong",null,"No Instagram account found.",-1),g(" The Instagram account must be a Business or Creator account linked to a Facebook Page. Convert the account in the Instagram app, link it to a Page, then reconnect. ",-1)])])):!a(j)&&!a(i)?.connected?(n(),r("div",Nt,[t[9]||(t[9]=e("h2",{class:"font-semibold text-gray-900 dark:text-gray-100"},"Connect Instagram",-1)),t[10]||(t[10]=e("p",{class:"mt-2 text-sm text-gray-500 dark:text-gray-400"}," One click to share read-only Instagram Insights with 42flows. We build a permanent daily archive of reach, follower growth, audience-by-city, and per-post performance. ",-1)),a(i)?.enabled?(n(),r("button",{key:0,class:"mt-4 rounded bg-gray-900 text-white text-sm px-3 py-1.5 hover:bg-gray-800 dark:bg-gray-100 dark:text-gray-900 dark:hover:bg-white",onClick:Q}," Connect Instagram ")):(n(),r("p",Ft," Instagram Insights is not enabled yet. It turns on once Meta App Review approves the Instagram Graph API permissions. "))])):a(i)?.connected?(n(),r(w,{key:4},[e("div",Rt,[e("div",Bt,[e("div",null,[e("h2",Dt,[t[11]||(t[11]=g(" Connected ",-1)),e("span",Lt,"@"+d(a(i).igUsername||a(i).igUserId),1)]),e("p",Ot,d(h(a(i).followerCount))+" followers · Facebook Page: "+d(a(i).fbPageName||"—")+" · Backfill: "+d(a(i).backfillCompletedAt?q(a(i).backfillCompletedAt):"in progress…")+" · Last sync: "+d(q(a(i).lastSyncedAt)),1),a(i).lastSyncError?(n(),r("p",qt,"Last error: "+d(a(i).lastSyncError),1)):k("",!0),a(i).connectionRevokedAt?(n(),r("p",Vt," Meta connection was revoked — reconnect to resume syncing. ")):k("",!0)]),e("div",zt,[e("button",{class:"rounded border border-gray-300 text-gray-700 text-sm px-2.5 py-1 hover:bg-gray-50 disabled:opacity-50 dark:border-gray-700 dark:hover:bg-gray-800 dark:text-gray-200",disabled:a(f),onClick:X},d(a(f)?"Syncing…":"Sync now"),9,Et),e("button",{class:"rounded border border-red-300 text-red-700 text-sm px-2.5 py-1 hover:bg-red-50 dark:border-red-800 dark:text-red-300 dark:hover:bg-red-950",onClick:J},"Disconnect")])])]),e("div",Ht,[t[12]||(t[12]=e("h2",{class:"text-sm font-semibold text-gray-900 dark:text-gray-100 uppercase tracking-wide"},"Trends",-1)),a(Z)?(n(),r("div",Wt,[(n(!0),r(w,null,$(a(V),s=>(n(),r("div",{key:s.key,class:"rounded border border-gray-200 bg-white p-4 dark:bg-gray-900 dark:border-gray-800"},[e("div",jt,d(s.label),1),e("div",Gt,[e("div",Kt,d(h(s.latest)),1),s.delta!=null&&s.delta!==0?(n(),r("div",{key:0,class:bt(["text-xs font-medium tabular-nums",s.delta>0?"text-green-700 dark:text-green-300":"text-red-700 dark:text-red-300"])},d(s.delta>0?"+":"")+d(h(s.delta)),3)):k("",!0)]),s.series.length>=2?(n(),r("svg",{key:0,viewBox:`0 0 ${E} ${A}`,class:"mt-3 w-full",style:z({height:A+"px"}),preserveAspectRatio:"none"},[e("polyline",{points:Y(s.series),fill:"none",stroke:"currentColor","stroke-width":"2",class:"text-gray-800 dark:text-gray-200","vector-effect":"non-scaling-stroke"},null,8,Xt)],12,Qt)):(n(),r("div",Jt,"One data point so far — the line draws as history accumulates."))]))),128))])):(n(),r("div",Yt," History builds from here. The first sync populates the archive within a few minutes of connecting; the trend lines fill in day by day. "))]),e("div",Zt,[t[13]||(t[13]=e("h2",{class:"font-semibold text-gray-900 dark:text-gray-100"},[g(" Audience by city "),e("span",{class:"text-xs font-normal text-gray-500 dark:text-gray-400"},"— top 10, current snapshot")],-1)),a(y)?.demographicsAvailable&&a(N).length?(n(),r("div",te,[(n(!0),r(w,null,$(a(N),s=>(n(),r("div",{key:s.dimension,class:"flex items-center gap-2 text-sm"},[e("div",ee,d(s.dimension),1),e("div",ae,[e("div",{class:"bg-gray-800 h-4 rounded dark:bg-gray-300",style:z({width:`${Math.max(3,s.value/a(tt)*100)}%`})},null,4)]),e("div",se,d(h(s.value)),1)]))),128))])):(n(),r("p",re," Audience demographics unlock once the account passes 100 followers — that is an Instagram threshold, not a 42flows limit. They begin accumulating the day the account crosses it. "))]),e("div",ne,[t[15]||(t[15]=e("h2",{class:"font-semibold text-gray-900 dark:text-gray-100"},[g(" Top posts "),e("span",{class:"text-xs font-normal text-gray-500 dark:text-gray-400"},"— recent media by engagement")],-1)),a(y)?.topMedia&&a(y).topMedia.length?(n(),r("div",oe,[(n(!0),r(w,null,$(a(y).topMedia,s=>(n(),r("a",{key:s.mediaId,href:s.permalink||void 0,target:"_blank",rel:"noreferrer",class:"flex items-center gap-3 py-2 hover:bg-gray-50 dark:hover:bg-gray-800 -mx-2 px-2 rounded"},[s.thumbnailUrl?(n(),r("img",{key:0,src:s.thumbnailUrl,alt:"",class:"w-12 h-12 rounded object-cover shrink-0"},null,8,ie)):(n(),r("div",le)),e("div",ce,[e("div",ge,d(s.caption||"(no caption)"),1),e("div",ue,d(s.mediaType||"POST"),1)]),e("div",ye,[g(d(h(s.likeCount))+" like
1s",1),t[14]||(t[14]=e("br",null,null,-1)),g(d(h(s.commentsCount))+" comments ",1)])],8,de))),128))])):(n(),r("p",me,"No posts pulled yet. They populate on the first sync."))])],64)):k("",!0)])}}});export{_e 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.