PageSourceSearch

https://wedraw.kr/assets/AdminAnalytics.B_LITj2m.js

js wedraw.kr collected 2026-10-04 07:43:41 UTC 217,994 bytes, 13 lines download raw bytes

1import{j as e}from"./vendor-ui.BwPBmVwt.js";import{r as h,L as Sa}from"./vendor-react.kR8tqwKZ.js";import{d as U}from"./vendor-utils.D2q0l15H.js";import{u as _a}from"./useTabParam.0zzDdGkW.js";import{T as Et,a as Mt,b as re,c as ne}from"./tabs.B_vF9hjw.js";import{S as ie,a as ce,b as oe,c as de,d as Y}from"./select.DEFUaHfV.js";import{C as me,a as xe,c as ue,b as he}from"./card.o7dQ1Cmv.js";import{c as rs,B as _,s as H,D as Me,f as Ie,h as Pe,i as Oe,m as Fe,X as ss,j as ka,E as cs,bi as Ca,bj as Da}from"./index.86ltQqcV.js";import{B as je}from"./badge.FoetXalN.js";import{C as It}from"./chart-column.wBcVfGnD.js";import{S as Ws}from"./shopping-cart.Bv2TAsUG.js";import{A as Ra}from"./arrow-up-down.CM5-VOOy.js";import{A as $a}from"./arrow-up.BDxdDhXq.js";import{A as Ua}from"./arrow-down.gmQdmOzE.js";import{S as os}from"./separator.TklRRnFA.js";import{I as F}from"./input.Bn8hRSEL.js";import{T as Ls}from"./textarea.CzIuFU26.js";import{U as Ta}from"./user.DXD9lpvm.js";import{C as Pt}from"./calendar.o8eP9MLv.js";import{S as Te}from"./square-pen.DBASX-8w.js";import{S as La}from"./save.DyDnqxYS.js";import{F as Aa}from"./file-text.nN_hT_47.js";import{E as Ea}from"./external-link.DbPD9Ep6.js";import{C as ee}from"./copy.DJG9JpkG.js";import{T as Ot}from"./trending-up.DrO9OvSf.js";import{R as Ps,P as Ma,c as Ia,d as Ft,T as Os,L as Pa,C as Kt,X as zt,Y as fs,a as Bt,b as Xe,e as Oa,B as Fa}from"./admin.DlinAKoh.js";import{L as K}from"./label.BLlGNrU0.js";import{A as vs,a as Ns,b as bs,c as ys,d as ws,e as Ss,f as Hs,g as _s}from"./alert-dialog.BHjbWqdT.js";import{S as Ka,b as za,c as Ba,d as Va,e as Ga}from"./sheet.Z9FHxKzN.js";import{S as Vt}from"./settings.Eoz354Vz.js";import{P as ke}from"./plus.VSSFQhJP.js";import{T as ks}from"./trash-2.DYInpbaD.js";import{P as Gt}from"./palette.hHZMJXYD.js";import{T as Wt,a as Ht,b as Le,c as le,d as qt,e as q}from"./table.l4sAptai.js";import{P as Cs}from"./package.sYWGe6pn.js";import{C as Ds}from"./check.Qs6HOoRX.js";import{P as st}from"./pencil.DZ4g47Je.js";import{L as Wa}from"./link-2.DDDPdL8H.js";import{C as Fs}from"./circle-check.C2VxFn-u.js";import{S as Ha}from"./search.CoLV_vkF.js";import{A as qa,u as Ya}from"./AdminWriteGuard.xT1R3h4-.js";import{L as Ja}from"./link.C7meRvbg.js";import{i as qs,M as Ke,G as Yt,a as Za,C as Ks,g as Qa,f as tt,b as Xa,c as er,A as sr}from"./orderStatsService.d340VX4G.js";import{T as we}from"./triangle-alert.DiFS_pz6.js";import{L as fe}from"./loader-circle.PPp0m7l9.js";import{R as tr}from"./refresh-cw.BJ6elI4y.js";import{C as ar}from"./clipboard-copy.CGwlA46h.js";import{b as rr}from"./storeNameMapper.ClbqmDtR.js";import{g as nr}from"./holidayService.BlnfHbxz.js";import{C as lr}from"./chevron-down.8Oyg22r0.js";import{C as ir}from"./chevron-right.BO4QQ722.js";import{t as cr}from"./dateHelpers.cqHLwmI3.js";import{G as or}from"./gauge.Y_njQaDL.js";import{C as dr}from"./clipboard-list.g9OC5FEe.js";import{W as mr}from"./wallet.DdXdTyrq.js";import{D as xr}from"./database.C0RVhMlI.js";import{L as ur}from"./list.Z2JkA3WC.js";import"./chevron-up.B4ORgOxs.js";import"./vendor-three.C5-HLXBy.js";import"./index.DhjlLJSn.js";import"./upload.C9RE_zBD.js";import"./xlsx.Dpp0MmBx.js";import"./layers.BwH-iwOg.js";import"./salesBreakdownService.BAd2lTVj.js";import"./useQuery.CKEnFAuE.js";import"./orderConfig.CcU-12Hu.js";import"./paymentMethod.CWEyCWd3.js";const hr=[["path",{d:"M12.5 22H18a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v9.5",key:"1couwa"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4",key:"tnqrlb"}],["path",{d:"M13.378 15.626a1 1 0 1 0-3.004-3.004l-5.01 5.012a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506z",key:"1y4qbx"}]],pr=rs("file-pen",hr);const gr=[["path",{d:"M13 5h8",key:"a7qcls"}],["path",{d:"M13 12h8",key:"h98zly"}],["path",{d:"M13 19h8",key:"c3s6r1"}],["path",{d:"m3 17 2 2 4-4",key:"1jhpwq"}],["path",{d:"m3 7 2 2 4-4",key:"1obspn"}]],jr=rs("list-checks",gr);const fr=[["path",{d:"M12.586 12.586 19 19",key:"ea5xo7"}],["path",{d:"M3.688 3.037a.497.497 0 0 0-.651.651l6.5 15.999a.501.501 0 0 0 .947-.062l1.569-6.083a2 2 0 0 1 1.448-1.479l6.124-1.579a.5.5 0 0 0 .063-.947z",key:"277e5u"}]],Ys=rs("mouse-pointer",fr);const vr=[["line",{x1:"19",x2:"5",y1:"5",y2:"19",key:"1x9vlm"}],["circle",{cx:"6.5",cy:"6.5",r:"2.5",key:"4mh3h7"}],["circle",{cx:"17.5",cy:"17.5",r:"2.5",key:"1mdrzq"}]],Nr=rs("percent",vr);const br=[["path",{d:"M11 2v2",key:"1539x4"}],["path",{d:"M5 2v2",key:"1yf1q8"}],["path",{d:"M5 3H4a2 2 0 0 0-2 2v4a6 6 0 0 0 12 0V5a2 2 0 0 0-2-2h-1",key:"rb5t3r"}],["path",{d:"M8 15a6 6 0 0 0 12 0v-3",key:"x18d4x"}],["circle",{cx:"20",cy:"10",r:"2",key:"ts1r5v"}]],yr=rs("stethoscope",br);function Jt({data:s,compact:t=!1}){const a=h.useMemo(()=>{const c=[];return s.impressions!==void 0&&s.impressions>0&&c.push({name:"impressions",label:"노출",count:s.impressions}),s.waypoint!==void 0&&c.push({name:"waypoint",label:"경유지",count:s.waypoint}),c.push({name:"landing",label:"랜딩",count:s.landing},{name:"product_view",label:"제품보기",count:s.product_view},{name:"add_to_cart",label:"장바구니",count:s.add_to_cart},{name:"checkout",label:"주문서",count:s.checkout},{name:"purchase",label:"결제완료",count:s.purchase}
1),c.forEach((x,N)=>{if(N===0)x.conversionRate=100;else{const j=c[N-1];j.count>0?x.conversionRate=x.count/j.count*100:x.conversionRate=0}}),c},[s]),r=Math.max(...a.map(c=>c.count)),l=t?100:140,n=100,o={top:20,bottom:30},i=l-o.top-o.bottom,m=a.map((c,x)=>{const N=n/a.length,j=N*x+N/2,p=r>0?o.top+i*(1-c.count/r):o.top+i;return{x:j,y:p,step:c}}),d=m.map((c,x)=>`${x===0?"M":"L"} ${c.x} ${c.y}`).join(" "),g=`${d} L ${m[m.length-1].x} ${l-o.bottom} L 0 ${l-o.bottom} Z`;return e.jsx("div",{className:"w-full",children:e.jsxs("div",{className:"relative",style:{height:`${l}px`},children:[e.jsxs("svg",{width:"100%",height:"100%",viewBox:`0 0 100 ${l}`,preserveAspectRatio:"none",className:"absolute inset-0",children:[e.jsx("path",{d:g,fill:"url(#gradient)",opacity:"0.2"}),e.jsx("path",{d,fill:"none",stroke:"rgb(59, 130, 246)",strokeWidth:"0.8",vectorEffect:"non-scaling-stroke"}),e.jsx("defs",{children:e.jsxs("linearGradient",{id:"gradient",x1:"0%",y1:"0%",x2:"0%",y2:"100%",children:[e.jsx("stop",{offset:"0%",stopColor:"rgb(59, 130, 246)",stopOpacity:"0.5"}),e.jsx("stop",{offset:"100%",stopColor:"rgb(59, 130, 246)",stopOpacity:"0.05"})]})})]}),m.map((c,x)=>e.jsxs("div",{children:[e.jsx("div",{className:"absolute",style:{left:`${c.x}%`,top:`${c.y-20}px`,transform:"translate(-50%, -100%)"},children:e.jsx("span",{className:`${t?"text-xs":"text-sm"} text-gray-700 font-semibold text-center whitespace-nowrap`,children:c.step.label})}),e.jsx("div",{className:"absolute",style:{left:`${c.x}%`,top:`${c.y}px`,transform:"translate(-50%, -50%)"},children:e.jsx("div",{className:"w-3 h-3 rounded-full bg-white border-2 border-blue-500"})}),e.jsx("div",{className:"absolute",style:{left:`${c.x}%`,top:`${c.y+8}px`,transform:"translateX(-50%)"},children:e.jsxs("div",{className:"flex flex-col items-center",children:[e.jsx("span",{className:`${t?"text-sm":"text-base"} font-bold text-gray-900`,children:c.step.count.toLocaleString()}),x>0&&c.step.conversionRate!==void 0&&e.jsxs("span",{className:`${t?"text-xs":"text-sm"} text-gray-500`,children:[c.step.conversionRate.toFixed(0),"%"]})]})})]},x))]})})}const wr=h.memo(function({urls:t,productName:a,channelColorMap:r,sortField:l,sortDirection:n,onSort:o,onCampaignClick:i}){const m=t.reduce((x,N)=>x+(N.revenue||0),0),d=[...t].sort((x,N)=>{let j,p;switch(l){case"visits":j=x.clicks,p=N.clicks;break;case"conversions":j=x.conversions,p=N.conversions;break;case"conversionRate":j=x.conversions/x.clicks*100,p=N.conversions/N.clicks*100;break;case"revenue":j=x.revenue||0,p=N.revenue||0;break;case"contribution":j=m>0?(x.revenue||0)/m*100:0,p=m>0?(N.revenue||0)/m*100:0;break;default:j=x[l],p=N[l]}return n==="asc"?j-p:p-j}),g=({field:x})=>l!==x?e.jsx(Ra,{className:"h-4 w-4"}):n==="asc"?e.jsx($a,{className:"h-4 w-4"}):e.jsx(Ua,{className:"h-4 w-4"}),c=()=>a==="전체 제품"?"전체 제품 대비 매출 기여도":`${a} 매출 기여도`;return e.jsxs(me,{children:[e.jsxs(xe,{className:"space-y-4",children:[e.jsxs(ue,{className:"flex items-center gap-2 text-base md:text-lg",children:[e.jsx(It,{className:"h-5 w-5"}),e.jsxs("span",{className:"line-clamp-2",children:["캠페인별 성과 ",a!=="전체 제품"&&`- ${a}`]})]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsxs(_,{variant:l==="visits"?"default":"outline",size:"sm",onClick:()=>o("visits"),className:"gap-2 cursor-pointer",children:["방문수",e.jsx(g,{field:"visits"})]}),e.jsxs(_,{variant:l==="conversions"?"default":"outline",size:"sm",onClick:()=>o("conversions"),className:"gap-2 cursor-pointer",children:["결제건수",e.jsx(g,{field:"conversions"})]}),e.jsxs(_,{variant:l==="conversionRate"?"default":"outline",size:"sm",onClick:()=>o("conversionRate"),className:"gap-2 cursor-pointer",children:["전환율",e.jsx(g,{field:"conversionRate"})]}),e.jsxs(_,{variant:l==="revenue"?"default":"outline",size:"sm",onClick:()=>o("revenue"),className:"gap-2 cursor-pointer",children:["매출액",e.jsx(g,{field:"revenue"})]}),e.jsxs(_,{variant:l==="contribution"?"default":"outline",size:"sm",onClick:()=>o("contribution"),className:"gap-2 cursor-pointer",children:["기여도",e.jsx(g,{field:"contribution"})]})]})]}),e.jsx(he,{children:d.length===0?e.jsxs("div",{className:"text-center py-12 text-muted-foreground",children:[e.jsx("p",{children:"등록된 캠페인이 없습니다."}),e.jsx("p",{className:"text-sm mt-2",children:"URL 관리 탭에서 캠페인을 추가하세요."})]}):e.jsx("div",{className:"space-y-3",children:d.map((x,N)=>{const j=x.revenue||0,p=m>0?j/m*100:0,u=x.clicks>0?(x.conversions/x.clicks*100).toFixed(1):"0.0";return e.jsxs("div",{className:"border rounded-lg hover:bg-accent/50 transition-colors",children:[e.jsxs("div",{onClick:()=>i?.(x),className:"flex flex-col sm:flex-row items-start sm:items-center gap-3 sm:gap-4 p-3 sm:p-4 cursor-pointer",children:[e.jsxs("div",{className:"flex items-center gap-3 sm:gap-4 w-full sm:w-auto",children:[e.jsx("div",{className:"flex items-center justify-center w-8 h-8 rounded-full bg-muted flex-shrink-0",children:e.jsx("span",{className:"text-sm",children:N+1})}),e.jsx("div",{className:`w-1 h-12 rounded-full flex-shrink-0 ${r[x.channel]}`}),e.jsxs("div",{className:"flex-1 min-w-0 flex items-center gap-2",children:[e.jsx("h4",{className:"truncate",children:x.campaign}),x.isTwoStep&&x.step===2&&e.jsx(je,{variant:"outline",className:"bg-blue-100 text-blue-700 border-blue-300 shrink-0 text-xs",children:"2단계유입"})]})]}),e.jsxs("div",{className:"flex flex-col sm:flex-row sm:flex-1 gap-2 sm:gap-4 text-sm text-muted-foreground w-full sm:w-auto pl-11 sm:pl-0",children:[e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(Ys,{className:"h-3 w-3"}
1),e.jsx("span",{children:x.clicks.toLocaleString()})]}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(Ws,{className:"h-3 w-3"}),e.jsxs("span",{children:[x.conversions," 구매"]})]}),e.jsxs("div",{className:"text-green-600",children:["구매 전환율 ",u,"%"]}),e.jsx("div",{className:"flex items-center gap-1",children:e.jsxs("span",{children:["총 매출액 ",(j/1e4).toFixed(0),"만원"]})}),e.jsxs("div",{className:"text-blue-600",children:[c()," ",p.toFixed(1),"%"]}),e.jsxs("div",{className:"flex items-center gap-3 sm:ml-auto",children:[e.jsxs("span",{className:"text-foreground",children:["담당자: ",x.manager]}),e.jsxs("span",{className:"text-gray-400",children:["생성일: ",x.createdAt]})]})]})]}),x.funnel&&e.jsx("div",{className:"px-3 sm:px-4 pb-3 sm:pb-4 pt-0 border-t bg-muted/30",children:e.jsxs("div",{className:"pt-3",children:[e.jsx("div",{className:"flex items-center gap-2 mb-2",children:e.jsx("h5",{className:"text-xs font-medium text-muted-foreground",children:"전환 퍼널"})}),e.jsx(Jt,{data:x.funnel,compact:!0})]})})]},x.id)})})})]})});async function Sr(s){const{data:t,error:a}=await H.from("tp_campaigns").insert({campaign_name:s.campaign_name,manager_name:s.manager_name||null,start_date:s.start_date||null,end_date:s.end_date||null,status:s.status||"active",memo:s.memo||null,post_url:s.post_url||null}).select().single();if(a)throw console.error("캠페인 생성 실패:",a),new Error(`캠페인 생성 실패: ${a.message}`);return t}async function Zt(s,t){const{data:a,error:r}=await H.from("tp_campaigns").update({...t,updated_at:new Date().toISOString()}).eq("id",s).select().single();if(r)throw console.error("캠페인 수정 실패:",r),new Error(`캠페인 수정 실패: ${r.message}`);return a}async function ts(s){const t=_r(),{data:a,error:r}=await H.from("ag_links").insert({short_code:t,original_url:s.original_url,campaign_id:s.campaign_id||null,product_id:s.product_id||null,channel_id:s.channel_id||null,is_active:!0}).select().single();if(r){if(r.code==="23505")return console.warn("short_code 중복, 재시도:",t),ts(s);throw console.error("Agent 링크 생성 실패:",r),new Error(`Agent 링크 생성 실패: ${r.message}`)}return a}function _r(){const s="abcdefghijklmnopqrstuvwxyz0123456789";let t="";for(let a=0;a<8;a++)t+=s.charAt(Math.floor(Math.random()*s.length));return t}function as(s){return`https://agent.wedraw.kr/go/${s}`}async function kr(s){const t=new URLSearchParams({utm_source:s.utm_params.source.toLowerCase(),utm_medium:s.utm_params.medium.toLowerCase(),utm_campaign:s.utm_params.campaign.toLowerCase()});s.utm_params.content&&t.append("utm_content",s.utm_params.content.toLowerCase()),s.utm_params.term&&t.append("utm_term",s.utm_params.term.toLowerCase());const a=`${s.final_destination_url}?${t.toString()}`,r=await ts({original_url:a,campaign_id:s.campaign_id}),l=as(r.short_code),n=new URL(s.waypoint_url);n.search="",n.searchParams.set("next",l);const o=n.toString(),i=await ts({original_url:o,campaign_id:s.campaign_id}),m=as(i.short_code);return{waypointLink:i,waypointShortUrl:m,finalLink:r,finalShortUrl:l}}function Qt({url:s,channelName:t,channelColor:a,productName:r,open:l,onOpenChange:n}){const o=s.groupUrls&&s.groupUrls.length>=2?s.groupUrls[1]:s,i=o?.clicks||0,m=o?.conversions||0,d=o?.revenue||0,g=i>0?m/i*100:0,c=m>0?d/m:0,x=i>0?d/i:0,[N,j]=h.useState(!1),[p,u]=h.useState(o.memo||""),[b,T]=h.useState(o.postUrl||""),[P,$]=h.useState(!1),D=async(w,I)=>{try{await navigator.clipboard.writeText(w),U.success(`${I}이 클립보드에 복사되었습니다!`)}catch{U.error("클립보드 복사에 실패했습니다.")}},V=async()=>{const w=o.campaignId||s.campaignId;if(!w){U.error("캠페인 ID가 없습니다. URL 데이터를 확인해주세요."),console.error("❌ campaignId not found in url or displayUrl");return}try{$(!0),await Zt(w,{memo:p||void 0,post_url:b||void 0}),o.memo=p,o.postUrl=b,s!==o&&(s.memo=p,s.postUrl=b),U.success("메모와 게시글 URL이 저장되었습니다!"),j(!1)}catch(I){console.error("저장 실패:",I),U.error(I.message||"저장에 실패했습니다.")}finally{$(!1)}},k=()=>{u(o.memo||""),T(o.postUrl||""),j(!1)};return e.jsx(Me,{open:l,onOpenChange:n,children:e.jsxs(Ie,{className:"sm:max-w-[600px] max-h-[90vh] overflow-y-auto",children:[e.jsxs(Pe,{children:[e.jsx(Oe,{children:"캠페인 상세 정보"}),e.jsxs(Fe,{children:[o.campaign,"의 성과를 자세히 확인하세요"]})]}),e.jsxs("div",{className:"space-y-6 py-4",children:[e.jsxs("div",{className:"space-y-3",children:[e.jsx("h4",{className:"text-sm text-muted-foreground",children:"캠페인 정보"}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-sm",children:"제품"}),e.jsx("span",{children:r})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-sm",children:"채널"}),e.jsx(je,{variant:"outline",className:`${a.text} ${a.border}`,children:t})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-sm",children:"소스"}),e.jsx("span",{children:o.source})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-sm",children:"담당자"}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(Ta,{className:"h-3 w-3 text-muted-foreground"}),e.jsx("span",{children:o.manager})]})]}),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"text-sm",children:"생성일"}),e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(Pt,{className:"h-3 w-3 text-muted-foreground"}),e.jsx("span",{children:o.createdAt})]})]})]})]}),e.jsx(os,{}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("h4",{className:"text-sm text-muted-foreground",children:"메모 및 게시글 URL"}),N?e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(_,{variant:"outline",size:"sm",onClick:k,disabled:P,children:[e.jsx(ss,{className:"h-3 w-3 mr-1"}),"취소"]}),e.jsxs(_,{variant:"default",size:"sm",onClick:V,disabled:P,children:[e.jsx(La,{className:"h-3 w-3 mr-1"}),P?"저장 중...":"저장"]})]}):e.jsxs(_,{variant:"outline",size:"sm",onClick:()=>j(!0),children:[e.jsx(Te,{className:"h-3 w-3 mr-1"}),"수정"]})]}),N?e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{children:[e.jsx("label",{className:"text-xs text-muted-foreground mb-1 block",children:"메모"}),e.jsx(Ls,{value:p,onChange:w=>u(w.target.value),placeholder:"캠페인 관련 메모를 입력하세요",rows:3})]}),e.jsxs("div",{children:[e.jsx("label",{className:"text-xs text-muted-foreground mb-1 block",children:"게시글 URL"}),e.jsx(F,{value:b,onChange:w=>T(w.target.value),placeholder:"https://blog.naver.com/..."})]})]}):e.jsxs("div",{className:"space-y-2",children:[o.memo?e.jsxs("div",{className:"p-3 rounded-lg bg-gray-100",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[e.jsx(Aa,{className:"h-3 w-3 text-muted-foreground"}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"메모"})]}),e.jsx("p",{className:"text-sm whitespace-pre-wrap",children:o.memo})]}):e.jsx("div",{className:"p-3 rounded-lg bg-gray-50 border border-dashed",children:e.jsx("p",{className:"text-xs text-muted-foreground",children:"메모 없음"})}),o.postUrl?e.jsxs("div",{className:"p-3 rounded-lg bg-blue-50 border border-blue-200",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-1",children:[e.jsx(Ea,{className:"h-3 w-3 text-blue-600"}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"게시글 URL"})]}),e.jsx("a",{href:o.postUrl,target:"_blank",rel:"noopener noreferrer",className:"text-sm text-blue-600 hover:underline break-all",children:o.postUrl})]}):e.jsx("div",{className:"p-3 rounded-lg bg-gray-50 border border-dashed",children:e.jsx("p",{className:"text-xs text-muted-foreground",children:"게시글 URL 없음"})})]})]}),e.jsx(os,{}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("h4",{className:"text-sm text-muted-foreground",children:"성과 지표"}),e.jsxs("div",{className:"grid grid-cols-2 gap-4",children:[e.jsxs("div",{className:"space-y-2 p-4 rounded-lg bg-blue-50 dark:bg-blue-950/20",children:[e.jsxs("div",{className:"flex items-center gap-2 text-blue-600 dar
1k:text-blue-400",children:[e.jsx(Ys,{className:"h-4 w-4"}),e.jsx("span",{className:"text-sm",children:"총 방문수"})]}),e.jsx("p",{className:"text-2xl",children:i.toLocaleString()})]}),e.jsxs("div",{className:"space-y-2 p-4 rounded-lg bg-green-50 dark:bg-green-950/20",children:[e.jsxs("div",{className:"flex items-center gap-2 text-green-600 dark:text-green-400",children:[e.jsx(Ws,{className:"h-4 w-4"}),e.jsx("span",{className:"text-sm",children:"총 전환수"})]}),e.jsx("p",{className:"text-2xl",children:m.toLocaleString()})]}),e.jsxs("div",{className:"space-y-2 p-4 rounded-lg bg-purple-50 dark:bg-purple-950/20",children:[e.jsxs("div",{className:"flex items-center gap-2 text-purple-600 dark:text-purple-400",children:[e.jsx("span",{className:"text-base",children:"₩"}),e.jsx("span",{className:"text-sm",children:"총 매출액"})]}),e.jsxs("p",{className:"text-2xl",children:[d.toLocaleString(),"원"]})]}),e.jsxs("div",{className:"space-y-2 p-4 rounded-lg bg-orange-50 dark:bg-orange-950/20",children:[e.jsxs("div",{className:"flex items-center gap-2 text-orange-600 dark:text-orange-400",children:[e.jsx(Nr,{className:"h-4 w-4"}),e.jsx("span",{className:"text-sm",children:"전환율"})]}),e.jsxs("p",{className:"text-2xl",children:[g.toFixed(2),"%"]})]})]})]}),e.jsx(os,{}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("h4",{className:"text-sm text-muted-foreground",children:"추가 분석"}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between p-3 rounded-lg bg-gray-100",children:[e.jsx("span",{className:"text-sm",children:"평균 객단가"}),e.jsxs("span",{children:[c.toLocaleString(),"원"]})]}),e.jsxs("div",{className:"flex items-center justify-between p-3 rounded-lg bg-gray-100",children:[e.jsx("span",{className:"text-sm",children:"클릭당 매출"}),e.jsxs("span",{children:[x.toLocaleString(),"원"]})]})]})]}),e.jsx(os,{}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("h4",{className:"text-sm text-muted-foreground",children:"추적 URL"}),s.groupUrls&&s.groupUrls.length>=2?e.jsx("div",{className:"space-y-4",children:s.groupUrls.map((w,I)=>e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(je,{variant:"outline",className:I===0?"bg-blue-100 text-blue-700 border-blue-300":"bg-purple-100 text-purple-700 border-purple-300",children:I===0?"1단계":"2단계"}),e.jsx("span",{className:"text-xs text-muted-foreground",children:I===0?"(외부 → 경유지)":"(경유지 → 최종목적지)"})]}),w.shortUrl&&e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-xs text-muted-foreground px-1",children:"🔗 Short URL (공유용)"}),e.jsxs("div",{className:"flex items-center gap-2 p-3 rounded-lg bg-blue-50 border border-blue-200",children:[e.jsx("span",{className:"text-sm font-mono text-blue-700 break-all flex-1",children:w.shortUrl}),e.jsx("button",{onClick:()=>D(w.shortUrl,"Short URL"),className:"p-2 hover:bg-blue-100 rounded transition-colors flex-shrink-0",children:e.jsx(ee,{className:"h-4 w-4 text-blue-600"})})]})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-xs text-muted-foreground px-1",children:"📋 Original UTM URL"}),e.jsxs("div",{className:"flex items-center gap-2 p-3 rounded-lg bg-gray-100 border border-gray-200",children:[e.jsx("span",{className:"text-xs text-gray-700 break-all flex-1",children:w.url}),e.jsx("button",{onClick:()=>D(w.url,"Original URL"),className:"p-2 hover:bg-gray-200 rounded transition-colors flex-shrink-0",children:e.jsx(ee,{className:"h-4 w-4 text-gray-600"})})]})]})]},w.id))}):e.jsxs("div",{className:"space-y-3",children:[s.shortUrl&&e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-xs text-muted-foreground px-1",children:"🔗 Short URL (공유용)"}),e.jsxs("div",{className:"flex items-center gap-2 p-3 rounded-lg bg-green-50 border border-green-200",children:[e.jsx("span",{className:"text-sm font-mono text-green-700 break-all flex-1",children:s.shortUrl}),e.jsx("button",{onClick:()=>D(s.shortUrl,"Short URL"),className:"p-2 hover:bg-green-100 rounded transition-colors flex-shrink-0",children:e.jsx(ee,{className:"h-4 w-4 text-green-600"})})]})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-xs text-muted-foreground px-1",children:"📋 Original UTM URL"}),e.jsxs("div",{className:"flex items-center gap-2 p-3 rounded-lg bg-gray-100 border border-gray-200",children:[e.jsx("span",{className:"text-xs text-gray-700 break-all flex-1",children:s.url}),e.jsx("button",{onClick:()=>D(s.url,"Original URL"),className:"p-2 hover:bg-gray-200 rounded transition-colors flex-shrink-0",children:e.jsx(ee,{className:"h-4 w-4 text-gray-600"})})]})]})]})]})]})]})})}function at({urls:s,productName:t,channels:a,dateRange:r,showCampaignTable:l=!1}){const[n,o]=h.useState("visits"),[i,m]=h.useState("visits"),[d,g]=h.useState("desc"),[c,x]=h.useState(null),N=h.useMemo(()=>{const f={};return a.forEach(v=>{f[v.id]=v.color}),f},[a]),j=h.useMemo(()=>{const f={};return a.forEach(v=>{f[v.id]=v.name}),f},[a]);h.useMemo(()=>{const f={};return a.forEach(v=>{f[v.id]=v.hex}),f},[a]);const p=h.useMemo(()=>{const f={};return a.forEach(v=>{const L=v.color.replace("600","50"),A=v.color.replace("600","700");f[v.id]={bg:L,text:A}}),f},[a]),u={sliding_shelf:"슬라이딩 선반",trones_top:"이케아 TRONES 상판",helmer_top:"이케아 HELMER 상판",lennart_top:"이케아 LENNART 맞춤 상판",kids_shoebench:"어린이 슈벤치",multipurpose_shelf:"다용도 ㄷ자 선반",fridge_gap:"냉장고 틈새장"},b=h.useMemo(()=>s.filter(f=>!(f.isTwoStep&&f.step===1)),[s]),T=h.useMemo(()=>b.reduce((f,v)=>f+v.clicks,0),[b]),P=h.useMemo(()=>b.reduce((f,v)=>f+v.conversions,0),[b]),$=h.useMemo(()=>b.reduce((f,v)=>f+(v.revenue||0),0),[b]),D=h.useMemo(()=>T>0?P/T*100:0,[T,P]),V=h.useMemo(()=>P>0?$/P:0,[$,P]),k=h.useMemo(()=>{const f={impressions:0,landing:0,product_view:0,add_to_cart:0,checkout:0,purchase:0};return b.forEach(v=>{v.funnel&&(f.impressions=(f.impressions||0)+(v.funnel.impressions||0),f.landing+=v.funnel.landing||0,f.product_view+=v.funnel.product_view||0,f.add_to_cart+=v.funnel.add_to_cart||0,f.checkout+=v.funnel.checkout||0,f.purchase+=v.funnel.purchase||0)}),f.impressions===0&&delete f.impressions,f},[b]),w=h.useMemo(()=>{const f={};return b.forEach(L=>{const A=L.createdAt;f[A]||(f[A]={visits:0,conversions:0,revenue:0}),f[A].visits+=L.clicks,f[A].conversions+=L.conversions,f[A].revenue+=L.revenue||0}),Object.keys(f).sort().map(L=>{const A=f[L].visits,R=f[L].conversions,O=f[L].revenue,G=A>0?R/A*100:0;return{date:L.substring(5),visits:A,conversions:R,revenue:O/1e4,conversionRate:parseFloat(G.toFixed(1))}})},[b]),I=h.useMemo(()=>{const f={};
1if(a.forEach(v=>{f[v.id]=0}),b.forEach(v=>{if(f[v.channel]!==void 0)switch(n){case"visits":f[v.channel]+=v.clicks;break;case"conversions":f[v.channel]+=v.conversions;break;case"revenue":f[v.channel]+=v.revenue||0;break}}),n==="conversionRate"||n==="aov"){const v={},L={},A={};a.forEach(R=>{v[R.id]=0,L[R.id]=0,A[R.id]=0}),b.forEach(R=>{v[R.channel]!==void 0&&(v[R.channel]+=R.clicks,L[R.channel]+=R.conversions,A[R.channel]+=R.revenue||0)}),n==="conversionRate"?a.forEach(R=>{f[R.id]=v[R.id]>0?L[R.id]/v[R.id]*100:0}):n==="aov"&&a.forEach(R=>{f[R.id]=L[R.id]>0?A[R.id]/L[R.id]:0})}return a.map(v=>({name:v.name,value:f[v.id],color:v.hex})).filter(v=>v.value>0)},[b,a,n]),S=()=>{switch(n){case"visits":return T;case"conversions":return P;case"revenue":return $;case"conversionRate":return D;case"aov":return V;default:return 0}},Q=(f,v)=>{switch(v){case"visits":case"conversions":return f.toLocaleString();case"revenue":case"aov":return`${f.toLocaleString()}원`;case"conversionRate":return`${f.toFixed(1)}%`;default:return f.toString()}},y=f=>{i===f?g(d==="asc"?"desc":"asc"):(m(f),g("desc"))},M=f=>{switch(f){case"visits":return"방문 수";case"conversions":return"결제 건수";case"revenue":return"매출액";case"conversionRate":return"전환율";case"aov":return"객단가";default:return""}};return e.jsxs("div",{className:"space-y-6",children:[!l&&e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-4",children:[e.jsxs(me,{children:[e.jsxs(xe,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ue,{className:"text-sm",children:"총 방문 수"}),e.jsx(Ys,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsx(he,{children:e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-2xl",children:T.toLocaleString()}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:[e.jsx("span",{className:"text-green-600",children:"▲ 15%"})," vs 이전 기간"]})]})})]}),e.jsxs(me,{children:[e.jsxs(xe,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ue,{className:"text-sm",children:"총 결제 건수"}),e.jsx(Ws,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsx(he,{children:e.jsxs("div",{className:"space-y-1",children:[e.jsx("div",{className:"text-2xl",children:P.toLocaleString()}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:[e.jsx("span",{className:"text-green-600",children:"▲ 22%"})," vs 이전 기간"]})]})})]}),e.jsxs(me,{children:[e.jsxs(xe,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ue,{className:"text-sm",children:"총 매출액"}),e.jsx("span",{className:"text-lg text-muted-foreground",children:"₩"})]}),e.jsx(he,{children:e.jsxs("div",{className:"space-y-1",children:[e.jsxs("div",{className:"text-2xl",children:[$.toLocaleString(),"원"]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:[e.jsx("span",{className:"text-green-600",children:"▲ 28%"})," vs 이전 기간"]})]})})]}),e.jsxs(me,{children:[e.jsxs(xe,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ue,{className:"text-sm",children:"구매 전환율"}),e.jsx(Ot,{className:"h-4 w-4 text-muted-foreground"})]}),e.jsx(he,{children:e.jsxs("div",{className:"space-y-1",children:[e.jsxs("div",{className:"text-2xl",children:[D.toFixed(1),"%"]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:[e.jsx("span",{className:"text-green-600",children:"▲ 0.8%p"})," vs 이전 기간"]})]})})]}),e.jsxs(me,{children:[e.jsxs(xe,{className:"flex flex-row items-center justify-between space-y-0 pb-2",children:[e.jsx(ue,{className:"text-sm",children:"객단가 (AOV)"}),e.jsx("span",{className:"text-lg text-muted-foreground",children:"₩"})]}),e.jsx(he,{children:e.jsxs("div",{className:"space-y-1",children:[e.jsxs("div",{className:"text-2xl",children:[Math.round(V).toLocaleString(),"원"]}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:[e.jsx("span",{className:"text-green-600",children:"▲ 5%"})," vs 이전 기간"]})]})})]})]}),!l&&e.jsxs(me,{children:[e.jsxs(xe,{children:[e.jsx(ue,{children:"전체 캠페인 전환 퍼널"}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:"모든 캠페인의 전환 퍼널을 합산한 데이터입니다"})]}),e.jsx(he,{children:e.jsx(Jt,{data:k})})]}),!l&&e.jsxs("div",{className:"grid grid-cols-1 lg:grid-cols-2 gap-6",children:[e.jsxs(me,{children:[e.jsx(xe,{children:e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(ue,{children:"채널별 성과 분석"}),e.jsxs(ie,{value:n,onValueChange:f=>o(f),children:[e.jsx(ce,{className:"w-[140px]",children:e.jsx(oe,{})}),e.jsxs(de,{children:[e.jsx(Y,{value:"visits",children:"방문 수"}),e.jsx(Y,{value:"conversions",children:"결제 건수"}),e.jsx(Y,{value:"revenue",children:"매출액"}),e.jsx(Y,{value:"conversionRate",children:"전환율"}),e.jsx(Y,{value:"aov",children:"객단가"})]})]})]})}),e.jsx(he,{children:e.jsx(Ps,{width:"100%",height:300,children:e.jsxs(Ma,{children:[e.jsx(Ia,{data:I,cx:"50%",cy:"50%",labelLine:!0,label:({name:f,value:v})=>{const L=S();if(L===0)return`${f} 0%`;const A=n==="conversionRate"||n==="aov"?v/I.reduce((O,G)=>O+G.value,0)*100:v/L*100,R=Q(v,n);return`${f}
2${R} (${A.toFixed(1)}%)`},outerRadius:80,fill:"#8884d8",dataKey:"value",children:I.map((f,v)=>e.jsx(Ft,{fill:f.color},`cell-${v}`))}),e.jsx(Os,{formatter:f=>{const v=Q(f,n),L=S(),A=n==="conversionRate"||n==="aov"?f/I.reduce((R,O)=>R+O.value,0)*100:f/L*100;return[`${v} (${A.toFixed(1)}%)`,M(n)]}})]})})})]}),e.jsxs(me,{children:[e.jsx(xe,{children:e.jsx(ue,{children:"일별 성과 추이"})}),e.jsx(he,{children:e.jsx(Ps,{width:"100%",height:300,children:e.jsxs(Pa,{data:w,children:[e.jsx(Kt,{strokeDasharray:"3 3"}),e.jsx(zt,{dataKey:"date",tick:{fontSize:11}}),e.jsx(fs,{yAxisId:"left",tick:{fontSize:11}}),e.jsx(fs,{yAxisId:"right",orientation:"right",tick:{fontSize:11}}),e.jsx(Os,{contentStyle:{fontSize:12},formatter:(f,v)=>
2v==="방문수"?[f.toLocaleString(),v]:v==="결제건수"?[f.toLocaleString(),v]:v==="매출액"?[`${f.toFixed(1)}만원`,v]:v==="전환율"?[`${f}%`,v]:[f,v]}),e.jsx(Bt,{wrapperStyle:{fontSize:12}}),e.jsx(Xe,{yAxisId:"left",type:"monotone",dataKey:"visits",stroke:"#3b82f6",strokeWidth:2,name:"방문수",dot:{r:3}}),e.jsx(Xe,{yAxisId:"left",type:"monotone",dataKey:"conversions",stroke:"#10b981",strokeWidth:2,name:"결제건수",dot:{r:3}}),e.jsx(Xe,{yAxisId:"right",type:"monotone",dataKey:"revenue",stroke:"#f59e0b",strokeWidth:2,name:"매출액",dot:{r:3}}),e.jsx(Xe,{yAxisId:"right",type:"monotone",dataKey:"conversionRate",stroke:"#8b5cf6",strokeWidth:2,name:"전환율",dot:{r:3}})]})})})]})]}),l&&e.jsx(wr,{urls:b,productName:t,channelColorMap:N,sortField:i,sortDirection:d,onSort:y,onCampaignClick:f=>x(f)}),l&&c&&e.jsx(Qt,{url:c,channelName:j[c.channel]||c.channel,channelColor:p[c.channel]||{bg:"bg-gray-50",text:"text-gray-700"},productName:u[c.product]||c.product,open:!!c,onOpenChange:f=>!f&&x(null)})]})}const Be=[{id:"blue",name:"파랑",bg:"bg-blue-600",hex:"#2563eb"},{id:"green",name:"초록",bg:"bg-green-600",hex:"#16a34a"},{id:"purple",name:"보라",bg:"bg-purple-600",hex:"#9333ea"},{id:"orange",name:"주황",bg:"bg-orange-600",hex:"#ea580c"},{id:"pink",name:"핑크",bg:"bg-pink-600",hex:"#db2777"},{id:"cyan",name:"청록",bg:"bg-cyan-600",hex:"#0891b2"},{id:"red",name:"빨강",bg:"bg-red-600",hex:"#dc2626"},{id:"yellow",name:"노랑",bg:"bg-yellow-600",hex:"#ca8a04"},{id:"indigo",name:"남색",bg:"bg-indigo-600",hex:"#4f46e5"},{id:"teal",name:"청록",bg:"bg-teal-600",hex:"#0d9488"}];function Cr({channel:s,availableColors:t,onColorChange:a}){const[r,l]=h.useState(!1);return e.jsxs("div",{className:"hidden sm:block relative",children:[e.jsx("button",{onClick:()=>l(!r),onBlur:()=>setTimeout(()=>l(!1),200),className:"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 hover:bg-accent hover:text-accent-foreground h-9 px-2",title:"색상 변경",children:e.jsx(Gt,{className:"h-4 w-4"})}),r&&e.jsx("div",{className:"absolute right-0 top-full mt-1 p-2 bg-popover border rounded-lg shadow-lg z-50",children:e.jsx("div",{className:"flex gap-1 flex-wrap max-w-[160px]",children:t.map(n=>e.jsx("button",{onClick:()=>{a(s.id,n),l(!1)},className:`w-6 h-6 rounded-full ${n.bg} hover:ring-2 hover:ring-offset-1 hover:ring-primary transition-all`,title:n.name},n.id))})})]})}function Dr({channel:s,availableColors:t,onColorChange:a}){const[r,l]=h.useState(!1);return e.jsxs(Ka,{open:r,onOpenChange:l,children:[e.jsx(_,{variant:"ghost",size:"sm",onClick:()=>l(!0),children:e.jsx(Gt,{className:"h-4 w-4"})}),e.jsxs(za,{side:"bottom",className:"h-auto",children:[e.jsxs(Ba,{children:[e.jsx(Va,{children:"색상 선택"}),e.jsxs(Ga,{children:[s.name," 채널의 색상을 선택하세요"]})]}),e.jsx("div",{className:"grid grid-cols-5 gap-3 mt-6 pb-6",children:t.map(n=>e.jsx("button",{onClick:()=>{a(s.id,n),l(!1)},className:`w-full aspect-square rounded-lg ${n.bg} hover:ring-2 hover:ring-offset-2 hover:ring-primary transition-all`,title:n.name},n.id))})]})]})}function Xt({channels:s,onChannelsChange:t,urls:a}){const[r,l]=h.useState(!1),[n,o]=h.useState(null),[i,m]=h.useState(""),[d,g]=h.useState(""),[c,x]=h.useState(Be[0]),[N,j]=h.useState(!1),[p,u]=h.useState(null),b=()=>{if(!i.trim()||!d.trim()){U.error("채널 ID와 이름을 모두 입력해주세요.");return}if(s.find(w=>w.id===d)){U.error("이미 존재하는 채널 ID입니다.");return}const k={id:d,name:i,color:c.bg,hex:c.hex};t([...s,k]),m(""),g(""),x(Be[0]),U.success(`채널 "${i}"이(가) 추가되었습니다.`)},T=(k,w)=>{if(!w.trim()){U.error("채널 이름을 입력해주세요.");return}const I=s.map(S=>S.id===k?{...S,name:w}:S);t(I),o(null),U.success("채널 이름이 수정되었습니다.")},P=(k,w)=>{const I=s.map(S=>S.id===k?{...S,color:w.bg,hex:w.hex}:S);t(I),U.success("채널 색상이 변경되었습니다.")},$=k=>{if(a.some(I=>I.channel===k)){U.error("해당 채��을 사용 중인 URL이 있어 삭제할 수 없습니다.");return}u(k),j(!0)},D=()=>
2{if(p){const k=s.find(w=>w.id===p)?.name;t(s.filter(w=>w.id!==p)),U.success(`채널 "${k}"이(가) 삭제되었습니다.`)}j(!1),u(null)},V=k=>a.filter(w=>w.channel===k).length;return e.jsxs(e.Fragment,{children:[e.jsxs(Me,{open:r,onOpenChange:l,children:[e.jsxs(_,{variant:"outline",size:"sm",className:"gap-2 cursor-pointer",onClick:()=>l(!0),children:[e.jsx(Vt,{className:"h-4 w-4"}),"채널 관리"]}),e.jsxs(Ie,{className:"w-[95vw] sm:max-w-2xl max-h-[85vh] overflow-y-scroll",children:[e.jsxs(Pe,{children:[e.jsx(Oe,{className:"text-lg",children:"마케팅 채널 관리"}),e.jsx(Fe,{className:"text-sm",children:"마케팅 채널을 추가, 수정, 삭제하고 색상을 설정하세요."})]}),e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-4 p-4 border rounded-lg bg-muted/30",children:[e.jsxs("h4",{className:"flex items-center gap-2 text-base",children:[e.jsx(ke,{className:"h-4 w-4"}),"새 채널 추가"]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(K,{htmlFor:"new-channel-id",children:"채널 ID (영문)"}),e.jsx(F,{id:"new-channel-id",placeholder:"예: cpc, email",value:d,onChange:k=>g(k.target.value)})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(K,{htmlFor:"new-channel-name",children:"채널 이름"}),e.jsx(F,{id:"new-channel-name",placeholder:"예: CPC 광고, 이메일",value:i,onChange:k=>m(k.target.value)})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(K,{children:"채널 색상"}),e.jsx("div",{className:"flex gap-2 flex-wrap",children:Be.map(k=>e.jsx("button",{onClick:()=>x(k),className:`w-10 h-10 sm:w-8 sm:h-8 rounded-full ${k.bg} ${c.id===k.id?"ring-2 ring-offset-2 ring-primary":""}`,title:k.name},k.id))})]}),e.jsxs(_,{onClick:b,className:"w-full",children:[e.jsx(ke,{className:"h-4 w-4 mr-2"}),"채널 추가"]})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("h4",{className:"text-base",children:"등록된 채널"}),s.length===0?e.jsx("p",{className:"text-sm text-muted-foreground text-center py-8",children:"등록된 ��널이 없습니다."}):e.jsx("div",{className:"space-y-2 min-h-[300px]",children:s.map(k=>e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center gap-3 p-3 border rounded-lg hover:bg-accent/50",children:[e.jsxs("div",{className:"flex items-center gap-3 flex-1 min-w-0",children:[e.jsx("div",{className:`w-4 h-4 rounded-full flex-shrink-0 ${k.color}`}),n===k.id?e.jsx(F,{defaultValue:k.name,onBlur:w=>T(k.id,w.target.value),onKeyDown:w=>{w.key==="Enter"&&T(k.id,w.currentTarget.value)},autoFocus:!0,className:"flex-1"}):e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("div",{className:"truncate",children:k.name}),e.jsxs("div",{className:"text-xs text-muted-foreground",children:["(",k.id,") · ",V(k.id),"개 사용 중"]})]})]}),e.jsxs("div",{className:"flex items-center gap-2 sm:gap-1",children:[e.jsx(Cr,{channel:k,availableColors:Be,onColorChange:P}),e.jsx("div",{className:"sm:hidden",children:e.jsx(Dr,{channel:k,availableColors:Be,onColorChange:P})}),e.jsxs(_,{variant:"ghost",size:"sm",onClick:()=>o(k.id),disabled:n===k.id,className:"gap-1",children:[e.jsx(Te,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:"수정"})]}),e.jsxs(_,{variant:"ghost",size:"sm",onClick:()=>$(k.id),className:"gap-1 text-destructive hover:text-destructive",children:[e.jsx(ks,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:"삭제"})]})]})]},k.id))})]})]})]})]}),e.jsx(vs,{open:N,onOpenChange:j,children:e.jsxs(Ns,{children:[e.jsxs(bs,{children:[e.jsx(ys,{children:"채널을 삭제하시겠습니까?"}),e.jsxs(ws,{children:['이 작업은 되돌릴 수 없습니다. 채널 "',s.find(k=>k.id===p)?.name,'"이(가) 영구적으로 삭제됩니다.']})]}),e.jsxs(Ss,{children:[e.jsx(Hs,{children:"취소"}),e.jsx(_s,{onClick:D,children:"삭제"})]})]})})]})}function ea({products:s,onProductsChange:t,urls:a}){const[r,l]=h.useState(!1),[n,o]=h.useState(""),[i,m]=h.useState(!1),[d,g]=h.useState(!1),[c,x]=h.useState(null),[N,j]=h.useState(null),[p,u]=h.useState(""),b=()=>{if(!n.trim()){U.error("제품명을 입력해주세요");return}if(s.some(I=>I.name===n.trim())){U.error("이미 존재하는 제품명입니다");return}const w={id:`product_${Date.now()}`,name:n.trim()};t([...s,w]),o(""),U.success("제품이 추가되었습니다!")},T=w=>{j(w.id),u(w.name)},P=w=>{if(!p.trim()){U.error("제품명을 입력해주세요");return}if(s.some(S=>S.id!==w&&S.name===p.trim())){U.error("이미 존재하는 제품명입니다");return}const I=s.map(S=>S.id===w?{...S,name:p.trim()}:S);t(I),j(null),u(""),U.success("제품명이 수정되었습니다!")},$=()=>{j(null),u("")},D=w=>{if(w.id==="all"){U.error('"전체 제품"은 삭제할 수 없습니다');return}if(a.filter(S=>
2S.product===w.id).length>0){x(w),g(!0);return}x(w),m(!0)},V=()=>{if(!c)return;const w=s.filter(I=>I.id!==c.id);t(w),U.success("제품이 삭제되었습니다!"),m(!1),x(null)},k=s.filter(w=>w.id!=="all");return e.jsxs(e.Fragment,{children:[e.jsxs(Me,{open:r,onOpenChange:l,children:[e.jsxs(_,{variant:"outline",size:"sm",className:"gap-2 cursor-pointer",onClick:()=>l(!0),children:[e.jsx(Cs,{className:"h-4 w-4"}),"제품 관리"]}),e.jsxs(Ie,{className:"w-[95vw] sm:w-[70vw] max-w-[800px] max-h-[85vh] overflow-y-auto",children:[e.jsxs(Pe,{children:[e.jsxs(Oe,{className:"flex items-center gap-2 text-lg",children:[e.jsx(Cs,{className:"h-5 w-5"}),"제품 관리"]}),e.jsx(Fe,{className:"text-sm",children:"제품을 추가하거나 삭제할 수 있습니다. 캠페인이 연결된 제품은 삭제할 수 없습니다."})]}),e.jsxs("div",{className:"space-y-6 mt-4",children:[e.jsxs("div",{className:"space-y-3",children:[e.jsx(K,{children:"새 제품 추가"}),e.jsxs("div",{className:"flex flex-col sm:flex-row gap-2",children:[e.jsx(F,{value:n,onChange:w=>o(w.target.value),placeholder:"제품명을 입력하세요",onKeyDown:w=>{w.key==="Enter"&&b()},className:"flex-1"}),e.jsxs(_,{onClick:b,className:"gap-2 w-full sm:w-auto",children:[e.jsx(ke,{className:"h-4 w-4"}),"추가"]})]})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs(K,{children:["등록된 제품 (",k.length,"개)"]}),e.jsx("div",{className:"hidden md:block border rounded-lg",children:e.jsxs(Wt,{children:[e.jsx(Ht,{children:e.jsxs(Le,{children:[e.jsx(le,{className:"w-[50%]",children:"제품명"}),e.jsx(le,{className:"w-[25%]",children:"연결된 캠페인"}),e.jsx(le,{className:"text-right w-[25%]",children:"액션"})]})}),e.jsx(qt,{children:k.length===0?e.jsx(Le,{children:e.jsx(q,{colSpan:3,className:"text-center text-muted-foreground py-8",children:"등록된 제품이 없습니다"})}):k.map(w=>{const I=a.filter(S=>S.product===w.id).length;return e.jsxs(Le,{children:[e.jsx(q,{children:N===w.id?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(F,{value:p,onChange:S=>u(S.target.value),onKeyDown:S=>{S.key==="Enter"?P(w.id):S.key==="Escape"&&$()},className:"h-8",autoFocus:!0}),e.jsx(_,{variant:"ghost",size:"sm",onClick:()=>P(w.id),className:"h-8 w-8 p-0",children:e.jsx(Ds,{className:"h-4 w-4 text-green-600"})}),e.jsx(_,{variant:"ghost",size:"sm",onClick:$,className:"h-8 w-8 p-0",children:e.jsx(ss,{className:"h-4 w-4"})})]}):w.name}),e.jsx(q,{children:e.jsxs("span",{className:"text-sm text-muted-foreground",children:[I,"개"]})}),e.jsx(q,{className:"text-right",children:N===w.id?null:e.jsxs("div",{className:"flex items-center justify-end gap-1",children:[e.jsxs(_,{variant:"ghost",size:"sm",onClick:()=>T(w),className:"gap-1 h-8",children:[e.jsx(st,{className:"h-3 w-3"}),"수정"]}),e.jsxs(_,{variant:"ghost",size:"sm",onClick:()=>D(w),className:"gap-1 text-destructive hover:text-destructive h-8",children:[e.jsx(ks,{className:"h-3 w-3"}),"삭제"]})]})})]},w.id)})})]})}),e.jsx("div",{className:"md:hidden space-y-3",children:k.length===0?e.jsx("div",{className:"text-center text-muted-foreground py-8 border rounded-lg",children:"등록된 제품이 없습니다"}):k.map(w=>{const I=a.filter(S=>S.product===w.id).length;return e.jsx("div",{className:"border rounded-lg p-4 space-y-3",children:N===w.id?e.jsxs("div",{className:"space-y-2",children:[e.jsx(F,{value:p,onChange:S=>u(S.target.value),onKeyDown:S=>{S.key==="Enter"?P(w.id):S.key==="Escape"&&$()},autoFocus:!0}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(_,{variant:"outline",size:"sm",onClick:()=>P(w.id),className:"flex-1 gap-2",children:[e.jsx(Ds,{className:"h-4 w-4 text-green-600"}),"저장"]}),e.jsxs(_,{variant:"outline",size:"sm",onClick:$,className:"flex-1 gap-2",children:[e.jsx(ss,{className:"h-4 w-4"}),"취소"]})]})]}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"flex items-start justify-between",children:e.jsxs("div",{children:[e.jsx("h4",{className:"break-words",children:w.name}),e.jsxs("p",{className:"text-sm text-muted-foreground mt-1",children:["연결된 캠페인: ",I,"개"]})]})}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs(_,{variant:"outline",size:"sm",onClick:()=>T(w),className:"flex-1 gap-2",children:[e.jsx(st,{className:"h-3 w-3"}),"수정"]}),e.jsxs(_,{variant:"outline",size:"sm",onClick:()=>D(w),className:"flex-1 gap-2 text-destructive hover:text-destructive",children:[e.jsx(ks,{className:"h-3 w-3"}),"삭제"]})]})]})},w.id)})})]})]})]})]}),e.jsx(vs,{open:i,onOpenChange:m,children:e.jsxs(Ns,{children:[e.jsxs(bs,{children:[e.jsx(ys,{children:"제품 삭제"}
2),e.jsxs(ws,{children:['"',c?.name,'" 제품을 삭제하시겠습니까?',e.jsx("br",{}),"이 작업은 되돌릴 수 없습니다."]})]}),e.jsxs(Ss,{children:[e.jsx(Hs,{children:"취소"}),e.jsx(_s,{onClick:V,className:"bg-destructive text-destructive-foreground hover:bg-destructive/90",children:"삭제"})]})]})}),e.jsx(vs,{open:d,onOpenChange:g,children:e.jsxs(Ns,{children:[e.jsxs(bs,{children:[e.jsx(ys,{children:"제품 삭제 불가"}),e.jsxs(ws,{children:['"',c?.name,'" 제품에는'," ",e.jsxs("span",{className:"font-medium text-foreground",children:[a.filter(w=>w.product===c?.id).length,"개의 연결된 캠페인"]}),"이 있습니다.",e.jsx("br",{}),e.jsx("br",{}),"제품을 삭제하려면 먼저 연결된 캠페인을 삭제하거나 다른 제품으로 변경해주세요."]})]}),e.jsx(Ss,{children:e.jsx(_s,{onClick:()=>{g(!1),x(null)},children:"확인"})})]})})]})}function Rr({sources:s,onSourcesChange:t,urls:a}){const[r,l]=h.useState(!1),[n,o]=h.useState(null),[i,m]=h.useState(""),[d,g]=h.useState(""),[c,x]=h.useState(!1),[N,j]=h.useState(null),p=()=>{if(!i.trim()||!d.trim()){U.error("소스 ID와 이름을 모두 입력해주세요.");return}if(s.find(D=>D.id===d)){U.error("이미 존재하는 소스 ID입니다.");return}const $={id:d,name:i};t([...s,$]),m(""),g(""),U.success(`소스 "${i}"이(가) 추가되었습니다.`)},u=($,D)=>{if(!D.trim()){U.error("소스 이름을 입력해주세요.");return}const V=s.map(k=>k.id===$?{...k,name:D}:k);t(V),o(null),U.success("소스 이름이 수정되었습니다.")},b=$=>{if(a.some(V=>V.source===$)){U.error("해당 소스를 사용 중인 URL이 있어 삭제할 수 없습니다.");return}j($),x(!0)},T=()=>{if(N){const $=s.find(D=>D.id===N)?.name;t(s.filter(D=>D.id!==N)),U.success(`소스 "${$}"이(가) 삭제되었습니다.`)}x(!1),j(null)},P=$=>a.filter(D=>D.source===$).length;return e.jsxs(e.Fragment,{children:[e.jsxs(Me,{open:r,onOpenChange:l,children:[e.jsxs(_,{variant:"outline",size:"sm",className:"gap-2 cursor-pointer",onClick:()=>l(!0),children:[e.jsx(Vt,{className:"h-4 w-4"}),"소스 관리"]}),e.jsxs(Ie,{className:"w-[95vw] sm:max-w-2xl max-h-[85vh] overflow-y-scroll",children:[e.jsxs(Pe,{children:[e.jsx(Oe,{className:"text-lg",children:"UTM Source 관리"}),e.jsx(Fe,{className:"text-sm",children:"UTM Source를 추가, 수정, 삭제하세요."})]}),e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-4 p-4 border rounded-lg bg-muted/30",children:[e.jsxs("h4",{className:"flex items-center gap-2 text-base",children:[e.jsx(ke,{className:"h-4 w-4"}),"새 소스 추가"]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(K,{htmlFor:"new-source-id",children:"소스 ID (영문)"}),e.jsx(F,{id:"new-source-id",placeholder:"예: facebook, tiktok",value:d,onChange:$=>g($.target.value)})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(K,{htmlFor:"new-source-name",children:"소스 이름"}),e.jsx(F,{id:"new-source-name",placeholder:"예: Facebook, TikTok",value:i,onChange:$=>m($.target.value)})]})]}),e.jsxs(_,{onClick:p,className:"w-full",children:[e.jsx(ke,{className:"h-4 w-4 mr-2"}),"소스 추가"]})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsx("h4",{className:"text-base",children:"등록된 소스"}),s.length===0?e.jsx("p",{className:"text-sm text-muted-foreground text-center py-8",children:"등록된 소스가 없습니다."}):e.jsx("div",{className:"space-y-2 min-h-[300px]",children:s.map($=>e.jsxs("div",{className:"flex flex-col sm:flex-row sm:items-center gap-3 p-3 border rounded-lg hover:bg-accent/50",children:[e.jsx("div",{className:"flex items-center gap-3 flex-1 min-w-0",children:n===$.id?e.jsx(F,{defaultValue:$.name,onBlur:D=>u($.id,D.target.value),onKeyDown:D=>{D.key==="Enter"&&u($.id,D.currentTarget.value)},autoFocus:!0,className:"flex-1"}):e.jsxs("div",{className:"flex-1 min-w-0",children:[e.jsx("div",{className:"truncate",children:$.name}),e.jsxs("div",{className:"text-xs text-muted-foreground",children:["(",$.id,") · ",P($.id),"개 사용 중"]})]})}),e.jsxs("div",{className:"flex items-center gap-2 sm:gap-1",children:[e.jsxs(_,{variant:"ghost",size:"sm",onClick:()=>o($.id),disabled:n===$.id,className:"gap-1",children:[e.jsx(Te,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:"수정"})]}),e.jsxs(_,{variant:"ghost",size:"sm",onClick:()=>b($.id),className:"gap-1 text-destructive hover:text-destructive",children:[e.jsx(ks,{className:"h-4 w-4"}),e.jsx("span",{className:"hidden sm:inline",children:"삭제"})]})]})]},$.id))})]})]})]})]}),e.jsx(vs,{open:c,onOpenChange:x,children:e.jsxs(Ns,{children:[e.jsxs(bs,{children:[e.jsx(ys,{children:"소스를 삭제하시겠습니까?"}),e.jsxs(ws,{children:['이 작업은 되돌릴 수 없습니다. 소스 "',s.find($=>
2$.id===N)?.name,'"이(가) 영구적으로 삭제됩니다.']})]}),e.jsxs(Ss,{children:[e.jsx(Hs,{children:"취소"}),e.jsx(_s,{onClick:T,children:"삭제"})]})]})})]})}function $r({onUrlAdded:s,products:t,channels:a,onChannelsChange:r,onProductsChange:l,sources:n,onSourcesChange:o,urls:i}){const[m,d]=h.useState("https://wedraw.kr"),[g,c]=h.useState(""),[x,N]=h.useState(""),[j,p]=h.useState(""),[u,b]=h.useState(""),[T,P]=h.useState(""),[$,D]=h.useState(""),[V,k]=h.useState(""),[w,I]=h.useState(""),[S,Q]=h.useState(!1),[y,M]=h.useState(""),[f,v]=h.useState(""),[L,A]=h.useState(""),[R,O]=h.useState(""),[G,z]=h.useState(""),[se,ve]=h.useState(""),[ae,Se]=h.useState(!1),E=async()=>{if(!g||!x||!j||!u||!T){U.error("필수 항목을 모두 입력해주세요");return}try{Se(!0);const C=await Sr({campaign_name:j,manager_name:u,status:"active",memo:$||void 0,post_url:V||void 0}),J=a.find(W=>W.name===x)?.id||x,De=n.find(W=>W.name===g)?.id||g;if(S){if(!y){U.error("중간 경유지 URL을 입력해주세요");return}const W=await kr({campaign_id:C.id,waypoint_url:y,final_destination_url:m,utm_params:{source:g.toLowerCase(),medium:x.toLowerCase(),campaign:j.toLowerCase()}});v(W.waypointLink.original_url),A(W.finalLink.original_url),z(W.waypointShortUrl),ve(W.finalShortUrl);const pe=Date.now(),is=`group_${pe}`,Re={id:pe,url:W.waypointLink.original_url,shortUrl:W.waypointShortUrl,campaign:j,campaignId:C.id,channel:J,source:De,manager:u,product:T,memo:C.memo,postUrl:C.post_url,createdAt:new Date().toLocaleDateString("ko-KR"),clicks:0,conversions:0,isTwoStep:!0,groupId:is,step:1},ze={id:pe+1,url:W.finalLink.original_url,shortUrl:W.finalShortUrl,campaign:j,campaignId:C.id,channel:J,source:De,manager:u,product:T,memo:C.memo,postUrl:C.post_url,createdAt:new Date().toLocaleDateString("ko-KR"),clicks:0,conversions:0,isTwoStep:!0,groupId:is,step:2};W.waypointShortUrl,W.finalShortUrl,s([Re,ze]),U.success("2단계 UTM URL과 Short URL이 생성되고 리스트에 추가되었습니다!")}else{const W=new URLSearchParams;W.append("utm_source",g.toLowerCase()),W.append("utm_medium",x.toLowerCase()),W.append("utm_campaign",j.toLowerCase());const pe=`${m}?${W.toString()}`;I(pe);const is=await ts({original_url:pe,campaign_id:C.id}),Re=as(is.short_code);O(Re);const ze={id:Date.now(),url:pe,shortUrl:Re,campaign:j,campaignId:C.id,channel:J,source:De,manager:u,product:T,memo:C.memo,postUrl:C.post_url,createdAt:new Date().toLocaleDateString("ko-KR"),clicks:0,conversions:0};s(ze),U.success("UTM URL과 Short URL이 생성되고 리스트에 추가되었습니다!")}}catch(C){console.error("URL 생성 실패:",C),U.error(C.message||"URL 생성에 실패했습니다")}finally{Se(!1)}},B=(C,J)=>{navigator.clipboard.writeText(C),U.success(`${J} URL이 클립보드에 복사되었습니다!`)};return e.jsxs("div",{className:"space-y-6",children:[e.jsx("div",{className:"p-6 border rounded-lg bg-gray-50",children:e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("h4",{className:"text-base font-semibold mb-1",children:"유입 경로 설정"}),e.jsx("p",{className:"text-sm text-gray-600",children:"사용자가 우리 사이트로 유입되는 경로를 선택하세요"})]}),e.jsxs("div",{className:"grid grid-cols-1 sm:grid-cols-2 gap-4",children:[e.jsx("button",{onClick:()=>Q(!1),className:`p-4 rounded-xl text-left transition-all cursor-pointer ${S?"border border-gray-300 bg-white hover:border-gray-400":"border-2 border-blue-600 bg-blue-50"}`,children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:`mt-1 w-5 h-5 rounded-full border-2 flex items-center justify-center flex-shrink-0 ${S?"border-gray-400":"border-blue-600"}`,children:!S&&e.jsx("div",{className:"w-3 h-3 rounded-full bg-blue-600"})}),e.jsxs("div",{className:"flex-1",children:[e.jsx("div",{className:"mb-2",children:e.jsx("span",{className:"font-semibold text-gray-900",children:"직접 유입"})}),e.jsxs("p",{className:"text-xs text-gray-600 leading-relaxed",children:[e.jsx("strong",{className:"text-gray-900",children:"외부(시작 지점) → 공식 홈페이지"}),e.jsx("br",{}),"외부에서 직접 공식 홈페이지로 유입시키는 ",e.jsx("strong",{className:"text-gray-900",children:"URL 1개"}),"를 생성합니다."]})]})]})}),e.jsx("button",{onClick:()=>Q(!0),className:`p-4 rounded-xl text-left transition-all cursor-pointer ${S?"border-2 border-blue-600 bg-blue-50":"border border-gray-300 bg-white hover:border-gray-400"}`,children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:`mt-1 w-5 h-5 rounded-full border-2 flex items-center justify-center flex-shrink-0 ${S?"border-blue-600":"border-gray-400"}`,children:S&&e.jsx("div",{className:"w-3 h-3 rounded-full bg-blue-600"})}),e.jsxs("div",{className:"flex-1",children:[e.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[e.jsx("span",{className:"font-semibold text-gray-900",children:"2단계 유입"}),e.jsx("span",{className:"text-xs px-2 py-0.5 bg-blue-100 text-blue-700 rounded",children:"중간 경유"})]}),e.jsxs("p",{className:"text-xs text-gray-600 leading-relaxed",children:[e.jsx("strong",{className:"text-gray-900",children:"외부(시작 지점) → 경유지 → 공식 홈페이지"}),e.jsx("br",{}),"외부에서 경유지로 유입시키는 URL과 경유지에서 공식 홈페이지로 유입시키는 URL을 ",e.jsx("strong",{className:"text-gray-900",children:"동시에 생성"}),"합니다. 경유지 정보를 아래에 추가로 입력하세요."]})]})]})})]})]})}),S&&e.jsxs("div",{className:"space-y-2",children:[e.jsxs(K,{htmlFor:"intermediateUrl",children:["중간 경유지 주소 *",e.jsx("span",{className:"text-xs text-muted-foreground ml-2",children:"(블로그, SNS, 카페 등)"})]}),e.jsx(F,{id:"intermediateUrl",value:y,onChange:C=>M(C.target.value),placeholder:"https://blog.naver.com/yourstore"})]}),e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx("div",{className:"flex items-center justify-between h-8",children:e.jsxs(K,{htmlFor:"baseUrl",children:["최종 목적지 URL *",e.
2jsx("span",{className:"text-xs text-muted-foreground ml-2",children:"(공식 홈페이지)"})]})}),e.jsx(F,{id:"baseUrl",value:m,onChange:C=>d(C.target.value),placeholder:"https://wedraw.kr"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between h-8",children:[e.jsxs(K,{htmlFor:"source",children:["UTM Source *",e.jsx("span",{className:"text-xs text-muted-foreground ml-2",children:"(유입 출처)"})]}),e.jsx(Rr,{sources:n,onSourcesChange:o,urls:i})]}),e.jsxs(ie,{value:g,onValueChange:c,children:[e.jsx(ce,{children:e.jsx(oe,{placeholder:"소스 선택 (예: 맘카페, 인스타그램)"})}),e.jsx(de,{children:n.map(C=>e.jsx(Y,{value:C.id,children:C.name},C.id))})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between h-8",children:[e.jsx(K,{htmlFor:"medium",children:"UTM Channel *"}),e.jsx(Xt,{channels:a,onChannelsChange:r,urls:i})]}),e.jsxs(ie,{value:x,onValueChange:N,children:[e.jsx(ce,{children:e.jsx(oe,{placeholder:"채널 선택"})}),e.jsx(de,{children:a.map(C=>e.jsx(Y,{value:C.id,children:C.name},C.id))})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("div",{className:"flex items-center justify-between h-8",children:e.jsx(K,{htmlFor:"campaign",children:"UTM Campaign *"})}),e.jsx(F,{id:"campaign",value:j,onChange:C=>p(C.target.value),placeholder:"예: trolley_launch"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("div",{className:"flex items-center justify-between h-8",children:e.jsx(K,{htmlFor:"manager",children:"담당자 *"})}),e.jsx(F,{id:"manager",value:u,onChange:C=>b(C.target.value),placeholder:"담당자 이름"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between h-8",children:[e.jsx(K,{htmlFor:"product",children:"제품 *"}),e.jsx(ea,{products:t,onProductsChange:l,urls:i})]}),e.jsxs(ie,{value:T,onValueChange:P,children:[e.jsx(ce,{children:e.jsx(oe,{placeholder:"제품 선택"})}),e.jsx(de,{children:t.filter(C=>C.id!=="all").map(C=>e.jsx(Y,{value:C.id,children:C.name},C.id))})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("div",{className:"flex items-center justify-between h-8",children:e.jsx(K,{htmlFor:"memo",children:"메모"})}),e.jsx(F,{id:"memo",value:$,onChange:C=>D(C.target.value),placeholder:"캠페인 관련 메모"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("div",{className:"flex items-center justify-between h-8",children:e.jsx(K,{htmlFor:"postUrl",children:"게시글 URL"})}),e.jsx(F,{id:"postUrl",value:V,onChange:C=>k(C.target.value),placeholder:"https://blog.naver.com/..."})]})]}),e.jsx("div",{children:e.jsxs(_,{onClick:E,className:"w-full cursor-pointer",disabled:ae,children:[e.jsx(Wa,{className:"h-4 w-4 mr-2"}),ae?"생성 중...":S?"2개 URL 동시 생성 및 등록 (Short URL 포함)":"URL 생성 및 등록 (Short URL 포함)"]})}),S&&(f||L)&&e.jsxs("div",{className:"space-y-3 p-4 bg-green-50 border border-green-200 rounded-lg",children:[e.jsxs("div",{className:"flex items-center gap-2 text-green-700",children:[e.jsx(Fs,{className:"h-5 w-5"}),e.jsx("span",{children:"2단계 UTM URL과 Short URL이 생성되었습니다!"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"px-2 py-1 bg-blue-100 text-blue-700 rounded text-xs",children:"1단계"}),e.jsx("span",{className:"text-sm",children:"외부에서 중간 경유지로 (카페/SNS 등에 게시)"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-600 mb-1",children:"📋 원본 URL:"}),e.jsx("div",{className:"p-3 bg-white rounded border break-all text-sm",children:f})]}),G&&e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-600 mb-1",children:"🔗 Short URL (공유용):"}),e.jsx("div",{className:"p-3 bg-blue-50 rounded border border-blue-200 break-all text-sm font-mono",children:G})]})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[e.jsxs(_,{onClick:()=>B(f,"1단계 원본"),variant:"outline",size:"sm",className:"cursor-pointer",children:[e.jsx(ee,{className:"h-4 w-4 mr-2"}),"원본 복사"]}),G&&e.jsxs(_,{onClick:()=>B(G,"1단계 Short"),variant:"default",size:"sm",className:"cursor-pointer",children:[e.jsx(ee,{className:"h-4 w-4 mr-2"}),"Short URL 복사"]})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("div",{className:"px-2 py-1 bg-purple-100 text-purple-700 rounded text-xs",children:"2단계"}),e.jsx("span",{className:"text-sm",children:"중간 경유지에서 최종 목적지로 (블로그 등에 게시)"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-600 mb-1",children:"📋 원본 URL:"}),e.jsx("div",{className:"p-3 bg-white rounded border break-all text-sm",children:L})]}),se&&e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-600 mb-1",children:"🔗 Short URL (공유용):"}),e.jsx("div",{className:"p-3 bg-blue-50 rounded border border-blue-200 break-all text-sm font-mono",children:se})]})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[e.jsxs(_,{onClick:()=>B(L,"2단계 원본"),variant:"outline",size:"sm",className:"cursor-pointer",children:[e.jsx(ee,{className:"h-4 w-4 mr-2"}),"원본 복사"]}),se&&e.jsxs(_,{onClick:()=>
2B(se,"2단계 Short"),variant:"default",size:"sm",className:"cursor-pointer",children:[e.jsx(ee,{className:"h-4 w-4 mr-2"}),"Short URL 복사"]})]})]}),e.jsxs("div",{className:"pt-2 text-xs text-gray-600 border-t",children:["💡 ",e.jsx("strong",{children:"사용 방법:"})," 1단계 Short URL은 카페/SNS에 공유하세요. 사용자가 클릭하면 경유지로 이동한 후, 자동으로 최종 목적지로 연결됩니다. 두 URL 모두 리스트에 자동 등록되었습니다."]})]}),!S&&w&&e.jsxs("div",{className:"p-4 bg-green-50 border border-green-200 rounded-lg space-y-3",children:[e.jsxs("div",{className:"flex items-center gap-2 text-green-700",children:[e.jsx(Fs,{className:"h-5 w-5"}),e.jsx("span",{children:"UTM URL과 Short URL이 생성되었습니다!"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-600 mb-1",children:"📋 원본 UTM URL:"}),e.jsx("div",{className:"p-3 bg-white rounded border break-all text-sm",children:w})]}),R&&e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-600 mb-1",children:"🔗 Short URL (공유용):"}),e.jsx("div",{className:"p-3 bg-blue-50 rounded border border-blue-200 break-all text-sm font-mono",children:R})]})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[e.jsxs(_,{onClick:()=>B(w,"원본"),variant:"outline",size:"sm",className:"cursor-pointer",children:[e.jsx(ee,{className:"h-4 w-4 mr-2"}),"원본 URL 복사"]}),R&&e.jsxs(_,{onClick:()=>B(R,"Short"),variant:"default",size:"sm",className:"cursor-pointer",children:[e.jsx(ee,{className:"h-4 w-4 mr-2"}),"Short URL 복사"]})]}),e.jsxs("div",{className:"pt-2 text-xs text-gray-600 border-t",children:["💡 ",e.jsx("strong",{children:"사용 방법:"})," Short URL을 복사하여 마케팅 채널에 공유하세요. 리스트에 자동 등록되었습니다."]})]})]})}function Ur({onUrlAdded:s,products:t,channels:a,onChannelsChange:r,onProductsChange:l,urls:n}){const[o,i]=h.useState(""),[m,d]=h.useState(""),[g,c]=h.useState(""),[x,N]=h.useState(""),[j,p]=h.useState(""),[u,b]=h.useState(""),[T,P]=h.useState(""),$=()=>{if(!o||!m||!g||!x||!j){U.error("모든 항목을 입력해주세요");return}const D={id:Date.now(),url:o,campaign:m,channel:g,source:new URL(o).searchParams.get("utm_source")||"직접입력",manager:x,product:j,createdAt:new Date().toLocaleDateString("ko-KR"),clicks:0,conversions:0};s(D),U.success("URL이 등록되었습니다!"),i(""),d(""),c(""),N(""),p(""),b(""),P("")};return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4",children:[e.jsxs("div",{className:"space-y-2 md:col-span-2",children:[e.jsx(K,{htmlFor:"manual-url",className:"py-2",children:"UTM URL *"}),e.jsx(F,{id:"manual-url",value:o,onChange:D=>i(D.target.value),placeholder:"https://wedraw.kr?utm_source=instagram&utm_medium=social..."})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(K,{htmlFor:"manual-campaign",className:"py-2",children:"UTM Campaign *"}),e.jsx(F,{id:"manual-campaign",value:m,onChange:D=>d(D.target.value),placeholder:"예: 슬라이딩 선반 런칭"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(K,{htmlFor:"manual-channel",className:"py-2",children:"UTM Channel *"}),e.jsx(Xt,{channels:a,onChannelsChange:r,urls:n})]}),e.jsxs(ie,{value:g,onValueChange:c,children:[e.jsx(ce,{children:e.jsx(oe,{placeholder:"채널 선택"})}),e.jsx(de,{children:a.map(D=>e.jsx(Y,{value:D.id,children:D.name},D.id))})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(K,{htmlFor:"manual-manager",className:"py-2",children:"담당자 *"}),e.jsx(F,{id:"manual-manager",value:x,onChange:D=>N(D.target.value),placeholder:"담당자 이름"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(K,{htmlFor:"manual-product",className:"py-2",children:"제품 *"}),e.jsx(ea,{products:t,onProductsChange:l,urls:n})]}),e.jsxs(ie,{value:j,onValueChange:p,children:[e.jsx(ce,{children:e.jsx(oe,{placeholder:"제품 선택"})}),e.jsx(de,{children:t.filter(D=>D.id!=="all").map(D=>e.jsx(Y,{value:D.id,children:D.name},D.id))})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(K,{htmlFor:"manual-memo",className:"py-2",children:"메모"}),e.jsx(F,{id:"manual-memo",value:u,onChange:D=>b(D.target.value),placeholder:"캠페인 관련 메모"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(K,{htmlFor:"manual-postUrl",className:"py-2",children:"게시글 URL"}),e.jsx(F,{id:"manual-postUrl",value:T,onChange:D=>P(D.target.value),placeholder:"https://blog.naver.com/..."})]})]}),e.jsx("div",{children:e.jsx(_,{onClick:$,className:"w-full md:w-auto",children:"URL 등록하기"})})]})}function Tr({url:s,products:t,channels:a,open:r,onOpenChange:l,onSave:n}){const[o,i]=h.useState(s.campaign),[m,d]=h.useState(s.product),[g,c]=h.useState(s.channel),[x,N]=h.useState(s.source),[j,p]=h.useState(s.manager),[u,b]=h.useState(s.memo||""),[T,P]=h.useState(s.postUrl||""),[$,D]=h.useState(s.totalImpressions||0),[V,k]=h.useState(!1),w=async()=>{s.id,s.id;const S=Number(s.id);if(!(!isNaN(S)&&S>0&&Number.isInteger(S))){U.error("이 URL은 아직 데이터베이스에 저장되지 않았습니다. 수정하려면 먼저 해당 URL을 삭제하고, UTM 생성 탭에서 새로 만들어주세요.");return}try{if(k(!0),s.campaignId){s.campaignId;const L=await Zt(s.campaignId,{memo:u||void 0,post_url:T||void 0,total_impressions:$})}const y="https://wedraw.co.kr",M=new URLSearchParams({utm_source:x,utm_medium:g,utm_campaign:o.toLowerCase().replace(/\s+/g,"_")}),f=`${y}?${M.toString()}`,v={...s,campaign:o,product:m,channel:g,source:x,manager:j,memo:u,postUrl:T,totalImpressions:$,url:f};n(v),l(!1)}catch(y){console.error("❌ [EditUrlDialog] Save failed:",y),U.error(y.message||"저장에 실패했습니다.")}finally{k(!1)}},I=()=>{i(s.campaign),d(s.product),c(s.channel),N(s.source),p(s.manager),b(s.memo||""),P(s.postUrl||""),D(s.totalImpressions||0),l(!1)};return e.jsx(Me,{open:r,onOpenChange:l,children:e.jsxs(Ie,{className:"sm:max-w-[500px]",children:[e.jsxs(Pe,{children:[e.jsx(Oe,{children:"UTM URL 수정"}),e.jsx(Fe,{children:"캠페인 정보를 수정하면 UTM URL이 자동으로 업데이트됩니다."})]}),e.jsxs("div",{className:"space-y-4 py-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx(K,{htmlFor:"campaign",children:"캠페인명"}),e.jsx(F,{id:"campaign",value:o,onChange:S=>i(S.target.value),placeholder:"예: 슬라이딩 선반 런칭"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(K,{htmlFor:"product",children:"제품"}),e.jsxs(ie,{value:m,onValueChange:d,children:[e.jsx(ce,{id:"product",children:e.jsx(oe,{})}),e.jsx(de,{children:t.filter(S=>S.id!=="all").map(S=>e.jsx(Y,{value:S.id,children:S.name},S.id))})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(K,{htmlFor:"channel",children:"채널"}),e.jsxs(ie,{value:g,onValueChange:c,children:[e.jsx(ce,{id:"channel",children:e.jsx(oe,{})}),e.jsx(de,{children:a.map(S=>e.jsx(Y,{value:S.id,children:S.name},S.id))})]})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(K,{htmlFor:"source",children:"소스"}),e.jsx(F,{id:"source",value:x,onChange:S=>N(S.target.value),placeholder:"예: instagram, blog, youtube"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(K,{htmlFor:"manager",children:"담당자"}),e.jsx(F,{id:"manager",value:j,onChange:S=>p(S.target.value),placeholder:"담당자 이름"})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(K,{htmlFor:"memo",children:"메모"}),e.jsx(Ls,{id:"memo",value:u,onChange:S=>b(S.target.value),placeholder:"캠페인 관련 메모",rows:3})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx(K,{htmlFor:"postUrl",children:"게시글 URL"}),e.jsx(F,{id:"postUrl",value:T,onChange:S=>P(S.target.value),placeholder:"https://blog.naver.com/..."})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsxs(K,{htmlFor:"totalImpressions",children:["총 노출 수",e.jsx("span",{className:"text-xs text-muted-foreground ml-2",children:"(광고 플랫폼의 노출 수)"})]}),e.jsx(F,{id:"totalImpressions",type:"number",min:"0",value:$,onChange:S=>{const Q=S.target.value===""?0:parseInt(S.target.value,10);D(isNaN(Q)?0:Q)},placeholder:"0"}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"퍼널 시각화에 사용됩니다. 0이면 노출 단계가 표시되지 않습니다."})]})]}),e.jsxs(ka,{children:[e.jsx(_,{variant:"outline",onClick:I,disabled:V,children:"취소"}),e.jsx(_,{onClick:w,disabled:V,children:V?"저장 중...":"저장"})]})]})})}const Ve={sliding_shelf:"슬라이딩 선반",trones_top:"이케아 TRONES 상판",helmer_top:"이케아 HELMER 상판",lennart_top:"이케아 LENNART 맞춤 상판",kids_shoebench:"어린이 슈벤치",multipurpose_shelf:"다용도 ㄷ자 선반",fridge_gap:"냉장고 틈새장"};function Lr({urls:s,channels:t,products:a,onUrlUpdate:r}){const l=h.useMemo(()=>{const p={};return t.forEach(u=>{const b=u.color.replace("bg-","border-"),T=u.color.replace("bg-","text-");p[u.id]={bg:"",text:T,border:b}}),p},[t]),n=h.useMemo(()=>{const p={};return t.forEach(u=>{p[u.id]=u.name}),p},[t]),[o,i]=h.useState(""),[m,d]=h.useState(null),[g,c]=h.useState(null),x=h.useMemo(()=>{const p={},u=[];
2return s.forEach(b=>{b.isTwoStep&&b.groupId?(p[b.groupId]||(p[b.groupId]=[]),p[b.groupId].push(b)):u.push(b)}),Object.keys(p).forEach(b=>{p[b].sort((T,P)=>T.step-P.step)}),{groups:p,singles:u}},[s]),N=h.useMemo(()=>{const p=[];return x.singles.forEach(u=>{(u.campaign.toLowerCase().includes(o.toLowerCase())||u.source.toLowerCase().includes(o.toLowerCase())||u.manager.toLowerCase().includes(o.toLowerCase()))&&p.push(u)}),Object.entries(x.groups).forEach(([u,b])=>{const T=b[0];(T.campaign.toLowerCase().includes(o.toLowerCase())||T.source.toLowerCase().includes(o.toLowerCase())||T.manager.toLowerCase().includes(o.toLowerCase()))&&p.push({isGroup:!0,groupId:u,urls:b})}),p.sort((u,b)=>{const T=u.isGroup?new Date(u.urls[0].createdAt).getTime():new Date(u.createdAt).getTime();return(b.isGroup?new Date(b.urls[0].createdAt).getTime():new Date(b.createdAt).getTime())-T})},[x,o]),j=async p=>{try{await navigator.clipboard.writeText(p),U.success("URL이 클립보드에 복사되었습니다!")}catch{try{const b=document.createElement("textarea");b.value=p,b.style.position="fixed",b.style.left="-999999px",b.style.top="-999999px",document.body.appendChild(b),b.focus(),b.select();const T=document.execCommand("copy");document.body.removeChild(b),T?U.success("URL이 클립보드에 복사되었습니다!"):U.error("클립보드 복사에 실패했습니다. URL을 직접 복사해주세요.")}catch{U.error("클립보드 복사에 실패했습니다. URL을 직접 복사해주세요.")}}};return e.jsxs(me,{children:[e.jsx(xe,{children:e.jsxs("div",{className:"flex flex-col md:flex-row md:items-center justify-between gap-4",children:[e.jsx(ue,{children:"UTM URL 리스트 & 상세 보기"}),e.jsxs("div",{className:"relative w-full md:w-64",children:[e.jsx(Ha,{className:"absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-muted-foreground"}),e.jsx(F,{placeholder:"캠페인/소스/담당자 검색...",value:o,onChange:p=>i(p.target.value),className:"pl-9 pr-9"}),o&&e.jsx("button",{type:"button",onClick:()=>i(""),className:"absolute right-3 top-1/2 transform -translate-y-1/2 p-0.5 rounded hover:bg-gray-100 text-muted-foreground hover:text-gray-600",title:"검색어 지우기",children:e.jsx(ss,{className:"h-4 w-4"})})]})]})}),e.jsx(he,{children:N.length===0?e.jsxs("div",{className:"text-center py-12 text-muted-foreground",children:[e.jsx("p",{children:"등록된 URL이 없습니다."}),e.jsx("p",{className:"text-sm mt-2",children:"위의 생성기 또는 등록 폼을 사용하여 URL을 추가하세요."})]}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"hidden lg:block overflow-x-auto",children:e.jsxs(Wt,{children:[e.jsx(Ht,{children:e.jsxs(Le,{children:[e.jsx(le,{children:"캠페인명"}),e.jsx(le,{children:"제품"}),e.jsx(le,{children:"채널"}),e.jsx(le,{children:"소스"}),e.jsx(le,{children:"생성일"}),e.jsx(le,{children:"담당자"}),e.jsx(le,{children:"URL"}),e.jsx(le,{className:"text-center",children:"액션"})]})}),e.jsx(qt,{children:N.map(p=>{if(p.isGroup&&p.urls&&p.urls.length>=2){const u=p.urls[0],b=p.urls[0];return p.urls[1],e.jsxs(Le,{className:"hover:bg-accent/50",children:[e.jsx(q,{children:u.postUrl?e.jsx("a",{href:u.postUrl,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:underline cursor-pointer",children:u.campaign||"(제목 없음)"}):e.jsx("span",{children:u.campaign||"(제목 없음)"})}),e.jsx(q,{children:e.jsx("span",{className:"text-sm",children:Ve[u.product]||u.product})}),e.jsx(q,{children:e.jsx(je,{variant:"outline",className:`${l[u.channel]?.text||"text-gray-700"} ${l[u.channel]?.border||"border-gray-300"}`,children:n[u.channel]||u.channel})}),e.jsx(q,{children:e.jsx("span",{className:"text-sm text-muted-foreground",children:u.source})}),e.jsx(q,{children:e.jsx("span",{className:"text-sm",children:u.createdAt})}),e.jsx(q,{children:e.jsx("span",{className:"text-sm",children:u.manager})}),e.jsx(q,{children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(je,{variant:"outline",className:"bg-blue-100 text-blue-700 border-blue-300 shrink-0 text-xs",children:"2단계유입"}),e.jsx("span",{className:"text-xs font-mono text-blue-600 truncate flex-1 max-w-[250px]",children:b.shortUrl||b.url}),e.jsx(_,{variant:"ghost",size:"sm",onClick:()=>j(b.shortUrl||b.url),className:"shrink-0",title:"공유용 Short URL 복사",children:e.jsx(ee,{className:"h-3 w-3 text-blue-600"})})]})}),e.jsx(q,{children:e.jsxs("div",{className:"flex items-center justify-center gap-1",children:[e.jsx(_,{variant:"ghost",size:"sm",onClick:()=>d(u),title:"수정",children:e.jsx(Te,{className:"h-4 w-4"})}),e.jsx(_,{variant:"ghost",size:"sm",onClick:()=>c({...u,groupUrls:p.urls}),title:"상세보기",children:e.jsx(cs,{className:"h-4 w-4"})})]})})]},p.groupId)}else{const u=p;return e.jsxs(Le,{className:"hover:bg-accent/50",children:[e.jsx(q,{children:u.postUrl?e.jsx("a",{href:u.postUrl,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:underline cursor-pointer",children:u.campaign||"(
2제목 없음)"}):e.jsx("span",{children:u.campaign||"(제목 없음)"})}),e.jsx(q,{children:e.jsx("span",{className:"text-sm",children:Ve[u.product]||u.product})}),e.jsx(q,{children:e.jsx(je,{variant:"outline",className:`${l[u.channel]?.text||"text-gray-700"} ${l[u.channel]?.border||"border-gray-300"}`,children:n[u.channel]||u.channel})}),e.jsx(q,{children:e.jsx("span",{className:"text-sm text-muted-foreground",children:u.source})}),e.jsx(q,{children:e.jsx("span",{className:"text-sm",children:u.createdAt})}),e.jsx(q,{children:e.jsx("span",{className:"text-sm",children:u.manager})}),e.jsx(q,{children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-xs font-mono text-green-600 truncate flex-1 max-w-[300px]",children:(u.shortUrl,u.url,u.shortUrl||u.url)}),e.jsx(_,{variant:"ghost",size:"sm",onClick:()=>j(u.shortUrl||u.url),className:"shrink-0",title:"Short URL 복사",children:e.jsx(ee,{className:"h-3 w-3 text-green-600"})})]})}),e.jsx(q,{children:e.jsxs("div",{className:"flex items-center justify-center gap-1",children:[e.jsx(_,{variant:"ghost",size:"sm",onClick:()=>d(u),title:"수정",children:e.jsx(Te,{className:"h-4 w-4"})}),e.jsx(_,{variant:"ghost",size:"sm",onClick:()=>c(u),title:"상세보기",children:e.jsx(cs,{className:"h-4 w-4"})})]})})]},u.id)}})})]})}),e.jsx("div",{className:"lg:hidden space-y-4",children:N.map(p=>{if(p.isGroup&&p.urls&&p.urls.length>=2){const u=p.urls[0];return e.jsxs("div",{className:"border rounded-lg p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[u.postUrl?e.jsx("a",{href:u.postUrl,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:underline cursor-pointer",children:e.jsx("h4",{className:"line-clamp-2",children:u.campaign})}):e.jsx("h4",{className:"line-clamp-2",children:u.campaign}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:Ve[u.product]||u.product})]}),e.jsx(je,{variant:"outline",className:`${l[u.channel]?.text||"text-gray-700"} ${l[u.channel]?.border||"border-gray-300"} flex-shrink-0`,children:n[u.channel]||u.channel})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 text-sm",children:[e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"소스:"})," ",u.source]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"담당자:"})," ",u.manager]})]}),e.jsxs("div",{className:"flex items-center gap-2 p-2 rounded bg-blue-50 border border-blue-200",children:[e.jsx(je,{variant:"outline",className:"bg-blue-100 text-blue-700 border-blue-300 shrink-0 text-xs",children:"2단계유입"}),e.jsx("span",{className:"truncate flex-1 text-xs font-mono text-blue-600",children:u.shortUrl||u.url}),e.jsx(_,{variant:"ghost",size:"sm",onClick:()=>j(u.shortUrl||u.url),title:"공유용 Short URL 복사",children:e.jsx(ee,{className:"h-3 w-3 text-blue-600"})})]}),e.jsx("div",{className:"flex items-center justify-end gap-2 pt-2",children:e.jsxs(_,{variant:"outline",size:"sm",onClick:()=>c({...u,groupUrls:p.urls}),className:"flex-1",children:[e.jsx(cs,{className:"h-3 w-3 mr-1"}),"상세"]})})]},p.groupId)}else{const u=p;return e.jsxs("div",{className:"border rounded-lg p-4 space-y-3",children:[e.jsxs("div",{className:"flex items-start justify-between gap-2",children:[e.jsxs("div",{className:"flex-1 min-w-0",children:[u.postUrl?e.jsx("a",{href:u.postUrl,target:"_blank",rel:"noopener noreferrer",className:"text-blue-600 hover:underline cursor-pointer",children:e.jsx("h4",{className:"line-clamp-2",children:u.campaign})}):e.jsx("h4",{className:"line-clamp-2",children:u.campaign}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:Ve[u.product]||u.product})]}),e.jsx(je,{variant:"outline",className:`${l[u.channel]?.text||"text-gray-700"} ${l[u.channel]?.border||"border-gray-300"} flex-shrink-0`,children:n[u.channel]||u.channel})]}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 text-sm",children:[e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"소스:"})," ",u.source]}),e.jsxs("div",{children:[e.jsx("span",{className:"text-muted-foreground",children:"담당자:"})," ",u.manager]}),e.jsxs("div",{className:"col-span-2",children:[e.jsx("span",{className:"text-muted-foreground",children:"생성일:"})," ",u.createdAt]})]}),e.jsxs("div",{className:"flex items-center gap-2 bg-green-50 p-2 rounded",children:[e.jsx("span",{className:"text-green-600 truncate flex-1 text-xs font-mono",children:u.shortUrl||u.url}),e.jsx(_,{variant:"ghost",size:"sm",onClick:()=>j(u.shortUrl||u.url),children:e.jsx(ee,{className:"h-3 w-3 text-green-600"})})]}),e.jsxs("div",{className:"flex items-center justify-end gap-2 pt-2",children:[e.jsxs(_,{variant:"outline",size:"sm",onClick:()=>d(u),className:"flex-1",children:[e.jsx(Te,{className:"h-3 w-3 mr-1"}),"수정"]}),e.jsxs(_,{variant:"outline",size:"sm",onClick:()=>c(u),className:"flex-1",children:[e.jsx(cs,{className:"h-3 w-3 mr-1"}),"상세"]})]})]},u.id)}})})]})}),m&&e.jsx(Tr,{url:m,products:a,channels:t,open:!!m,onOpenChange:p=>!p&&d(null),onSave:r}),g&&e.jsx(Qt,{url:g,channelName:n[g.channel]||g.channel,channelColor:l[g.channel]||{bg:"",text:"text-gray-700",border:"border-gray-300"},productName:Ve[g.product]||g.product,open:!!g,onOpenChange:p=>!p&&c(null)})]})}function Ar({urls:s,allUrls:t,onUrlAdded:a,onUrlUpdate:r,products:l,selectedProduct:n,channels:o,onChannelsC
2hange:i,onProductsChange:m,sources:d,onSourcesChange:g}){const[c,x]=h.useState(!1),N=j=>{a(j),x(!1)};return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("div",{children:[e.jsx("h2",{children:"캠페인 리스트 관리"}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:"등록된 캠페인을 관리하고 성과를 추적하세요"})]}),e.jsx(qa,{children:e.jsxs(Me,{open:c,onOpenChange:x,children:[e.jsx(Ca,{asChild:!0,children:e.jsxs(_,{className:"cursor-pointer",children:[e.jsx(ke,{className:"h-4 w-4 mr-2"}),"캠페인 생성/등록"]})}),e.jsxs(Ie,{className:"w-[70vw] max-w-[800px] max-h-[85vh] overflow-y-auto",children:[e.jsxs(Pe,{children:[e.jsx(Oe,{children:"캠페인 생성 및 등록"}),e.jsx(Fe,{children:"자동 생성 또는 수동 등록으로 캠페인을 추가하세요"})]}),e.jsxs(Et,{defaultValue:"generator",className:"w-full",children:[e.jsxs(Mt,{className:"grid w-full grid-cols-2",children:[e.jsxs(re,{value:"generator",className:"gap-2 cursor-pointer",children:[e.jsx(Ja,{className:"h-4 w-4"}),"자동 생성"]}),e.jsxs(re,{value:"manual",className:"gap-2 cursor-pointer",children:[e.jsx(pr,{className:"h-4 w-4"}),"수동 등록"]})]}),e.jsx(ne,{value:"generator",className:"mt-6",children:e.jsx($r,{onUrlAdded:N,products:l,channels:o,onChannelsChange:i,onProductsChange:m,sources:d,onSourcesChange:g,urls:t})}),e.jsx(ne,{value:"manual",className:"mt-6",children:e.jsx(Ur,{onUrlAdded:N,products:l,channels:o,onChannelsChange:i,onProductsChange:m,urls:t})})]})]})]})})]}),e.jsx(Lr,{urls:s,channels:o,products:l,onUrlUpdate:r})]})}function Er({value:s,onChange:t}){const a=l=>{t(l)},r=()=>({all:"전체 기간",yesterday:"어제",last7days:"최근 7일",last30days:"최근 30일",thisMonth:"이번 달"})[s];return e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Pt,{className:"h-4 w-4 text-muted-foreground"}),e.jsxs(ie,{value:s,onValueChange:a,children:[e.jsx(ce,{className:"w-[200px]",children:e.jsx(oe,{children:r()})}),e.jsxs(de,{children:[e.jsx(Y,{value:"all",children:"전체 기간"}),e.jsx(Y,{value:"yesterday",children:"어제"}),e.jsx(Y,{value:"last7days",children:"최근 7일"}),e.jsx(Y,{value:"last30days",children:"최근 30일"}),e.jsx(Y,{value:"thisMonth",children:"이번 달"})]})]})]})}const sa={naver:"네이버",meta:"메타",google:"구글",coupang:"쿠팡",service:"서비스개발",team:"팀 공통"},rt={naver:"박서연(네이버) 프로",meta:"이도윤(메타) 프로",google:"최하은(구글) 프로",coupang:"한지우(쿠팡) 프로",service:"정우진(서비스개발) 프로",team:"강민준(퍼포먼스) 파트장"},Mr={proposed:"승인 대기",approved:"실행 예정",rejected:"반려",executed:"관찰 중",judged:"판정 완료"},ta={improved:"개선",unchanged:"무변화",worsened:"악화"},zs={naver:3,meta:7,google:3,coupang:3,service:7,team:3},Js="tp_marketing_queue";function Zs(s){return{id:s.id,owner:s.owner,channel:s.channel,title:s.title,whatToDo:s.what_to_do,whereToDo:s.where_to_do,howToRevert:s.how_to_revert,whatToWatch:s.what_to_watch,status:s.status,proposedAt:s.proposed_at,decidedAt:s.decided_at,decidedNote:s.decided_note,executedAt:s.executed_at,observeUntil:s.observe_until,result:s.result,resultNote:s.result_note,judgedAt:s.judged_at,updatedAt:s.updated_at}}async function Ir(){const{data:s,error:t}=await H.from(Js).select("*").order("proposed_at",{ascending:!1});if(t)throw new Error(`실행 큐 조회 실패: ${t.message}`);return(s??[]).map(Zs)}async function Pr(s){const{data:t,error:a}=await H.from(Js).insert({owner:s.owner,channel:s.channel,title:s.title,what_to_do:s.whatToDo,where_to_do:s.whereToDo,how_to_revert:s.howToRevert,what_to_watch:s.whatToWatch,status:"proposed"}).select().maybeSingle();if(a)throw new Error(`제안 등록 실패: ${a.message}`);if(!t)throw new Error("제안 등록 실패: 저장된 행을 돌려받지 못했습니다");return Zs(t)}async function As(s,t){const{data:a,error:r}=await H.from(Js).update({...t,updated_at:new Date().toISOString()}).eq("id",s).select().maybeSingle();if(r)throw new Error(`큐 갱신 실패: ${r.message}`);if(!a)throw new Error(`큐 갱신 실패: id ${s} 행을 찾지 못했습니다`);return Zs(a)}function Or(s,t){return As(s,{status:"approved",decided_at:new Date().toISOString(),decided_note:t??null})}function Fr(s,t){return As(s,{status:"rejected",decided_at:new Date().toISOString(),decided_note:t})}function Kr(s){const t=zs[s.channel]??3,a=new Date;return a.setDate(a.getDate()+t),As(s.id,{status:"executed",executed_at:new Date().toISOString(),observe_until:a.toISOString().slice(0,10)})}function zr(s,t,a){return As(s,{status:"judged",result:t,result_note:a,judged_at:new Date().toISOString()})}function Br(){const s=new Date;return new Date(s.getTime()+(s.getTimezoneOffset()+540)*6e4).toISOString().slice(0,10)}function Vr(){const[s,t]=h.useState([]),[a,r]=h.useState(!0),[l,n]=h.useState(null),[o,i]=h.useState(null),m=h.useCallback(async()=>{r(!0),n(null);try{t(await Ir())}catch(c){n(c instanceof Error?c.message:String(c))}finally{r(!1)}},[]);h.useEffect(()=>{m()},[m]);const d=h.useCallback(async(c,x)=>{i(c),n(null);try{return await x(),await m(),!0}catch(N){return n(N instanceof Error?N.message:String(N)),!1}finally{i(null)}},[m]),g=h.useMemo(()=>{const c=Br();return{pending:s.filter(x=>x.status==="proposed"),approved:s.filter(x=>x.status==="approved"),observing:s.filter(x=>x.status==="executed"),dueForJudgement:s.filter(x=>x.status==="executed"&&x.observeUntil!==null&&x.observeUntil<=c),done:s.filter(x=>x.status==="judged"||x.status==="rejected")}},[s]);return{items:s,grouped:g,loading:a,error:l,busyId:o,reload:m,propose:c=>d(null,()=>Pr(c)),approve:(c,x)=>d(c,()=>Or(c,x)),reject:(c,x)=>d(c,()=>Fr(c,x)),markExecuted:c=>d(c.id,()=>Kr(c)),judge:(c,x,N)=>d(c,()=>zr(c,x,N))}}const Gr=["naver","meta","google","coupang","service","team"],Wr={proposed:"bg-amber-100 text-amber-800",approved:"bg-blue-100 text-blue-800",executed:"bg-violet-100 text-violet-800",judged:"bg-gray-100 text-gray-600",rejected:"bg-gray-100 text-gray-500"},Hr={improved:"bg-emerald-100 text-emerald-800",unchanged:"bg-gray-100 text-gray-600",worsened:"bg-red-100 text-red-800"},aa=s=>s?s.slice(0,10):"—",nt=[{key:"whatToDo",label:"무엇을",ph:"예: 주말 입찰 가중치 85% 로 조정"},{key:"whereToDo",label:"어디서",ph:"예: 쇼핑검색 캠페인 전체"},{key:"howToRevert",label:"되돌리기",ph:"예: 가중치 100% 복원, 즉시 반영"},{key:"whatToWatch",label:"관찰",ph:"예: 2주간 주말 ROAS 445% → 520% 이상"}];function qr(){const s=Vr(),[t,a]=h.useState(!1),[r,l]=h.useState({channel:"naver",title:"",whatToDo:"",whereToDo:"",howToRevert:"",whatToWatch:""}),[n,o]=h.useState({}),i=c=>n[c]??"",m=(c,x)=>o(N=>({...N,[c]:x})),d=r.title.trim()!==""&&nt.every(c=>r[c.key].trim()!=="");async function g(){await s.propose({...r,owner:rt[r.channel]})&&(a(!1),l({channel:"naver",title:"",whatToDo:"",whereToDo:"",howToRevert:"",whatToWatch:""}))}return e.jsxs("div",{className:"space-y-6",children:[s.error&&e.jsxs("div",{className:"flex items-start gap-2 rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-800",children:[e.jsx(we,{className:"mt-0.5 h-4 w-4 shrink-0"}),e.jsx("span",{children:s.error})]}),e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsx("p",{className:"text-sm text-gray-500",children:"큐에 기록 없는 예산·입찰 변경은 집행하지 않는다. 제안은 4줄로 올린다."}),e.jsxs(_,{size:"sm",onClick:()=>a(c=>!c),children:[t?e.jsx(ss,{className:"mr-1 h-4 w-4"}):e.jsx(ke,{className:"mr-1 h-4 w-4"}),t?"닫기":"제안 올리기"]})]}),t&&e.jsxs("div",{className:"space-y-3 rounded-lg border bg-white p-4",children:[e.jsxs("div",{className:"flex flex-wrap gap-3",children:[e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-xs text-gray-500",children:"채널"}),e.jsx("select",{className:"h-9 rounded-md border px-2 text-sm",value:r.channel,onChange:c=>l(x=>({...x,channel:c.target.value})),children:Gr.map(c=>e.jsx("option",{value:c,children:sa[c]},c))})]}),e.jsxs("div",{className:"flex-1 min-w-[240px]",children:[e.jsxs("label",{className:"mb-1 block text-xs text-gray-500",children:["제목 · 담당 ",rt[r.channel]]}),e.jsx(F,{value:r.title,onChange:c=>l(x=>({...x,title:c.target.value})),placeholder:"한 줄로 무엇을 바꾸는지"})]})]}),nt.map(c=>e.jsxs("div",{children:[e.jsxs("label",{className:"mb-1 block text-xs text-gray-500",children:["[",c.label,"]"]}),e.jsx(Ls,{rows:2,value:r[c.key],onChange:x=>l(N=>({...N,[c.key]:x.target.value})),placeholder:c.ph})]},c.key)),e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsxs("span",{className:"text-xs text-gray-500",children:["승인되면 관찰 기간 ",zs[r.channel],"일이 자동으로 잡힌다",r.channel==="meta"&&" (메타는 학습 리셋 때문에 길다)"]}),e.jsx(_,{size:"sm",disabled:!d||s.busyId!==null,onClick:g,children:"올리기"})]})]}),s.loading?e.jsxs("div",{className:"flex items-center gap-2 p-8 text-sm text-gray-500",children:[e.jsx(fe,{className:"h-4 w-4 animate-spin"})," 불러오는 중…"]}):e.jsxs(e.Fragment,{children:[e.jsx(Ge,{title:"승인 대기",count:s.grouped.pending.length,emphasis:!0,empty:"올라온 제안이 없다.",children:s.grouped.pending.map(c=>e.jsx(We,{item:c,children:e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(F,{className:"h-8 flex-1 min-w-[200px]",placeholder:"승인·반려 메모 (반려는 필수)",value:i(c.id),onChange:x=>m(c.id,x.target.value)}),e.jsxs(_,{size:"sm",disabled:s.busyId===c.id,onClick:()=>s.approve(c.id,i(c.id)||void 0),children:[e.jsx(Ds,{className:"mr-1 h-4 w-4"})," 승인"]}
2),e.jsx(_,{size:"sm",variant:"outline",disabled:s.busyId===c.id||i(c.id).trim()==="",onClick:()=>s.reject(c.id,i(c.id)),children:"반려"})]})},c.id))}),e.jsx(Ge,{title:"판정 대기 — 관찰 끝남",count:s.grouped.dueForJudgement.length,emphasis:!0,empty:"판정할 건이 없다.",children:s.grouped.dueForJudgement.map(c=>e.jsx(We,{item:c,children:e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(F,{className:"h-8 flex-1 min-w-[200px]",placeholder:"무엇이 어떻게 움직였나 (숫자로)",value:i(c.id),onChange:x=>m(c.id,x.target.value)}),["improved","unchanged","worsened"].map(x=>e.jsx(_,{size:"sm",variant:"outline",disabled:s.busyId===c.id||i(c.id).trim()==="",onClick:()=>s.judge(c.id,x,i(c.id)),children:ta[x]},x))]})},c.id))}),e.jsx(Ge,{title:"실행 예정",count:s.grouped.approved.length,empty:"없다.",children:s.grouped.approved.map(c=>e.jsx(We,{item:c,children:e.jsxs(_,{size:"sm",variant:"outline",disabled:s.busyId===c.id,onClick:()=>s.markExecuted(c),children:["실행함으로 표시 (관찰 ",zs[c.channel],"일 시작)"]})},c.id))}),e.jsx(Ge,{title:"관찰 중",count:s.grouped.observing.length-s.grouped.dueForJudgement.length,empty:"없다.",children:s.grouped.observing.filter(c=>!s.grouped.dueForJudgement.includes(c)).map(c=>e.jsx(We,{item:c,children:e.jsxs("p",{className:"text-xs text-gray-500",children:[aa(c.observeUntil),"까지 같은 대상을 다시 바꾸지 않는다."]})},c.id))}),e.jsx(Ge,{title:"지난 건",count:s.grouped.done.length,empty:"없다.",children:s.grouped.done.slice(0,20).map(c=>e.jsx(We,{item:c},c.id))})]})]})}function Ge({title:s,count:t,emphasis:a,empty:r,children:l}){return e.jsxs("section",{children:[e.jsxs("h3",{className:"mb-2 flex items-center gap-2 text-sm font-semibold",children:[s,e.jsx("span",{className:`rounded px-1.5 py-0.5 text-xs ${a&&t>0?"bg-red-500 text-white":"bg-gray-100 text-gray-600"}`,children:t})]}),t===0?e.jsx("p",{className:"rounded-lg border border-dashed p-4 text-sm text-gray-400",children:r}):e.jsx("div",{className:"space-y-2",children:l})]})}function We({item:s,children:t}){return e.jsxs("div",{className:"space-y-2 rounded-lg border bg-white p-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("span",{className:"rounded bg-gray-100 px-1.5 py-0.5 text-xs text-gray-700",children:sa[s.channel]}),e.jsx("span",{className:"font-medium",children:s.title}),e.jsx("span",{className:`rounded px-1.5 py-0.5 text-xs ${Wr[s.status]}`,children:Mr[s.status]}),s.result&&e.jsx("span",{className:`rounded px-1.5 py-0.5 text-xs ${Hr[s.result]}`,children:ta[s.result]}),e.jsxs("span",{className:"ml-auto text-xs text-gray-400",children:[s.owner," · ",aa(s.proposedAt)]})]}),e.jsxs("dl",{className:"grid gap-x-4 gap-y-1 text-xs sm:grid-cols-2",children:[e.jsx(ds,{label:"무엇을",value:s.whatToDo}),e.jsx(ds,{label:"어디서",value:s.whereToDo}),e.jsx(ds,{label:"되돌리기",value:s.howToRevert}),e.jsx(ds,{label:"관찰",value:s.whatToWatch})]}),s.decidedNote&&e.jsxs("p",{className:"text-xs text-gray-500",children:["팀장 메모: ",s.decidedNote]}),s.resultNote&&e.jsxs("p",{className:"text-xs text-gray-700",children:["판정: ",s.resultNote]}),t]})}function ds({label:s,value:t}){return e.jsxs("div",{className:"flex gap-1.5",children:[e.jsxs("dt",{className:"shrink-0 text-gray-400",children:["[",s,"]"]}),e.jsx("dd",{className:"text-gray-700",children:t})]})}function Yr(s){return{id:Number(s.id),statDate:String(s.stat_date),code:String(s.code),area:s.area,severity:s.severity,scope:String(s.scope??""),title:String(s.title),detail:String(s.detail??""),prescription:String(s.prescription??""),observed:s.observed===null||s.observed===void 0?null:Number(s.observed),baseline:s.baseline===null||s.baseline===void 0?null:Number(s.baseline),threshold:s.threshold===null||s.threshold===void 0?null:Number(s.threshold),unit:String(s.unit??""),baselineDates:Array.isArray(s.baseline_dates)?s.baseline_dates.map(String):[],sourceFreshUntil:s.source_fresh_until==null?null:String(s.source_fresh_until),suppressed:!!s.suppressed,suppressedReason:s.suppressed_reason==null?null:String(s.suppressed_reason),status:s.status,handledNote:s.handled_note==null?null:String(s.handled_note),falsePositive:!!s.false_positive,handledAt:s.handled_at==null?null:String(s.handled_at)}}async function Qs(s,t={}){return(await qs({action:"query",table:s,...t})).rows??[]}async function Jr(){const t=(await Qs("marketing_diagnostic_runs"))[0];return t?{statDate:String(t.stat_date),ranAt:String(t.ran_at),rulesRun:Number(t.rules_run),issuesFound:Number(t.issues_found),blocked:Number(t.blocked),sourceFreshness:t.source_freshness??{}}:null}async function Zr(s){return(await Qs("marketing_issues",{statDate:s})).map(Yr)}async function Qr(){return(await Qs("marketing_media_config")).map(t=>({media:String(t.media),owner:String(t.owner??""),collection:t.collection,active:!!t.active}))}async function Xr(s,t,a,r=!1){const l=a.trim();if(t!=="new"&&l==="")throw new Error("상태를 바꾸려면 메모가 필요합니다. 메모가 없으면 다음 날 새벽에 표시가 사라집니다.");await qs({action:"update",table:"marketing_issues",id:s,patch:{status:t,handled_note:l===""?null:l,false_positive:r,handled_at:t==="new"?null:new Date().toISOString()}})}function en(){const[s,t]=h.useState(null),[a,r]=h.useState([]),[l,n]=h.useState([]),[o,i]=h.useState(!0),[m,d]=h.useState(null),g=h.useCallback(async()=>{i(!0),d(null);try{const[p,u]=await Promise.all([Jr(),Qr()]);t(p),n(u),r(p?await Zr(p.statDate):[])}catch(p){d(p instanceof Error?p.message:"브리핑을 불러오지 못했습니다"),t(null),r([])}finally{i(!1)}},[]);h.useEffect(()=>{g()},[g]);const c=h.useCallback(async(p,u,b,T=!1)=>{await Xr(p,u,b,T),await g()},[g]),x=h.useMemo(()=>{const p=new Map(l.map(u=>[u.media,u.owner]));return u=>p.get(u)??""},[l]),N=h.useMemo(()=>{const p=a.filter(u=>!u.suppressed&&u.status!=="resolved"&&u.status!=="ignored");return{blocked:p.filter(u=>u.severity==="block"),check:p.filter(u=>u.severity==="check"),log:p.filter(u=>u.severity==="log"),suppressed:a.filter(u=>u.suppressed),closed:a.filter(u=>!u.suppressed&&(u.status==="resolved"||u.status==="ignored"))}},[a]),j=h.useMemo(()=>s?Object.entries(s.sourceFreshness).map(([p,u])=>{const b=u===null?null:Math.round((new Date(s.statDate).getTime()-new Date(u).getTime())/864e5);return{media:p,last:u,days:b,owner:x(p)}}).sort((p,u)=>(u.days??999)-(p.days??999)):[],[s,x]);return{run:s,issues:a,groups:N,freshness:j,ownerOf:x,loading:o,error:m,reload:g,changeStatus:c}}const sn={block:"차단",check:"확인",log:"기록"},tn={AD:"광고운영",RV:"매출",FN:"퍼널",DT:"데이터",OP:"운영"},ra={new:"미확인",ack:"확인중",resolved:"해결",ignored:"보류"},an={block:"bg-red-100 text-red-800",check:"bg-amber-100 text-amber-800",log:"bg-gray-100 text-gray-600"};
2function na(s){return new Date(s).toLocaleString("ko-KR",{timeZone:"Asia/Seoul"})}function rn({issue:s,owner:t,onChange:a}){const[r,l]=h.useState(""),[n,o]=h.useState(!1),[i,m]=h.useState(null),d=async(g,c=!1)=>{o(!0),m(null);try{await a(g,r,c),l("")}catch(x){m(x instanceof Error?x.message:"변경에 실패했습니다")}finally{o(!1)}};return e.jsxs("div",{className:"rounded-lg border p-4 space-y-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("span",{className:`rounded px-2 py-0.5 text-xs font-medium ${an[s.severity]}`,children:sn[s.severity]}),e.jsx("span",{className:"rounded bg-slate-100 px-2 py-0.5 text-xs text-slate-700",children:tn[s.area]}),e.jsx("span",{className:"font-mono text-xs text-slate-500",children:s.code}),s.scope&&e.jsx("span",{className:"rounded bg-slate-100 px-2 py-0.5 text-xs text-slate-700",children:s.scope}),t&&e.jsxs("span",{className:"ml-auto text-xs text-slate-500",children:["담당 ",t]})]}),e.jsx("p",{className:"font-medium",children:s.title}),s.detail&&e.jsx("p",{className:"text-sm text-slate-600 whitespace-pre-line",children:s.detail}),s.observed!==null&&e.jsxs("p",{className:"text-sm text-slate-700",children:["관측 ",e.jsxs("b",{children:[s.observed.toLocaleString(),s.unit]}),s.baseline!==null&&e.jsxs(e.Fragment,{children:[" · 기준 ",s.baseline.toLocaleString(),s.unit]}),s.threshold!==null&&e.jsxs(e.Fragment,{children:[" · 임계 ",s.threshold.toLocaleString(),s.unit]}),s.baselineDates.length>0&&e.jsxs("span",{className:"text-slate-500",children:[" · 비교일 ",s.baselineDates.join(", ")]})]}),s.prescription&&e.jsxs("div",{className:"rounded bg-slate-50 p-3 text-sm",children:[e.jsx("span",{className:"text-xs font-medium text-slate-500",children:"먼저 볼 것"}),e.jsx("p",{className:"mt-1 whitespace-pre-line",children:s.prescription})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-xs text-slate-500",children:[e.jsxs("span",{children:["상태 ",ra[s.status]]}),s.handledNote&&e.jsxs("span",{children:["· ",s.handledNote]}),s.handledAt&&e.jsxs("span",{children:["· ",na(s.handledAt)]})]}),e.jsx(Ls,{value:r,onChange:g=>l(g.target.value),placeholder:"무엇을 확인했고 어떻게 처리했는지. 메모 없이 상태를 바꾸면 다음 날 새벽에 표시가 사라집니다.",rows:2,className:"text-sm"}),i&&e.jsx("p",{className:"text-sm text-red-600",children:i}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx(_,{size:"sm",variant:"outline",disabled:n,onClick:()=>d("ack"),children:"확인중"}),e.jsx(_,{size:"sm",disabled:n,onClick:()=>d("resolved"),children:"해결"}),e.jsx(_,{size:"sm",variant:"outline",disabled:n,onClick:()=>d("ignored"),children:"보류"}),e.jsx(_,{size:"sm",variant:"ghost",className:"text-slate-500",disabled:n,onClick:()=>d("ignored",!0),children:"오탐 신고"}),n&&e.jsx(fe,{className:"h-4 w-4 animate-spin text-slate-400"})]})]})}function Ms({title:s,hint:t,issues:a,ownerOf:r,onChange:l}){return a.length===0?null:e.jsxs("section",{className:"space-y-3",children:[e.jsxs("div",{children:[e.jsxs("h3",{className:"text-lg font-semibold",children:[s," ",e.jsx("span",{className:"text-slate-400",children:a.length})]}),e.jsx("p",{className:"text-sm text-slate-500",children:t})]}),a.map(n=>e.jsx(rn,{issue:n,owner:r(n.scope),onChange:(o,i,m)=>l(n.id,o,i,m)},n.id))]})}function nn(){const{run:s,groups:t,freshness:a,ownerOf:r,loading:l,error:n,reload:o,changeStatus:i}=en();if(l)return e.jsxs("div",{className:"flex items-center gap-2 p-8 text-slate-500",children:[e.jsx(fe,{className:"h-5 w-5 animate-spin"})," 브리핑을 불러오는 중"]});if(n)return e.jsxs("div",{className:"rounded-lg border border-red-200 bg-red-50 p-6",children:[e.jsxs("p",{className:"flex items-center gap-2 font-medium text-red-800",children:[e.jsx(we,{className:"h-5 w-5"})," 브리핑을 불러오지 못했습니다"]}),e.jsx("p",{className:"mt-1 text-sm text-red-700",children:n}),e.jsx("p",{className:"mt-2 text-sm text-red-700",children:"목록이 비어 보이는 것과 다릅니다. 이상이 없다는 뜻이 아니라 확인 자체를 못 한 상태입니다."}),e.jsx(_,{size:"sm",variant:"outline",className:"mt-3",onClick:()=>void o(),children:"다시 시도"})]});if(!s)return e.jsxs("div",{className:"rounded-lg border border-amber-200 bg-amber-50 p-6",children:[e.jsxs("p",{className:"flex items-center gap-2 font-medium text-amber-900",children:[e.jsx(we,{className:"h-5 w-5"})," 판정 기록이 없습니다"]}),e.jsxs("p",{className:"mt-1 text-sm text-amber-800",children:["이상이 0건인 게 아니라 진단이 한 번도 돌지 않았습니다. cron",e.jsx("code",{className:"mx-1 rounded bg-amber-100 px-1",children:"marketing-d
2aily-diagnostics"}),"가 살아 있는지 먼저 확인해야 합니다."]})]});const m=t.blocked.length+t.check.length+t.log.length;return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"rounded-lg border bg-slate-50 p-4",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-sm text-slate-500",children:"판정 기준일"}),e.jsx("p",{className:"text-xl font-semibold",children:s.statDate}),e.jsxs("p",{className:"mt-1 text-xs text-slate-500",children:[na(s.ranAt)," 실행 · 규칙 ",s.rulesRun,"개 · 차단 ",s.blocked,"건"]})]}),e.jsxs(_,{size:"sm",variant:"outline",onClick:()=>void o(),children:[e.jsx(tr,{className:"mr-1 h-4 w-4"})," 새로고침"]})]}),a.length>0&&e.jsx("div",{className:"mt-4 flex flex-wrap gap-2",children:a.map(d=>e.jsxs("span",{className:`rounded px-2 py-1 text-xs ${d.days===null||d.days>0?"bg-red-100 text-red-800":"bg-emerald-100 text-emerald-800"}`,title:d.owner?`담당 ${d.owner}`:void 0,children:[d.media," ",d.last??"수집 없음",d.days!==null&&d.days>0&&` (${d.days}일 밀림)`]},d.media))})]}),m===0&&e.jsxs("div",{className:"rounded-lg border border-emerald-200 bg-emerald-50 p-6",children:[e.jsxs("p",{className:"flex items-center gap-2 font-medium text-emerald-900",children:[e.jsx(Fs,{className:"h-5 w-5"})," 열린 이슈가 없습니다"]}),e.jsxs("p",{className:"mt-1 text-sm text-emerald-800",children:[s.statDate," 기준으로 규칙 ",s.rulesRun,"개가 모두 돌았고 걸린 항목이 없습니다."]})]}),e.jsx(Ms,{title:"차단",hint:"오늘 손대야 하는 것. 이걸 두고 다른 걸 먼저 하면 안 됩니다.",issues:t.blocked,ownerOf:r,onChange:i}),e.jsx(Ms,{title:"확인",hint:"사람이 한 번 봐야 하는 것. 방치하면 차단으로 넘어갑니다.",issues:t.check,ownerOf:r,onChange:i}),e.jsx(Ms,{title:"기록",hint:"조치는 필요 없지만 흐름으로 남겨 둘 것.",issues:t.log,ownerOf:r,onChange:i}),t.suppressed.length>0&&e.jsxs("section",{className:"space-y-2",children:[e.jsxs("h3",{className:"text-lg font-semibold",children:["판정 보류 ",e.jsx("span",{className:"text-slate-400",children:t.suppressed.length})]}),e.jsx("p",{className:"text-sm text-slate-500",children:"이상이 없어서가 아니라 판정할 수 없어서 건너뛴 항목입니다."}),e.jsx("div",{className:"rounded-lg border divide-y",children:t.suppressed.map(d=>e.jsxs("div",{className:"flex flex-wrap items-center gap-2 p-3 text-sm",children:[e.jsx("span",{className:"font-mono text-xs text-slate-500",children:d.code}),e.jsx("span",{className:"rounded bg-slate-100 px-2 py-0.5 text-xs",children:d.scope}),e.jsx("span",{children:d.title}),e.jsxs("span",{className:"ml-auto text-xs text-slate-500",children:["사유 ",d.suppressedReason]})]},d.id))})]}),t.closed.length>0&&e.jsxs("section",{className:"space-y-2",children:[e.jsxs("h3",{className:"text-lg font-semibold",children:["처리됨 ",e.jsx("span",{className:"text-slate-400",children:t.closed.length})]}),e.jsx("div",{className:"rounded-lg border divide-y",children:t.closed.map(d=>e.jsxs("div",{className:"flex flex-wrap items-center gap-2 p-3 text-sm",children:[e.jsx("span",{className:"font-mono text-xs text-slate-500",children:d.code}),e.jsx("span",{className:"rounded bg-slate-100 px-2 py-0.5 text-xs",children:d.scope}),e.jsx("span",{children:d.title}),e.jsx("span",{className:"text-xs text-slate-500",children:ra[d.status]}),d.falsePositive&&e.jsx("span",{className:"rounded bg-amber-100 px-2 py-0.5 text-xs text-amber-800",children:"오탐 신고"}),d.handledNote&&e.jsxs("span",{className:"text-xs text-slate-500",children:["· ",d.handledNote]})]},d.id))})]})]})}const ln={auto:"자동",file:"파일",manual:"수기"},lt=[{name:"관리자 주문 DB",kind:"auto",cadence:"실시간",why:"이 저장소의 DB — 매출·주문의 단일 기준. 자사몰 주문의 유입경로(attribution_raw)는 2026-09-17 부터 저장한다"},{name:"TM 접수 (셀프 도어 교체 리드)",kind:"auto",cadence:"실시간",why:"웹 상담 폼 · 메타 인스턴트 양식(10분마다 수집). 유입 매체는 접수의 utm_source, 공간(주방·현관)은 접수의 service 칸"},{name:"쿠팡 로켓 매출",kind:"file",cadence:"발주 시",why:"밀크런 도매 발주는 사방넷·주문 DB를 거치
2지 않아 엑셀 업로드로만 들어온다"},{name:"네이버 검색광고",kind:"auto",cadence:"매시 (일별)",why:"검색광고 API 로 캠페인 × 일 단위 자동 수집(마케팅 DB). 8월 이전·대행사 월보고서는 업로드분"},{name:"메타 (페이스북·인스타)",kind:"auto",cadence:"매시 (일별)",why:"Insights API 로 캠페인 × 일 단위 자동 수집(마케팅 DB). 인스턴트 양식 리드는 TM 접수로 따로 들어온다"},{name:"구글 Ads",kind:"auto",cadence:"매시 (일별)",why:"Google Ads Script 가 캠페인 × 일 단위로 적재(2026-09-04~). 그 이전은 대행사 월·주보고서 업로드분"},{name:"쿠팡 광고",kind:"file",cadence:"주·월별",why:"광고 API 가 없어 wing 리포트를 올려야 들어온다. 안 올리면 「입력 안 됨」으로 경고한다"},{name:"당근/디스플레이",kind:"file",cadence:"주·일별",why:"대행사(ONE_K) 보고서 CSV. 2026-09 집행 중단(팀장 확인) — 재개하면 다시 올린다"},{name:"리타겟 (모비온·ADN)",kind:"file",cadence:"일별",why:"보고서 파일 업로드. 집행 중단(마지막 2026-07-31)"},{name:"GA4",kind:"auto",cadence:"매일",why:"BigQuery 동기화 → 마케팅 DB(ga4_fact_*). 캠페인 성과 탭의 방문·전환 지표에 쓴다"},{name:"목표·기준선",kind:"manual",cadence:"월 1회",why:"사람이 정하는 값. 현재는 브라우저 저장 (예산과 함께 DB 로 옮길 예정)"}],cn=[{name:"쿠팡 광고 리포트 (wing)",cadence:"주 1회",unlocks:"쿠팡 광고비율·ROAS. 안 올리면 성과 개요에 「입력 안 됨」 경고가 뜬다"},{name:"월 매출 목표 · 목표 광고비율",cadence:"월 1회",unlocks:"목표 대비 달성률, 월말 예상 착지, 목표 관련 진단 코드"},{name:"월 × 매체 예산",cadence:"월 1회",unlocks:"예산 대비 소진률·월말 예상 (저장 기능은 다음 단계)"},{name:"market 코드 매핑표",cadence:"변경 시",unlocks:"외부몰 경유 유입의 브랜드별 분해"},{name:"캠페인 마스터",cadence:"변경 시",unlocks:"캠페인명 → 브랜드 귀속 (네이버 캠페인 기준)"},{name:"운영 변경 이력",cadence:"변경 시",unlocks:"차트 주석선 — 숫자가 튄 날의 이유"},{name:"전화·카톡 리드 출처",cadence:"수시",unlocks:"당근 전환 귀속 (TM 접수 목록의 유입경로)"}],on=[{topic:"월간 KPI vs 일·주 추이",detail:"get_revenue_kpis 는 쿠팡 로켓·팩토리 재단까지 더한 GMV 이고, get_revenue_trend 는 tp_order 만 읽는다. 같은 기간이라도 추이 합계가 더 작다."}
2,{topic:"광고비 해상도",detail:'네이버·메타·구글은 일 단위로 들어오지만, 쿠팡은 주·월 단위 리포트이고 8월 이전 네이버·구글은 대행사 월·주보고서다. 조회 기간에 통째로 들어오지 않는 금액은 광고비율 계산에서 빠지고 화면에 "기간 미제공"으로 표시된다.'},{topic:"구글 금액의 부가세",detail:"구글 광고 화면 금액은 부가세 별도다(A-12 확정, 8월 청구 대조). 대행사 업로드분 보정과 업로드 코드 수정이 별도 작업으로 남아 있어, 그 전까지 구글 금액은 부가세 기준이 섞여 있을 수 있다."},{topic:"객단가(AOV) 정의",detail:"이 화면의 객단가는 GMV ÷ 주문 건수다. 주문 통계 화면의 AOV 는 CPQ 주문만으로 계산해 분모·분자가 달라 값이 다르다."},{topic:"매체 자체 보고 전환매출",detail:"매체 리포트의 전환매출 합은 실매출의 153% 수준(중복 기여)이다. ROAS 는 반드시 관리자 실매출 ÷ 광고비로 계산한다."}],dn=[{term:"GMV",meaning:"취소 전 총 거래액. 이 화면 모든 매출의 단일 기준"},{term:"광고비율",meaning:"광고비 ÷ 매출. 낮을수록 좋다"},{term:"ROAS",meaning:"매출 ÷ 광고비. 광고비율의 역수이며 퍼센트로 표기"},{term:"객단가",meaning:"GMV ÷ 주문 건수"},{term:"확정 광고비",meaning:"집계 구간이 조회 기간에 통째로 들어오는 광고비만 합산한 값"},{term:"기간 미제공",meaning:'구간이 조회 기간에 걸쳐만 있어 합산에서 제외한 광고비. 0원이 아니라 "모른다"는 뜻'},{term:"요일 가중치",meaning:"월 목표를 일·주로 나눌 때 쓰는 요일별 배분 비율. 공휴일은 토요일 가중치를 쓴다"},{term:"월말 예상 착지",meaning:"현재 페이스가 유지될 때의 월말 예상 매출"},{term:"진단 코드",meaning:"규칙에 걸린 이슈. 신규 → 확인 중 → 해결/무시 로 사람이 관리한다"}];async function mn(){const s=Object.keys(Ke);return(await Promise.all(s.map(async a=>{const[r,l]=await Promise.all([H.from("tp_ad_costs").select("period_end, updated_at").eq("media",a).order("period_end",{ascending:!1}).order("updated_at",{ascending:!1}).limit(1),H.from("tp_ad_costs").select("id",{count:"exact",head:!0}).eq("media",a)]);if(r.error)throw r.error;if(l.error)throw l.error;const n=(r.data??[])[0];return{media:a,latestPeriodEnd:n?.period_end??null,updatedAt:n?.updated_at??null,rowCount:l.count??0}}))).sort((a,r)=>a.latestPeriodEnd===null&&r.latestPeriodEnd!==null?-1:a.latestPeriodEnd!==null&&r.latestPeriodEnd===null?1:a.latestPeriodEnd===null&&r.latestPeriodEnd===null?0:r.latestPeriodEnd.localeCompare(a.latestPeriodEnd))}function xn(s,t){const a=new Date(`${s.slice(0,10)}T00:00:00Z`).getTime(),r=new Date(`${t}T00:00:00Z`).getTime();return Math.round((r-a)/864e5)}const un={auto:"bg-emerald-50 text-emerald-700",file:"bg-sky-50 text-sky-700",manual:"bg-amber-50 text-amber-800"},it=8;function hn(){return new Date(Date.now()+9*36e5).toISOString().slice(0,10)}function pn(){const[s,t]=h.useState([]),[a,r]=h.useState(!0),l=hn();h.useEffect(()=>{let o=!0;return mn().then(i=>{o&&t(i)}).catch(i=>{U.error(`데이터 신선도를 확인하지 못했습니다: ${i instanceof Error?i.message:String(i)}`)}).finally(()=>{o&&r(!1)}),()=>{o=!1}},[]);const n=lt.reduce((o,i)=>({...o,[i.kind]:(o[i.kind]??0)+1}),{});return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"rounded-lg border bg-white",children:[e.jsxs("div",{className:"flex flex-wrap items-baseline gap-2 border-b px-4 py-3",children:[e.jsx("span",{className:"text-sm font-semibold text-gray-800",children:"데이터 소스"}),e.jsxs("span",{className:"text-xs text-gray-500",children:["자동 ",n.auto??0," · 파일 ",n.file??0," · 수기 ",n.manual??0]})]}),e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-gray-50 text-left text-xs whitespace-nowrap text-gray-500",children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-4 py-2",children:"소스"}),e.jsx("th",{className:"px-4 py-2",children:"구분"}),e.jsx("th",{className:"px-4 py-2",children:"주기"}),e.jsx("th",{className:"px-4 py-2",children:"왜 이렇게 되나"})]})}),e.jsx("tbody",{children:lt.map(o=>e.jsxs("tr",{className:"border-t",children:[e.jsx("td",{className:"whitespace-nowrap px-4 py-2 font-medium",children:o.name}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2",children:e.jsx("span",{className:`inline-block whitespace-nowrap rounded px-1.5 py-0.5 text-[11px] font-medium ${un[o.kind]}`,children:ln[o.kind]})}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2 text-gray-500",children:o.cadence}),e.jsx("td",{className:"px-4 py-2 text-gray-600",children:o.why})]},o.name))})]})})]}),e.jsxs("div",{className:"rounded-lg border bg-white",children:[e.jsxs("div",{className:"flex flex-wrap items-baseline gap-2 border-b px-4 py-3",children:[e.jsx("span",{className:"text-sm font-semibold text-gray-800",children:"광고비 신선도"}),e.jsxs("span",{className:"text-xs text-gray-500",children:["마지막으로 적재된 집계 구간 기준 · ",it,"일 이상이면 경고"]})]}),a?e.jsxs("div",{className:"flex items-center gap-2 px-4 py-8 text-sm text-gray-400",children:[e.jsx(fe,{className:"h-4 w-4 animate-spin"})," 확인 중…"]}):s.length===0?e.jsx("div",{className:"px-4 py-8 text-center text-sm text-gray-400",children:"적재된 광고비가 없습니다. 광고비 탭에서 리포트를 올리거나 수기로 입력하세요."}):e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-gray-50 text-left text-xs whitespace-nowrap text-gray-500",children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-4 py-2",children:"매체"}),e.jsx("th",{className:"px-4 py-2",children:"제공 해상도"}),e.jsx("th",{className:"px-4 py-2",children:"마지막 집계 구간"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"경과"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"행 수"})]})}),e.jsx("tbody",{children:s.map(o=>{const i=o.latestPeriodEnd===null,m=i?null:xn(o.latestPeriodEnd,l),d=m!==null&&m>=it;return e.jsxs("tr",{className:"border-t",children:[e.jsx("td",{className:"whitespace-nowrap px-4 py-2 font-medium",children:Ke[o.media]}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2 text-gray-500",children:Yt[Za[o.media]]}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2",children:i?e.jsx("span",{className:"font-medium text-red-600",children:"적재된 적 없음"}):o.latestPeriodEnd}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2 text-right tabular-nums",children:i?e.jsx("span",{className:"font-medium text-red-600",children:"⚠"}):e.jsxs("span",{className:d?"font-medium text-red-600":"text-gray-500",children:[m,"일",d&&" ⚠"]})}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2 text-right text-gray-500 tabular-nums",children:o.rowCount.toLocaleStr
2ing("ko-KR")})]},o.media)})})]})})]}),e.jsxs("div",{className:"rounded-lg border bg-white",children:[e.jsx("div",{className:"border-b px-4 py-3 text-sm font-semibold text-gray-800",children:"수기로 채워야 하는 것"}),e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-gray-50 text-left text-xs whitespace-nowrap text-gray-500",children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-4 py-2",children:"항목"}),e.jsx("th",{className:"px-4 py-2",children:"갱신 주기"}),e.jsx("th",{className:"px-4 py-2",children:"채워지면 열리는 것"})]})}),e.jsx("tbody",{children:cn.map(o=>e.jsxs("tr",{className:"border-t",children:[e.jsx("td",{className:"whitespace-nowrap px-4 py-2 font-medium",children:o.name}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2 text-gray-500",children:o.cadence}),e.jsx("td",{className:"px-4 py-2 text-gray-600",children:o.unlocks})]},o.name))})]})})]}),e.jsx("div",{className:"rounded-lg border border-amber-200 bg-amber-50 p-4",children:e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(we,{className:"mt-0.5 h-4 w-4 shrink-0 text-amber-600"}),e.jsxs("div",{className:"flex-1",children:[e.jsx("div",{className:"text-sm font-semibold text-amber-900",children:"알아둬야 할 기준 차이"}),e.jsx("ul",{className:"mt-2 space-y-2",children:on.map(o=>e.jsxs("li",{className:"text-sm text-amber-900",children:[e.jsx("span",{className:"font-medium",children:o.topic}),e.jsx("p",{className:"mt-0.5 text-amber-800",children:o.detail})]},o.topic))})]})]})}),e.jsxs("div",{className:"rounded-lg border bg-white p-4",children:[e.jsx("div",{className:"mb-3 text-sm font-semibold text-gray-800",children:"용어 풀이"}),e.jsx("dl",{className:"grid gap-x-6 gap-y-2 sm:grid-cols-2",children:dn.map(o=>e.jsxs("div",{className:"flex gap-2 text-sm",children:[e.jsx("dt",{className:"w-24 shrink-0 font-medium text-gray-700",children:o.term}),e.jsx("dd",{className:"text-gray-600",children:o.meaning})]},o.term))})]})]})}const la="wedraw.marketing.diagnostics.v1";function ia(){try{const s=localStorage.getItem(la);if(!s)return{};const t=JSON.parse(s);return typeof t=="object"&&t!==null?t:{}}catch{return{}}}function ct(s){try{localStorage.setItem(la,JSON.stringify(s))}catch(t){throw new Error(`진단 상태를 저장하지 못했습니다: ${t instanceof Error?t.message:String(t)}`)}}function gn(s,t,a){const r={...t},l=[];for(const n of s){const o=t[n.code];let i=!1,m;o?o.status==="resolved"?(i=!0,m={status:"new",firstSeen:a,lastSeen:a,recurrenceCount:o.recurrenceCount+1,streak:1}):m={...o,lastSeen:a,streak:o.lastSeen===a?o.streak:o.streak+1}:m={status:"new",firstSeen:a,lastSeen:a,recurrenceCount:0,streak:1},r[n.code]=m,l.push({...n,state:m,recurred:i})}return{items:l,next:r}}function jn(s,t,a,r){const l=s[t];return{...s,[t]:l?{...l,status:a,lastSeen:r}:{status:a,firstSeen:r,lastSeen:r,recurrenceCount:0,streak:1}}}function ns(s){return s==="new"||s==="ack"}function fn(){return Object.values(ia()).filter(s=>ns(s.status)).length}function vn(s){const t={new:0,ack:0,resolved:0,ignored:0,openCritical:0,openWarn:0};for(const a of s)t[a.state.status]+=1,ns(a.state.status)&&(a.level==="critical"&&(t.openCritical+=1),a.level==="warn"&&(t.openWarn+=1));return t}const Nn=.3,bn=15,yn=15,X=s=>`₩${Math.round(s).toLocaleString("ko-KR")}`,ot=s=>`${s>0?"+":""}${s.toFixed(2)}%p`,dt=s=>`${s>0?"+":""}${s.toFixed(1)}%`;function wn(s){const t=[],{kpis:a,primaryComparison:r,goals:l,target:n,adSummary:o,channels:i,mode:m}=s;if(a?.adRatio!=null&&r?.kpis.adRatio!=null){const c=a.adRatio-r.kpis.adRatio;if(Math.abs(c)>=Nn){const x=c>0;t.push({code:x?"AD-101":"AD-102",area:"AD",level:x?"warn":"info",title:x?"광고비율 상승":"광고비율 개선",evidence:`${r.label} ${r.kpis.adRatio.toFixed(2)}% → ${a.adRatio.toFixed(2)}% (${ot(c)})`,action:x?"① 매체별 광고비 증감 확인 → ② 매체 안 유형(쇼핑/검색/PMax) → ③ 키워드 유형 → ④ 저효율 캠페인 예산 조정":"개선 요인을 기록해 두고 같은 조건을 다른 매체에도 적용할지 검토합니다.",ruleId:"ad_ratio_delta"})}}if(a?.adRatio!=null&&l.targetAdRatio>0&&a.adRatio>l.targetAdRatio){const c=a.adRatio-l.targetAdRatio;t.push({code:"AD-110",area:"AD",level:c>=1?"critical":"warn",title:"목표 광고비율 초과",evidence:`목표 ${l.targetAdRatio}% / 실제 ${a.adRatio.toFixed(2)}% (${ot(c)})${n?` · 목표 광고비 ${X(n.adCost)} 대비 ${X((a.adCost??0)-n.adCost)} 초과`:""}`,action:"광고비를 줄일지 매출을 올릴지 먼저 정합니다. 채널별 광고비율 표에서 가장 나쁜 채널부터 봅니다.",ruleId:"ad_ratio_target"})}if(l.targetAdRatio>
20)for(const c of i)c.adRatio!=null&&(c.adRatio<=l.targetAdRatio*1.2||t.push({code:`AD-120-${c.channel}`,area:"AD",level:"warn",title:`${Ks[c.channel]} 광고비율 목표 초과`,evidence:`${c.adRatio.toFixed(2)}% (목표 ${l.targetAdRatio}% 의 1.2배 초과) · 매출 ${X(c.revenue)} / 광고비 ${X(c.adCost??0)}`,action:`${Ks[c.channel]} 캠페인별 광고비를 열어 전환 0 인 항목부터 정리합니다.`,ruleId:"channel_ad_ratio"}));if(a&&r&&r.kpis.gmv>0){const c=(a.gmv-r.kpis.gmv)/r.kpis.gmv*100;if(Math.abs(c)>=bn){const x=c<0;t.push({code:x?"RV-201":"RV-202",area:"RV",level:x?"warn":"info",title:x?"매출 급락":"매출 급등",evidence:`${r.label} ${X(r.kpis.gmv)} → ${X(a.gmv)} (${dt(c)})`,action:x?"① 채널별 매출 비중 변화 → ② 상품유형별 매출 → ③ 주문 건수 vs 객단가 중 어느 쪽이 빠졌는지 분해":"어떤 채널·상품이 끌어올렸는지 확인해 재현 가능한 요인인지 판단합니다.",ruleId:"revenue_delta"})}}if(a&&n&&n.revenue>0){const c=a.gmv/n.revenue*100;c<90?t.push({code:"RV-210",area:"RV",level:"critical",title:"목표 미달",evidence:`달성률 ${c.toFixed(1)}% · 목표 ${X(n.revenue)} / 실적 ${X(a.gmv)} (부족 ${X(n.revenue-a.gmv)})`,action:"남은 기간 필요한 일평균을 확인하고, 광고비를 늘릴 여력이 있는지 광고비율로 판단합니다.",ruleId:"goal_rate"}):c<100&&t.push({code:"RV-211",area:"RV",level:"warn",title:"목표 근접 미달",evidence:`달성률 ${c.toFixed(1)}% · 부족 ${X(n.revenue-a.gmv)}`,action:"마감까지 남은 일수와 요일 구성을 확인합니다. 주말·공휴일이 남았다면 가중치를 감안하세요.",ruleId:"goal_rate"})}if(a?.aov!=null&&r?.kpis.aov!=null&&r.kpis.aov>0){const c=(a.aov-r.kpis.aov)/r.kpis.aov*100;Math.abs(c)>=yn&&t.push({code:"RV-220",area:"RV",level:"warn",title:"객단가 급변",evidence:`${r.label} ${X(r.kpis.aov)} → ${X(a.aov)} (${dt(c)})`,action:"① 상품유형별 건당 단가 → ② 채널별 객단가 순으로 분해합니다. 저가 상품 비중이 늘었는지 먼저 봅니다.",ruleId:"aov_delta"})}const d=o?.excluded??[];if(d.length>0){const c=d.reduce((x,N)=>x+N.cost,0);t.push({code:"DT-301",area:"DT",level:m==="monthly"?"info":"warn",title:"광고비 일부가 광고비율에 반영되지 않음",evidence:`${X(c)} 제외 · ${d.map(x=>Ke[x.media]).join(", ")} (집계 구간이 조회 기간에 통째로 들어오지 않음)`,action:"이 기간의 실제 광고비는 표시값보다 큽니다. 월 단위로 조회하면 전체가 반영됩니다. 일별 광고비가 필요하면 매체 리포트 해상도를 먼저 확인하세요.",ruleId:"ad_cost_coverage"})}a&&a.gmv>0&&a.adCost==null&&d.length===0&&t.push({code:"DT-302",area:"DT",level:"warn",title:"광고비가 적재되지 않음",evidence:`매출 ${X(a.gmv)} 은 있으나 이 기간 광고비가 0건 — 광고비율·ROAS 를 계산할 수 없습니다.`,action:"광고비 탭에서 매체 리포트를 업로드하거나 수기로 입력합니다.",ruleId:"ad_cost_missing"});const g={critical:0,warn:1,info:2};return t.sort((c,x)=>g[c.level]-g[x.level]||c.code.localeCompare(x.code))}function mt(){const s=new Date;return new Date(s.getTime()+9*36e5).toISOString().slice(0,10)}function ca(s){const[t,a]=h.useState(()=>ia()),r=mt(),l=h.useMemo(()=>wn(s),[s]),n=h.useMemo(()=>gn(l,t,r),[l,t,r]);h.useEffect(()=>{if(JSON.stringify(n.next)!==JSON.stringify(t))try{ct(n.next),a(n.next)}catch(m){U.error(m instanceof Error?m.message:String(m))}},[n,t]);const o=h.useCallback((m,d)=>{const g=jn(t,m,d,mt());try{ct(g),a(g)}catch(c){U.error(c instanceof Error?c.message:String(c))}},[t]),i=h.useMemo(()=>vn(n.items),[n.items]);return{items:n.items,summary:i,updateStatus:o}}const oa={AD:"광고 효율",RV:"매출·목표",FN:"퍼널·전환",DT:"데이터 품질",OP:"운영"},da={critical:"심각",warn:"주의",info:"참고"},es={new:"신규",ack:"확인 중",resolved:"해결",ignored:"무시"},Sn={critical:"bg-red-500",warn:"bg-amber-500",info:"bg-sky-500"},_n={critical:"bg-red-50 text-red-700",warn:"bg-amber-50 text-amber-800",info:"bg-sky-50 text-sky-700"},kn=["new","ack","resolved","ignored"];function ma({items:s,onStatusChange:t,emptyMessage:a}){return s.length===0?e.jsx("div",{className:"rounded-lg border border-dashed bg-white p-8 text-center text-sm text-gray-400",children:a??"걸린 코드가 없습니다."}):e.jsx("ul",{className:"space-y-2",children:s.map(r=>e.jsxs("li",{className:"flex overflow-hidden rounded-lg border bg-white",children:[e.jsx("div",{className:`w-1 shrink-0 ${Sn[r.level]}`}),e.jsxs("div",{className:"flex-1 p-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("code",{className:"rounded bg-gray-100 px-1.5 py-0.5 text-xs font-medium text-gray-700",children:r.code}),e.jsx("span",{className:`rounded px-1.5 py-0.5 text-[10px] font-medium ${_n[r.level]}`,children:da[r.level]}),e.jsx("span",{className:"text-sm font-medium text-gray-900",children:r.title}),r.recurred&&e.jsxs("span",{className:"rounded bg-purple-50 px-1.5 py-0.5 text-[10px] font-medium text-purple-700",children:["재발 ",r.state.recurrenceCount,"회"]}),r.state.streak>1&&e.jsxs("span",{className:"text-[11px] text-gray-400",children:["지속 ",r.state.streak,"일"]}),e.jsx("div",{className:"ml-auto flex items-center gap-1",children:kn.map(l=>e.jsx("button",{type:"button",onClick:()=>t(r.code,l),className:`rounded px-2 py-0.5 text-xs ${r.state.status===l?"bg-gray-900 font-medium text-white":"text-gray-500 hover:bg-gray-100"}`,children:es[l]},l))})]}),e.jsx("p",{className:"mt-1.5 text-sm text-gray-700",children:r.evidence}),e.jsxs("p",{className:"mt-1 text-xs text-gray-500",children:[e.jsx("span",{className:"font-medium text-gray-600",children:"처방"})," · ",r.action]}),e.jsxs("p",{className:"mt-1 text-[11px] text-gray-400",children:["최초 ",r.state.firstSeen," · 규칙 ",r.ruleId]})]})]},r.code))})}function Cn({items:s,onStatusChange:t,slackText:a}){const[r,l]=h.useState(!1),n=s.filter(i=>ns(i.state.status)),o=async()=>{try{await navigator.clipboard.writeText(a),l(!0),U.success("슬랙 양식으로 복사했습니다."),setTimeout(()=>l(!1),2e3)}catch(i){U.error(`복사하지 못했습니다: ${i instanceof Error?i.message:String(i)}. 아래 텍스트를 직접 선택해 복사하세요.`)}};return e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[e.jsxs("h3",{className:"text-sm font-semibold text-gray-800",children:["이 데이터에서 읽히는 것",n.length>
20&&e.jsxs("span",{className:"ml-2 rounded bg-gray-900 px-1.5 py-0.5 text-xs font-medium text-white",children:["열린 코드 ",n.length]})]}),e.jsxs(_,{variant:"outline",size:"sm",onClick:()=>void o(),children:[r?e.jsx(Ds,{className:"mr-2 h-4 w-4 text-emerald-600"}):e.jsx(ar,{className:"mr-2 h-4 w-4"}),"슬랙용 복사"]})]}),e.jsx(ma,{items:n,onStatusChange:t,emptyMessage:"규칙에 걸린 항목이 없습니다. 임계값은 진단 탭에서 확인하세요."})]})}const He=s=>`₩${Math.round(s).toLocaleString("ko-KR")}`,Dn={daily:"일간",weekly:"주간",monthly:"월간"};function Rn(s){const{mode:t,period:a,kpis:r,comparisons:l,target:n,diagnostics:o}=s,i=[],m=a.startDate===a.endDate?a.startDate:`${a.startDate} ~ ${a.endDate}`;if(i.push(`*마케팅 성과 (${Dn[t]})* ${m}`),!r)return i.push("· 데이터를 불러오지 못했습니다."),i.join(`
3`);const d=l[0],g=(x,N)=>N===0?"—":`${x-N>0?"+":""}${((x-N)/N*100).toFixed(1)}%`;if(i.push(`· 매출 ${He(r.gmv)}${d?` (${d.label} ${g(r.gmv,d.kpis.gmv)})`:""}`),i.push(`· 광고비 ${r.adCost==null?"—":He(r.adCost)}${d&&r.adCost!=null&&d.kpis.adCost!=null?` (${d.label} ${g(r.adCost,d.kpis.adCost)})`:""}`),i.push(`· 광고비율 ${r.adRatio==null?"—":`${r.adRatio.toFixed(2)}%`}${d&&r.adRatio!=null&&d.kpis.adRatio!=null?` (${d.label} ${(r.adRatio-d.kpis.adRatio>0?"+":"")+(r.adRatio-d.kpis.adRatio).toFixed(2)}%p)`:""}`),i.push(`· ROAS ${r.roas==null?"—":`${Math.round(r.roas).toLocaleString("ko-KR")}%`}`),i.push(`· 객단가 ${r.aov==null?"—":He(r.aov)} / 주문 ${r.orderCount.toLocaleString("ko-KR")}건`),n&&n.revenue>0){const x=r.gmv/n.revenue*100;i.push(`· 목표 달성률 ${x.toFixed(1)}% (목표 ${He(n.revenue)}, ${r.gmv>=n.revenue?"초과":"부족"} ${He(Math.abs(r.gmv-n.revenue))})`)}else i.push("· 목표 미확정");const c=o.filter(x=>ns(x.state.status));if(c.length===0)i.push("· 열린 진단 코드 없음");else{i.push(`*열린 진단 코드 ${c.length}건*`);for(const x of c.slice(0,5))i.push(`· [${da[x.level]}] ${x.code} ${x.title} — ${x.evidence}`);c.length>5&&i.push(`· … 외 ${c.length-5}건`)}return i.join(`
4`)}const ms=s=>`₩${Math.round(s).toLocaleString("ko-KR")}`,$n=new Set(["etc"]);function Un({channels:s,loading:t}){const a=s.reduce((r,l)=>r+l.revenue,0);return e.jsxs("div",{className:"rounded-lg border bg-white",children:[e.jsxs("div",{className:"flex flex-wrap items-baseline gap-2 border-b px-4 py-3",children:[e.jsx("span",{className:"text-sm font-semibold text-gray-800",children:"채널별 성과"}),e.jsx("span",{className:"text-xs text-gray-500",children:"판매처 기준 · 광고비는 그 판매처로 직접 보내는 매체만 귀속"})]}),e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-gray-50 text-left text-xs whitespace-nowrap text-gray-500",children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-4 py-2",children:"채널"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"매출"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"비중"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"광고비"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"광고비율"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"ROAS"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"주문"})]})}),e.jsxs("tbody",{children:[s.length===0&&!t&&e.jsx("tr",{children:e.jsx("td",{colSpan:7,className:"px-4 py-8 text-center text-gray-400",children:"이 기간에 매출이 없습니다."})}),s.map(r=>e.jsxs("tr",{className:"border-t align-top",children:[e.jsxs("td",{className:"px-4 py-2",children:[e.jsx("div",{className:"font-medium whitespace-nowrap",children:Ks[r.channel]}),r.stores.length>0&&e.jsx("div",{className:"mt-0.5 max-w-[220px] truncate text-xs text-gray-400",children:r.stores.map(l=>l.name).join(" · ")})]}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2 text-right font-medium tabular-nums",children:ms(r.revenue)}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2 text-right text-gray-500 tabular-nums",children:a>0?`${(r.revenue/a*100).toFixed(1)}%`:"—"}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2 text-right tabular-nums",children:r.adCost==null?e.jsx("span",{className:"text-gray-300",title:$n.has(r.channel)?"이 채널로 직접 보내는 광고가 없습니다":"확정 광고비 없음",children:"—"}):ms(r.adCost)}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2 text-right tabular-nums",children:r.adRatio==null?e.jsx("span",{className:"text-gray-300",children:"—"}):`${r.adRatio.toFixed(2)}%`}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2 text-right tabular-nums",children:r.roas==null?e.jsx("span",{className:"text-gray-300",children:"—"}
4):`${Math.round(r.roas).toLocaleString("ko-KR")}%`}),e.jsxs("td",{className:"whitespace-nowrap px-4 py-2 text-right text-gray-500 tabular-nums",children:[r.orderCount.toLocaleString("ko-KR"),"건"]})]},r.channel))]}),s.length>0&&e.jsx("tfoot",{children:e.jsxs("tr",{className:"border-t bg-gray-50 font-medium",children:[e.jsx("td",{className:"px-4 py-2",children:"합계"}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2 text-right tabular-nums",children:ms(a)}),e.jsx("td",{className:"px-4 py-2 text-right text-gray-500",children:"100.0%"}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2 text-right tabular-nums",children:ms(s.reduce((r,l)=>r+(l.adCost??0),0))}),e.jsx("td",{colSpan:2}),e.jsxs("td",{className:"whitespace-nowrap px-4 py-2 text-right tabular-nums",children:[s.reduce((r,l)=>r+l.orderCount,0).toLocaleString("ko-KR"),"건"]})]})})]})})]})}const xt="wedraw-holiday-hatch",$e={revenue:"#3b82f6",revenueMuted:"#bfdbfe",adCost:"#ef4444"},ut=s=>Math.abs(s)>=1e8?`${(s/1e8).toFixed(1)}억`:Math.abs(s)>=1e4?`${Math.round(s/1e4).toLocaleString("ko-KR")}만`:s.toLocaleString("ko-KR"),ht=s=>`₩${Math.round(s).toLocaleString("ko-KR")}`;function Tn({active:s,payload:t}){if(!s||!t?.length)return null;const a=t[0].payload;return e.jsxs("div",{className:"rounded border bg-white px-3 py-2 text-xs shadow",children:[e.jsxs("div",{className:"font-medium",children:[a.date,a.isHoliday&&e.jsx("span",{className:"ml-1 text-amber-600",children:"· 공휴일"}),!a.isHoliday&&a.isWeekend&&e.jsx("span",{className:"ml-1 text-gray-400",children:"· 주말"})]}),e.jsxs("div",{className:"mt-1 text-gray-700",children:["매출 ",ht(a.revenue)]}),e.jsxs("div",{className:"text-gray-700",children:["광고비"," ",a.adCost==null?e.jsx("span",{className:"text-gray-400",children:"— 일별 미제공"}):ht(a.adCost)]})]})}function Ln({points:s,adCostNote:t}){const a=s.some(r=>r.adCost!=null);return e.jsxs("div",{className:"rounded-lg border bg-white p-4",children:[e.jsxs("div",{className:"mb-1 flex flex-wrap items-baseline gap-2",children:[e.jsx("h3",{className:"text-sm font-semibold text-gray-800",children:"일별 매출 · 광고비"}),e.jsx("span",{className:"text-xs text-gray-500",children:"빗금 = 공휴일 · 연한 막대 = 선택 기간 밖"})]}),!a&&t&&e.jsx("p",{className:"mb-2 text-xs text-amber-700",children:t}),e.jsx(Ps,{width:"100%",height:280,children:e.jsxs(Oa,{data:s,margin:{top:8,right:8,bottom:4,left:8},children:[e.jsx("defs",{children:e.jsxs("pattern",{id:xt,patternUnits:"userSpaceOnUse",width:6,height:6,patternTransform:"rotate(45)",children:[e.jsx("rect",{width:6,height:6,fill:$e.revenueMuted}),e.jsx("line",{x1:0,y1:0,x2:0,y2:6,stroke:$e.revenue,strokeWidth:2})]})}),e.jsx(Kt,{strokeDasharray:"3 3",vertical:!1}),e.jsx(zt,{dataKey:"label",tick:{fontSize:11},interval:"preserveStartEnd"}),e.jsx(fs,{yAxisId:"revenue",tick:{fontSize:11},tickFormatter:ut,width:56}),e.jsx(fs,{yAxisId:"adCost",orientation:"right",tick:{fontSize:11},tickFormatter:ut,width:56}),e.jsx(Os,{content:e.jsx(Tn,{})}),e.jsx(Bt,{wrapperStyle:{fontSize:12}}),e.jsx(Fa,{yAxisId:"revenue",dataKey:"revenue",name:"매출",fill:$e.revenue,radius:[2,2,0,0],children:s.map(r=>e.jsx(Ft,{fill:r.isHoliday?`url(#${xt})`:r.inPeriod?$e.revenue:$e.revenueMuted},r.date))}),e.jsx(Xe,{yAxisId:"adCost",type:"monotone",dataKey:"adCost",name:"광고비",stroke:$e.adCost,strokeWidth:2,dot:{r:2},connectNulls:!1})]})})]})}function Xs(s){const t=new Date(`${s}T00:00:00Z`);if(Number.isNaN(t.getTime()))throw new Error(`날짜 형식이 올바르지 않습니다: ${s}`);return t}function xa(s){return s.toISOString().slice(0,10)}function te(s,t){const a=Xs(s);return a.setUTCDate(a.getUTCDate()+t),xa(a)}function An(s){const a=Xs(s).getUTCDay(),r=a===0?6:a-1;return te(s,-r)}function Ce(s){return`${s.slice(0,7)}-01`}function ls(s){const t=Xs(Ce(s));return t.setUTCMonth(t.getUTCMonth()+1),t.setUTCDate(0),xa(t)}function En(s,t){if(s==="daily")return{startDate:t,endDate:t};if(s==="weekly"){const a=An(t);return{startDate:a,endDate:te(a,6)}}return{startDate:Ce(t),endDate:ls(t)}}function ua(s,t){if(s==="daily"){const r=te(t.startDate,-1),l=te(t.startDate,-7);return[{key:"prev_day",label:"전일",range:{startDate:r,endDate:r}},{key:"prev_week_same_dow",label:"전주 동일 요일",range:{startDate:l,endDate:l}}]}if(s==="weekly"){const r=te(t.startDate,-7);return[{key:"prev_week",label:"전주",range:{startDate:r,endDate:te(r,6)}}]}const a=te(Ce(t.startDate),-1);return[{key:"prev_month",label:"전월",range:{startDate:Ce(a),endDate:ls(a)}}]}function Mn(s,t,a){const r=a!=null&&a>0;return{gmv:s,orderCount:t,adCost:a??null,adRatio:r&&s>0?a/s*100:null,roas:r?s/a*100:null,aov:t>0?s/t:null}}function Ne(s,t){return s==null||t==null?null:{abs:s-t,pct:t===0?null:(s-t)/Math.abs(t)*100}}const In=new Set(["adCost","adRatio"]);function Pn(s,t){if(!t||t.abs===0)return"flat";const a=t.abs>0,r=!In.has(s);return a===r?"good":"bad"}function On(s){return!s||s.abs===0?"flat":s.abs>0?"up":"down"}function ha(s,t){return{direction:On(t),tone:Pn(s,t)}}const pa=[.644,1.285,1.277,1.164,1.1,.948,.583],Fn=pa[6];function Kn(s){const t=new Date(`${s}T00:00:00Z`);
4if(Number.isNaN(t.getTime()))throw new Error(`날짜 형식이 올바르지 않습니다: ${s}`);return t.getUTCDay()}function Rs(s,t,a="weighted"){return a==="even"?1:t.has(s)?Fn:pa[Kn(s)]}function Ae(s){const t=[];let a=s.startDate;if(s.endDate<s.startDate)return t;for(;a<=s.endDate;)t.push(a),a=te(a,1);return t}function zn(s,t,a="weighted"){return Ae(s).reduce((r,l)=>r+Rs(l,t,a),0)}const $s={monthlyRevenue:0,targetAdRatio:0,allocation:"weighted"};function Us(s){return s.monthlyRevenue>0&&s.targetAdRatio>0}function Bn(s){return s>0?1/(s/100)*100:null}function Is(s,t,a){if(!Us(s))return null;const r=Ae(t);if(r.length===0)return null;const l=new Map;for(const i of r){const m=i.slice(0,7),d=l.get(m);d?d.push(i):l.set(m,[i])}let n=0,o=0;for(const[i,m]of l){const d=`${i}-01`,g=zn({startDate:Ce(d),endDate:ls(d)},a,s.allocation);if(g<=0)continue;const c=m.reduce((x,N)=>x+Rs(N,a,s.allocation),0);n+=s.monthlyRevenue*(c/g),o+=c/g}return{revenue:Math.round(n),adCost:Math.round(n*(s.targetAdRatio/100)),share:o}}function Vn(s,t,a,r){const l=Ce(t),n=ls(t);if(t<l||t>n)return null;const o=Ae({startDate:l,endDate:t}),i=o.reduce((b,T)=>b+(s.get(T)??0),0),m=te(t,-13),d=Ae({startDate:m,endDate:t}),g=d.reduce((b,T)=>b+(s.get(T)??0),0),c=d.reduce((b,T)=>b+Rs(T,a,r.allocation),0),x=c>0?g/c:0,N=t>=n?[]:Ae({startDate:te(t,1),endDate:n}),j=N.reduce((b,T)=>b+Rs(T,a,r.allocation),0),p=Math.round(i+j*x),u=r.monthlyRevenue-i;return{revenue:p,remainingDays:N.length,requiredDailyAverage:Us(r)&&N.length>0&&u>0?Math.round(u/N.length):null,provisional:o.length<=3}}const ga="wedraw.marketing.goals.v1";function Gn(){try{const s=localStorage.getItem(ga);if(!s)return $s;const t=JSON.parse(s);return{monthlyRevenue:Number(t.monthlyRevenue)||0,targetAdRatio:Number(t.targetAdRatio)||0,allocation:t.allocation==="even"?"even":"weighted"}}catch{return $s}}function pt(s){try{localStorage.setItem(ga,JSON.stringify(s))}catch(t){throw new Error(`목표를 브라우저에 저장하지 못했습니다: ${t instanceof Error?t.message:String(t)}`)}}const qe=s=>`₩${Math.round(s).toLocaleString("ko-KR")}`;function Wn(s){return s>=100?"text-emerald-600":s>=90?"text-amber-600":"text-red-600"}function Hn({goals:s,editing:t,setEditing:a,onSave:r,onReset:l,kpis:n,target:o,forecast:i}){const[m,d]=h.useState(()=>({monthlyRevenue:s.monthlyRevenue?String(s.monthlyRevenue):"",targetAdRatio:s.targetAdRatio?String(s.targetAdRatio):"",allocation:s.allocation}));if(t)return e.jsxs("div",{className:"rounded-lg border bg-white p-4",children:[e.jsx("h3",{className:"mb-3 text-sm font-semibold text-gray-800",children:"목표 설정"}),e.jsxs("div",{className:"flex flex-wrap items-end gap-3",children:[e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-xs text-gray-500",children:"월 매출 목표 (원)"}),e.jsx(F,{inputMode:"numeric",value:m.monthlyRevenue,onChange:N=>d({...m,monthlyRevenue:N.target.value}),placeholder:"280000000",className:"w-44"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-xs text-gray-500",children:"목표 광고비율 (%)"}),e.jsx(F,{inputMode:"decimal",value:m.targetAdRatio,onChange:N=>d({...m,targetAdRatio:N.target.value}),placeholder:"7",className:"w-32"})]}),e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-xs text-gray-500",children:"일·주 배분"}),e.jsx("div",{className:"flex rounded-md border p-0.5",children:["weighted","even"].map(N=>e.jsx("button",{type:"button",onClick:()=>d({...m,allocation:N}),className:`rounded px-3 py-1.5 text-sm ${m.allocation===N?"bg-gray-900 font-medium text-white":"text-gray-600 hover:bg-gray-100"}`,children:N==="weighted"?"요일 가중":"균등"},N))})]}),e.jsx(_,{onClick:()=>r({monthlyRevenue:Number(m.monthlyRevenue.replace(/,/g,""))||0,targetAdRatio:Number(m.targetAdRatio.replace(/,/g,""))||0,allocation:m.allocation}),children:"저장"}),e.jsx(_,{variant:"outline",onClick:()=>a(!1),children:"취소"}),Us(s)&&e.jsx(_,{variant:"ghost",className:"text-red-600",onClick:l,children:"목표 지우기"})]}),e.jsx("p",{className:"mt-2 text-xs text-gray-500",children:"요일 가중을 쓰는 이유: 요일별 매출 편차가 2.2ë°°(월 vs 토)라 균등 배분하면 주말마다 목표 미달이 떠서 알림이 무의미해집니다. 공휴일은 토요일 가중치로 자동 하향됩니다."})]});if(!Us(s)||!o||!n)return e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3 rounded-lg border border-dashed bg-white p-4",children:[e.jsxs("div",{className:"text-sm text-gray-600",children:[e.jsx("span",{className:"font-medium text-gray-800",children:"목표 미확정"})," — 월 매출 목표와 목표 광고비율을 넣으면 달성률·월말 예ìƒ
4 착지가 표시됩니다."]}),e.jsx(_,{variant:"outline",onClick:()=>a(!0),children:"목표 설정"})]});const g=o.revenue>0?n.gmv/o.revenue*100:0,c=n.gmv-o.revenue,x=Bn(s.targetAdRatio);return e.jsxs("div",{className:"rounded-lg border bg-white p-4",children:[e.jsxs("div",{className:"mb-3 flex flex-wrap items-baseline justify-between gap-2",children:[e.jsx("h3",{className:"text-sm font-semibold text-gray-800",children:"목표 대비"}),e.jsx("button",{type:"button",onClick:()=>a(!0),className:"text-xs text-gray-500 underline hover:text-gray-700",children:"목표 수정"})]}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2 xl:grid-cols-4",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500",children:"매출 달성률"}),e.jsxs("div",{className:`mt-1 text-2xl font-semibold tabular-nums ${Wn(g)}`,children:[g.toFixed(1),"%"]}),e.jsxs("div",{className:"mt-0.5 text-xs text-gray-400",children:["목표 ",qe(o.revenue)," · ",c>=0?"초과":"부족"," ",qe(Math.abs(c))]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500",children:"광고비율 vs 목표"}),e.jsx("div",{className:"mt-1 text-2xl font-semibold tabular-nums",children:n.adRatio==null?e.jsx("span",{className:"text-gray-300",children:"—"}):e.jsxs("span",{className:n.adRatio<=s.targetAdRatio?"text-emerald-600":"text-red-600",children:[n.adRatio.toFixed(2),"%"]})}),e.jsxs("div",{className:"mt-0.5 text-xs text-gray-400",children:["목표 ",s.targetAdRatio,"% 이하 · 목표 광고비 ",qe(o.adCost)]})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-xs text-gray-500",children:"ROAS vs 목표"}),e.jsx("div",{className:"mt-1 text-2xl font-semibold tabular-nums",children:n.roas==null||x==null?e.jsx("span",{className:"text-gray-300",children:"—"}):e.jsxs("span",{className:n.roas>=x?"text-emerald-600":"text-red-600",children:[Math.round(n.roas).toLocaleString("ko-KR"),"%"]})}),e.jsxs("div",{className:"mt-0.5 text-xs text-gray-400",children:["목표 ",x==null?"—":`${Math.round(x).toLocaleString("ko-KR")}%`," 이상"]})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center gap-1.5 text-xs text-gray-500",children:["월말 예상 착지",i?.provisional&&e.jsx("span",{className:"rounded bg-amber-100 px-1.5 py-0.5 text-[10px] font-medium text-amber-800",children:"참고치"})]}),i?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"mt-1 text-2xl font-semibold tabular-nums",children:qe(i.revenue)}),e.jsxs("div",{className:"mt-0.5 text-xs text-gray-400",children:["목표 대비 ",(i.revenue/s.monthlyRevenue*100).toFixed(1),"%",i.requiredDailyAverage!=null&&e.jsxs(e.Fragment,{children:[" · 남은 ",i.remainingDays,"일 일평균 ",qe(i.requiredDailyAverage)," 필요"]})]})]}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"mt-1 text-2xl font-semibold text-gray-300",children:"—"}),e.jsx("div",{className:"mt-0.5 text-xs text-gray-400",children:"진행 중인 달에만 표시됩니다"})]})]})]})]})}const qn={good:"bg-emerald-50 text-emerald-700",bad:"bg-red-50 text-red-700",flat:"bg-gray-50 text-gray-400"},Yn={up:"▲",down:"▼",flat:"–"},Jn={good:"긍정",bad:"부정",flat:"변화 없음"};function Zn({kpiKey:s,delta:t,text:a}){const{direction:r,tone:l}=ha(s,t);return e.jsxs("span",{className:`inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-xs font-medium tabular-nums ${qn[l]}`,title:`${r==="up"?"증가":r==="down"?"감소":"변화 없음"} · ${Jn[l]}`,children:[e.jsx("span",{"aria-hidden":"true",className:"text-[10px] leading-none",children:Yn[r]}),a]})}function Ye({label:s,kpiKey:t,value:a,emptyReason:r,hint:l,badge:n,comparisons:o,formatDelta:i}){return e.jsxs("div",{className:"rounded-lg border bg-white p-4",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"text-xs text-gray-500",children:s}),n&&e.jsx("span",{className:"rounded bg-amber-100 px-1.5 py-0.5 text-[10px] font-medium text-amber-800",children:n})]}),a!==null?e.jsx("div",{className:"mt-1 text-2xl font-semibold tabular-nums",children:a}):e.jsxs("div",{className:"mt-1",children:[e.jsx("span",{className:"text-2xl font-semibold text-gray-300",children:"—"}),r&&e.jsx("span",{className:"ml-2 text-xs text-gray-500",children:r})]}),l&&e.jsx("div",{className:"mt-0.5 text-[11px] text-gray-400",children:l}),e.jsx("div",{className:"mt-2 space-y-1",children:o.map(m=>e.jsxs("div",{className:"flex items-center justify-between text-xs",children:[e.jsx("span",{className:"text-gray-400",children:m.label}),m.delta?e.jsx(Zn,{kpiKey:t,delta:m.delta,text:i(m.delta)}):e.jsx("span",{className:"text-gray-300",children:"비교 불가"})]},m.label))})]})}const gt=s=>
4`₩${Math.round(s).toLocaleString("ko-KR")}`,Qn={good:"text-emerald-700",bad:"text-red-700",flat:"text-gray-400"};function jt({d:s,kpiKey:t}){if(!s)return e.jsx("span",{className:"text-gray-300",children:"—"});const{direction:a,tone:r}=ha(t,s),l=a==="up"?"▲":a==="down"?"▼":"–",n=s.pct==null?"신규":`${s.pct>0?"+":""}${s.pct.toFixed(1)}%`;return e.jsxs("span",{className:`whitespace-nowrap tabular-nums ${Qn[r]}`,children:[e.jsx("span",{className:"mr-0.5 text-[10px]",children:l}),n]})}function Xn({rows:s,comparisonLabel:t}){return e.jsxs("div",{className:"rounded-lg border bg-white",children:[e.jsxs("div",{className:"flex flex-wrap items-baseline gap-2 border-b px-4 py-3",children:[e.jsx("span",{className:"text-sm font-semibold text-gray-800",children:"상품유형별 매출 · 건당 단가"}),t&&e.jsxs("span",{className:"text-xs text-gray-500",children:["증감은 ",t," 대비"]})]}),e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-gray-50 text-left text-xs whitespace-nowrap text-gray-500",children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-4 py-2",children:"상품유형"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"매출"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"증감"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"건수"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"건당 단가"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"증감"})]})}),e.jsxs("tbody",{children:[s.length===0&&e.jsx("tr",{children:e.jsx("td",{colSpan:6,className:"px-4 py-8 text-center text-gray-400",children:"이 기간에 상품유형별 매출이 없습니다."})}),s.map(a=>e.jsxs("tr",{className:"border-t",children:[e.jsx("td",{className:"whitespace-nowrap px-4 py-2 font-medium",children:a.label}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2 text-right tabular-nums",children:gt(a.revenue)}),e.jsx("td",{className:"px-4 py-2 text-right",children:e.jsx(jt,{d:a.revenueDelta,kpiKey:"gmv"})}),e.jsxs("td",{className:"whitespace-nowrap px-4 py-2 text-right text-gray-500 tabular-nums",children:[a.orderCount.toLocaleString("ko-KR"),"건"]}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2 text-right tabular-nums",children:a.unitPrice==null?e.jsx("span",{className:"text-gray-300",children:"—"}):gt(a.unitPrice)}),e.jsx("td",{className:"px-4 py-2 text-right",children:e.jsx(jt,{d:a.unitPriceDelta,kpiKey:"aov"})})]},a.productType))]})]})})]})}function ja(){const[s,t]=h.useState(()=>Gn()),[a,r]=h.useState(!1),l=h.useCallback(o=>{try{pt(o),t(o),r(!1),U.success("목표를 저장했습니다.")}catch(i){U.error(i instanceof Error?i.message:String(i))}},[]),n=h.useCallback(()=>{try{pt($s),t($s),U.success("목표를 지웠습니다.")}catch(o){U.error(o instanceof Error?o.message:String(o))}},[]);return{goals:s,editing:a,setEditing:r,update:l,reset:n}}function ft(s,t){return t>0?s/t:null}function el(s,t){const a=new Map(t.map(r=>[r.productType,r]));return s.map(r=>{const l=a.get(r.productType),n=ft(r.revenue,r.orderCount),o=l?ft(l.revenue,l.orderCount):null;return{productType:r.productType,label:r.label,revenue:r.revenue,orderCount:r.orderCount,unitPrice:n,revenueDelta:l?Ne(r.revenue,l.revenue):null,unitPriceDelta:Ne(n,o)}}).sort((r,l)=>l.revenue-r.revenue)}function vt(s,t=!1){return t?`${s}T23:59:59.999+09:00`:`${s}T00:00:00+09:00`}async function Nt(s,t,a="daily"){const{data:r,error:l}=await H.rpc("get_store_revenue_trend",{p_start:vt(s),p_end:vt(t,!0),p_granularity:a});if(l)throw l;return(r??[]).map(n=>({bucketDate:String(n.bucket_date),storeCode:String(n.store_code??""),mallUserId:n.mall_user_id??null,orderCount:Number(n.order_count??0),revenue:Number(n.revenue??0)}))}const Ee={direct:"__direct__",factory:"__factory__",coupangRocket:"__coupang_rocket__"},sl={shop0055:"smartstore",shop0075:"coupang"};function tl(s,t){const a=(s??"").trim();if(a===Ee.direct||a===Ee.factory)return"own";if(a===Ee.coupangRocket)return"coupang";const r=sl[a];return r||(t&&t.toLowerCase().startsWith("ncp_")?"smartstore":"etc")}function al(s,t){switch(s){case Ee.direct:return"공홈 (자사몰)";case Ee.factory:return"간편재단";case Ee.coupangRocket:return"쿠팡 로켓";default:return t}}const bt=["smartstore","own","coupang","etc"];function rl(s){const t={};
4for(const a of s)a.coverage==="full"&&(t[a.channel]=(t[a.channel]??0)+a.cost);return t}function nl(s,t,a){const r=new Map;for(const n of s){const o=tl(n.storeCode,n.mallUserId);let i=r.get(o);i||(i={revenue:0,orderCount:0,stores:new Map},r.set(o,i)),i.revenue+=n.revenue,i.orderCount+=n.orderCount;const m=al(n.storeCode,a(n.storeCode,n.mallUserId)),d=i.stores.get(m)??{name:m,revenue:0,orderCount:0};d.revenue+=n.revenue,d.orderCount+=n.orderCount,i.stores.set(m,d)}const l=[];for(const n of bt){const o=r.get(n);if(!o)continue;const i=t[n]??null,m=i!=null&&i>0;l.push({channel:n,revenue:o.revenue,orderCount:o.orderCount,adCost:i,adRatio:m&&o.revenue>0?i/o.revenue*100:null,roas:m?o.revenue/i*100:null,stores:[...o.stores.values()].sort((d,g)=>g.revenue-d.revenue)})}for(const[n,o]of r)bt.includes(n)||l.push({channel:n,revenue:o.revenue,orderCount:o.orderCount,adCost:null,adRatio:null,roas:null,stores:[...o.stores.values()].sort((i,m)=>m.revenue-i.revenue)});return l}function ll(s,t){return s==="daily"?{startDate:te(t.startDate,-13),endDate:t.endD
4ate}:s==="weekly"?{startDate:te(t.startDate,-7),endDate:t.endDate}:t}function il(s,t,a,r,l){const n=new Map;for(const i of a)n.set(i.bucketDate,(n.get(i.bucketDate)??0)+i.revenue);const o=new Map;for(const i of r)o.set(i.costDate,(o.get(i.costDate)??0)+i.cost);return Ae(s).map(i=>{const m=new Date(`${i}T00:00:00Z`).getUTCDay();return{date:i,label:`${i.slice(5,7)}/${i.slice(8,10)}`,revenue:n.get(i)??0,adCost:o.has(i)?o.get(i):null,isHoliday:l.has(i),isWeekend:m===0||m===6,inPeriod:i>=t.startDate&&i<=t.endDate}})}function cl(s){const t=new Map;for(const a of s)t.set(a.bucketDate,(t.get(a.bucketDate)??0)+a.revenue);return t}function yt(){const s=new Date;return new Date(s.getTime()+9*36e5).toISOString().slice(0,10)}async function wt(s){const[t,a]=await Promise.all([Xa(s,"all"),er(s.startDate,s.endDate)]),l=a.rows.some(n=>n.coverage==="full")?a.confirmedCost:null;return{kpis:Mn(t.gmv,t.orderCount,l),ad:a}}function fa(s){const[t,a]=h.useState("weekly"),[r,l]=h.useState(yt()),n=h.useMemo(()=>En(t,r),[t,r]),o=h.useMemo(()=>ua(t,n),[t,n]),[i,m]=h.useState(null),[d,g]=h.useState(null),[c,x]=h.useState([]),[N,j]=h.useState([]),[p,u]=h.useState([]),[b,T]=h.useState([]),[P,$]=h.useState(null),[D,V]=h.useState(null),[k,w]=h.useState(null),[I,S]=h.useState(!1),[Q,y]=h.useState(null),M=h.useCallback(async()=>{S(!0),y(null);try{const f=ll(t,n),v={startDate:[f.startDate,Ce(n.startDate)].sort()[0],endDate:[f.endDate,ls(n.endDate)].sort().reverse()[0]},L=o[0]?.range??null,[A,R,O,G,z,se,ve]=await Promise.all([wt(n),Nt(n.startDate,n.endDate,t),Nt(v.startDate,v.endDate,"daily"),Qa(v.startDate,v.endDate),nr(v.startDate,v.endDate),tt(n,"all"),L?tt(L,"all"):Promise.resolve([])]);T(el(se,ve)),x(nl(R,rl(A.ad.rows),(C,J)=>rr(C,J,C||"기타"))),u(il(f,n,O,G,z)),$(Is(s,n,z));const ae=yt(),Se=n.startDate.slice(0,7)===ae.slice(0,7),E=ae>=n.startDate&&ae<n.endDate;V(E?Is(s,{startDate:n.startDate,endDate:ae},z):Is(s,n,z)),w(Se?Vn(cl(O),ae,z,s):null);const B=await Promise.all(o.map(async C=>{const J=await wt(C.range);return{key:C.key,label:C.label,range:C.range,kpis:J.kpis,deltas:{gmv:Ne(A.kpis.gmv,J.kpis.gmv),adCost:Ne(A.kpis.adCost,J.kpis.adCost),adRatio:Ne(A.kpis.adRatio,J.kpis.adRatio),roas:Ne(A.kpis.roas,J.kpis.roas),aov:Ne(A.kpis.aov,J.kpis.aov),orderCount:Ne(A.kpis.orderCount,J.kpis.orderCount)}}}));m(A.kpis),g(A.ad),j(B)}catch(f){const v=f instanceof Error?f.message:String(f);y(v),U.error(`성과 개요를 불러오지 못했습니다: ${v}`)}finally{S(!1)}},[n,o,t,s]);return h.useEffect(()=>{M()},[M]),{mode:t,setMode:a,anchor:r,setAnchor:l,period:n,kpis:i,adSummary:d,channels:c,results:N,points:p,productTypes:b,target:P,paceTarget:D,forecast:k,loading:I,error:Q,reload:M}}const ol={direct:"직접 방문 (UTM 없음)",unknown:"유입경로 없음",blog:"블로그",internal:"사이트 내부",kakao:"카카오"};function _e(s){return Object.prototype.hasOwnProperty.call(Ke,s)}function Es(s){return _e(s)?Ke[s]:ol[s]??s}const dl={auto:"자동 수집",manual:"파일 업로드",none:"집행 중단"};function ml(s){const t=Date.parse(`${s}T00:00:00Z`);if(Number.isNaN(t))throw new Error(`날짜 형식이 올바르지 않습니다: ${s}`);return t}function Bs(s,t){return new Date(ml(s)+t*864e5).toISOString().slice(0,10)}function xl(s,t,a){if(s.spans.some(n=>n.start<=t&&t<=n.end))return"data";if(s.active===!1||s.collection==="none")return"no_spend";const r=Math.max(0,s.graceDays),l=Bs(a,-1-r);return t>l?"pending":s.collection==="auto"?s.latestPeriodEnd!==null&&t<=s.latestPeriodEnd?"no_spend":"feed_stale":"not_entered"}function ul(s,t,a){if(t.endDate<t.startDate)throw new Error(`기간이 올바르지 않습니다: ${t.startDate} ~ ${t.endDate}`);const r={data:0,no_spend:0,feed_stale:0,not_entered:0,pending:0},l=[],n=t.endDate<a?t.endDate:a;for(let d=t.startDate;d<=n;
4d=Bs(d,1)){const g=xl(s,d,a);if(r[g]+=1,g==="data")continue;const c=l[l.length-1];c&&c.cause===g&&Bs(c.to,1)===d?(c.to=d,c.days+=1):l.push({cause:g,from:d,to:d,days:1})}const o=s.spans.some(d=>(d.start<t.startDate||d.end>t.endDate)&&d.start<=n),i=r.data+r.no_spend+r.feed_stale+r.not_entered;let m;return r.feed_stale>0?m="feed_stale":r.not_entered>0?m="not_entered":i===0?m="pending":r.data===0?m="no_spend":o?m="estimated":m="ok",{media:s.media,collection:s.collection,active:s.active,owner:s.owner,latestPeriodEnd:s.latestPeriodEnd,judgedDays:i,dataDays:r.data,noSpendDays:r.no_spend,staleDays:r.feed_stale,notEnteredDays:r.not_entered,pendingDays:r.pending,gaps:l,estimated:o,status:m}}const hl={feed_stale:"수집 끊김",not_entered:"입력 안 됨",estimated:"추정 포함",ok:"정상",no_spend:"집행 없음",pending:"집계 전"};function et(s){switch(s){case"feed_stale":return"없음 · 수집 끊김";case"not_entered":return"없음 · 입력 안 됨";case"pending":return"집계 전";case null:return"없음 · 판정 못 함";default:return"집행 없음"}}function va(s){return s.filter(t=>t.status==="feed_stale"||t.status==="not_entered")}function St(s,t){const a=r=>`${Number(r.slice(5,7))}/${Number(r.slice(8,10))}`;return s===t?a(s):`${a(s)}~${a(t)}`}function pl(s,t){const a=l=>s.gaps.filter(n=>n.cause===l).map(n=>St(n.from,n.to)).join(", "),r=s.owner?`담당 ${s.owner}`:"담당 미지정";if(s.status==="feed_stale"){const l=s.latestPeriodEnd?`마지막 적재 ${St(s.latestPeriodEnd,s.latestPeriodEnd)}`:"적재된 적 없음";return`${t} — ${a("feed_stale")} 수집 끊김 (자동 수집, ${l}). ${r} 확인 필요.`}return s.status==="not_entered"?`${t} — ${a("not_entered")} 광고비 입력 안 됨. 광고비 탭에서 이 기간 리포트를 올려 주세요. 실제로 집행하지 않았다면 ${r}에게 알려 주세요.`:null}const _t=s=>`₩${Math.round(s).toLocaleString("ko-KR")}`,gl={feed_stale:"bg-red-50 text-red-700",not_entered:"bg-orange-50 text-orange-700",estimated:"bg-amber-50 text-amber-800",ok:"bg-emerald-50 text-emerald-700",no_spend:"bg-gray-100 text-gray-600",pending:"bg-gray-100 text-gray-500"};function jl({coverage:s,loading:t,error:a}){if(a)return e.jsxs("div",{className:"rounded-lg border border-red-200 bg-red-50 p-4 text-sm text-red-800",children:[e.jsx("div",{className:"font-medium",children:"매체별 데이터 유무를 판정하지 못했습니다"}),e.jsxs("div",{className:"mt-1",children:[a," — 아래 광고비 합계에 빠진 매체가 있는지 알 수 없습니다."]})]});if(t&&!s)return e.jsxs("div",{className:"flex items-center gap-2 rounded-lg border bg-white px-4 py-3 text-sm text-gray-400",children:[e.jsx(fe,{className:"h-4 w-4 animate-spin"})," 매체별 데이터 유무 확인 중…"]});if(!s)return null;const r=va(s);return r.length===0?null:e.jsx("div",{children:e.jsx("div",{className:"rounded-lg border border-orange-200 bg-orange-50 p-4",children:e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(we,{className:"mt-0.5 h-4 w-4 shrink-0 text-orange-600"}),e.jsxs("div",{className:"flex-1 text-sm",children:[e.jsxs("div",{className:"font-semibold text-orange-900",children:["광고비가 빠졌을 수 있는 매체 ",r.length,"곳 — 아래 광고비 합계는 실제보다 작을 수 있습니다"]}),e.jsx("ul",{className:"mt-2 space-y-1.5",children:r.map(l=>e.jsxs("li",{className:l.status==="feed_stale"?"text-red-800":"text-orange-900",children:["· ",pl(l,Es(l.media)),l.status==="not_entered"&&e.jsx(Sa,{to:{search:"?tab=ad-costs"},className:"ml-2 font-medium underline underline-offset-2",children:"광고비 탭에서 올리기"})]},l.media))})]})]})})})}function fl({coverage:s,adSummary:t}){if(!s)return null;const a=new Map;for(const r of t?.excluded??[])a.set(r.media,(a.get(r.media)??0)+r.cost);return e.jsxs("div",{className:"rounded-lg border bg-white",children:[e.jsxs("div",{className:"flex flex-wrap items-baseline gap-2 border-b px-4 py-3",children:[e.jsx("span",{className:"text-sm font-semibold text-gray-800",children:"매체별 데이터 유무 (전 매체)"}),e.jsx("span",{className:"text-xs text-gray-500",children:"광고비 집행일 기준 · 오늘과 유예일 안은 「집계 전」 · 매체 설정 = marketing_media_config"})]}),e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-gray-50 text-left text-xs whitespace-nowrap text-gray-500",children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-4 py-2",children:"매체"}),e.jsx("th",{className:"px-4 py-2",children:"수집"}),e.jsx("th",{className:"px-4 py-2",children:"담당"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"데이터 있는 날"}),e.jsx("th",{className:"px-4 py-2",children:"상태"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"확정 광고비"})]})}),e.jsx("tbody",{children:s.map(r=>{const l=t?.byMedia[r.media]??0,n=a.get(r.media)??0;return e.jsxs("tr",{className:"border-t",children:[e.jsx("td",{className:"whitespace-nowrap px-4 py-2 font-medium",children:Es(r.media)}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2 text-gray-500",children:r.collection?dl[r.collection]:"설정 없음"}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2 text-gray-500",children:r.owner??"—"}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2 text-right tabular-nums text-gray-600",children:r.judgedDays===0?"—":`${r.dataDays} / ${r.judgedDays}일`}),e.jsx("td",{className:"whitespace-nowrap px-4 py-2",children:e.jsx("span",{className:`inline-block rounded px-1.5 py-0.5 text-[11px] font-medium ${gl[r.status]}`,children:hl[r.status]})}),e.jsxs("td",{className:"whitespace-nowrap px-4 py-2 text-right tabular-nums",children:[l>0?_t(l):e.jsx("span",{className:"text-gray-400",children:et(r.status)}),n>0&&e.jsxs("div",{className:"text-[11px] text-amber-700",children:["기간 미제공 ",_t(n)]})]})]},r.media)})})]})})]})}const Na={kitchen:"주방",entrance:"현관"},Vs=30;function Ue(s){const t=m=>s.reduce((d,g)=>d+m(g),0),a=t(m=>m.adCostUsed),r=t(m=>m.leads),l=t(m=>m.leadsConverted),n=t(m=>m.leadsConvertedLinked),o=t(m=>m.directOrders),i=t(m=>m.leadRevenue+m.directRevenue);return{adCost:a,adCostEstimate:t(m=>
4m.adCostPartialEst),leads:r,conversions:l+o,leadsConverted:l,convertedWithoutOrder:l-n,directOrders:o,revenue:i,cpl:a>0&&r>0?a/r:null,roas:a>0?i/a*100:null,smallSample:r<Vs}}function vl(s,t){return t==="all"?s:s.filter(a=>a.space===t)}function Nl(s,t){const a=new Map;for(const l of t){const n=`${l.space}|${l.campaign}`,o=a.get(n)??[];o.push(l),a.set(n,o)}const r=[...a.values()].map(l=>{const n=Ue(l),o=l.some(m=>m.adCostUsed>0||m.adCostPartial>0),i=n.leads>0||n.directOrders>0;return{...n,campaign:l[0].campaign,space:l[0].space,nameUnmatched:_e(s)&&o!==i}});return r.sort((l,n)=>n.adCost-l.adCost||n.leads-l.leads||l.campaign.localeCompare(n.campaign)),{...Ue(t),media:s,label:Es(s),isAdMedia:_e(s),hasAdRows:t.some(l=>l.adCostUsed>0||l.adCostPartial>0),campaigns:r}}function kt(s,t){const a=vl(s,t),r=new Map;for(const i of a){const m=r.get(i.media)??[];m.push(i),r.set(i.media,m)}const l=[...r.entries()].map(([i,m])=>Nl(i,m)),n=l.filter(i=>i.isAdMedia).sort((i,m)=>m.adCost-i.adCost||m.leads-i.leads),o=l.filter(i=>!i.isAdMedia).sort((i,m)=>m.leads-i.leads||m.revenue-i.revenue);return{adMedia:n,otherSources:o,adTotal:Ue(a.filter(i=>_e(i.media))),projectTotal:Ue(a),bySpace:{kitchen:Ue(s.filter(i=>i.space==="kitchen"&&_e(i.media))),entrance:Ue(s.filter(i=>i.space==="entrance"&&_e(i.media)))}}}function bl(s,t,a){const r=new Set(s.adMedia.map(n=>n.media)),l=new Set;for(const n of t?.adMedia??[])n.adCost>0&&!r.has(n.media)&&l.add(n.media);for(const[n,o]of a)!r.has(n)&&_e(n)&&(o==="feed_stale"||o==="not_entered")&&t?.adMedia.some(i=>i.media===n)&&l.add(n);return[...l].sort()}function yl(s,t){return s?s.adMedia.find(a=>a.media===t)??s.otherSources.find(a=>a.media===t)??null:null}const xs=s=>`₩${Math.round(s).toLocaleString("ko-KR")}`;function wl(s,t,a,r){const l=[];l.push(s.adCost>0?`광고비 ${xs(s.adCost)}`:"확정 광고비 없음"),l.push(`리드 ${s.leads}건${s.cpl!=null?`(CPL ${xs(s.cpl)}${s.smallSample?", 관측":""})`:""}`),l.push(`주문 전환 ${s.conversions}건`),l.push(s.roas!=null?`실매출 ${xs(s.revenue)} · ROAS ${Math.round(s.roas)}%`:`실매출 ${xs(s.revenue)} · ROAS 계산 불가(광고비 없음)`);let n=l.join(" → ");if(t&&r)if(s.cpl!=null&&t.cpl!=null){const o=(s.cpl-t.cpl)/t.cpl*100;n+=`. ${r} 대비 CPL ${o>=0?"+":""}${o.toFixed(0)}%`}else(t.leads>0||s.leads>0)&&(n+=`. ${r} 리드 ${t.leads}건`);return a>0&&(n+=` · 광고비 누락 가능 매체 ${a}곳(위 경고)`),n}const Z=s=>`₩${Math.round(s).toLocaleString("ko-KR")}`;function be(s){return s.cpl==null?"–":Z(s.cpl)}function ye(s){return s.roas==null?"–":`${Math.round(s.roas).toLocaleString("ko-KR")}%`}function Sl({m:s,status:t}){const a=t==="feed_stale"||t==="not_entered";return e.jsxs("div",{children:[s.adCost>0?e.jsx("span",{children:Z(s.adCost)}):e.jsx("span",{className:a?"font-medium text-orange-700":"text-gray-400",children:s.adCostEstimate>0?"확정분 없음":et(t)}),s.adCostEstimate>0&&e.jsxs("div",{className:"text-[11px] text-amber-700",children:["추정 +",Z(s.adCostEstimate)," (걸친 리포트)"]}),s.adCost>0&&a&&e.jsx("div",{className:"text-[11px] text-orange-700",children:t==="feed_stale"?"수집 끊김 — 더 있을 수 있음":"입력 안 됨 — 더 있을 수 있음"})]})}function _l({view:s,prevView:t,cmpLabel:a,statusByMedia:r,statusOf:l}){const[n,o]=h.useState(new Set),i=d=>o(g=>{const c=new Set(g);return c.has(d)?c.delete(d):c.add(d),c}),m=t?.adTotal??null;return e.jsx("div",{className:"overflow-x-auto rounded-lg border bg-white",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-gray-50 text-left text-xs whitespace-nowrap text-gray-500",children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-3 py-2",children:"매체 · 캠페인"}),e.jsxs("th",{className:"px-3 py-2 text-right",children:["광고비",e.jsx("div",{className:"font-normal",children:"집행일"})]}),e.jsxs("th",{className:"px-3 py-2 text-right",children:["리드",e.jsx("div",{className:"font-normal",children:"접수일"})]}),e.jsxs("th",{className:"px-3 py-2 text-right",children:["주문 전환",e.jsx("div",{className:"font-normal",children:"접수 코호트 + 직접 주문"})]}),e.jsx("th",{className:"px-3 py-2 text-right",children:"실매출"}),e.jsx("th",{className:"px-3 py-2 text-right",children:"CPL"}),e.jsx("th",{className:"px-3 py-2 text-right",children:"실매출 ROAS"}),a&&e.jsxs("th",{className:"px-3 py-2 text-right",children:[a," CPL · ROAS"]})]})}),e.jsxs("tbody",{children:[s.adMedia.map(d=>{const g=yl(t,d.media),c=n.has(d.media);return e.jsxs(h.Fragment,{children:[e.jsxs("tr",{className:"cursor-pointer border-t hover:bg-gray-50",onClick:()=>i(d.media),children:[e.jsxs("td",{className:"whitespace-nowrap px-3 py-2 font-medium",children:[c?e.jsx(lr,{className:"mr-1 inline h-3.5 w-3.5"}):e.jsx(ir,{className:"mr-1 inline h-3.5 w-3.5"}),d.label,e.jsxs("span",{className:"ml-1 text-xs font-normal text-gray-400",children:["캠페인 ",d.campaigns.length]})]}),e.jsx("td",{className:"whitespace-nowrap px-3 py-2 text-right tabular-nums",children:e.jsx(Sl,{m:d,status:l(d.media)})}),e.jsxs("td",{className:"px-3 py-2 text-right tabular-nums",children:[d.leads,"건"]}),e.jsxs("td",{className:"px-3 py-2 text-right tabular-nums",children:[d.conversions,"건"]}),e.jsx("td",{className:"px-3 py-2 text-right tabular-nums",children:Z(d.revenue)}),e.jsxs("td",{className:"whitespace-nowrap px-3 py-2 text-right tabular-nums",children:[be(d),d.cpl!=null&&d.smallSample&&e.jsx("span",{className:"ml-1 rounded bg-gray-100 px-1 text-[10px] text-gray-500",children:"관측"})]}),e.jsx("td",{className:"px-3 py-2 text-right tabular-nums",children:ye(d)}),a&&e.jsx("td",{className:"whitespace-nowrap px-3 py-2 text-right text-xs tabular-nums text-gray-500",children:g?`${be(g)} · ${ye(g)}`:"줄 없음"})]}),c&&d.campaigns.map(x=>e.jsxs("tr",{className:"border-t bg-gray-50/60 text-xs",children:[e.jsxs("td",{className:"px-3 py-1.5 pl-8",children:[e.jsx("span",{className:`mr-1.5 rounded px-1 py-0.5 text-[10px] font-medium ${x.space==="entrance"?"bg-pink-50 text-pink-700":"bg-indigo-50 text-indigo-700"}`,children:Na[x.space]}),x.campaign||e.jsx("span",{className:"text-gray-400",children:"(캠페인 이름 없음)"}),x.nameUnmatched&&e.jsx("span",{className:"ml-1.5 text-amber-700",title:"광고비 캠페인 이름과 접수·주문의 utm_campaign 이 글자 그대로 같아야 이어진다 (이름 규칙 v3)",children:"이름 안 맞음"})]}),e.jsx("td",{className:"px-3 py-1.5 text-right tabular-nums",children:x.adCost>0?Z(x.adCost):x.adCostEstimate>0?`추정 ${Z(x.adCostEstimate)}`:"–"}),e.jsx("td",{className:"px-3 py-1.5 text-right tabular-nums",children:x.leads}),e.jsx("td",{className:"px-3 py-1.5 text-right tabular-nums",children:x.conversions}),e.jsx("td",{className:"px-3 py-1.5 text-right tabular-nums",children:x.revenue>0?Z(x.revenue):"–"}),e.jsx("td",{className:"px-3 py-1.5 text-right tabular-nums",children:be(x)}),e.jsx("td",{className:"px-3 py-1.5 text-right tabular-nums",children:ye(
4x)}),a&&e.jsx("td",{})]},`${d.media}-${x.space}-${x.campaign}`))]},d.media)}),t&&bl(s,t,r).map(d=>e.jsxs("tr",{className:"border-t",children:[e.jsx("td",{className:"px-3 py-2 font-medium text-gray-500",children:Es(d)}),e.jsx("td",{className:"px-3 py-2 text-right",colSpan:a?7:6,children:e.jsxs("span",{className:"inline-flex items-center gap-1 text-orange-700",children:[e.jsx(we,{className:"h-3.5 w-3.5"}),"이번 기간 셀프 도어 광고비·리드 없음 — ",et(l(d)),a&&` (${a}에는 있었음)`]})})]},`silent-${d}`)),s.adMedia.length===0&&e.jsx("tr",{className:"border-t",children:e.jsx("td",{className:"px-3 py-4 text-center text-gray-400",colSpan:a?8:7,children:"이 기간 셀프 도어 광고비·광고 유입 리드가 없습니다."})}),e.jsxs("tr",{className:"border-t-2 bg-gray-50 font-semibold",children:[e.jsx("td",{className:"px-3 py-2",children:"광고 매체 합계"}),e.jsx("td",{className:"px-3 py-2 text-right tabular-nums",children:s.adTotal.adCost>0?Z(s.adTotal.adCost):"확정분 없음"}),e.jsxs("td",{className:"px-3 py-2 text-right tabular-nums",children:[s.adTotal.leads,"건"]}),e.jsxs("td",{className:"px-3 py-2 text-right tabular-nums",children:[s.adTotal.conversions,"건"]}),e.jsx("td",{className:"px-3 py-2 text-right tabular-nums",children:Z(s.adTotal.revenue)}),e.jsx("td",{className:"px-3 py-2 text-right tabular-nums",children:be(s.adTotal)}),e.jsx("td",{className:"px-3 py-2 text-right tabular-nums",children:ye(s.adTotal)}),a&&e.jsx("td",{className:"px-3 py-2 text-right text-xs tabular-nums text-gray-500",children:m?`${be(m)} · ${ye(m)}`:"–"})]})]})]})})}const kl=["일","월","화","수","목","금","토"],us=s=>{const t=new Date(`${s}T00:00:00Z`);return`${t.getUTCMonth()+1}/${t.getUTCDate()}(${kl[t.getUTCDay()]})`},Cl=[{value:"all",label:"전체"},{value:"kitchen",label:"주방"},{value:"entrance",label:"현관"}];function Je({label:s,value:t,sub:a,note:r}){return e.jsxs("div",{className:"rounded-lg border bg-white p-3",children:[e.jsx("div",{className:"text-xs text-gray-500",children:s}),e.jsx("div",{className:"mt-1 text-xl font-semibold tabular-nums text-gray-900",children:t}),a&&e.jsx("div",{className:"mt-0.5 text-xs text-gray-500",children:a}),r&&e.jsx("div",{className:"mt-0.5 text-[11px] text-amber-700",children:r})]})}function Dl({period:s,comparison:t,current:a,previous:r,loading:l,error:n,coverage:o}){const[i,m]=h.useState("all"),d=h.useMemo(()=>a?kt(a,i):null,[a,i]),g=h.useMemo(()=>r?kt(r,i):null,[r,i]),c=h.useMemo(()=>new Map((o??[]).map(u=>[u.media,u.status])),[o]),x=u=>o?c.get(u)??null:null,N=(o??[]).filter(u=>u.status==="feed_stale"||u.status==="not_entered").length,j=t?.label??null,p=g?.adTotal??null;return e.jsxs("section",{className:"space-y-4 rounded-xl border-2 border-gray-900/10 bg-gray-50 p-4",children:[e.jsxs("div",{className:"flex flex-wrap items-end justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"text-lg font-bold text-gray-900",children:"셀프 도어 교체"}),e.jsxs("div",{className:"text-xs text-gray-500",children:[us(s.startDate)," ~ ",us(s.endDate),t&&e.jsxs("span",{children:[" ","· 비교 ",t.label," ",us(t.range.startDate)," ~ ",us(t.range.endDate)]})]})]}),e.jsx("div",{className:"flex rounded-md border bg-white p-0.5",children:Cl.map(u=>e.jsx("button",{type:"button",onClick:()=>m(u.value),className:`rounded px-3 py-1 text-sm ${i===u.value?"bg-gray-900 font-medium text-white":"text-gray-600 hover:bg-gray-100"}`,children:u.label},u.value))})]}),n&&e.jsxs("div",{className:"rounded-lg border border-red-200 bg-red-50 p-3 text-sm text-red-700",children:["셀프 도어 교체 숫자를 불러오지 못했습니다: ",n]}),l&&!d&&e.jsxs("div",{className:"flex items-center gap-2 text-sm text-gray-400",children:[e.jsx(fe,{className:"h-4 w-4 animate-spin"})," 불러오는 중…"]}),d&&e.jsxs(e.Fragment,{children:[e.jsx("p",{className:"rounded-lg bg-white px-3 py-2 text-sm font-medium text-gray-800",children:wl(d.adTotal,p,N,j)}),e.jsxs("div",{className:"grid gap-3 sm:grid-cols-3 xl:grid-cols-5",children:[e.jsx(Je,{label:"광고비 (집행일)",value:d.adTotal.adCost>0?Z(d.adTotal.adCost):"확정분 없음",sub:p&&j?`${j} ${p.adCost>0?Z(p.adCost):"없음"}`:void 0,note:N>0?`${N}개 매체 누락 가능`:d.adTotal.adCostEstimate>0?`추정 +${Z(d.adTotal.adCostEstimate)}`:void 0}),e.jsx(Je,{label:"리드 · TM 접수 (접수일)",value:`${d.adTotal.leads.toLocaleStr
4ing("ko-KR")}건`,sub:p&&j?`${j} ${p.leads}건`:void 0,note:"광고 매체 유입만 · 중복 접수 제외"}),e.jsx(Je,{label:"주문 전환",value:`${d.adTotal.conversions.toLocaleString("ko-KR")}건`,sub:p&&j?`${j} ${p.conversions}건`:void 0,note:d.adTotal.convertedWithoutOrder>0?`전환 표시 ${d.adTotal.convertedWithoutOrder}건은 주문 연결 없음`:void 0}),e.jsx(Je,{label:"CPL (광고비 ÷ 리드)",value:be(d.adTotal),sub:p&&j?`${j} ${be(p)}`:void 0,note:d.adTotal.cpl!=null&&d.adTotal.smallSample?`관측 — 리드 ${Vs}건 미만`:void 0}),e.jsx(Je,{label:"실매출 ROAS",value:ye(d.adTotal),sub:`실매출 ${Z(d.adTotal.revenue)}${p&&j?` · ${j} ${ye(p)}`:""}`,note:"판매처 실매출 ÷ 광고비 (매체 보고 전환매출 아님)"})]}),e.jsxs("div",{className:"overflow-x-auto rounded-lg border bg-white",children:[e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-gray-50 text-left text-xs whitespace-nowrap text-gray-500",children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-3 py-2",children:"공간"}),e.jsx("th",{className:"px-3 py-2 text-right",children:"광고비"}),e.jsx("th",{className:"px-3 py-2 text-right",children:"리드"}),e.jsx("th",{className:"px-3 py-2 text-right",children:"주문 전환"}),e.jsx("th",{className:"px-3 py-2 text-right",children:"실매출"}),e.jsx("th",{className:"px-3 py-2 text-right",children:"CPL"}),e.jsx("th",{className:"px-3 py-2 text-right",children:"ROAS"})]})}),e.jsx("tbody",{children:["kitchen","entrance"].map(u=>{const b=d.bySpace[u];return e.jsxs("tr",{className:"border-t",children:[e.jsx("td",{className:"px-3 py-2 font-medium",children:Na[u]}),e.jsx("td",{className:"px-3 py-2 text-right tabular-nums",children:b.adCost>0?Z(b.adCost):e.jsx("span",{className:"text-gray-400",children:"확정분 없음"})}),e.jsxs("td",{className:"px-3 py-2 text-right tabular-nums",children:[b.leads,"건"]}),e.jsxs("td",{className:"px-3 py-2 text-right tabular-nums",children:[b.conversions,"건"]}),e.jsx("td",{className:"px-3 py-2 text-right tabular-nums",children:Z(b.revenue)}),e.jsx("td",{className:"px-3 py-2 text-right tabular-nums",children:be(b)}),e.jsx("td",{className:"px-3 py-2 text-right tabular-nums",children:ye(b)})]},u)})})]}),e.jsx("div",{className:"border-t px-3 py-1.5 text-[11px] text-gray-500",children:"공간 판정: 접수는 TM 서비스 구분(웹 /entrance-reform · 메타 현관 양식 · 캠페인 이름 _신발장_ = 현관), 광고비는 캠페인 이름 _신발장_ = 현관, 나머지 주방. 광고 매체 기준(광고 외 유입은 아래 따로)."})]}),e.jsx(_l,{view:d,prevView:g,cmpLabel:j,statusByMedia:c,statusOf:x}),d.otherSources.length>0&&e.jsxs("div",{className:"overflow-x-auto rounded-lg border bg-white",children:[e.jsx("div",{className:"border-b px-3 py-2 text-xs font-semibold text-gray-700",children:"광고 외 유입 — 광고비가 없어 CPL·ROAS 를 계산하지 않는다"}),e.jsx("table",{className:"w-full text-sm",children:e.jsx("tbody",{children:d.otherSources.map(u=>e.jsxs("tr",{className:"border-t first:border-t-0",children:[e.jsx("td",{className:"whitespace-nowrap px-3 py-2",children:u.label}),e.jsxs("td",{className:"px-3 py-2 text-right tabular-nums",children:["리드 ",u.leads,"건"]}),e.jsxs("td",{className:"px-3 py-2 text-right tabular-nums",children:["주문 전환 ",u.conversions,"건",u.directOrders>0&&e.jsxs("span",{className:"text-xs text-gray-400",children:[" (직접 주문 ",u.directOrders,")"]})]}),e.jsxs("td",{className:"px-3 py-2 text-right tabular-nums",children:["실매출 ",Z(u.revenue)]})]},u.media))})}),d.otherSources.some(u=>u.media==="unknown")&&e.jsx("div",{className:"border-t px-3 py-1.5 text-[11px] text-amber-700",children:"「유입경로 없음」 = 유입경로가 저장되지 않은 자사몰 셀프 도어 주문(저장은 2026-09-17 부터, 브라우저 저장 차단 포함). 어느 광고의 매출인지 알 수 없어 광고 ROAS 에 넣지 않았다."})]}),e.jsxs("p",{className:"text-[11px] leading-relaxed text-gray-500",children:["기준 — 광고비: 셀프 도어 캠페인(당근 전액 · 이름에 주방도어 / _도어_ / _신발장_)의 확정분, 기간에 걸친 주·월 리포트는 추정으로만 표시. 리드: TM 접수(중복 제외), 매체 = 접수의 utm_source. 주문 전환·실매출: 그 기간 접수 중 주문까지 간 것(취소·입금 대기 제외) + TM 을 거치지 않은 자사몰 셀프 도어 주문(매출 인식일). 리드 ",Vs,"건 미만 CPL 은 「관측」. 캠페인 줄의 「이름 안 맞음」 = 광고비와 접수의 캠페인 이름이 달라 한 줄로 잇지 못한 것."]})]})]})}const Ct=s=>
4`₩${Math.round(s).toLocaleString("ko-KR")}`,Rl=(s,t=2)=>`${s.toFixed(t)}%`;function $l({results:s}){return s.length===0?null:e.jsxs("div",{className:"rounded-lg border bg-white",children:[e.jsx("div",{className:"border-b px-4 py-3 text-sm font-semibold text-gray-800",children:"비교 기간 값"}),e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{className:"bg-gray-50 text-left text-xs whitespace-nowrap text-gray-500",children:e.jsxs("tr",{children:[e.jsx("th",{className:"px-4 py-2",children:"기간"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"매출"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"광고비"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"광고비율"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"ROAS"}),e.jsx("th",{className:"px-4 py-2 text-right",children:"주문"})]})}),e.jsx("tbody",{children:s.map(t=>e.jsxs("tr",{className:"border-t",children:[e.jsxs("td",{className:"whitespace-nowrap px-4 py-2",children:[e.jsx("span",{className:"font-medium",children:t.label}),e.jsxs("span",{className:"ml-2 text-xs text-gray-400",children:[t.range.startDate,t.range.startDate!==t.range.endDate&&` ~ ${t.range.endDate}`]})]}),e.jsx("td",{className:"px-4 py-2 text-right tabular-nums",children:Ct(t.kpis.gmv)}),e.jsx("td",{className:"px-4 py-2 text-right tabular-nums",children:t.kpis.adCost==null?"—":Ct(t.kpis.adCost)}),e.jsx("td",{className:"px-4 py-2 text-right tabular-nums",children:t.kpis.adRatio==null?"—":Rl(t.kpis.adRatio)}),e.jsx("td",{className:"px-4 py-2 text-right tabular-nums",children:t.kpis.roas==null?"—":`${Math.round(t.kpis.roas).toLocaleString("ko-KR")}%`}),e.jsxs("td",{className:"px-4 py-2 text-right tabular-nums",children:[t.kpis.orderCount.toLocaleString("ko-KR"),"건"]})]},t.key))})]})})]})}function Ul(s){if(s==="kitchen"||s==="entrance")return s;throw new Error(`셀프 도어 공간 값을 알 수 없습니다: ${String(s)}`)}const ge=s=>Number(s??0);async function Dt(s,t){const{data:a,error:r}=await H.rpc("get_self_door_performance",{p_start:s,p_end:t});if(r)throw r;return(a??[]).map(l=>({media:String(l.media),space:Ul(l.space),campaign:String(l.campaign??""),adCostUsed:ge(l.ad_cost_used),adCostPartial:ge(l.ad_cost_partial),adCostPartialEst:ge(l.ad_cost_partial_est),leads:ge(l.leads),leadsConverted:ge(l.leads_converted),leadsConvertedLinked:ge(l.leads_converted_linked),leadRevenue:ge(l.lead_revenue),directOrders:ge(l.direct_orders),directRevenue:ge(l.direct_revenue)}))}function Tl(s,t){const[a,r]=h.useState(null),[l,n]=h.useState(null),[o,i]=h.useState(!1),[m,d]=h.useState(null),g=h.useCallback(async()=>{i(!0),d(null);try{const[c,x]=await Promise.all([Dt(s.startDate,s.endDate),t?Dt(t.startDate,t.endDate):Promise.resolve(null)]);r(c),n(x)}catch(c){r(null),n(null),d(c instanceof Error?c.message:String(c))}finally{i(!1)}},[s,t]);return h.useEffect(()=>{g()},[g]),{current:a,previous:l,loading:o,error:m,reload:g}}const Ll=new Set(["auto","manual","none"]);function Al(s,t){if(s==null)return null;const a=String(s);if(!Ll.has(a))throw new Error(`매체 설정의 수집 방식을 알 수 없습니다: ${t} = ${a}`);return a}function El(s,t){if(!Array.isArray(s))throw new Error(`광고비 구간 목록 형식이 올바르지 않습니다: ${t}`);return s.map(a=>({start:String(a.start),end:String(a.end),granularity:String(a.granularity)}))}async function Ml(s,t){const{data:a,error:r}=await H.rpc("get_ad_cost_coverage",{p_start:s,p_end:t});if(r)throw r;return(a??[]).map(l=>{const n=String(l.media);return{media:n,collection:Al(l.collection,n),active:l.active==null?null:!!l.active,graceDays:l.grace_days==null?0:Number(l.grace_days),owner:l.owner==null||l.owner===""?null:String(l.owner),latestPeriodEnd:l.latest_period_end==null?null:String(l.latest_period_end),spans:El(l.spans,n)}})}function Il(){return new Date(Date.now()+9*36e5).toISOString().slice(0,10)}function Pl(s){const[t,a]=h.useState(null),[r,l]=h.useState(!1),[n,o]=h.useState(null),i=h.useCallback(async()=>{l(!0),o(null);
4try{const m=await Ml(s.startDate,s.endDate),d=Il();a(m.map(g=>ul(g,s,d)))}catch(m){a(null),o(m instanceof Error?m.message:String(m))}finally{l(!1)}},[s]);return h.useEffect(()=>{i()},[i]),{coverage:t,loading:r,error:n,reload:i}}const Ol=[{value:"daily",label:"일간"},{value:"weekly",label:"주간"},{value:"monthly",label:"월간"}],Ze=s=>`₩${Math.round(s).toLocaleString("ko-KR")}`,Fl=(s,t=2)=>`${s.toFixed(t)}%`;function Qe(s){return t=>{const a=t.abs>0?"+":"";return s==="percent"?`${a}${t.abs.toFixed(2)}%p`:t.pct==null?`${a}${Math.round(t.abs).toLocaleString("ko-KR")} (신규)`:`${a}${t.pct.toFixed(1)}%`}}function Kl(){const s=ja(),t=fa(s.goals),a=Pl(t.period),r=h.useMemo(()=>ua(t.mode,t.period)[0]??null,[t.mode,t.period]),l=h.useMemo(()=>r?.range??null,[r]),n=Tl(t.period,l),o=a.coverage?va(a.coverage).length:0,i=t.kpis,m=j=>t.results.map(p=>({label:p.label,delta:j(p)})),d=t.adSummary?.excluded??[],g=d.reduce((j,p)=>j+p.cost,0),c=h.useMemo(()=>({mode:t.mode,kpis:t.kpis,primaryComparison:t.results[0]?{label:t.results[0].label,kpis:t.results[0].kpis}:null,goals:s.goals,target:t.paceTarget,adSummary:t.adSummary,channels:t.channels}),[t.mode,t.kpis,t.results,s.goals,t.paceTarget,t.adSummary,t.channels]),x=ca(c),N=h.useMemo(()=>Rn({mode:t.mode,period:t.period,kpis:t.kpis,comparisons:t.results.map(j=>({label:j.label,kpis:j.kpis})),target:t.target,diagnostics:x.items}),[t.mode,t.period,t.kpis,t.results,s.goals,t.target,x.items]);return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"flex flex-wrap items-end gap-3 rounded-lg border bg-white p-4",children:[e.jsx("div",{className:"flex rounded-md border p-0.5",children:Ol.map(j=>e.jsx("button",{type:"button",onClick:()=>t.setMode(j.value),className:`rounded px-3 py-1.5 text-sm ${t.mode===j.value?"bg-gray-900 font-medium text-white":"text-gray-600 hover:bg-gray-100"}`,children:j.label},j.value))}),e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-xs text-gray-500",children:"기준일"}),e.jsx(F,{type:"date",value:t.anchor,onChange:j=>t.setAnchor(j.target.value),className:"w-40"})]}),e.jsxs("div",{className:"pb-2 text-sm text-gray-500",children:[t.period.startDate,t.period.startDate!==t.period.endDate&&` ~ ${t.period.endDate}`,t.results.length>0&&e.jsxs("span",{className:"ml-2 text-gray-400",children:["· 비교: ",t.results.map(j=>j.label).join(" / ")]})]}),e.jsx(_,{variant:"outline",onClick:()=>{t.reload(),a.reload(),n.reload()},disabled:t.loading,children:t.loading?e.jsx(fe,{className:"h-4 w-4 animate-spin"}):"조회"})]}),t.error&&e.jsx("div",{className:"rounded-lg border border-red-200 bg-red-50 p-4 text-sm text-red-700",children:t.error}),e.jsx(jl,{coverage:a.coverage,loading:a.loading,error:a.error}),e.jsx(Dl,{period:t.period,comparison:r,current:n.current,previous:n.previous,loading:n.loading,error:n.error,coverage:a.coverage}),e.jsxs("h3",{className:"pt-2 text-sm font-semibold text-gray-800",children:["전체 매출 · 광고비 ",e.jsx("span",{className:"font-normal text-gray-500",children:"(전 채널 · 전 제품)"})]}),i&&e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2 xl:grid-cols-5",children:[e.jsx(Ye,{label:"총 매출 (GMV)",kpiKey:"gmv",value:Ze(i.gmv),hint:"취소 전 총 거래액",comparisons:m(j=>j.deltas.gmv),formatDelta:Qe("currency")}),e.jsx(Ye,{label:"총 광고비",kpiKey:"adCost",value:i.adCost==null?null:Ze(i.adCost),emptyReason:g>0?"이 기간 해상도로는 알 수 없음":"적재된 광고비 없음",hint:"VAT 포함 · 확정분만",badge:o>0?`${o}개 매체 누락 가능`:a.error?"누락 판정 못 함":g>0?"일부 기간 미제공":void 0,comparisons:m(j=>j.deltas.adCost),formatDelta:Qe("currency")}),e.jsx(Ye,{label:"광고비율",kpiKey:"adRatio",value:i.adRatio==null?null:Fl(i.adRatio),emptyReason:"광고비 미적재",hint:"광고비 ÷ 매출 · 낮을수록 좋음",comparisons:m(j=>j.deltas.adRatio),formatDelta:Qe("percent")}),e.jsx(Ye,{label:"ROAS",kpiKey:"roas",value:i.roas==null?null:`${Math.round(i.roas).toLocaleString("ko-KR")}%`,emptyReason:"광고비 미적재",hint:"매출 ÷ 광고비 · 광고비율의 역수",comparisons:m(j=>j.deltas.roas),formatDelta:Qe("currency")}),e.jsx(Ye,{label:"객단가 / 주문",kpiKey:"aov",value:i.aov==null?null:`${Ze(i.aov)}
4 / ${i.orderCount.toLocaleString("ko-KR")}건`,emptyReason:"주문 없음",hint:"GMV ÷ 주문 건수",comparisons:m(j=>j.deltas.aov),formatDelta:Qe("currency")})]}),e.jsx(fl,{coverage:a.coverage,adSummary:t.adSummary}),g>0&&e.jsx("div",{className:"rounded-lg border border-amber-200 bg-amber-50 p-4",children:e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(we,{className:"mt-0.5 h-4 w-4 shrink-0 text-amber-600"}),e.jsxs("div",{className:"text-sm text-amber-900",children:[e.jsxs("div",{className:"font-medium",children:["광고비율에 반영되지 않은 광고비 ",Ze(g)]}),e.jsx("div",{className:"mt-1 text-amber-800",children:"아래 매체는 집계 구간이 선택 기간에 통째로 들어오지 않습니다. 안분하면 추정치가 되므로 광고비율·ROAS 계산에서 제외했습니다 — 이 기간의 실제 광고비는 표시값보다 큽니다."}),e.jsx("ul",{className:"mt-2 space-y-0.5",children:d.map((j,p)=>e.jsxs("li",{children:["· ",Ke[j.media]," (",Yt[j.granularity]," 집계) —"," ",Ze(j.cost)]},`${j.media}-${p}`))})]})]})}),e.jsx(Hn,{goals:s.goals,editing:s.editing,setEditing:s.setEditing,onSave:s.update,onReset:s.reset,kpis:i,target:t.target,forecast:t.forecast}),e.jsx(Ln,{points:t.points,adCostNote:"이 기간에 일별로 들어온 광고비가 없습니다 — 쿠팡은 주·월 단위 리포트만 있고, 네이버·메타·구글 일별분이 비어 있다면 수집 상태를 데이터 관리 탭에서 확인하세요."}),e.jsx(Un,{channels:t.channels,loading:t.loading}),e.jsx(Xn,{rows:t.productTypes,comparisonLabel:t.results[0]?.label??null}),e.jsx($l,{results:t.results}),e.jsx(Cn,{items:x.items,onStatusChange:x.updateStatus,slackText:N})]})}const zl={카드:"카드 (토스)",간편결제:"간편결제 (토스)",계좌이체:"계좌이체 (토스)",가상계좌:"가상계좌 (토스)",휴대폰:"휴대폰 (토스)","bank-transfer":"무통장입금",NAVER_PAY:"네이버페이",외부몰:"외부몰 (사방넷)"};function ba(s){return zl[s]??s}function hs(s,t){const a=Number(s);if(!Number.isFinite(a))throw new Error(`[attributionCoverage] ${t} 값이 숫자가 아닙니다: ${String(s)}`);return a}function Rt(s){return s==null?null:String(s)}function Bl(s){if(s==null)return[];if(!Array.isArray(s))throw new Error("[attributionCoverage] RPC 응답이 배열이 아닙니다");return s.map(t=>{const a=t;if(typeof a.payment_method!="string"||typeof a.is_target!="boolean")throw new Error("[attributionCoverage] RPC 응답에 payment_method / is_target 이 없습니다");return{paymentMethod:a.payment_method,isTarget:a.is_target,orders24h:hs(a.orders_24h,"orders_24h"),saved24h:hs(a.saved_24h,"saved_24h"),ordersPeriod:hs(a.orders_period,"orders_period"),savedPeriod:hs(a.saved_period,"saved_period"),lastOrderAt:Rt(a.last_order_at),lastSavedAt:Rt(a.last_saved_at)}})}function ps(s,t){return t<=0?null:Math.round(s/t*1e3)/10}function gs(s){return s===null?"주문 없음":`${s}%`}function Vl(s){return s.filter(t=>t.isTarget&&t.orders24h>=1&&t.saved24h===0).map(t=>({paymentMethod:t.paymentMethod,label:ba(t.paymentMethod),orders24h:t.orders24h,lastOrderAt:t.lastOrderAt,lastSavedAt:t.lastSavedAt}))}function ya(s){return s.reduce((t,a)=>({orders24h:t.orders24h+a.orders24h,saved24h:t.saved24h+a.saved24h,ordersPeriod:t.ordersPeriod+a.ordersPeriod,savedPeriod:t.savedPeriod+a.savedPeriod}),{orders24h:0,saved24h:0,ordersPeriod:0,savedPeriod:0})}async function Gl(s=7){const{data:t,error:a}=await H.rpc("get_order_attribution_coverage",{p_days:s});if(a)throw a;return Bl(t)}const Gs=7;function Ts(s){return s?new Date(s).toLocaleString("ko-KR",{timeZone:"Asia/Seoul",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"}):"-"}function $t(s){return s===null?"text-gray-400":s===0?"text-red-600 font-semibold":s<90?"text-amber-600":"text-emerald-600"}function Ut({rows:s,muted:t}){const a=ya(s);return e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:`w-full text-sm ${t?"text-gray-500":""}`,children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b text-left text-xs text-gray-500",children:[e.jsx("th",{className:"py-2 pr-3 font-medium",children:"결제 방식"}),e.jsx("th",{className:"py-2 pr-3 text-right font-medium",children:"24시간 주문"}),e.jsx("th",{className:"py-2 pr-3 text-right font-medium",children:"저장"}),e.jsx("th",{className:"py-2 pr-3 text-right font-medium",children:"저장률"}),e.jsxs("th",{className:"py-2 pr-3 text-right font-medium",children:[Gs,"일 주문"]}),e.jsx("th",{className:"py-2 pr-3 text-right font-medium",children:"저장"}),e.jsx("th",{className:"py-2 pr-3 text-right font-medium",children:"저장률"}),e.jsx("th",{className:"py-2 pr-3 text-right font-medium",children:"마지막 주문"}),e.jsx("th",{className:"py-2 text-right font-medium",children:"마지막 저장"})]})}),e.jsxs("tbody",{className:"tabular-nums",children:[s.map(r=>{const l=ps(r.saved24h,r.orders24h),n=ps(r.savedPeriod,r.ordersPeriod);return e.jsxs("tr",{className:"border-b last:border-0",children:[e.jsx("td",{className:"py-2 pr-3",children:ba(r.paymentMethod)}),e.jsx("td",{className:"py-2 pr-3 text-right",children:r.orders24h}),e.jsx("td",{className:"py-2 pr-3 text-right",children:r.saved24h}),e.jsx("td",{className:`py-2 pr-3 text-right ${t?"":$t(l)}`,children:gs(l)}),e.jsx("td",{className:"py-2 pr-3 text-right",children:r.ordersPeriod}),e.jsx("td",{className:"py-2 pr-3 text-right",children:r.savedPeriod}),e.jsx("td",{className:`py-2 pr-3 text-right ${t?"":$t(n)}`,children:gs(n)}),e.jsx("td",{className:"py-2 pr-3 text-right",children:Ts(r.lastOrderAt)}),e.jsx("td",{className:"py-2 text-right",children:Ts(r.lastSavedAt)})]},r.paymentMethod)}),s.length>1&&!t&&e.jsxs("tr",{className:"font-medium",children:[e.jsx("td",{className:"py-2 pr-3",children:"합계"}),e.jsx("td",{className:"py-2 pr-3 text-right",children:a.orders24h}),e.jsx("td",{className:"py-2 pr-3 text-right",children:a.saved24h}),e.jsx("td",{className:"py-2 pr-3 text-right",children:gs(ps(a.saved24h,a.orders24h))}),e.jsx("td",{className:"py-2 pr-3 text-right",children:a.ordersPeriod}),e.jsx("td",{className:"py-2 pr-3 text-right",children:a.savedPeriod}),e.jsx("td",{className:"py-2 pr-3 text-right",children:gs(ps(a.savedPeriod,a.ordersPeriod))}),e.jsx("td",{className:"py-2 pr-3"}),e.jsx("td",{className:"py-2"})]})]})]})})}function Wl(){const[s,t]=h.useState(null),[a,r]=h.useState(!1),[l,n]=h.useState(null),o=h.useCallback(async()=>{r(!0),n(null);try{t(await Gl(Gs))}catch(g){console.error("[AttributionCoverageSection] 저장률 조회 실패:",g);const c=g instanceof Error?g.message:String(g?.message??g);n(`유입경로 저장률을 불러오지 못했습니다: ${c}`),t(null)}finally{r(!1)}},[]);h.useEffect(()=>{o()},[o]);const i=h.useMemo(()=>(s??[]).filter(g=>g.isTarget),[s]),m=h.useMemo(()=>(s??[]).filter(g=>!g.isTarget),[s]),d=h.useMemo(()=>Vl(s??[]),[s]);return e.jsxs("section",{className:"space-y-3 rounded-lg border bg-white p-4",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-2",children:[e.jsxs("div",{children:[e.jsx("h3",{className:"text-sm font-semibold text-gray-900",children:"자사몰 주문 유입경로 저장률"}),e.jsx("p",{className:"text-xs text-gray-500",children:"결제 방식별로 주문에 광고 유입경로(attribution_raw)가 남았는지 봅니다. 행 생성 시각 기준."})]}),e.jsx(_,{variant:"outline",size:"sm",onClick:()=>void o(),disabled:a,children:a?e.jsx(fe,{className:"h-4 w-4 animate-spin"}):"다시 조회"})]}),l&&e.jsx("div",{className:"rounded-md border border-red-200 bg-red-50 p-3 text-sm text-red-700",children:l}),d.length>0&&e.jsxs("div",{className:"rounded-md border border-red-300 bg-red-50 p-3 text-sm text-red-800",role:"alert",children:[e.jsxs("div",{className:"flex items-center gap-2 font-semibold",children:[e.jsx(we,{className:"h-4 w-4"}),"최근 24시간 주문이 있는데 유입경로가 하나도 저장되지 않은 결제 방식이 있습니다"]}),e.jsx("ul",{className:"mt-2 list-disc space-y-0.5 pl-6",children:d.map(g=>e.jsxs("li",{children:[g.label,": 24시간 주문 ",g.orders24h,"건 중 저장 0건 (마지막 주문 ",Ts(g.lastOrderAt),", 마지막 저장"," ",Ts(g.lastSavedAt),")"]},g.paymentMethod))}),e.jsx("p",{className:"mt-2 text-xs text-red-700",children:"먼저 결제 경로의 Edge Function 배포 여부를 확인하세요 (카드·간편결제: confirm-payment, 네이버페이: naver-pay-register). 절차: docs/operations/ORDER_ATTRIBUTION_ROLLOUT.md"})]}),s!==null&&e.jsxs(e.Fragment,{children:[i.length===0?e.jsxs("p",{className:"text-sm text-gray-500",children:["최근 ",Gs,"일 자사몰 주문이 없습니다."]}):e.jsx(Ut,{rows:i}),m.length>0&&e.jsxs("details",{className:"text-sm",children:[e.jsxs("summary",{className:"cursor-pointer text-xs text-gray-500",children:["대상 아님 — 외부몰(사방넷 수집) 주문 ",ya(m).ordersPeriod,"건 (브라우저 유입경로가 원래 없음)"]}),e.jsx("div",{className:"mt-2",children:e.jsx(Ut,{rows:m,muted:!0}
4)})]})]})]})}const Hl=[{value:"open",label:"열린 것"},{value:"new",label:es.new},{value:"ack",label:es.ack},{value:"resolved",label:es.resolved},{value:"ignored",label:es.ignored},{value:"all",label:"전체"}],ql=Object.keys(oa);function Yl(){const s=ja(),t=fa(s.goals),a=h.useMemo(()=>({mode:t.mode,kpis:t.kpis,primaryComparison:t.results[0]?{label:t.results[0].label,kpis:t.results[0].kpis}:null,goals:s.goals,target:t.paceTarget,adSummary:t.adSummary,channels:t.channels}),[t.mode,t.kpis,t.results,s.goals,t.paceTarget,t.adSummary,t.channels]),r=ca(a),[l,n]=h.useState("open"),[o,i]=h.useState("all"),m=r.items.filter(d=>o!=="all"&&d.area!==o?!1:l==="all"?!0:l==="open"?ns(d.state.status):d.state.status===l);return e.jsxs("div",{className:"space-y-4",children:[e.jsx(Wl,{}),e.jsxs("div",{className:"flex flex-wrap items-end gap-3 rounded-lg border bg-white p-4",children:[e.jsxs("div",{children:[e.jsx("label",{className:"mb-1 block text-xs text-gray-500",children:"기준일 (월간 기준으로 평가)"}),e.jsx(F,{type:"date",value:t.anchor,onChange:d=>t.setAnchor(d.target.value),className:"w-40"})]}),e.jsxs("div",{className:"pb-2 text-sm text-gray-500",children:[t.period.startDate," ~ ",t.period.endDate]}),e.jsx(_,{variant:"outline",onClick:()=>void t.reload(),disabled:t.loading,children:t.loading?e.jsx(fe,{className:"h-4 w-4 animate-spin"}):"다시 평가"})]}),e.jsx("div",{className:"grid gap-3 sm:grid-cols-3 lg:grid-cols-6",children:[["신규",r.summary.new,"text-gray-900"],["확인 중",r.summary.ack,"text-gray-900"],["해결",r.summary.resolved,"text-emerald-600"],["무시",r.summary.ignored,"text-gray-400"],["열린 심각",r.summary.openCritical,"text-red-600"],["열린 주의",r.summary.openWarn,"text-amber-600"]].map(([d,g,c])=>e.jsxs("div",{className:"rounded-lg border bg-white p-3",children:[e.jsx("div",{className:"text-xs text-gray-500",children:d}),e.jsx("div",{className:`mt-0.5 text-xl font-semibold tabular-nums ${c}`,children:g})]},d))}),e.jsxs("div",{className:"flex flex-wrap items-center gap-3 rounded-lg border bg-white p-3",children:[e.jsx("div",{className:"flex flex-wrap gap-1",children:Hl.map(d=>e.jsx("button",{type:"button",onClick:()=>n(d.value),className:`rounded px-2.5 py-1 text-xs ${l===d.value?"bg-gray-900 font-medium text-white":"text-gray-600 hover:bg-gray-100"}`,children:d.label},d.value))}),e.jsx("div",{className:"h-4 w-px bg-gray-200"}),e.jsxs("div",{className:"flex flex-wrap gap-1",children:[e.jsx("button",{type:"button",onClick:()=>i("all"),className:`rounded px-2.5 py-1 text-xs ${o==="all"?"bg-gray-900 font-medium text-white":"text-gray-600 hover:bg-gray-100"}`,children:"전체 영역"}),ql.map(d=>e.jsxs("button",{type:"button",onClick:()=>i(d),className:`rounded px-2.5 py-1 text-xs ${o===d?"bg-gray-900 font-medium text-white":"text-gray-600 hover:bg-gray-100"}`,children:[d," ",oa[d]]},d))]})]}),t.error&&e.jsx("div",{className:"rounded-lg border border-red-200 bg-red-50 p-4 text-sm text-red-700",children:t.error}),e.jsx(ma,{items:m,onStatusChange:r.updateStatus,emptyMessage:r.items.length===0?"이 기간에 걸린 규칙이 없습니다.":"이 필터에 해당하는 코드가 없습니다."}),e.jsx("p",{className:"text-xs text-gray-400",children:"상태는 이 브라우저에만 저장됩니다. 2단계에서 marketing_issues 테이블로 옮기면 사람이 바뀌어도 이력이 남습니다."})]})}async function Jl(s){const t=Xl(s.base_url,{utm_source:s.utm_source,utm_medium:s.utm_medium,utm_campaign:s.utm_campaign,utm_content:s.utm_content,utm_term:s.utm_term});let a=s.campaign_id;if(!a){const{data:o}=await H.from("tp_campaigns").select("id").eq("campaign_name",s.utm_campaign).single();if(o)a=o.id;else{const{data:i,error:m}=await H.from("tp_campaigns").insert({campaign_name:s.utm_campaign,manager_name:s.manager_name||null,status:"active",start_date:cr()}).select("id").single();m?console.error("캠페인 생성 실패:",m):a=i.id}}let r=s.agent_short_code||null;s.create_agent_link&&!r&&(r=(await ts({original_url:t,campaign_id:a,product_id:s.product_id,channel_id:s.channel_id})).short_code);const{data:l,error:n}=await H.from("tp_utm_urls").insert({campaign_id:a||null,utm_url:t,utm_source:s.utm_source,utm_medium:s.utm_medium,utm_campaign:s.utm_campaign,utm_c
4ontent:s.utm_content||null,utm_term:s.utm_term||null,product_id:s.product_id||null,channel_id:s.channel_id||null,manager_name:s.manager_name||null,agent_short_code:r,is_active:!0,is_two_step:s.is_two_step||!1,group_id:s.group_id||null,step:s.step||1}).select().single();if(n)throw console.error("UTM URL 생성 실패:",n),new Error(`UTM URL 생성 실패: ${n.message}`);return l}async function Zl(){const{data:s,error:t}=await H.from("tp_utm_urls").select(`
5      *,
6      tp_campaigns (
7        id,
8        campaign_name,
9        total_impressions,
10        memo,
11        post_url
12      )
13    `).order("created_at",{ascending:!1});if(t)throw console.error("UTM URL 조회 실패:",t),new Error(`UTM URL 조회 실패: ${t.message}`);if(!s||s.length===0)return[];const a=s.map(i=>i.campaign_id).filter(i=>i!==null);if(a.length===0)return s;const{data:r,error:l}=await H.from("ag_links").select("campaign_id, original_url, short_code").in("campaign_id",a);l?console.error("❌ [getUtmUrls] Agent 링크 조회 실패:",l):r?.length;const n=new Map;return r&&r.forEach(i=>{n.set(i.original_url,i.short_code),`${i.original_url}${i.short_code}`}),n.size,s.map(i=>{const m=n.get(i.utm_url);`${i.utm_url}${m}`;const d=i.tp_campaigns;return{...i,agent_short_code:m||i.agent_short_code||null,totalImpressions:d?.total_impressions||0,campaignMemo:d?.memo||"",campaignPostUrl:d?.post_url||""}})}async function Ql(s,t){const{data:a,error:r}=await H.from("tp_utm_urls").update({...t,updated_at:new Date().toISOString()}).eq("id",s).select().single();if(r)throw console.error("UTM URL 수정 실패:",r),new Error(`UTM URL 수정 실패: ${r.message}`);return a}function Xl(s,t){const a=new URL(s);return a.searchParams.set("utm_source",t.utm_source),a.searchParams.set("utm_medium",t.utm_medium),a.searchParams.set("utm_campaign",t.utm_campaign),t.utm_content&&a.searchParams.set("utm_content",t.utm_content),t.utm_term&&a.searchParams.set("utm_term",t.utm_term),a.toString()}async function ei(){const{data:s,error:t}=await H.from("tp_channels").select("*").eq("is_active",!0).order("display_order",{ascending:!0});if(t)throw console.error("채널 조회 실패:",t),new Error(`채널 조회 실패: ${t.message}`);return s||[]}async function si(){const{data:s,error:t}=await H.from("tp_sources").select("*").eq("is_active",!0).order("display_order",{ascending:!0});if(t)throw console.error("소스 조회 실패:",t),new Error(`소스 조회 실패: ${t.message}`);return s||[]}async function wa(s,t,a){return(await qs({action:"query",table:s,startDate:t.startDate,endDate:t.endD
13ate})).rows??[]}async function ti(s){return wa("ga4_fact_daily_campaign_performance",s)}async function Tt(s,t){return wa("ga4_fact_daily_event_performance",s)}async function ai(s,t){const{data:a,error:r}=await H.from("ag_links").select("clicks").eq("campaign_id",s);if(r)throw console.error("Agent 링크 조회 실패:",r),new Error(`Agent 링크 조회 실패: ${r.message}`);return!a||a.length===0?0:a.reduce((l,n)=>l+n.clicks,0)}async function Lt(s){const{data:t,error:a}=await H.from("tp_campaigns").select("id, campaign_name, manager_name").eq("status","active");if(a)throw console.error("캠페인 조회 실패:",a),new Error(`캠페인 조회 실패: ${a.message}`);if(!t||t.length===0)return[];const r=await ti(s);return await Promise.all(t.map(async n=>{const o=r.filter(c=>c.campaign_name===n.campaign_name),i=o.reduce((c,x)=>c+x.sessions,0),m=o.reduce((c,x)=>c+x.purchases,0),d=o.reduce((c,x)=>c+x.revenue,0),g=await ai(n.id);return{campaignName:n.campaign_name,managerName:n.manager_name,visits:i,purchases:m,revenue:d,conversionRate:i>0?m/i*100:0,clicks:g}}))}function js(s){const t=new Date,a=new Date;return a.setDate(a.getDate()-s),{startDate:a.toISOString().split("T")[0],endDate:t.toISOString().split("T")[0]}}function At(){const s=new Date;return{startDate:new Date("2020-01-01").toISOString().split("T")[0],endDate:s.toISOString().split("T")[0]}}async function ri(){const{data:s}=await H.from("tp_campaigns").select("id, memo, post_url, total_impressions");return new Map(s?.map(t=>[t.id,{memo:t.memo,postUrl:t.post_url,totalImpressions:t.total_impressions}])||[])}const ni=[{id:"all",name:"전체 제품"},{id:"sliding_shelf",name:"슬라이딩 선반"},{id:"trones_top",name:"이케아 TRONES 상판"},{id:"helmer_top",name:"이케아 HELMER 상판"},{id:"lennart_top",name:"이케아 LENNART 맞춤 상판"},{id:"kids_shoebench",name:"어린이 슈벤치"},{id:"multipurpose_shelf",name:"다용도 ㄷ자 선반"},{id:"fridge_gap",name:"냉장고 틈새장"}],li=[{id:"social",name:"SNS",color:"bg-blue-600",hex:"#2563eb"},{id:"viral",name:"바이럴",color:"bg-green-600",hex:"#16a34a"},{id:"influencer",name:"인플루언서",color:"bg-purple-600",hex:"#9333ea"},{id:"offline",name:"오프라인",color:"bg-orange-600",hex:"#ea580c"}],ii=[{id:"instagram",name:"Instagram"},{id:"youtube",name:"YouTube"},{id:"threads",name:"Threads"},{id:"blog",name:"Blog"},{id:"moms_cafe",name:"맘카페"},{id:"interior_cafe",name:"인테리어카페"},{id:"naver",name:"Naver"},{id:"kakao",name:"Kakao"},{id:"google",name:"Google"},{id:"apartment_board",name:"아파트 게시판"}];function bc(){const s=Ya(),[t,a]=h.useState([]),[r,l]=h.useState(ni),[n,o]=h.useState(li),[i,m]=h.useState(ii),[d,g]=_a(s?"dashboard":"overview"),c=d==="dashboard"||d==="campaigns"||d==="management",x=h.useMemo(()=>fn(),[d]),[N,j]=h.useState("all"),[p,u]=h.useState("all"),[b,T]=h.useState(!0);h.useEffect(()=>{(async()=>{try{T(!0);const M=await Da.getAnalyticsProducts();if(M.length>0){const z=[{id:"all",name:"전체 제품"},...M.map(se=>({id:se.id,name:se.name}))];l(z)}const f=await ei();f.length>0&&o(f.map(z=>({id:z.id,name:z.name,color:z.color,hex:z.hex})));const v=await si();v.length>0&&m(v.map(z=>({id:z.id,name:z.name})));const L=At(),A=await Lt(L),R=new Map(A.map(z=>[z.campaignName,z])),O=await ri(),G=await Zl();if(G.length>0){const z=await Promise.all(G.map(async(E,B)=>{const C=R.get(E.utm_campaign);let J=0;if(E.agent_short_code)try{J=C?.clicks||0}catch(pe){console.error("Failed to get agent clicks:",pe)}`${B}`,E.agent_short_code,`${B}`,E.utm_url;const De=E.agent_short_code?as(E.agent_short_code):void 0;`${B}`;const W=E.campaign_id?O.get(E.campaign_id):null;return{id:E.id,url:E.utm_url,shortUrl:De,campaign:E.utm_campaign,campaignId:E.campaign_id,channel:E.channel_id||"",source:E.utm_source,manager:E.manager_name||"",memo:W?.memo||null,postUrl:W?.postUrl||null,totalImpressions:W?.totalImpressions||0,createdAt:new Date(E.created_at).toISOString().split("T")[0],clicks:J||C?.visits||0,conversions:C?.purchases||0,revenue:C?.revenue||0,product:E.product_id||"",isTwoStep:E.is_two_step||!1,groupId:E.group_id||null,step:E.step||1,funnel:{landing:0,product_view:0,add_to_cart:0,checkout:0,purchase:0}}})),se=await Tt(L),ve=new Map;se.forEach(E=>{ve.has(E.campaign_name)||ve.set(E.campaign_name,new Map);const B=ve.get(E.campaign_name),C=B.get(E.event_name)||0;B.set(E.event_name,C+E.event_count)}
13);const ae=z.map(E=>{const B=ve.get(E.campaign);return B?{...E,funnel:{impressions:E.totalImpressions||0,landing:B.get("page_view")||0,product_view:B.get("view_item")||0,add_to_cart:B.get("add_to_cart")||0,checkout:B.get("begin_checkout")||0,purchase:B.get("purchase")||0}}:{...E,funnel:{...E.funnel,impressions:E.totalImpressions||0}}}),Se=ae.map(E=>{if(E.isTwoStep&&E.groupId&&E.step===2){const B=ae.find(C=>C.isTwoStep&&C.groupId===E.groupId&&C.step===1);if(B)return{...E,funnel:{...E.funnel,waypoint:B.clicks}}}return E});a(Se)}else a([])}catch(M){console.error("❌ [Error] Failed to load analytics data:",M)}finally{T(!1)}})()},[]),h.useEffect(()=>{(async()=>{if(!(t.length===0||b))try{let M;if(p==="all")M=At();else if(p==="yesterday")M=js(1);else if(p==="last7days")M=js(7);else if(p==="last30days")M=js(30);else if(p==="thisMonth"){const O=new Date;M={startDate:new Date(O.getFullYear(),O.getMonth(),1).toISOString().split("T")[0],endDate:O.toISOString().split("T")[0]}}else M=js(30);const f=await Lt(M),v=await Tt(M),L=new Map(f.map(O=>[O.campaignName,O])),A=new Map;v.forEach(O=>{A.has(O.campaign_name)||A.set(O.campaign_name,new Map);const G=A.get(O.campaign_name),z=G.get(O.event_name)||0;G.set(O.event_name,z+O.event_count)});const R=t.map(O=>{const G=L.get(O.campaign),z=A.get(O.campaign);return{...O,clicks:G?.clicks||G?.visits||O.clicks,conversions:G?.purchases||O.conversions,revenue:G?.revenue||O.revenue,funnel:{waypoint:O.funnel.waypoint,landing:z?.get("page_view")||0,product_view:z?.get("view_item")||0,add_to_cart:z?.get("add_to_cart")||0,checkout:z?.get("begin_checkout")||0,purchase:z?.get("purchase")||0}}});a(R)}catch(M){console.error("Failed to reload GA4 data:",M)}})()},[p]);const P=async y=>{const M=n.find(R=>R.id===y.channel)?.name||y.channel,f=i.find(R=>R.id===y.source)?.name||y.source;y.channel,y.source;let v=null;if(y.shortUrl){const R=y.shortUrl.match(/\/go\/([a-z0-9]+)$/i);R&&(v=R[1])}const L=await Jl({base_url:y.url.split("?")[0],utm_source:f,utm_medium:M,utm_campaign:y.campaign,product_id:y.product,channel_id:y.channel,manager_name:y.manager,campaign_id:y.campaignId||null,create_agent_link:!1,agent_short_code:v,is_two_step:y.isTwoStep||!1,group_id:y.groupId||null,step:y.step||1}),A=y.shortUrl;return{id:L.id,url:L.utm_url,shortUrl:A,campaign:L.utm_campaign,campaignId:L.campaign_id||y.campaignId,channel:L.channel_id||y.channel,source:L.utm_source,manager:L.manager_name||"",product:L.product_id||"",memo:y.memo||null,postUrl:y.postUrl||null,createdAt:new Date(L.created_at).toLocaleDateString("ko-KR"),clicks:0,conversions:0,revenue:0,isTwoStep:y.isTwoStep,groupId:y.groupId,step:y.step,preStepUrls:y.preStepUrls||[]}},$=async y=>{try{if(Array.isArray(y)){const v=[];for(const A of y){const R=await P(A);v.push(R)}const L=v.map(A=>{if(A.step===2){const R=v.find(O=>O.step===1);if(R)return{...A,funnel:{waypoint:R.clicks,...A.funnel}}}return A});a([...L,...t]),U.success("UTM URL이 성공적으로 저장되었습니다!");return}const M=y,f=await P(M);a([f,...t]),U.success("UTM URL이 성공적으로 저장되었습니다!")}catch(M){console.error("❌ [handleUrlAdded] Failed to save:",M),U.error("UTM URL 저장에 실패했습니다. 다시 시도해주세요.")}},D=async y=>{try{const M=n.find(R=>R.id===y.channel)?.name||y.channel,f=i.find(R=>R.id===y.source)?.name||y.source,v=await Ql(y.id,{utm_source:f,utm_medium:M,utm_campaign:y.campaign,manager_name:y.manager,is_active:!0}),L=v.agent_short_code?as(v.agent_short_code):y.shortUrl,A={id:v.id,url:v.utm_url,shortUrl:L,campaign:v.utm_campaign,campaignId:v.campaign_id||y.campaignId,channel:v.channel_id||M,source:v.utm_source,manager:v.manager_name||"",product:v.product_id||"",memo:y.memo||null,postUrl:y.postUrl||null,createdAt:new Date(v.created_at).toLocaleDateString("ko-KR"),clicks:y.clicks||0,conversions:y.conversions||0,revenue:y.revenue||0,isTwoStep:y.isTwoStep,groupId:y.groupId,step:y.step,preStepUrls:y.preStepUrls||[]};a(t.map(R=>R.id===y.id?A:R)),U.success("UTM URL이 성공적으로 수정되었습니다!")}catch(M){console.error("❌ [handleUrlUpdate] Failed to update:",M),U.error("UTM URL 수정에 실패했습니다. 다시 시도해주세요.")}},V=y=>{l(y),y.find(M=>M.id===N)||j("all")},k=y=>{o(y)},w=y=>{m(y)},I=y=>{u(y)},S=h.useMemo(()=>N==="all"?t:t.filter(y=>y.product===N),[t,N]),Q=r.find(y=>y.id===N)?.name||"전체 제품";return b&&c?e.jsx("div",{className:"flex items-center justify-center h-96",children:e.jsxs("div",{className:"text-center",children:[e.jsx("div",{className:"animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4"}),e.jsx("p",{className:"text-gray-600",children:"데이터를 불러오는 중..."})]})}):e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{className:"space-y-6",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold text-gray-900",children:"마케팅 추적 · 관리"}),e.jsx("p",{className:"text-gray-600 mt-1",children:s?"UTM / URL을 생성, 등록, 관리하고 마케팅 성과를 분석합니다.":"마케팅 예산·성과를 관리합니다 — 광고비 · 리드(TM 접수) · 실매출. 없는 데이터는 0원이 아니라 경고로 보입니다."})]}),c&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"hidden md:flex items-center justify-between gap-6",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(Cs,{className:"h-5 w-5 text-muted-foreground"}),e.jsxs(ie,{value:N,onValueChange:j,children:[e.jsx(ce,{className:"w-[240px]",children:e.jsx(oe,{placeholder:"제품 선택"})}),e.jsx(de,{children:r.map(y=>e.jsx(Y,{value:y.id,children:y.name},y.id))})]})]}),e.jsx("div",{className:"flex items-center gap-3 flex-wrap",children:n.map(y=>e.jsxs("div",{className:"flex items-center gap-2 text-sm",children:[e.jsx("div",{className:`w-3 h-3 rounded-full ${y.c
13olor}`}),e.jsx("span",{children:y.name})]},y.id))})]}),e.jsx("div",{className:"md:hidden space-y-3",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(Cs,{className:"h-5 w-5 text-muted-foreground"}),e.jsxs(ie,{value:N,onValueChange:j,children:[e.jsx(ce,{className:"flex-1",children:e.jsx(oe,{placeholder:"제품 선택"})}),e.jsx(de,{children:r.map(y=>e.jsx(Y,{value:y.id,children:y.name},y.id))})]})]})})]})]}),e.jsxs(Et,{value:d,onValueChange:g,className:"space-y-6",children:[e.jsxs("div",{className:"flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4",children:[e.jsxs(Mt,{className:`grid w-full sm:w-auto ${s?"grid-cols-2":"grid-cols-9"} h-12 p-1`,children:[!s&&e.jsxs(re,{value:"overview",className:"gap-2 px-4 cursor-pointer data-[state=active]:bg-background data-[state=active]:shadow-sm",children:[e.jsx(or,{className:"h-5 w-5"}),e.jsx("span",{children:"성과 개요"})]}),!s&&e.jsxs(re,{value:"briefing",className:"gap-2 px-4 cursor-pointer data-[state=active]:bg-background data-[state=active]:shadow-sm",children:[e.jsx(dr,{className:"h-5 w-5"}),e.jsx("span",{children:"브리핑"})]}),!s&&e.jsxs(re,{value:"queue",className:"gap-2 px-4 cursor-pointer data-[state=active]:bg-background data-[state=active]:shadow-sm",children:[e.jsx(jr,{className:"h-5 w-5"}),e.jsx("span",{children:"실행 큐"})]}),!s&&e.jsxs(re,{value:"diagnostics",className:"gap-2 px-4 cursor-pointer data-[state=active]:bg-background data-[state=active]:shadow-sm",children:[e.jsx(yr,{className:"h-5 w-5"}),e.jsx("span",{children:"진단"}),x>0&&e.jsx("span",{className:"ml-1 rounded bg-red-500 px-1.5 text-[10px] font-medium text-white",children:x})]}),!s&&e.jsxs(re,{value:"ad-costs",className:"gap-2 px-4 cursor-pointer data-[state=active]:bg-background data-[state=active]:shadow-sm",children:[e.jsx(mr,{className:"h-5 w-5"}),e.jsx("span",{children:"광고비"})]}),!s&&e.jsxs(re,{value:"data",className:"gap-2 px-4 cursor-pointer data-[state=active]:bg-background data-[state=active]:shadow-sm",children:[e.jsx(xr,{className:"h-5 w-5"}),e.jsx("span",{children:"데이터 관리"})]}),e.jsxs(re,{value:"dashboard",className:"gap-2 px-4 cursor-pointer data-[state=active]:bg-background data-[state=active]:shadow-sm",children:[e.jsx(It,{className:"h-5 w-5"}),e.jsx("span",{children:"대시보드"})]}),e.jsxs(re,{value:"campaigns",className:"gap-2 px-4 cursor-pointer data-[state=active]:bg-background data-[state=active]:shadow-sm",children:[e.jsx(Ot,{className:"h-5 w-5"}),e.jsx("span",{children:"캠페인 성과"})]}),!s&&e.jsxs(re,{value:"management",className:"gap-2 px-4 cursor-pointer data-[state=active]:bg-background data-[state=active]:shadow-sm",children:[e.jsx(ur,{className:"h-5 w-5"}),e.jsx("span",{children:"UTM관리"})]})]}),(d==="dashboard"||d==="campaigns")&&e.jsx(Er,{value:p,onChange:I})]}),!s&&e.jsx(ne,{value:"overview",children:e.jsx(Kl,{})}),!s&&e.jsx(ne,{value:"briefing",children:e.jsx(nn,{})}),!s&&e.jsx(ne,{value:"queue",children:e.jsx(qr,{})}),e.jsx(ne,{value:"dashboard",children:e.jsx(at,{urls:S,productName:Q,channels:n,dateRange:p,showCampaignTable:!1})}),e.jsx(ne,{value:"campaigns",children:e.jsx(at,{urls:S,productName:Q,channels:n,dateRange:p,showCampaignTable:!0})}),!s&&e.jsx(ne,{value:"diagnostics",children:e.jsx(Yl,{})}),!s&&e.jsx(ne,{value:"ad-costs",children:e.jsx(sr,{})}),!s&&e.jsx(ne,{value:"data",children:e.jsx(pn,{})}),!s&&e.jsx(ne,{value:"management",children:e.jsx(Ar,{urls:S,allUrls:t,onUrlAdded:$,onUrlUpdate:D,products:r,selectedProduct:N,channels:n,onChannelsChange:k,onProductsChange:V,sources:i,onSourcesChange:w})})]})]})}export{bc 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.