PageSourceSearch

https://comms-weave-link.lovable.app/assets/social-comments-B3loDsO4.js

js comms-weave-link.lovable.app collected 2026-10-03 03:27:57 UTC 18,241 bytes, 1 lines download raw bytes

1import{c as ee,m as Y,j as e,u as ne,E as ie,G as ce,H as le,a as de,r as i,s as b,l as me,w as ue,t as u}from"./index-Cjiu4FUh.js";import{h as Je}from"./index-Cjiu4FUh.js";import{u as q}from"./useQuery-Dhz9AfLP.js";import{u as D}from"./useServerFn-BULoe4Hg.js";import{M,R as te,E as xe,T as pe,c as fe,n as he}from"./emoji-picker-react.esm-BW-XZCim.js";import{b as ge}from"./facebook.functions-DuT02Vzt.js";import{c as p}from"./utils-0exNfmSl.js";import{M as be}from"./message-circle-DsMctvAU.js";import{M as ye}from"./message-square-text-CxAON9xa.js";import{R as ve}from"./refresh-cw-Dmc3wwYp.js";import{L as F}from"./loader-circle-CdMlWBWt.js";import{C as je}from"./chevron-left-B8PN4Ti6.js";import{T as se}from"./trash-2-5_Q0B7vm.js";import{P as Ne}from"./paperclip-C6jBwoKn.js";import{E as ke}from"./external-link-CPgUrqmx.js";import{C as we}from"./circle-alert-B-35ydJL.js";import"./link-2-BkMh-O-q.js";import"./clsx-B-dksMZM.js";const _e=[["circle",{cx:"8",cy:"18",r:"4",key:"1fc0mg"}],["path",{d:"M12 18V2l7 4",key:"g04rme"}]],Ie=ee("music-2",_e);const Ce=[["path",{d:"M15 18h-5",key:"95g1m2"}],["path",{d:"M18 14h-8",key:"sponae"}],["path",{d:"M4 22h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H8a2 2 0 0 0-2 2v16a2 2 0 0 1-4 0v-9a2 2 0 0 1 2-2h2",key:"39pd36"}],["rect",{width:"8",height:"4",x:"10",y:"6",rx:"1",key:"aywv1n"}]],X=ee("newspaper",Ce),Z={whatsapp:{label:"WhatsApp",className:"bg-emerald-500/15 text-emerald-500",Icon:be},facebook:{label:"FB DM",className:"bg-blue-500/15 text-blue-500",Icon:Y},facebook_feed:{label:"FB Comment",className:"bg-indigo-500/15 text-indigo-400",Icon:Y},facebook_ad:{label:"FB Ad",className:"bg-amber-500/15 text-amber-500",Icon:M},tiktok:{label:"TikTok",className:"bg-pink-500/15 text-pink-500",Icon:Ie}};function P({source:o,className:h,showLabel:y=!0}){const x=Z[o]??Z.facebook_feed,{Icon:v}=x;return e.jsxs("span",{className:p("inline-flex items-center gap-1 rounded-full px-1.5 py-0.5 text-[10px] font-semibold leading-none",x.className,h),title:`Source: ${x.label}`,children:[e.jsx(v,{className:"size-3 shrink-0"}),y&&x.label]})}function Oe(){return e.jsx(Fe,{})}function Fe(){const o=ne(),h=D(ie),y=D(ce),x=D(ge),v=D(le),{can:j}=de(),T=j("can_reply_social_comments"),c=j("can_delete_social_comments"),d=async(t,a)=>{if(c&&confirm(`Delete ${a}? This permanently removes the chat and its messages.`))try{await v({data:{conversationIds:t}}),u.success("Deleted"),N(l=>l),o.invalidateQueries({queryKey:["social-threads"]}),o.invalidateQueries({queryKey:["social-thread-msgs"]}),o.invalidateQueries({queryKey:["social-unreplied-count"]})}catch(l){u.error(l?.message??"Failed to delete")}},r=q({queryKey:["social-threads"],queryFn:()=>h({data:{}}),refetchInterval:3e4,staleTime:1e4}),[m,N]=i.useState(null),f=r.data??[],s=i.useMemo(()=>f.find(t=>t.postId===m)??null,[f,m]);i.useEffect(()=>{!m&&f.length&&N(f[0].postId)},[f,m]),i.useEffect(()=>{const t=b.channel(`social-comments-${crypto.randomUUID()}`).on("postgres_changes",{event:"*",schema:"public",table:"messages"},a=>{const l=a.new;o.invalidateQueries({queryKey:["social-threads"]}),o.invalidateQueries({queryKey:["social-unreplied-count"]}),l?.conversation_id&&o.invalidateQueries({queryKey:["social-thread-msgs"]})}).on("postgres_changes",{event:"*",schema:"public",table:"conversations"},()=>{o.invalidateQueries({queryKey:["social-threads"]})}).subscribe();return()=>{b.removeChannel(t)}},[o]);const E=s?.commenters.map(t=>t.conversationId)??[],g=q({queryKey:["social-thread-msgs",s?.postId,E.join(",")],enabled:!!s&&E.length>0,queryFn:async()=>{const{data:t,error:a}=await b.from("messages").select("id, conversation_id, direction, content, media_url, media_type, created_at, external_id, parent_external_id, sender_id, is_internal_note").in("conversation_id",E).order("created_at",{ascending:!0});if(a)throw a;return t??[]}}),n=q({queryKey:["social-post-ctx",s?.pageDbId,s?.postId],enabled:!!s&&!!s.pageDbId,staleTime:5*6e4,queryFn:()=>y({data:{pageDbId:s.pageDbId,postId:s.postId}})}),k=i.useMemo(()=>{if(!s)return null;const t=(g.data??[]).find(a=>a.direction==="in"&&!a.is_internal_note);return{pageName:s.pageName??"Facebook page",postId:s.postId,commentText:t?.content??s.commenters[0]?.lastMessage??null,commentTime:t?.created_at??s.lastCommentAt}},[g.data,s]),ae=n.data&&!n.data.ok?n.data.error:n.error instanceof Error?n.error.message:n.error?String(n.error):null,[w,_]=i.useState(""),[S,I]=i.useState(null),[K,Q]=i.useState(!1),[re,R]=i.useState(!1),[U,L]=i.useState(!1),A=i.useRef(null),$=i.useRef(null),z=i.useRef(null);i.useEffect(()=>{_(""),I(null),R(!1)},[m]),i.useEffect(()=>{z.current&&(z.current.scrollTop=z.current.scrollHeight)},[g.data]);const B=()=>
1{if(S)return S;const a=[...g.data??[]].reverse().find(l=>l.direction==="in"&&l.external_id);return a?{conversationId:a.conversation_id,commentId:a.external_id,label:"latest comment"}:null},G=async()=>{if(!w.trim()||!s)return;const t=B();if(!t){u.error("No inbound comment to reply to yet.");return}Q(!0);try{await x({data:{conversationId:t.conversationId,text:w.trim(),parentCommentId:t.commentId}}),_(""),I(null),u.success("Reply posted to Facebook"),await Promise.all([o.refetchQueries({queryKey:["social-thread-msgs"]}),o.refetchQueries({queryKey:["social-threads"]}),o.refetchQueries({queryKey:["social-unreplied-count"]})])}catch(a){u.error(a?.message??"Failed to post reply")}finally{Q(!1)}},oe=async t=>{if(!s)return;if(!t.type.startsWith("image/")){u.error("Facebook comment replies only accept photos — not videos or files. Supported photos: JPG, PNG, GIF, WEBP or AVIF (max 8 MB).");return}const a=fe(t,"facebook");if(!a.ok){u.error(a.message);return}const l=B();if(!l){u.error("No inbound comment to reply to yet.");return}L(!0);try{const C=await he(t),{data:W}=await b.auth.getUser();if(!W?.user)throw new Error("Please sign in again.");const O=`${W.user.id}/social-comments/${l.conversationId}/${Date.now()}-${C.name.replace(/[^\w.\-]+/g,"_")}`,{error:H}=await b.storage.from("chat-uploads").upload(O,C,{upsert:!1,contentType:C.type});if(H)throw H;const{data:V,error:J}=await b.storage.from("chat-uploads").createSignedUrl(O,3600*24*365);if(J||!V?.signedUrl)throw J??new Error("Signed URL failed");await x({data:{conversationId:l.conversationId,text:w.trim(),parentCommentId:l.commentId,attachmentUrl:V.signedUrl}}),_(""),I(null),u.success("Image reply posted to Facebook"),await Promise.all([o.refetchQueries({queryKey:["social-thread-msgs"]}),o.refetchQueries({queryKey:["social-threads"]}),o.refetchQueries({queryKey:["social-unreplied-count"]})])}catch(C){u.error(C?.message??"Upload failed")}finally{L(!1)}};return e.jsxs("div",{className:"flex h-full w-full overflow-hidden bg-background",children:[e.jsxs("aside",{className:p("w-full md:w-72 lg:w-80 shrink-0 border-r border-border flex-col",s?"hidden md:flex":"flex"),children:[e.jsxs("div",{className:"px-4 py-3 border-b border-border flex items-center gap-2",children:[e.jsx(ye,{className:"size-4 text-primary"}),e.jsxs("div",{className:"flex-1",children:[e.jsx("div",{className:"text-sm font-semibold",children:"Social Comments"}),e.jsx("div",{className:"text-[11px] text-muted-foreground",children:"Facebook posts & ads"})]}),e.jsx("button",{onClick:()=>r.refetch(),className:"p-1.5 rounded hover:bg-accent",title:"Refresh",children:e.jsx(ve,{className:p("size-3.5",r.isFetching&&"animate-spin")})})]}),e.jsx("div",{className:"flex-1 overflow-auto",children:r.isLoading?e.jsx("div",{className:"p-6 text-center text-muted-foreground text-sm",children:e.jsx(F,{className:"size-4 animate-spin mx-auto"})}):f.length===0?e.jsx("div",{className:"p-6 text-center text-muted-foreground text-sm",children:"No Facebook comments yet."}):f.map(t=>{const a=t.postId===m,l=t.itemType==="ad"?M:X;return e.jsxs("button",{onClick:()=>N(t.postId),className:p("w-full text-left px-4 py-3 border-b border-border/50 hover:bg-accent/40 transition",a&&"bg-accent/60"),children:[e.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[e.jsx(P,{source:t.itemType==="ad"?"facebook_ad":"facebook_feed",showLabel:!1}),e.jsx(l,{className:"size-3.5 text-muted-foreground shrink-0"}),e.jsx("span",{className:"text-[10px] uppercase tracking-wide text-muted-foreground",children:t.itemType==="ad"?"Ad":t.itemType==="comment"?"Reply thread":"Post"}),t.unrepliedCount>0&&e.jsx("span",{className:"ml-auto min-w-[1.25rem] h-5 px-1.5 rounded-full bg-primary text-primary-foreground text-[10px] font-semibold flex items-center justify-center",children:t.unrepliedCount})]}),e.jsx("div",{className:"text-sm font-medium truncate",children:t.pageName??"Facebook page"}),e.jsxs("div",{className:"text-xs text-muted-foreground truncate",children:[t.commenters.length," commenter",t.commenters.length===1?"":"s"," · ",new Date(t.lastCommentAt).toLocaleStr
1ing()]})]},t.postId)})})]}),e.jsx("section",{className:p("flex-1 min-w-0 flex-col",s?"flex":"hidden md:flex"),children:s?e.jsxs(e.Fragment,{children:[e.jsxs("header",{className:"px-4 py-3 border-b border-border flex items-start gap-2",children:[e.jsx("button",{onClick:()=>N(null),className:"md:hidden p-1.5 -ml-1 rounded hover:bg-accent shrink-0 mt-0.5","aria-label":"Back to posts",children:e.jsx(je,{className:"size-4"})}),e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsxs("div",{className:"text-sm font-semibold flex items-center gap-2",children:[e.jsx(P,{source:s.itemType==="ad"?"facebook_ad":"facebook_feed"}),e.jsxs("span",{className:"truncate",children:[s.commenters.map(t=>t.contactName??"Facebook user").slice(0,3).join(", "),s.commenters.length>3?` +${s.commenters.length-3} more`:""]})]}),e.jsxs("div",{className:"text-xs text-muted-foreground truncate flex items-center gap-1.5",children:[s.itemType==="ad"?e.jsx(M,{className:"size-3.5 shrink-0"}):e.jsx(X,{className:"size-3.5 shrink-0"}),e.jsx("span",{className:"truncate",children:s.pageName??"Facebook page"}),e.jsxs("span",{children:["· ",s.totalComments," thread",s.totalComments===1?"":"s"," · ",s.unrepliedCount," unreplied"]})]}),e.jsx(te,{referral:s.referral,className:"mt-1"})]}),c&&e.jsxs("button",{onClick:()=>d(s.commenters.map(t=>t.conversationId),`all ${s.commenters.length} chat${s.commenters.length===1?"":"s"} on this post`),className:"inline-flex items-center gap-1 text-xs px-2 py-1 rounded border border-destructive/40 text-destructive hover:bg-destructive/10 shrink-0",title:"Delete all chats on this post (admin)",children:[e.jsx(se,{className:"size-3.5"})," ",e.jsx("span",{className:"hidden sm:inline",children:"Delete all"})]})]}),e.jsx("div",{ref:z,className:"flex-1 overflow-auto p-4 space-y-3 bg-muted/20",children:g.isLoading?e.jsx("div",{className:"text-center text-muted-foreground text-sm",children:e.jsx(F,{className:"size-4 animate-spin mx-auto"})}
1):e.jsx(Te,{messages:g.data??[],commenters:s.commenters,isAdmin:c,onDelete:(t,a)=>d([t],`chat with ${a}`),onReply:t=>I({conversationId:t.conversation_id,commentId:t.external_id,label:s.commenters.find(a=>a.conversationId===t.conversation_id)?.contactName??"comment"})})}),T?e.jsxs("div",{className:"border-t border-border p-3 bg-background relative",children:[S&&e.jsxs("div",{className:"mb-2 flex items-center gap-2 text-xs text-muted-foreground bg-accent/40 rounded px-2 py-1",children:["Replying to ",e.jsx("span",{className:"font-medium text-foreground",children:S.label}),e.jsx("button",{className:"ml-auto underline",onClick:()=>I(null),children:"cancel"})]}),re&&e.jsx("div",{className:"absolute bottom-full left-3 mb-2 z-20",children:e.jsx(xe,{theme:pe.AUTO,onEmojiClick:t=>{_(a=>a+t.emoji),R(!1),$.current?.focus()}})}),e.jsx("input",{ref:A,type:"file",accept:"image/*",className:"hidden",onChange:t=>{const a=t.target.files?.[0];a&&oe(a),t.currentTarget.value=""}}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx("textarea",{ref:$,value:w,onChange:t=>_(t.target.value),onKeyDown:t=>{t.key==="Enter"&&(t.metaKey||t.ctrlKey)&&(t.preventDefault(),G())},rows:2,placeholder:"Reply publicly to this Facebook comment…",className:"flex-1 resize-none rounded-md border border-border bg-background px-3 py-2 text-sm outline-none focus:ring-2 focus:ring-primary/40"}),e.jsxs("button",{onClick:G,disabled:K||!w.trim(),className:"self-end inline-flex items-center gap-2 px-4 py-2 rounded-md bg-primary text-primary-foreground text-sm font-medium disabled:opacity-50 hover:opacity-90",children:[K?e.jsx(F,{className:"size-4 animate-spin"}):e.jsx(me,{className:"size-4"}),"Reply"]})]}),e.jsxs("div",{className:"mt-2 flex items-center gap-1.5",children:[e.jsx("button",{type:"button",onClick:()=>R(t=>!t),title:"Emoji",className:"p-2 rounded-md bg-muted hover:bg-muted/70 text-muted-foreground hover:text-foreground",children:e.jsx(ue,{className:"size-4"})}),e.jsx("button",{type:"button",onClick:()=>A.current?.click(),disabled:U,title:"Attach image",className:"p-2 rounded-md bg-muted hover:bg-muted/70 text-muted-foreground hover:text-foreground disabled:opacity-50",children:U?e.jsx(F,{className:"size-4 animate-spin"}):e.jsx(Ne,{className:"size-4"})}),e.jsx("div",{className:"ml-auto text-[11px] text-muted-foreground",children:"Cmd/Ctrl+Enter to send · images post via Graph API"})]})]}):e.jsx("div",{className:"border-t border-border p-3 text-center text-xs text-muted-foreground",children:"You can view comments, but you do not have permission to reply."})]}):e.jsx("div",{className:"flex-1 flex items-center justify-center text-muted-foreground text-sm",children:"Select a post to see its comment thread."})}),e.jsxs("aside",{className:"hidden lg:flex w-80 xl:w-96 shrink-0 border-l border-border flex-col",children:[e.jsx("div",{className:"px-4 py-3 border-b border-border text-sm font-semibold",children:"Post context"}),e.jsx("div",{className:"flex-1 overflow-auto p-4",children:s?n.isLoading?e.jsx("div",{className:"text-muted-foreground text-sm",children:e.jsx(F,{className:"size-4 animate-spin"})}):n.data?.ok?e.jsxs("div",{className:"space-y-3",children:[n.data.post.imageUrl&&e.jsx("img",{src:n.data.post.imageUrl,alt:"Post preview",className:"w-full rounded-md border border-border"}),e.jsxs("div",{className:"text-xs text-muted-foreground",children:[n.data.post.fromName??n.data.page.name,n.data.post.createdTime&&` · ${new Date(n.data.post.createdTime).toLocaleString()}`]}),e.jsx("div",{className:"text-sm whitespace-pre-wrap",children:n.data.post.message??e.jsx("span",{className:"text-muted-foreground italic",children:"(no post text)"})}),n.data.post.permalinkUrl&&e.jsxs("a",{href:n.data.post.permalinkUrl,target:"_blank",rel:"noreferrer",className:"inline-flex items-center gap-1 text-xs text-primary hover:underline",children:[e.jsx(ke,{className:"size-3"})," Open on Facebook"]})]}):e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex gap-2 text-sm text-muted-foreground",children:[e.jsx(we,{className:"size-4 shrink-0 text-destructive"}),e.jsxs("div",{children:["Could not load post preview.",e.jsx("div",{className:"text-xs mt-1",children:ae??"Meta did not return preview details for this post."})]})]}),e.jsxs("div",{className:"rounded-md border border-border bg-muted/30 p-3 space-y-2",children:[e.jsx("div",{className:"text-xs text-muted-foreground",children:"Local comment context"}),e.jsx("div",{className:"text-sm font-medium",children:k?.pageName??"Facebook page"}),k?.commentTime&&e.jsx("div",{className:"text-xs text-muted-foreground",children:new Date(k.commentTime).toLocaleStr
1ing()}),e.jsx("div",{className:"text-sm whitespace-pre-wrap",children:k?.commentText??e.jsx("span",{className:"text-muted-foreground italic",children:"No comment text saved."})}),e.jsxs("div",{className:"text-[11px] text-muted-foreground break-all",children:["Post ID: ",k?.postId??s.postId]})]})]}):e.jsx("div",{className:"text-muted-foreground text-sm",children:"Select a post."})})]})]})}function Te({messages:o,commenters:h,onReply:y,isAdmin:x,onDelete:v}){const j=c=>h.find(d=>d.conversationId===c)?.contactName??"Facebook user",T=i.useMemo(()=>{const c=new Map;for(const d of o){if(d.is_internal_note)continue;const r=c.get(d.conversation_id)??[];r.push(d),c.set(d.conversation_id,r)}return Array.from(c.entries()).sort((d,r)=>{const m=new Date(d[1][d[1].length-1]?.created_at??0).getTime();return new Date(r[1][r[1].length-1]?.created_at??0).getTime()-m})},[o]);return T.length===0?e.jsx("div",{className:"text-muted-foreground text-sm text-center",children:"No comments."}):e.jsx(e.Fragment,{children:T.map(([c,d])=>e.jsxs("div",{className:"rounded-lg border border-border bg-background",children:[e.jsxs("div",{className:"sticky top-0 z-10 flex items-center gap-2 rounded-t-lg border-b border-border bg-background/95 px-3 py-2 backdrop-blur",children:[e.jsx(P,{source:"facebook_feed",showLabel:!1}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("div",{className:"text-xs font-semibold text-foreground truncate",children:j(c)}),e.jsx(te,{referral:h.find(r=>r.conversationId===c)?.referral,className:"mt-0.5"})]}),x&&e.jsx("button",{onClick:()=>v(c,j(c)),className:"p-1 rounded text-muted-foreground hover:text-destructive hover:bg-destructive/10",title:"Delete this chat (admin)",children:e.jsx(se,{className:"size-3.5"})})]}),e.jsx("ul",{className:"space-y-2 p-3",children:d.map(r=>{const m=r.direction==="out";return e.jsx("li",{className:p("flex",m&&"justify-end"),children:e.jsxs("div",{className:p("max-w-[85%] rounded-md px-3 py-2 text-sm",m?"bg-primary text-primary-foreground":"bg-accent/50"),children:[r.media_url&&r.media_type?.startsWith("image")&&e.jsx("a",{href:r.media_url,target:"_blank",rel:"noreferrer",className:"mb-2 block",children:e.jsx("img",{src:r.media_url,alt:"Facebook comment attachment",loading:"lazy",className:"max-h-72 w-auto max-w-full rounded-md object-contain"})}),r.content?e.jsx("div",{className:"whitespace-pre-wrap break-words",children:r.content}):r.media_url?null:e.jsx("div",{className:"italic opacity-70",children:"(no text)"}),e.jsxs("div",{className:p("mt-1 flex items-center gap-2 text-[10px]",m?"text-primary-foreground/70":"text-muted-foreground"),children:[e.jsx("span",{children:new Date(r.created_at).toLocaleString()}),!m&&r.external_id&&e.jsx("button",{onClick:()=>y(r),className:"underline",children:"Reply"})]})]})},r.id)})})]},c))})}export{Oe as component,Je as getUnrepliedSocialCommentCount};

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.