From 88892be1d9dd01990ddf94fe2b009586fcc90b98 Mon Sep 17 00:00:00 2001 From: Macky Date: Sat, 8 Aug 2026 08:01:08 +0700 Subject: [PATCH] i18n(th): professional, natural Thai; make Users button prominent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rewrite TH translations to professional/natural Thai (e.g. app 'ระบบฝึกทักษะการขาย' instead of 'ตัวฝึกขาย', 'บุคคลต้นแบบ' for persona, tiers 'พร้อมตัดสินใจซื้อ', 'จุดอ่อนที่ควรฝึกเพิ่มเติม', 'ปิดการขายได้/ไม่ได้' for won/lost, etc.) - Users button in admin overview now solid sky-blue (was faint .soft gray) so it's visible. --- ...ers-C8wHHBeY.js => AdminUsers-r15xKxjs.js} | 2 +- frontend/dist/assets/Analytics-BothIrTb.js | 1 + frontend/dist/assets/Analytics-ButgVyTK.css | 1 + frontend/dist/assets/Analytics-DstNBgKK.css | 1 - frontend/dist/assets/Analytics-hzMFeY95.js | 1 - .../{Chat-DPgZfhp2.js => Chat-CYFTB7sZ.js} | 2 +- ...r-CRBEizer.js => GroupBuilder-CxLYlayH.js} | 2 +- ...Edit-qmIH-KdK.js => GroupEdit-DiRZ2lxy.js} | 2 +- .../{Login-DFuS2Llc.js => Login-71KwBI7P.js} | 2 +- ...yBoard-DoSeQn-O.js => MyBoard-CjsbrOsq.js} | 2 +- ...sonas-Ck-UhJ3k.js => Personas-BGoC8X56.js} | 2 +- ...tings-BcL2Fs6R.js => Settings-D5fpvNb-.js} | 2 +- .../{Setup-DwlVEQN4.js => Setup-DofFBOwX.js} | 2 +- ...ining-DntZcGFn.js => Training-CBrtrJhQ.js} | 2 +- .../{index-CNkuf2ya.js => index-gmrXNPrQ.js} | 4 +- frontend/dist/index.html | 2 +- frontend/src/i18n/index.js | 78 +++++++++---------- frontend/src/views/Analytics.vue | 4 +- 18 files changed, 57 insertions(+), 55 deletions(-) rename frontend/dist/assets/{AdminUsers-C8wHHBeY.js => AdminUsers-r15xKxjs.js} (96%) create mode 100644 frontend/dist/assets/Analytics-BothIrTb.js create mode 100644 frontend/dist/assets/Analytics-ButgVyTK.css delete mode 100644 frontend/dist/assets/Analytics-DstNBgKK.css delete mode 100644 frontend/dist/assets/Analytics-hzMFeY95.js rename frontend/dist/assets/{Chat-DPgZfhp2.js => Chat-CYFTB7sZ.js} (98%) rename frontend/dist/assets/{GroupBuilder-CRBEizer.js => GroupBuilder-CxLYlayH.js} (97%) rename frontend/dist/assets/{GroupEdit-qmIH-KdK.js => GroupEdit-DiRZ2lxy.js} (97%) rename frontend/dist/assets/{Login-DFuS2Llc.js => Login-71KwBI7P.js} (92%) rename frontend/dist/assets/{MyBoard-DoSeQn-O.js => MyBoard-CjsbrOsq.js} (96%) rename frontend/dist/assets/{Personas-Ck-UhJ3k.js => Personas-BGoC8X56.js} (97%) rename frontend/dist/assets/{Settings-BcL2Fs6R.js => Settings-D5fpvNb-.js} (96%) rename frontend/dist/assets/{Setup-DwlVEQN4.js => Setup-DofFBOwX.js} (96%) rename frontend/dist/assets/{Training-DntZcGFn.js => Training-CBrtrJhQ.js} (97%) rename frontend/dist/assets/{index-CNkuf2ya.js => index-gmrXNPrQ.js} (91%) diff --git a/frontend/dist/assets/AdminUsers-C8wHHBeY.js b/frontend/dist/assets/AdminUsers-r15xKxjs.js similarity index 96% rename from frontend/dist/assets/AdminUsers-C8wHHBeY.js rename to frontend/dist/assets/AdminUsers-r15xKxjs.js index dd35c59..1c00b46 100644 --- a/frontend/dist/assets/AdminUsers-C8wHHBeY.js +++ b/frontend/dist/assets/AdminUsers-r15xKxjs.js @@ -1 +1 @@ -import{k as x,c as r,a,t,u,i as d,w as n,v as m,C as g,e as _,F as U,p as k,q as f,r as p,o as i,z as V}from"./index-CNkuf2ya.js";const b={class:"card",style:{"margin-bottom":"16px"}},C={class:"row"},h={key:0,class:"error"},B={style:{flex:"1"}},M={class:"badge"},D={__name:"AdminUsers",setup(N){const v=p([]),o=p(""),s=p({name:"",email:"",password:"",role:"user"});async function c(){v.value=(await f.adminListUsers()).users}async function w(){o.value="";try{await f.adminCreateUser({...s.value}),s.value={name:"",email:"",password:"",role:"user"},await c()}catch(y){o.value=y.message}}return x(c),(y,l)=>(i(),r("div",null,[a("h2",null,t(u(d).t("users")),1),a("div",b,[a("h4",null,"+ "+t(u(d).t("create"))+" user",1),a("div",C,[n(a("input",{"onUpdate:modelValue":l[0]||(l[0]=e=>s.value.name=e),placeholder:"Name",style:{flex:"1"}},null,512),[[m,s.value.name]]),n(a("input",{"onUpdate:modelValue":l[1]||(l[1]=e=>s.value.email=e),placeholder:"Email",style:{flex:"1"}},null,512),[[m,s.value.email]]),n(a("input",{"onUpdate:modelValue":l[2]||(l[2]=e=>s.value.password=e),type:"password",placeholder:"Temp password",style:{flex:"1"}},null,512),[[m,s.value.password]]),n(a("select",{"onUpdate:modelValue":l[3]||(l[3]=e=>s.value.role=e),style:{flex:"1"}},[...l[4]||(l[4]=[a("option",{value:"user"},"user",-1),a("option",{value:"admin"},"admin",-1)])],512),[[g,s.value.role]]),a("button",{class:"primary",onClick:w},t(u(d).t("create")),1)]),o.value?(i(),r("div",h,t(o.value),1)):_("",!0)]),(i(!0),r(U,null,k(v.value,e=>(i(),r("div",{class:"card",key:e.id,style:{"margin-bottom":"8px",display:"flex","align-items":"center",gap:"12px"}},[a("strong",B,t(e.name)+" ("+t(e.email)+")",1),a("span",M,t(e.role),1),a("span",{class:V(["badge",e.active?"won":"lost"])},t(e.active?"active":"inactive"),3)]))),128))]))}};export{D as default}; +import{k as x,c as r,a,t,u,i as d,w as n,v as m,C as g,e as _,F as U,p as k,q as f,r as p,o as i,z as V}from"./index-gmrXNPrQ.js";const b={class:"card",style:{"margin-bottom":"16px"}},C={class:"row"},h={key:0,class:"error"},B={style:{flex:"1"}},M={class:"badge"},D={__name:"AdminUsers",setup(N){const v=p([]),o=p(""),s=p({name:"",email:"",password:"",role:"user"});async function c(){v.value=(await f.adminListUsers()).users}async function w(){o.value="";try{await f.adminCreateUser({...s.value}),s.value={name:"",email:"",password:"",role:"user"},await c()}catch(y){o.value=y.message}}return x(c),(y,l)=>(i(),r("div",null,[a("h2",null,t(u(d).t("users")),1),a("div",b,[a("h4",null,"+ "+t(u(d).t("create"))+" user",1),a("div",C,[n(a("input",{"onUpdate:modelValue":l[0]||(l[0]=e=>s.value.name=e),placeholder:"Name",style:{flex:"1"}},null,512),[[m,s.value.name]]),n(a("input",{"onUpdate:modelValue":l[1]||(l[1]=e=>s.value.email=e),placeholder:"Email",style:{flex:"1"}},null,512),[[m,s.value.email]]),n(a("input",{"onUpdate:modelValue":l[2]||(l[2]=e=>s.value.password=e),type:"password",placeholder:"Temp password",style:{flex:"1"}},null,512),[[m,s.value.password]]),n(a("select",{"onUpdate:modelValue":l[3]||(l[3]=e=>s.value.role=e),style:{flex:"1"}},[...l[4]||(l[4]=[a("option",{value:"user"},"user",-1),a("option",{value:"admin"},"admin",-1)])],512),[[g,s.value.role]]),a("button",{class:"primary",onClick:w},t(u(d).t("create")),1)]),o.value?(i(),r("div",h,t(o.value),1)):_("",!0)]),(i(!0),r(U,null,k(v.value,e=>(i(),r("div",{class:"card",key:e.id,style:{"margin-bottom":"8px",display:"flex","align-items":"center",gap:"12px"}},[a("strong",B,t(e.name)+" ("+t(e.email)+")",1),a("span",M,t(e.role),1),a("span",{class:V(["badge",e.active?"won":"lost"])},t(e.active?"active":"inactive"),3)]))),128))]))}};export{D as default}; diff --git a/frontend/dist/assets/Analytics-BothIrTb.js b/frontend/dist/assets/Analytics-BothIrTb.js new file mode 100644 index 0000000..0930610 --- /dev/null +++ b/frontend/dist/assets/Analytics-BothIrTb.js @@ -0,0 +1 @@ +import{_ as x,k,c,a as s,t,u as o,i as l,l as m,m as y,w as h,v as f,n as C,e as N,F as V,p as L,q as A,s as B,r as u,o as _}from"./index-gmrXNPrQ.js";const S={class:"row",style:{"align-items":"center","margin-bottom":"16px"}},j={style:{margin:"0"}},z={class:"row",style:{"margin-left":"auto",gap:"10px"}},D={class:"users-btn"},F={class:"primary"},M={class:"card filter-bar"},P={class:"muted"},R=["disabled"],T=["disabled"],U={class:"row",style:{gap:"16px",margin:"16px 0"}},W={class:"card stat"},q={class:"card stat"},E={style:{color:"var(--green)"}},I={class:"card stat"},O={style:{color:"var(--red)"}},G={class:"card stat"},H={class:"card stat"},J={class:"card"},K={class:"row",style:{"justify-content":"space-between","align-items":"center"}},Q={class:"bar"},X={class:"muted",style:{"font-size":"12px","margin-top":"6px"}},Y={style:{"margin-top":"20px"}},Z={key:0,class:"card empty-state"},$={class:"grid"},ss={class:"row",style:{"justify-content":"space-between"}},ts={class:"muted"},es={class:"row",style:{"margin-top":"10px",gap:"8px"}},as={class:"badge won"},os={class:"badge lost"},ls={class:"badge not_tried"},ns={class:"muted",style:{"margin-top":"8px"}},is={__name:"Analytics",setup(rs){const a=u({overall:{total_sessions:0,wins:0,losses:0,close_rate:0,avg_score:0},trainee_count:0,hardest_personas:[]}),i=u(""),r=u(""),d=u(!1);async function v(){d.value=!0;try{a.value=await A.analytics({from:i.value,to:r.value})}finally{d.value=!1}}function w(){v()}function b(){i.value="",r.value="",v()}return k(v),(ds,e)=>{const p=B("router-link");return _(),c("div",null,[s("div",S,[s("h2",j,"📊 "+t(o(l).t("adminOverview")),1),s("div",z,[m(p,{to:"/admin/users"},{default:y(()=>[s("button",D,"👥 "+t(o(l).t("users")),1)]),_:1}),m(p,{to:"/admin/new-group"},{default:y(()=>[s("button",F,"+ "+t(o(l).t("addProduct")),1)]),_:1})])]),s("div",M,[s("span",P,"🗓 "+t(o(l).t("dateRange")),1),h(s("input",{type:"date","onUpdate:modelValue":e[0]||(e[0]=n=>i.value=n)},null,512),[[f,i.value]]),e[2]||(e[2]=s("span",null,"–",-1)),h(s("input",{type:"date","onUpdate:modelValue":e[1]||(e[1]=n=>r.value=n)},null,512),[[f,r.value]]),s("button",{class:"primary",onClick:w,disabled:d.value},"→ "+t(o(l).t("apply")),9,R),s("button",{onClick:b,disabled:d.value},t(o(l).t("clear")),9,T)]),s("div",U,[s("div",W,[e[3]||(e[3]=s("div",null,"Sessions",-1)),s("strong",null,t(a.value.overall.total_sessions),1)]),s("div",q,[e[4]||(e[4]=s("div",null,"Wins",-1)),s("strong",E,t(a.value.overall.wins),1)]),s("div",I,[e[5]||(e[5]=s("div",null,"Losses",-1)),s("strong",O,t(a.value.overall.losses),1)]),s("div",G,[e[6]||(e[6]=s("div",null,"Avg score",-1)),s("strong",null,t(a.value.overall.avg_score),1)]),s("div",H,[e[7]||(e[7]=s("div",null,"Trainees",-1)),s("strong",null,t(a.value.trainee_count),1)])]),s("div",J,[s("div",K,[s("strong",null,t(o(l).t("closeRate")),1),s("strong",null,t(a.value.overall.close_rate)+"%",1)]),s("div",Q,[s("div",{class:"bar-fill",style:C({width:(a.value.overall.close_rate||0)+"%"})},null,4)]),s("div",X,t(a.value.overall.wins)+" "+t(o(l).t("won").toLowerCase())+" / "+t(a.value.overall.total_sessions)+" sessions ",1)]),s("h3",Y,t(o(l).t("hardestPersonas")),1),a.value.hardest_personas.length===0?(_(),c("div",Z,[...e[8]||(e[8]=[s("strong",null,"No data",-1),s("span",null,"No sessions in this date range.",-1)])])):N("",!0),s("div",$,[(_(!0),c(V,null,L(a.value.hardest_personas,(n,g)=>(_(),c("div",{key:g,class:"card lift tier-card"},[s("div",ss,[s("strong",null,t(n.persona_name),1),s("span",ts,"#"+t(g+1),1)]),s("div",es,[s("span",as,t(n.wins)+"W",1),s("span",os,t(n.losses)+"L",1),s("span",ls,t(n.plays)+" plays",1)]),s("div",ns,t(o(l).t("score"))+": "+t(n.avg_score),1)]))),128))])])}}},us=x(is,[["__scopeId","data-v-9558687f"]]);export{us as default}; diff --git a/frontend/dist/assets/Analytics-ButgVyTK.css b/frontend/dist/assets/Analytics-ButgVyTK.css new file mode 100644 index 0000000..6f0438c --- /dev/null +++ b/frontend/dist/assets/Analytics-ButgVyTK.css @@ -0,0 +1 @@ +.stat[data-v-9558687f]{text-align:center;min-width:110px}.stat div[data-v-9558687f]{color:var(--muted);font-size:12px}.stat strong[data-v-9558687f]{font-size:20px}.filter-bar[data-v-9558687f]{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.filter-bar input[type=date][data-v-9558687f]{width:auto}.grid[data-v-9558687f]{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:14px}.tier-card[data-v-9558687f]{display:flex;flex-direction:column}.badge.won[data-v-9558687f]{background:#dcfce7;color:#166534}.badge.lost[data-v-9558687f]{background:#fee2e2;color:#991b1b}.badge.not_tried[data-v-9558687f]{background:#eef2ff;color:#4338ca}.bar[data-v-9558687f]{background:#eef0f5;border-radius:999px;height:10px;overflow:hidden;margin-top:10px}.bar-fill[data-v-9558687f]{background:linear-gradient(90deg,var(--accent),var(--accent-2));height:100%;border-radius:999px;transition:width .4s ease}.users-btn[data-v-9558687f]{background:#0ea5e9;border-color:transparent;color:#fff;font-weight:600}.users-btn[data-v-9558687f]:not(:disabled):hover{background:#0284c7;box-shadow:0 6px 16px #0ea5e959} diff --git a/frontend/dist/assets/Analytics-DstNBgKK.css b/frontend/dist/assets/Analytics-DstNBgKK.css deleted file mode 100644 index e4f8ce3..0000000 --- a/frontend/dist/assets/Analytics-DstNBgKK.css +++ /dev/null @@ -1 +0,0 @@ -.stat[data-v-d6f85218]{text-align:center;min-width:110px}.stat div[data-v-d6f85218]{color:var(--muted);font-size:12px}.stat strong[data-v-d6f85218]{font-size:20px}.filter-bar[data-v-d6f85218]{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.filter-bar input[type=date][data-v-d6f85218]{width:auto}.grid[data-v-d6f85218]{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:14px}.tier-card[data-v-d6f85218]{display:flex;flex-direction:column}.badge.won[data-v-d6f85218]{background:#dcfce7;color:#166534}.badge.lost[data-v-d6f85218]{background:#fee2e2;color:#991b1b}.badge.not_tried[data-v-d6f85218]{background:#eef2ff;color:#4338ca}.bar[data-v-d6f85218]{background:#eef0f5;border-radius:999px;height:10px;overflow:hidden;margin-top:10px}.bar-fill[data-v-d6f85218]{background:linear-gradient(90deg,var(--accent),var(--accent-2));height:100%;border-radius:999px;transition:width .4s ease} diff --git a/frontend/dist/assets/Analytics-hzMFeY95.js b/frontend/dist/assets/Analytics-hzMFeY95.js deleted file mode 100644 index 041dc8c..0000000 --- a/frontend/dist/assets/Analytics-hzMFeY95.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as x,k,c,a as s,t,u as a,i as l,l as m,m as y,w as f,v as h,n as C,e as N,F as V,p as L,q as A,s as B,r as u,o as _}from"./index-CNkuf2ya.js";const S={class:"row",style:{"align-items":"center","margin-bottom":"16px"}},j={style:{margin:"0"}},z={class:"row",style:{"margin-left":"auto",gap:"10px"}},D={class:"soft"},F={class:"primary"},M={class:"card filter-bar"},P={class:"muted"},R=["disabled"],T=["disabled"],U={class:"row",style:{gap:"16px",margin:"16px 0"}},W={class:"card stat"},q={class:"card stat"},E={style:{color:"var(--green)"}},I={class:"card stat"},O={style:{color:"var(--red)"}},G={class:"card stat"},H={class:"card stat"},J={class:"card"},K={class:"row",style:{"justify-content":"space-between","align-items":"center"}},Q={class:"bar"},X={class:"muted",style:{"font-size":"12px","margin-top":"6px"}},Y={style:{"margin-top":"20px"}},Z={key:0,class:"card empty-state"},$={class:"grid"},ss={class:"row",style:{"justify-content":"space-between"}},ts={class:"muted"},es={class:"row",style:{"margin-top":"10px",gap:"8px"}},os={class:"badge won"},as={class:"badge lost"},ls={class:"badge not_tried"},ns={class:"muted",style:{"margin-top":"8px"}},is={__name:"Analytics",setup(rs){const o=u({overall:{total_sessions:0,wins:0,losses:0,close_rate:0,avg_score:0},trainee_count:0,hardest_personas:[]}),i=u(""),r=u(""),d=u(!1);async function v(){d.value=!0;try{o.value=await A.analytics({from:i.value,to:r.value})}finally{d.value=!1}}function w(){v()}function b(){i.value="",r.value="",v()}return k(v),(ds,e)=>{const p=B("router-link");return _(),c("div",null,[s("div",S,[s("h2",j,"📊 "+t(a(l).t("adminOverview")),1),s("div",z,[m(p,{to:"/admin/users"},{default:y(()=>[s("button",D,"👥 "+t(a(l).t("users")),1)]),_:1}),m(p,{to:"/admin/new-group"},{default:y(()=>[s("button",F,"+ "+t(a(l).t("addProduct")),1)]),_:1})])]),s("div",M,[s("span",P,"🗓 "+t(a(l).t("dateRange")),1),f(s("input",{type:"date","onUpdate:modelValue":e[0]||(e[0]=n=>i.value=n)},null,512),[[h,i.value]]),e[2]||(e[2]=s("span",null,"–",-1)),f(s("input",{type:"date","onUpdate:modelValue":e[1]||(e[1]=n=>r.value=n)},null,512),[[h,r.value]]),s("button",{class:"primary",onClick:w,disabled:d.value},"→ "+t(a(l).t("apply")),9,R),s("button",{onClick:b,disabled:d.value},t(a(l).t("clear")),9,T)]),s("div",U,[s("div",W,[e[3]||(e[3]=s("div",null,"Sessions",-1)),s("strong",null,t(o.value.overall.total_sessions),1)]),s("div",q,[e[4]||(e[4]=s("div",null,"Wins",-1)),s("strong",E,t(o.value.overall.wins),1)]),s("div",I,[e[5]||(e[5]=s("div",null,"Losses",-1)),s("strong",O,t(o.value.overall.losses),1)]),s("div",G,[e[6]||(e[6]=s("div",null,"Avg score",-1)),s("strong",null,t(o.value.overall.avg_score),1)]),s("div",H,[e[7]||(e[7]=s("div",null,"Trainees",-1)),s("strong",null,t(o.value.trainee_count),1)])]),s("div",J,[s("div",K,[s("strong",null,t(a(l).t("closeRate")),1),s("strong",null,t(o.value.overall.close_rate)+"%",1)]),s("div",Q,[s("div",{class:"bar-fill",style:C({width:(o.value.overall.close_rate||0)+"%"})},null,4)]),s("div",X,t(o.value.overall.wins)+" "+t(a(l).t("won").toLowerCase())+" / "+t(o.value.overall.total_sessions)+" sessions ",1)]),s("h3",Y,t(a(l).t("hardestPersonas")),1),o.value.hardest_personas.length===0?(_(),c("div",Z,[...e[8]||(e[8]=[s("strong",null,"No data",-1),s("span",null,"No sessions in this date range.",-1)])])):N("",!0),s("div",$,[(_(!0),c(V,null,L(o.value.hardest_personas,(n,g)=>(_(),c("div",{key:g,class:"card lift tier-card"},[s("div",ss,[s("strong",null,t(n.persona_name),1),s("span",ts,"#"+t(g+1),1)]),s("div",es,[s("span",os,t(n.wins)+"W",1),s("span",as,t(n.losses)+"L",1),s("span",ls,t(n.plays)+" plays",1)]),s("div",ns,t(a(l).t("score"))+": "+t(n.avg_score),1)]))),128))])])}}},us=x(is,[["__scopeId","data-v-d6f85218"]]);export{us as default}; diff --git a/frontend/dist/assets/Chat-DPgZfhp2.js b/frontend/dist/assets/Chat-CYFTB7sZ.js similarity index 98% rename from frontend/dist/assets/Chat-DPgZfhp2.js rename to frontend/dist/assets/Chat-CYFTB7sZ.js index 98e0920..0c51201 100644 --- a/frontend/dist/assets/Chat-DPgZfhp2.js +++ b/frontend/dist/assets/Chat-CYFTB7sZ.js @@ -1 +1 @@ -import{_ as K,k as M,q as k,c as t,l as S,m as D,u as l,a as s,t as e,z as C,e as i,j as m,i as n,F,p as I,w as q,v as E,b as H,h as J,r as c,B as L,s as O,o}from"./index-CNkuf2ya.js";const P={class:"row",style:{"align-items":"center","margin-bottom":"12px"}},R={style:{margin:"0"}},U={key:0,class:"muted"},$=["disabled"],A={key:0,class:"spinner",style:{"margin-right":"4px"}},G={key:0,class:"card task"},Q={key:0},W={key:0,class:"bubble msg-customer muted"},X={key:2,class:"composer"},Y=["disabled","placeholder"],Z=["disabled"],ee={key:3,class:"card debrief"},se={key:0},ae={class:"json"},te={class:"primary",style:{"margin-top":"12px"}},le={__name:"Chat",setup(ne){const N=J(),_=N.params.gid,g=N.params.pid,r=c(null),f=c(!1),v=c([]),p=c(""),d=c(!1),u=c(null),w=c(""),j=c(null);function T(){L(()=>{y.value&&(y.value.scrollTop=y.value.scrollHeight)})}const y=c(null);M(async()=>{r.value=(await k.getPersona(_,g)).persona;const a=await k.chatStart(_,g);j.value=a.session.id,a.session.task&&(w.value=a.session.task),v.value=a.session.messages||[],f.value=!0,v.value.length&&T()});async function V(){if(p.value.trim()){d.value=!0;try{const a=await k.chatSend(_,g,p.value.trim());v.value=a.messages,p.value="",T()}catch(a){alert(a.message)}finally{d.value=!1}}}async function z(){if(confirm(n.t("finish")+"?")){d.value=!0;try{const a=await k.chatFinish(_,g);u.value=a.debrief,v.value=a.session.messages}catch(a){alert(a.message)}finally{d.value=!1}}}return(a,b)=>{const B=O("router-link");return o(),t("div",null,[S(B,{to:`/groups/${l(_)}/personas`,class:"btn-back"},{default:D(()=>[m("← "+e(l(n).t("personas")),1)]),_:1},8,["to"]),s("div",P,[s("h2",R,e(r.value?r.value.name:"..."),1),s("span",{class:C(["badge",r.value&&r.value.channel])},e(r.value?r.value.channel:""),3),r.value?(o(),t("span",U,e(r.value.profession)+" · "+e(r.value.age_group),1)):i("",!0),s("button",{class:"danger",style:{"margin-left":"auto"},onClick:z,disabled:v.value.length===0||!!u.value},[d.value?(o(),t("span",A)):i("",!0),m(e(l(n).t("finish")),1)],8,$)]),f.value?i("",!0):(o(),t("div",G,[s("strong",null,"📣 "+e(l(n).t("sellerInitiated")),1),w.value?(o(),t("div",Q,e(w.value),1)):i("",!0)])),f.value?(o(),t("div",{key:1,class:"thread",ref_key:"thread",ref:y},[(o(!0),t(F,null,I(v.value,(h,x)=>(o(),t("div",{key:x,class:C(["bubble",h.role==="seller"?"msg-seller":"msg-customer"])},e(h.text),3))),128)),d.value?(o(),t("div",W,"...")):i("",!0)],512)):i("",!0),f.value&&!u.value?(o(),t("div",X,[q(s("input",{"onUpdate:modelValue":b[0]||(b[0]=h=>p.value=h),onKeyup:H(V,["enter"]),disabled:d.value,placeholder:l(n).t("send")},null,40,Y),[[E,p.value]]),s("button",{class:"primary",onClick:V,disabled:d.value||!p.value.trim()},e(l(n).t("send")),9,Z)])):i("",!0),u.value?(o(),t("div",ee,[s("h3",null,e(l(n).t("debrief")),1),s("p",null,[s("span",{class:C(["badge",u.value.outcome])},e(u.value.outcome==="won"?l(n).t("won"):l(n).t("lost")),3),m(" — "+e(l(n).t("score"))+": ",1),s("strong",null,e(u.value.score),1)]),s("p",null,[s("strong",null,e(l(n).t("pain"))+":",1),m(" "+e(u.value.pain||"—"),1)]),s("p",null,[s("strong",null,e(l(n).t("why"))+":",1),m(" "+e(u.value.why),1)]),u.value.coaching&&u.value.coaching.length?(o(),t("div",se,[b[1]||(b[1]=s("strong",null,"Coaching:",-1)),s("ul",null,[(o(!0),t(F,null,I(u.value.coaching,(h,x)=>(o(),t("li",{key:x},e(h),1))),128))])])):i("",!0),s("details",null,[s("summary",null,e(l(n).t("reveal")),1),s("pre",ae,e(JSON.stringify(u.value.revealed_persona,null,2)),1)]),S(B,{to:"/"},{default:D(()=>[s("button",te,e(l(n).t("dashboard")),1)]),_:1})])):i("",!0)])}}},ue=K(le,[["__scopeId","data-v-4f54526a"]]);export{ue as default}; +import{_ as K,k as M,q as k,c as t,l as S,m as D,u as l,a as s,t as e,z as C,e as i,j as m,i as n,F,p as I,w as q,v as E,b as H,h as J,r as c,B as L,s as O,o}from"./index-gmrXNPrQ.js";const P={class:"row",style:{"align-items":"center","margin-bottom":"12px"}},R={style:{margin:"0"}},U={key:0,class:"muted"},$=["disabled"],A={key:0,class:"spinner",style:{"margin-right":"4px"}},G={key:0,class:"card task"},Q={key:0},W={key:0,class:"bubble msg-customer muted"},X={key:2,class:"composer"},Y=["disabled","placeholder"],Z=["disabled"],ee={key:3,class:"card debrief"},se={key:0},ae={class:"json"},te={class:"primary",style:{"margin-top":"12px"}},le={__name:"Chat",setup(ne){const N=J(),_=N.params.gid,g=N.params.pid,r=c(null),f=c(!1),v=c([]),p=c(""),d=c(!1),u=c(null),w=c(""),j=c(null);function T(){L(()=>{y.value&&(y.value.scrollTop=y.value.scrollHeight)})}const y=c(null);M(async()=>{r.value=(await k.getPersona(_,g)).persona;const a=await k.chatStart(_,g);j.value=a.session.id,a.session.task&&(w.value=a.session.task),v.value=a.session.messages||[],f.value=!0,v.value.length&&T()});async function V(){if(p.value.trim()){d.value=!0;try{const a=await k.chatSend(_,g,p.value.trim());v.value=a.messages,p.value="",T()}catch(a){alert(a.message)}finally{d.value=!1}}}async function z(){if(confirm(n.t("finish")+"?")){d.value=!0;try{const a=await k.chatFinish(_,g);u.value=a.debrief,v.value=a.session.messages}catch(a){alert(a.message)}finally{d.value=!1}}}return(a,b)=>{const B=O("router-link");return o(),t("div",null,[S(B,{to:`/groups/${l(_)}/personas`,class:"btn-back"},{default:D(()=>[m("← "+e(l(n).t("personas")),1)]),_:1},8,["to"]),s("div",P,[s("h2",R,e(r.value?r.value.name:"..."),1),s("span",{class:C(["badge",r.value&&r.value.channel])},e(r.value?r.value.channel:""),3),r.value?(o(),t("span",U,e(r.value.profession)+" · "+e(r.value.age_group),1)):i("",!0),s("button",{class:"danger",style:{"margin-left":"auto"},onClick:z,disabled:v.value.length===0||!!u.value},[d.value?(o(),t("span",A)):i("",!0),m(e(l(n).t("finish")),1)],8,$)]),f.value?i("",!0):(o(),t("div",G,[s("strong",null,"📣 "+e(l(n).t("sellerInitiated")),1),w.value?(o(),t("div",Q,e(w.value),1)):i("",!0)])),f.value?(o(),t("div",{key:1,class:"thread",ref_key:"thread",ref:y},[(o(!0),t(F,null,I(v.value,(h,x)=>(o(),t("div",{key:x,class:C(["bubble",h.role==="seller"?"msg-seller":"msg-customer"])},e(h.text),3))),128)),d.value?(o(),t("div",W,"...")):i("",!0)],512)):i("",!0),f.value&&!u.value?(o(),t("div",X,[q(s("input",{"onUpdate:modelValue":b[0]||(b[0]=h=>p.value=h),onKeyup:H(V,["enter"]),disabled:d.value,placeholder:l(n).t("send")},null,40,Y),[[E,p.value]]),s("button",{class:"primary",onClick:V,disabled:d.value||!p.value.trim()},e(l(n).t("send")),9,Z)])):i("",!0),u.value?(o(),t("div",ee,[s("h3",null,e(l(n).t("debrief")),1),s("p",null,[s("span",{class:C(["badge",u.value.outcome])},e(u.value.outcome==="won"?l(n).t("won"):l(n).t("lost")),3),m(" — "+e(l(n).t("score"))+": ",1),s("strong",null,e(u.value.score),1)]),s("p",null,[s("strong",null,e(l(n).t("pain"))+":",1),m(" "+e(u.value.pain||"—"),1)]),s("p",null,[s("strong",null,e(l(n).t("why"))+":",1),m(" "+e(u.value.why),1)]),u.value.coaching&&u.value.coaching.length?(o(),t("div",se,[b[1]||(b[1]=s("strong",null,"Coaching:",-1)),s("ul",null,[(o(!0),t(F,null,I(u.value.coaching,(h,x)=>(o(),t("li",{key:x},e(h),1))),128))])])):i("",!0),s("details",null,[s("summary",null,e(l(n).t("reveal")),1),s("pre",ae,e(JSON.stringify(u.value.revealed_persona,null,2)),1)]),S(B,{to:"/"},{default:D(()=>[s("button",te,e(l(n).t("dashboard")),1)]),_:1})])):i("",!0)])}}},ue=K(le,[["__scopeId","data-v-4f54526a"]]);export{ue as default}; diff --git a/frontend/dist/assets/GroupBuilder-CRBEizer.js b/frontend/dist/assets/GroupBuilder-CxLYlayH.js similarity index 97% rename from frontend/dist/assets/GroupBuilder-CRBEizer.js rename to frontend/dist/assets/GroupBuilder-CxLYlayH.js index d53b1d2..cda1767 100644 --- a/frontend/dist/assets/GroupBuilder-CRBEizer.js +++ b/frontend/dist/assets/GroupBuilder-CxLYlayH.js @@ -1 +1 @@ -import{c as g,a as e,t as l,u as o,i as n,w as r,v,C as m,e as x,r as p,g as k,o as f,q as w}from"./index-CNkuf2ya.js";const V={class:"card"},B={class:"row"},C={style:{flex:"1"}},U={value:"facebook"},D={value:"line"},F={style:{flex:"1"}},S={value:"th"},E={value:"en"},G={key:0,class:"error"},M=["disabled"],A={__name:"GroupBuilder",setup(N){const h=k(),t=p({product:"",segment:"",description:"",channel:"facebook",language:"th"}),c=p([]),d=p(""),i=p(!1);function _(a){c.value=Array.from(a.target.files||[])}async function b(){i.value=!0,d.value="";try{const a=new FormData;a.append("product",t.value.product),a.append("segment",t.value.segment),a.append("description",t.value.description),a.append("channel",t.value.channel),a.append("language",t.value.language),c.value.forEach(y=>a.append("files",y));const u=(await w.createGroup(a)).group.id;h.push(`/admin/groups/${u}/edit`)}catch(a){d.value=a.message}finally{i.value=!1}}return(a,s)=>(f(),g("div",V,[e("h2",null,l(o(n).t("groupBuilder")),1),e("label",null,l(o(n).t("product")),1),r(e("textarea",{"onUpdate:modelValue":s[0]||(s[0]=u=>t.value.product=u),rows:"3",placeholder:"e.g. Cloud POS for small restaurants"},null,512),[[v,t.value.product]]),e("label",null,l(o(n).t("segment")),1),r(e("input",{"onUpdate:modelValue":s[1]||(s[1]=u=>t.value.segment=u)},null,512),[[v,t.value.segment]]),e("label",null,l(o(n).t("description")),1),r(e("textarea",{"onUpdate:modelValue":s[2]||(s[2]=u=>t.value.description=u),rows:"3"},null,512),[[v,t.value.description]]),e("div",B,[e("div",C,[e("label",null,l(o(n).t("channel")),1),r(e("select",{"onUpdate:modelValue":s[3]||(s[3]=u=>t.value.channel=u)},[e("option",U,l(o(n).t("facebook")),1),e("option",D,l(o(n).t("line")),1)],512),[[m,t.value.channel]])]),e("div",F,[e("label",null,l(o(n).t("language")),1),r(e("select",{"onUpdate:modelValue":s[4]||(s[4]=u=>t.value.language=u)},[e("option",S,l(o(n).t("thai")),1),e("option",E,l(o(n).t("english")),1)],512),[[m,t.value.language]])])]),e("label",null,"📎 Files (.pdf/.md/.txt) — "+l(o(n).t("product"))+" can come from here",1),e("input",{type:"file",multiple:"",accept:".pdf,.md,.txt",onChange:_},null,32),d.value?(f(),g("div",G,l(d.value),1)):x("",!0),e("button",{class:"primary",style:{"margin-top":"16px"},disabled:i.value||!t.value.product&&!c.value.length,onClick:b},l(i.value?"...":o(n).t("create")),9,M)]))}};export{A as default}; +import{c as g,a as e,t as l,u as o,i as n,w as r,v,C as m,e as x,r as p,g as k,o as f,q as w}from"./index-gmrXNPrQ.js";const V={class:"card"},B={class:"row"},C={style:{flex:"1"}},U={value:"facebook"},D={value:"line"},F={style:{flex:"1"}},S={value:"th"},E={value:"en"},G={key:0,class:"error"},M=["disabled"],A={__name:"GroupBuilder",setup(N){const h=k(),t=p({product:"",segment:"",description:"",channel:"facebook",language:"th"}),c=p([]),d=p(""),i=p(!1);function _(a){c.value=Array.from(a.target.files||[])}async function b(){i.value=!0,d.value="";try{const a=new FormData;a.append("product",t.value.product),a.append("segment",t.value.segment),a.append("description",t.value.description),a.append("channel",t.value.channel),a.append("language",t.value.language),c.value.forEach(y=>a.append("files",y));const u=(await w.createGroup(a)).group.id;h.push(`/admin/groups/${u}/edit`)}catch(a){d.value=a.message}finally{i.value=!1}}return(a,s)=>(f(),g("div",V,[e("h2",null,l(o(n).t("groupBuilder")),1),e("label",null,l(o(n).t("product")),1),r(e("textarea",{"onUpdate:modelValue":s[0]||(s[0]=u=>t.value.product=u),rows:"3",placeholder:"e.g. Cloud POS for small restaurants"},null,512),[[v,t.value.product]]),e("label",null,l(o(n).t("segment")),1),r(e("input",{"onUpdate:modelValue":s[1]||(s[1]=u=>t.value.segment=u)},null,512),[[v,t.value.segment]]),e("label",null,l(o(n).t("description")),1),r(e("textarea",{"onUpdate:modelValue":s[2]||(s[2]=u=>t.value.description=u),rows:"3"},null,512),[[v,t.value.description]]),e("div",B,[e("div",C,[e("label",null,l(o(n).t("channel")),1),r(e("select",{"onUpdate:modelValue":s[3]||(s[3]=u=>t.value.channel=u)},[e("option",U,l(o(n).t("facebook")),1),e("option",D,l(o(n).t("line")),1)],512),[[m,t.value.channel]])]),e("div",F,[e("label",null,l(o(n).t("language")),1),r(e("select",{"onUpdate:modelValue":s[4]||(s[4]=u=>t.value.language=u)},[e("option",S,l(o(n).t("thai")),1),e("option",E,l(o(n).t("english")),1)],512),[[m,t.value.language]])])]),e("label",null,"📎 Files (.pdf/.md/.txt) — "+l(o(n).t("product"))+" can come from here",1),e("input",{type:"file",multiple:"",accept:".pdf,.md,.txt",onChange:_},null,32),d.value?(f(),g("div",G,l(d.value),1)):x("",!0),e("button",{class:"primary",style:{"margin-top":"16px"},disabled:i.value||!t.value.product&&!c.value.length,onClick:b},l(i.value?"...":o(n).t("create")),9,M)]))}};export{A as default}; diff --git a/frontend/dist/assets/GroupEdit-qmIH-KdK.js b/frontend/dist/assets/GroupEdit-DiRZ2lxy.js similarity index 97% rename from frontend/dist/assets/GroupEdit-qmIH-KdK.js rename to frontend/dist/assets/GroupEdit-DiRZ2lxy.js index ea30ba6..766c4fe 100644 --- a/frontend/dist/assets/GroupEdit-qmIH-KdK.js +++ b/frontend/dist/assets/GroupEdit-DiRZ2lxy.js @@ -1 +1 @@ -import{_ as S,k as E,c as n,l as J,m as O,a as t,t as e,u as d,i as l,e as m,j as k,F as b,p as x,h as z,q as y,s as G,r as v,o}from"./index-CNkuf2ya.js";const V={class:"row",style:{"align-items":"center","margin-bottom":"16px"}},j={style:{margin:"0"}},A=["disabled"],P={key:0,class:"spinner",style:{"margin-right":"4px"}},F={key:0,class:"error"},I={key:1,class:"card empty-state"},L={class:"grid"},T={class:"row"},q={key:0,class:"badge"},D={class:"muted"},M={class:"muted",style:{"margin-top":"4px"}},R={style:{"margin-top":"8px"},open:""},$={class:"json"},H=["onClick"],K={__name:"GroupEdit",setup(Q){const _=z().params.gid,g=v(null),p=v([]),i=v(!1),u=v("");async function f(){const s=await y.getGroup(_);g.value=s.group,p.value=(await y.listPersonas(_)).personas}function N(s){return p.value.filter(r=>r.tier===s)}function w(s){return l.t(s==="A"?"tierA":s==="B"?"tierB":"tierC")}async function C(){i.value=!0,u.value="";try{const s=await y.analyzeGroup(_);p.value=s.personas,await f()}catch(s){u.value=s.message}finally{i.value=!1}}function B(s){const r=prompt("Edit persona JSON (full fields):",JSON.stringify(s,null,2));if(r)try{const c=JSON.parse(r);y.updatePersona(_,s.id,c).then(f)}catch(c){u.value="Invalid JSON: "+c.message}}return E(f),(s,r)=>{const c=G("router-link");return o(),n("div",null,[J(c,{to:"/",class:"btn-back"},{default:O(()=>[k("← "+e(d(l).t("dashboard")),1)]),_:1}),t("div",V,[t("h2",j,e(d(l).t("groupBuilder"))+" — "+e(g.value&&g.value.title),1),t("button",{class:"primary",style:{"margin-left":"auto"},onClick:C,disabled:i.value},[i.value?(o(),n("span",P)):m("",!0),k(e(d(l).t("analyze")),1)],8,A)]),u.value?(o(),n("div",F,e(u.value),1)):m("",!0),p.value.length===0&&!i.value?(o(),n("div",I,[r[0]||(r[0]=t("strong",null,"No personas yet",-1)),t("span",null,"Click "+e(d(l).t("analyze"))+" to generate the 15 personas (5 per tier).",1)])):m("",!0),(o(),n(b,null,x(["A","B","C"],h=>t("div",{key:h,style:{"margin-bottom":"20px"}},[t("h4",null,e(w(h)),1),t("div",L,[(o(!0),n(b,null,x(N(h),a=>(o(),n("div",{key:a.id,class:"card pcard"},[t("div",T,[t("strong",null,e(a.name),1),a.special==="wrong_text"?(o(),n("span",q,"⚠️ wrong_text")):m("",!0)]),t("div",D,e(a.profession)+" · "+e(a.age_group)+" · "+e(a.channel)+" · "+e(a.initiation_mode),1),t("div",M,"diff "+e(a.difficulty)+" · "+e(a.income)+" · "+e(a.personality),1),t("details",R,[t("summary",null,e(d(l).t("reveal")),1),t("pre",$,e(JSON.stringify(a,null,2)),1)]),t("button",{onClick:W=>B(a)},"✏️ Edit",8,H)]))),128))])])),64))])}}},Y=S(K,[["__scopeId","data-v-ee1c1944"]]);export{Y as default}; +import{_ as S,k as E,c as n,l as J,m as O,a as t,t as e,u as d,i as l,e as m,j as k,F as b,p as x,h as z,q as y,s as G,r as v,o}from"./index-gmrXNPrQ.js";const V={class:"row",style:{"align-items":"center","margin-bottom":"16px"}},j={style:{margin:"0"}},A=["disabled"],P={key:0,class:"spinner",style:{"margin-right":"4px"}},F={key:0,class:"error"},I={key:1,class:"card empty-state"},L={class:"grid"},T={class:"row"},q={key:0,class:"badge"},D={class:"muted"},M={class:"muted",style:{"margin-top":"4px"}},R={style:{"margin-top":"8px"},open:""},$={class:"json"},H=["onClick"],K={__name:"GroupEdit",setup(Q){const _=z().params.gid,g=v(null),p=v([]),i=v(!1),u=v("");async function f(){const s=await y.getGroup(_);g.value=s.group,p.value=(await y.listPersonas(_)).personas}function N(s){return p.value.filter(r=>r.tier===s)}function w(s){return l.t(s==="A"?"tierA":s==="B"?"tierB":"tierC")}async function C(){i.value=!0,u.value="";try{const s=await y.analyzeGroup(_);p.value=s.personas,await f()}catch(s){u.value=s.message}finally{i.value=!1}}function B(s){const r=prompt("Edit persona JSON (full fields):",JSON.stringify(s,null,2));if(r)try{const c=JSON.parse(r);y.updatePersona(_,s.id,c).then(f)}catch(c){u.value="Invalid JSON: "+c.message}}return E(f),(s,r)=>{const c=G("router-link");return o(),n("div",null,[J(c,{to:"/",class:"btn-back"},{default:O(()=>[k("← "+e(d(l).t("dashboard")),1)]),_:1}),t("div",V,[t("h2",j,e(d(l).t("groupBuilder"))+" — "+e(g.value&&g.value.title),1),t("button",{class:"primary",style:{"margin-left":"auto"},onClick:C,disabled:i.value},[i.value?(o(),n("span",P)):m("",!0),k(e(d(l).t("analyze")),1)],8,A)]),u.value?(o(),n("div",F,e(u.value),1)):m("",!0),p.value.length===0&&!i.value?(o(),n("div",I,[r[0]||(r[0]=t("strong",null,"No personas yet",-1)),t("span",null,"Click "+e(d(l).t("analyze"))+" to generate the 15 personas (5 per tier).",1)])):m("",!0),(o(),n(b,null,x(["A","B","C"],h=>t("div",{key:h,style:{"margin-bottom":"20px"}},[t("h4",null,e(w(h)),1),t("div",L,[(o(!0),n(b,null,x(N(h),a=>(o(),n("div",{key:a.id,class:"card pcard"},[t("div",T,[t("strong",null,e(a.name),1),a.special==="wrong_text"?(o(),n("span",q,"⚠️ wrong_text")):m("",!0)]),t("div",D,e(a.profession)+" · "+e(a.age_group)+" · "+e(a.channel)+" · "+e(a.initiation_mode),1),t("div",M,"diff "+e(a.difficulty)+" · "+e(a.income)+" · "+e(a.personality),1),t("details",R,[t("summary",null,e(d(l).t("reveal")),1),t("pre",$,e(JSON.stringify(a,null,2)),1)]),t("button",{onClick:W=>B(a)},"✏️ Edit",8,H)]))),128))])])),64))])}}},Y=S(K,[["__scopeId","data-v-ee1c1944"]]);export{Y as default}; diff --git a/frontend/dist/assets/Login-DFuS2Llc.js b/frontend/dist/assets/Login-71KwBI7P.js similarity index 92% rename from frontend/dist/assets/Login-DFuS2Llc.js rename to frontend/dist/assets/Login-71KwBI7P.js index c13a3e6..231de43 100644 --- a/frontend/dist/assets/Login-DFuS2Llc.js +++ b/frontend/dist/assets/Login-71KwBI7P.js @@ -1 +1 @@ -import{_ as b,c as d,a as e,t as s,u as c,i as o,w as y,v as x,b as w,d as k,e as S,r as l,f,g as V,h as B,o as v}from"./index-CNkuf2ya.js";const C={class:"login-wrap"},D={class:"card login-card"},K={class:"pw-wrap"},E=["type"],L=["aria-label"],M={key:0,class:"error",role:"alert"},N=["disabled"],R={key:0,class:"spinner"},U={key:1},q={__name:"Login",setup(H){const g=B(),_=V(),n=l(""),u=l(""),a=l(!1),r=l(""),i=l(!1);async function m(){r.value="",i.value=!0;try{await f.login(n.value.trim(),u.value),f.mustSetup?_.push({path:"/setup"}):_.push(g.query.redirect||"/")}catch{r.value=o.t("loginError")}finally{i.value=!1}}return(h,t)=>(v(),d("div",C,[e("div",D,[e("h1",null,"🎯 "+s(c(o).t("app")),1),t[3]||(t[3]=e("p",{class:"muted",style:{"margin-top":"-8px"}},"Sales training simulator",-1)),e("label",null,s(c(o).t("username")),1),y(e("input",{"onUpdate:modelValue":t[0]||(t[0]=p=>n.value=p),type:"text",autocomplete:"username",onKeyup:w(m,["enter"])},null,544),[[x,n.value]]),e("label",null,s(c(o).t("password")),1),e("div",K,[y(e("input",{"onUpdate:modelValue":t[1]||(t[1]=p=>u.value=p),type:a.value?"text":"password",autocomplete:"current-password",onKeyup:w(m,["enter"])},null,40,E),[[k,u.value]]),e("button",{type:"button",class:"pw-toggle",onClick:t[2]||(t[2]=p=>a.value=!a.value),"aria-label":a.value?"Hide password":"Show password"},s(a.value?"🙈":"👁"),9,L)]),r.value?(v(),d("div",M,s(r.value),1)):S("",!0),e("button",{class:"primary",style:{width:"100%","margin-top":"16px"},disabled:i.value||!n.value||!u.value,onClick:m},[i.value?(v(),d("span",R)):(v(),d("span",U,s(c(o).t("login")),1))],8,N)])]))}},P=b(q,[["__scopeId","data-v-f7904d9f"]]);export{P as default}; +import{_ as b,c as d,a as e,t as s,u as c,i as o,w as y,v as x,b as w,d as k,e as S,r as l,f,g as V,h as B,o as v}from"./index-gmrXNPrQ.js";const C={class:"login-wrap"},D={class:"card login-card"},K={class:"pw-wrap"},E=["type"],L=["aria-label"],M={key:0,class:"error",role:"alert"},N=["disabled"],R={key:0,class:"spinner"},U={key:1},q={__name:"Login",setup(H){const g=B(),_=V(),n=l(""),u=l(""),a=l(!1),r=l(""),i=l(!1);async function m(){r.value="",i.value=!0;try{await f.login(n.value.trim(),u.value),f.mustSetup?_.push({path:"/setup"}):_.push(g.query.redirect||"/")}catch{r.value=o.t("loginError")}finally{i.value=!1}}return(h,t)=>(v(),d("div",C,[e("div",D,[e("h1",null,"🎯 "+s(c(o).t("app")),1),t[3]||(t[3]=e("p",{class:"muted",style:{"margin-top":"-8px"}},"Sales training simulator",-1)),e("label",null,s(c(o).t("username")),1),y(e("input",{"onUpdate:modelValue":t[0]||(t[0]=p=>n.value=p),type:"text",autocomplete:"username",onKeyup:w(m,["enter"])},null,544),[[x,n.value]]),e("label",null,s(c(o).t("password")),1),e("div",K,[y(e("input",{"onUpdate:modelValue":t[1]||(t[1]=p=>u.value=p),type:a.value?"text":"password",autocomplete:"current-password",onKeyup:w(m,["enter"])},null,40,E),[[k,u.value]]),e("button",{type:"button",class:"pw-toggle",onClick:t[2]||(t[2]=p=>a.value=!a.value),"aria-label":a.value?"Hide password":"Show password"},s(a.value?"🙈":"👁"),9,L)]),r.value?(v(),d("div",M,s(r.value),1)):S("",!0),e("button",{class:"primary",style:{width:"100%","margin-top":"16px"},disabled:i.value||!n.value||!u.value,onClick:m},[i.value?(v(),d("span",R)):(v(),d("span",U,s(c(o).t("login")),1))],8,N)])]))}},P=b(q,[["__scopeId","data-v-f7904d9f"]]);export{P as default}; diff --git a/frontend/dist/assets/MyBoard-DoSeQn-O.js b/frontend/dist/assets/MyBoard-CjsbrOsq.js similarity index 96% rename from frontend/dist/assets/MyBoard-DoSeQn-O.js rename to frontend/dist/assets/MyBoard-CjsbrOsq.js index 12282f4..f242520 100644 --- a/frontend/dist/assets/MyBoard-DoSeQn-O.js +++ b/frontend/dist/assets/MyBoard-CjsbrOsq.js @@ -1 +1 @@ -import{_ as f,k as x,q as v,c as l,a as t,t as s,u as e,i as a,e as m,w as k,x as b,F as B,p as S,r as _,y as c,o as r,z as D}from"./index-CNkuf2ya.js";const M={key:0,class:"row stat-row"},N={class:"card stat"},T={class:"card stat won"},z={class:"card stat lost"},C={class:"card stat"},F={key:1,class:"card"},V={key:2,class:"card empty-state"},j={class:"card",style:{"margin-top":"20px"}},q={style:{"margin-top":"0"}},E={__name:"MyBoard",setup(G){const o=_([]),u=_([]),p=_(!0),y=c(()=>o.value.length),g=c(()=>o.value.filter(n=>n.my_outcome==="won").length),h=c(()=>o.value.filter(n=>n.my_outcome==="lost").length),w=c(()=>o.value.filter(n=>n.my_outcome==="not_tried").length);return x(async()=>{try{o.value=(await v.myBoard()).board||[],u.value=(await v.mySessions()).sessions||[]}finally{p.value=!1}}),(n,i)=>(r(),l("div",null,[t("h2",null,"📊 "+s(e(a).t("myDashboard")),1),p.value?m("",!0):(r(),l("div",M,[t("div",N,[t("span",null,s(e(a).t("total")),1),t("strong",null,s(y.value),1)]),t("div",T,[t("span",null,s(e(a).t("won")),1),t("strong",null,s(g.value),1)]),t("div",z,[t("span",null,s(e(a).t("lost")),1),t("strong",null,s(h.value),1)]),t("div",C,[t("span",null,s(e(a).t("notTried")),1),t("strong",null,s(w.value),1)])])),p.value?(r(),l("div",F,[...i[0]||(i[0]=[t("div",{class:"skeleton",style:{height:"50px"}},null,-1)])])):o.value.length===0?(r(),l("div",V,[...i[1]||(i[1]=[t("strong",null,"No practice yet",-1),t("span",null,"Go to Training and try closing a sale with a persona.",-1)])])):m("",!0),k(t("div",j,[t("h3",q,s(e(a).t("mySessions")),1),(r(!0),l(B,null,S(u.value,d=>(r(),l("div",{key:d.id,style:{display:"flex","justify-content":"space-between",padding:"8px 0","border-bottom":"1px solid var(--border)"}},[t("span",null,s(d.persona_name),1),t("span",{class:D(["badge",d.outcome])},s(d.outcome==="won"?e(a).t("won"):e(a).t("lost")),3)]))),128))],512),[[b,u.value.length]])]))}},L=f(E,[["__scopeId","data-v-1f6ea068"]]);export{L as default}; +import{_ as f,k as x,q as v,c as l,a as t,t as s,u as e,i as a,e as m,w as k,x as b,F as B,p as S,r as _,y as c,o as r,z as D}from"./index-gmrXNPrQ.js";const M={key:0,class:"row stat-row"},N={class:"card stat"},T={class:"card stat won"},z={class:"card stat lost"},C={class:"card stat"},F={key:1,class:"card"},V={key:2,class:"card empty-state"},j={class:"card",style:{"margin-top":"20px"}},q={style:{"margin-top":"0"}},E={__name:"MyBoard",setup(G){const o=_([]),u=_([]),p=_(!0),y=c(()=>o.value.length),g=c(()=>o.value.filter(n=>n.my_outcome==="won").length),h=c(()=>o.value.filter(n=>n.my_outcome==="lost").length),w=c(()=>o.value.filter(n=>n.my_outcome==="not_tried").length);return x(async()=>{try{o.value=(await v.myBoard()).board||[],u.value=(await v.mySessions()).sessions||[]}finally{p.value=!1}}),(n,i)=>(r(),l("div",null,[t("h2",null,"📊 "+s(e(a).t("myDashboard")),1),p.value?m("",!0):(r(),l("div",M,[t("div",N,[t("span",null,s(e(a).t("total")),1),t("strong",null,s(y.value),1)]),t("div",T,[t("span",null,s(e(a).t("won")),1),t("strong",null,s(g.value),1)]),t("div",z,[t("span",null,s(e(a).t("lost")),1),t("strong",null,s(h.value),1)]),t("div",C,[t("span",null,s(e(a).t("notTried")),1),t("strong",null,s(w.value),1)])])),p.value?(r(),l("div",F,[...i[0]||(i[0]=[t("div",{class:"skeleton",style:{height:"50px"}},null,-1)])])):o.value.length===0?(r(),l("div",V,[...i[1]||(i[1]=[t("strong",null,"No practice yet",-1),t("span",null,"Go to Training and try closing a sale with a persona.",-1)])])):m("",!0),k(t("div",j,[t("h3",q,s(e(a).t("mySessions")),1),(r(!0),l(B,null,S(u.value,d=>(r(),l("div",{key:d.id,style:{display:"flex","justify-content":"space-between",padding:"8px 0","border-bottom":"1px solid var(--border)"}},[t("span",null,s(d.persona_name),1),t("span",{class:D(["badge",d.outcome])},s(d.outcome==="won"?e(a).t("won"):e(a).t("lost")),3)]))),128))],512),[[b,u.value.length]])]))}},L=f(E,[["__scopeId","data-v-1f6ea068"]]);export{L as default}; diff --git a/frontend/dist/assets/Personas-Ck-UhJ3k.js b/frontend/dist/assets/Personas-BGoC8X56.js similarity index 97% rename from frontend/dist/assets/Personas-Ck-UhJ3k.js rename to frontend/dist/assets/Personas-BGoC8X56.js index 7cd44f2..259d011 100644 --- a/frontend/dist/assets/Personas-Ck-UhJ3k.js +++ b/frontend/dist/assets/Personas-BGoC8X56.js @@ -1 +1 @@ -import{_ as $,k as N,c as r,l as v,m as u,a as t,t as s,u as a,i as o,f as b,e as V,F as _,p as y,h as z,q as I,s as L,r as k,o as n,j as x,z as f,A as w}from"./index-CNkuf2ya.js";const T={class:"row",style:{"align-items":"center"}},j={style:{margin:"0"}},F={class:"muted",style:{"margin-left":"auto"}},q={key:0,class:"row",style:{margin:"12px 0",gap:"10px"}},D={class:"primary"},E={class:"grid"},M={class:"row",style:{"justify-content":"space-between"}},R={class:"diff"},S={class:"muted"},G={class:"muted"},H={class:"muted"},J={class:"muted",style:{"margin-top":"6px"}},K={class:"primary",style:{width:"100%"}},O={class:"primary",style:{width:"100%"}},Q={key:1,class:"muted",style:{"margin-top":"auto","font-size":"12px"}},U={__name:"Personas",setup(W){const c=z().params.gid,p=k([]),A=k(!0);async function B(){try{p.value=(await I.listPersonas(c)).personas}finally{A.value=!1}}function C(i){return p.value.filter(l=>l.tier===i)}function P(i){return o.t(i==="A"?"tierA":i==="B"?"tierB":"tierC")}function g(i){return i==="won"?o.t("won"):i==="lost"?o.t("lost"):o.t("notTried")}return N(B),(i,l)=>{const d=L("router-link");return n(),r("div",null,[v(d,{to:"/training",class:"btn-back"},{default:u(()=>[x("← "+s(a(o).t("training")),1)]),_:1}),t("div",T,[t("h2",j,s(a(o).t("personas")),1),t("span",F,s(a(o).t("selectPersona")),1)]),a(b).isAdmin?(n(),r("div",q,[v(d,{to:`/admin/groups/${a(c)}/edit`},{default:u(()=>[t("button",D,"🛠 "+s(a(o).t("managePersonas")),1)]),_:1},8,["to"]),l[0]||(l[0]=t("span",{class:"muted"},"Admin: full persona data + edit available here.",-1))])):V("",!0),(n(),r(_,null,y(["A","B","C"],m=>t("div",{key:m,style:{margin:"20px 0"}},[t("h4",null,s(P(m)),1),t("div",E,[(n(!0),r(_,null,y(C(m),e=>(n(),r("div",{key:e.id,class:"card pcard lift"},[t("div",M,[t("strong",null,s(e.name),1),t("span",{class:f(["badge",e.my_outcome])},s(g(e.my_outcome)),3)]),t("div",R,[(n(),r(_,null,y(5,h=>t("span",{key:h,class:f(["star",{on:h<=(e.difficulty||1)}])},"★",2)),64)),t("span",S,s(a(o).t("difficulty"))+" "+s(e.difficulty||1)+"/5",1)]),t("div",G,[x(s(e.profession)+" · "+s(e.age_group)+" · "+s(e.location),1),l[1]||(l[1]=t("br",null,null,-1)),t("span",{class:f(["badge",e.channel])},s(e.channel),3),t("span",H," · "+s(e.initiation_mode==="seller"?a(o).t("sellerInitiated"):a(o).t("customerInitiated")),1)]),t("div",J,s(e.product_context),1),a(b).isAdmin?(n(),w(d,{key:0,to:`/groups/${a(c)}/chat/${e.id}`,style:{"margin-top":"auto"}},{default:u(()=>[t("button",K,s(a(o).t("chat")),1)]),_:1},8,["to"])):(n(),r(_,{key:1},[e.my_outcome==="not_tried"?(n(),w(d,{key:0,to:`/groups/${a(c)}/chat/${e.id}`,style:{"margin-top":"auto"}},{default:u(()=>[t("button",O,s(a(o).t("chat")),1)]),_:1},8,["to"])):(n(),r("div",Q,"✓ "+s(a(o).t("trained"))+" ("+s(g(e.my_outcome))+")",1))],64))]))),128))])])),64))])}}},Z=$(U,[["__scopeId","data-v-f8bfbe2d"]]);export{Z as default}; +import{_ as $,k as N,c as r,l as v,m as u,a as t,t as s,u as a,i as o,f as b,e as V,F as _,p as y,h as z,q as I,s as L,r as k,o as n,j as x,z as f,A as w}from"./index-gmrXNPrQ.js";const T={class:"row",style:{"align-items":"center"}},j={style:{margin:"0"}},F={class:"muted",style:{"margin-left":"auto"}},q={key:0,class:"row",style:{margin:"12px 0",gap:"10px"}},D={class:"primary"},E={class:"grid"},M={class:"row",style:{"justify-content":"space-between"}},R={class:"diff"},S={class:"muted"},G={class:"muted"},H={class:"muted"},J={class:"muted",style:{"margin-top":"6px"}},K={class:"primary",style:{width:"100%"}},O={class:"primary",style:{width:"100%"}},Q={key:1,class:"muted",style:{"margin-top":"auto","font-size":"12px"}},U={__name:"Personas",setup(W){const c=z().params.gid,p=k([]),A=k(!0);async function B(){try{p.value=(await I.listPersonas(c)).personas}finally{A.value=!1}}function C(i){return p.value.filter(l=>l.tier===i)}function P(i){return o.t(i==="A"?"tierA":i==="B"?"tierB":"tierC")}function g(i){return i==="won"?o.t("won"):i==="lost"?o.t("lost"):o.t("notTried")}return N(B),(i,l)=>{const d=L("router-link");return n(),r("div",null,[v(d,{to:"/training",class:"btn-back"},{default:u(()=>[x("← "+s(a(o).t("training")),1)]),_:1}),t("div",T,[t("h2",j,s(a(o).t("personas")),1),t("span",F,s(a(o).t("selectPersona")),1)]),a(b).isAdmin?(n(),r("div",q,[v(d,{to:`/admin/groups/${a(c)}/edit`},{default:u(()=>[t("button",D,"🛠 "+s(a(o).t("managePersonas")),1)]),_:1},8,["to"]),l[0]||(l[0]=t("span",{class:"muted"},"Admin: full persona data + edit available here.",-1))])):V("",!0),(n(),r(_,null,y(["A","B","C"],m=>t("div",{key:m,style:{margin:"20px 0"}},[t("h4",null,s(P(m)),1),t("div",E,[(n(!0),r(_,null,y(C(m),e=>(n(),r("div",{key:e.id,class:"card pcard lift"},[t("div",M,[t("strong",null,s(e.name),1),t("span",{class:f(["badge",e.my_outcome])},s(g(e.my_outcome)),3)]),t("div",R,[(n(),r(_,null,y(5,h=>t("span",{key:h,class:f(["star",{on:h<=(e.difficulty||1)}])},"★",2)),64)),t("span",S,s(a(o).t("difficulty"))+" "+s(e.difficulty||1)+"/5",1)]),t("div",G,[x(s(e.profession)+" · "+s(e.age_group)+" · "+s(e.location),1),l[1]||(l[1]=t("br",null,null,-1)),t("span",{class:f(["badge",e.channel])},s(e.channel),3),t("span",H," · "+s(e.initiation_mode==="seller"?a(o).t("sellerInitiated"):a(o).t("customerInitiated")),1)]),t("div",J,s(e.product_context),1),a(b).isAdmin?(n(),w(d,{key:0,to:`/groups/${a(c)}/chat/${e.id}`,style:{"margin-top":"auto"}},{default:u(()=>[t("button",K,s(a(o).t("chat")),1)]),_:1},8,["to"])):(n(),r(_,{key:1},[e.my_outcome==="not_tried"?(n(),w(d,{key:0,to:`/groups/${a(c)}/chat/${e.id}`,style:{"margin-top":"auto"}},{default:u(()=>[t("button",O,s(a(o).t("chat")),1)]),_:1},8,["to"])):(n(),r("div",Q,"✓ "+s(a(o).t("trained"))+" ("+s(g(e.my_outcome))+")",1))],64))]))),128))])])),64))])}}},Z=$(U,[["__scopeId","data-v-f8bfbe2d"]]);export{Z as default}; diff --git a/frontend/dist/assets/Settings-BcL2Fs6R.js b/frontend/dist/assets/Settings-D5fpvNb-.js similarity index 96% rename from frontend/dist/assets/Settings-BcL2Fs6R.js rename to frontend/dist/assets/Settings-D5fpvNb-.js index f23f11f..e86ac58 100644 --- a/frontend/dist/assets/Settings-BcL2Fs6R.js +++ b/frontend/dist/assets/Settings-D5fpvNb-.js @@ -1 +1 @@ -import{_ as j,r as v,f as u,c as y,a as e,t as o,u as l,i as s,j as x,w as h,v as b,e as k,z as B,q as S,o as f}from"./index-CNkuf2ya.js";const z={class:"card"},D={style:{"margin-top":"0"}},E={class:"muted"},M=["value"],$={class:"row",style:{gap:"10px","margin-top":"16px"}},q=["disabled"],I={key:0,class:"spinner"},L={class:"card",style:{"margin-top":"16px"}},O={style:{"margin-top":"0"}},A={class:"row",style:{gap:"10px","margin-top":"16px"}},F=["disabled"],G={key:0,class:"spinner"},H={class:"card",style:{"margin-top":"16px"}},J={style:{"margin-top":"0"}},K={class:"row"},Q={key:0,class:"error",role:"alert"},R={key:1,class:"ok",role:"status"},W={__name:"Settings",setup(X){var V,C;const m=v(((V=u.user)==null?void 0:V.name)||""),c=v(((C=u.user)==null?void 0:C.email)||""),i=v(""),_=v(""),r=v(""),p=v(""),w=v(!1),g=v(!1);async function U(){var d,a;r.value="",p.value="",w.value=!0;try{const n={};if(m.value&&m.value!==((d=u.user)==null?void 0:d.name)&&(n.name=m.value),c.value&&c.value!==((a=u.user)==null?void 0:a.email)&&(n.email=c.value),Object.keys(n).length){const t=await S.updateProfile(n);u.user=t.user,p.value=s.t("saved")}}catch(n){r.value=n.message}finally{w.value=!1}}async function N(){var d,a,n;if(r.value="",p.value="",i.value.length<4){r.value=s.t("passwordTooShort");return}if(i.value!==_.value){r.value=s.t("passwordMismatch");return}g.value=!0;try{const t=((d=u.user)==null?void 0:d.username)||((a=u.user)==null?void 0:a.id)||"",T=await S.setup({username:t,email:c.value||((n=u.user)==null?void 0:n.email),password:i.value});u.user=T.user,i.value="",_.value="",p.value=s.t("saved")}catch(t){r.value=t.message}finally{g.value=!1}}function P(d){s.set(d)}return(d,a)=>{var n;return f(),y("div",null,[e("h2",null,"⚙️ "+o(l(s).t("settings")),1),e("div",z,[e("h3",D,"👤 "+o(l(s).t("profile")),1),e("label",null,[x(o(l(s).t("username"))+" ",1),e("span",E,"("+o(l(s).t("readonly"))+")",1)]),e("input",{value:((n=l(u).user)==null?void 0:n.username)||"",disabled:""},null,8,M),e("label",null,o(l(s).t("name")),1),h(e("input",{"onUpdate:modelValue":a[0]||(a[0]=t=>m.value=t),type:"text"},null,512),[[b,m.value]]),e("label",null,o(l(s).t("email")),1),h(e("input",{"onUpdate:modelValue":a[1]||(a[1]=t=>c.value=t),type:"email"},null,512),[[b,c.value]]),e("div",$,[e("button",{class:"primary",disabled:w.value,onClick:U},[w.value?(f(),y("span",I)):k("",!0),x(o(l(s).t("saveProfile")),1)],8,q)])]),e("div",L,[e("h3",O,"🔒 "+o(l(s).t("changePassword")),1),e("label",null,o(l(s).t("newPassword")),1),h(e("input",{"onUpdate:modelValue":a[2]||(a[2]=t=>i.value=t),type:"password",autocomplete:"new-password"},null,512),[[b,i.value]]),e("label",null,o(l(s).t("confirmPassword")),1),h(e("input",{"onUpdate:modelValue":a[3]||(a[3]=t=>_.value=t),type:"password",autocomplete:"new-password"},null,512),[[b,_.value]]),e("div",A,[e("button",{class:"primary",disabled:g.value||!i.value||i.value!==_.value,onClick:N},[g.value?(f(),y("span",G)):k("",!0),x(o(l(s).t("save")),1)],8,F)])]),e("div",H,[e("h3",J,"🌐 "+o(l(s).t("language")),1),e("div",K,[e("button",{class:B({active:l(s).locale==="th"}),onClick:a[4]||(a[4]=t=>P("th"))},"ไทย",2),e("button",{class:B({active:l(s).locale==="en"}),onClick:a[5]||(a[5]=t=>P("en"))},"English",2)])]),r.value?(f(),y("div",Q,o(r.value),1)):k("",!0),p.value?(f(),y("div",R,"✅ "+o(p.value),1)):k("",!0)])}}},Z=j(W,[["__scopeId","data-v-2dca72e5"]]);export{Z as default}; +import{_ as j,r as v,f as u,c as y,a as e,t as o,u as l,i as s,j as x,w as h,v as b,e as k,z as B,q as S,o as f}from"./index-gmrXNPrQ.js";const z={class:"card"},D={style:{"margin-top":"0"}},E={class:"muted"},M=["value"],$={class:"row",style:{gap:"10px","margin-top":"16px"}},q=["disabled"],I={key:0,class:"spinner"},L={class:"card",style:{"margin-top":"16px"}},O={style:{"margin-top":"0"}},A={class:"row",style:{gap:"10px","margin-top":"16px"}},F=["disabled"],G={key:0,class:"spinner"},H={class:"card",style:{"margin-top":"16px"}},J={style:{"margin-top":"0"}},K={class:"row"},Q={key:0,class:"error",role:"alert"},R={key:1,class:"ok",role:"status"},W={__name:"Settings",setup(X){var V,C;const m=v(((V=u.user)==null?void 0:V.name)||""),c=v(((C=u.user)==null?void 0:C.email)||""),i=v(""),_=v(""),r=v(""),p=v(""),w=v(!1),g=v(!1);async function U(){var d,a;r.value="",p.value="",w.value=!0;try{const n={};if(m.value&&m.value!==((d=u.user)==null?void 0:d.name)&&(n.name=m.value),c.value&&c.value!==((a=u.user)==null?void 0:a.email)&&(n.email=c.value),Object.keys(n).length){const t=await S.updateProfile(n);u.user=t.user,p.value=s.t("saved")}}catch(n){r.value=n.message}finally{w.value=!1}}async function N(){var d,a,n;if(r.value="",p.value="",i.value.length<4){r.value=s.t("passwordTooShort");return}if(i.value!==_.value){r.value=s.t("passwordMismatch");return}g.value=!0;try{const t=((d=u.user)==null?void 0:d.username)||((a=u.user)==null?void 0:a.id)||"",T=await S.setup({username:t,email:c.value||((n=u.user)==null?void 0:n.email),password:i.value});u.user=T.user,i.value="",_.value="",p.value=s.t("saved")}catch(t){r.value=t.message}finally{g.value=!1}}function P(d){s.set(d)}return(d,a)=>{var n;return f(),y("div",null,[e("h2",null,"⚙️ "+o(l(s).t("settings")),1),e("div",z,[e("h3",D,"👤 "+o(l(s).t("profile")),1),e("label",null,[x(o(l(s).t("username"))+" ",1),e("span",E,"("+o(l(s).t("readonly"))+")",1)]),e("input",{value:((n=l(u).user)==null?void 0:n.username)||"",disabled:""},null,8,M),e("label",null,o(l(s).t("name")),1),h(e("input",{"onUpdate:modelValue":a[0]||(a[0]=t=>m.value=t),type:"text"},null,512),[[b,m.value]]),e("label",null,o(l(s).t("email")),1),h(e("input",{"onUpdate:modelValue":a[1]||(a[1]=t=>c.value=t),type:"email"},null,512),[[b,c.value]]),e("div",$,[e("button",{class:"primary",disabled:w.value,onClick:U},[w.value?(f(),y("span",I)):k("",!0),x(o(l(s).t("saveProfile")),1)],8,q)])]),e("div",L,[e("h3",O,"🔒 "+o(l(s).t("changePassword")),1),e("label",null,o(l(s).t("newPassword")),1),h(e("input",{"onUpdate:modelValue":a[2]||(a[2]=t=>i.value=t),type:"password",autocomplete:"new-password"},null,512),[[b,i.value]]),e("label",null,o(l(s).t("confirmPassword")),1),h(e("input",{"onUpdate:modelValue":a[3]||(a[3]=t=>_.value=t),type:"password",autocomplete:"new-password"},null,512),[[b,_.value]]),e("div",A,[e("button",{class:"primary",disabled:g.value||!i.value||i.value!==_.value,onClick:N},[g.value?(f(),y("span",G)):k("",!0),x(o(l(s).t("save")),1)],8,F)])]),e("div",H,[e("h3",J,"🌐 "+o(l(s).t("language")),1),e("div",K,[e("button",{class:B({active:l(s).locale==="th"}),onClick:a[4]||(a[4]=t=>P("th"))},"ไทย",2),e("button",{class:B({active:l(s).locale==="en"}),onClick:a[5]||(a[5]=t=>P("en"))},"English",2)])]),r.value?(f(),y("div",Q,o(r.value),1)):k("",!0),p.value?(f(),y("div",R,"✅ "+o(p.value),1)):k("",!0)])}}},Z=j(W,[["__scopeId","data-v-2dca72e5"]]);export{Z as default}; diff --git a/frontend/dist/assets/Setup-DwlVEQN4.js b/frontend/dist/assets/Setup-DofFBOwX.js similarity index 96% rename from frontend/dist/assets/Setup-DwlVEQN4.js rename to frontend/dist/assets/Setup-DofFBOwX.js index 155c671..1d131f7 100644 --- a/frontend/dist/assets/Setup-DwlVEQN4.js +++ b/frontend/dist/assets/Setup-DofFBOwX.js @@ -1 +1 @@ -import{_ as x,c as v,a as e,t,u as s,i as a,j as S,f as _,w,v as f,b as y,e as V,r,g as K,o as m}from"./index-CNkuf2ya.js";const T={class:"setup-wrap"},B={class:"card setup-card"},N={class:"muted"},U={key:0,class:"error",role:"alert"},C=["disabled"],D={key:0,class:"spinner"},M={key:1},P={__name:"Setup",setup(j){const k=K(),i=r(""),l=r(""),p=r(""),o=r(""),d=r(!1);async function c(){if(o.value="",l.value.length<4){o.value=a.t("passwordTooShort");return}if(l.value!==p.value){o.value=a.t("passwordMismatch");return}d.value=!0;try{await _.finishSetup(i.value.trim(),l.value),k.push("/")}catch(h){o.value=h.message}finally{d.value=!1}}return(h,u)=>{var b,g;return m(),v("div",T,[e("div",B,[e("h1",null,"🔐 "+t(s(a).t("setupTitle")),1),e("p",N,[S(t(s(a).t("setupSubtitle"))+" ",1),e("strong",null,t(((b=s(_).user)==null?void 0:b.name)||((g=s(_).user)==null?void 0:g.username)),1)]),e("label",null,t(s(a).t("email")),1),w(e("input",{"onUpdate:modelValue":u[0]||(u[0]=n=>i.value=n),type:"email",autocomplete:"email",onKeyup:y(c,["enter"])},null,544),[[f,i.value]]),e("label",null,t(s(a).t("newPassword")),1),w(e("input",{"onUpdate:modelValue":u[1]||(u[1]=n=>l.value=n),type:"password",autocomplete:"new-password",onKeyup:y(c,["enter"])},null,544),[[f,l.value]]),e("label",null,t(s(a).t("confirmPassword")),1),w(e("input",{"onUpdate:modelValue":u[2]||(u[2]=n=>p.value=n),type:"password",autocomplete:"new-password",onKeyup:y(c,["enter"])},null,544),[[f,p.value]]),o.value?(m(),v("div",U,t(o.value),1)):V("",!0),e("button",{class:"primary",style:{width:"100%","margin-top":"16px"},disabled:d.value||!i.value||!l.value||l.value!==p.value,onClick:c},[d.value?(m(),v("span",D)):(m(),v("span",M,t(s(a).t("save")),1))],8,C)])])}}},I=x(P,[["__scopeId","data-v-f190e120"]]);export{I as default}; +import{_ as x,c as v,a as e,t,u as s,i as a,j as S,f as _,w,v as f,b as y,e as V,r,g as K,o as m}from"./index-gmrXNPrQ.js";const T={class:"setup-wrap"},B={class:"card setup-card"},N={class:"muted"},U={key:0,class:"error",role:"alert"},C=["disabled"],D={key:0,class:"spinner"},M={key:1},P={__name:"Setup",setup(j){const k=K(),i=r(""),l=r(""),p=r(""),o=r(""),d=r(!1);async function c(){if(o.value="",l.value.length<4){o.value=a.t("passwordTooShort");return}if(l.value!==p.value){o.value=a.t("passwordMismatch");return}d.value=!0;try{await _.finishSetup(i.value.trim(),l.value),k.push("/")}catch(h){o.value=h.message}finally{d.value=!1}}return(h,u)=>{var b,g;return m(),v("div",T,[e("div",B,[e("h1",null,"🔐 "+t(s(a).t("setupTitle")),1),e("p",N,[S(t(s(a).t("setupSubtitle"))+" ",1),e("strong",null,t(((b=s(_).user)==null?void 0:b.name)||((g=s(_).user)==null?void 0:g.username)),1)]),e("label",null,t(s(a).t("email")),1),w(e("input",{"onUpdate:modelValue":u[0]||(u[0]=n=>i.value=n),type:"email",autocomplete:"email",onKeyup:y(c,["enter"])},null,544),[[f,i.value]]),e("label",null,t(s(a).t("newPassword")),1),w(e("input",{"onUpdate:modelValue":u[1]||(u[1]=n=>l.value=n),type:"password",autocomplete:"new-password",onKeyup:y(c,["enter"])},null,544),[[f,l.value]]),e("label",null,t(s(a).t("confirmPassword")),1),w(e("input",{"onUpdate:modelValue":u[2]||(u[2]=n=>p.value=n),type:"password",autocomplete:"new-password",onKeyup:y(c,["enter"])},null,544),[[f,p.value]]),o.value?(m(),v("div",U,t(o.value),1)):V("",!0),e("button",{class:"primary",style:{width:"100%","margin-top":"16px"},disabled:d.value||!i.value||!l.value||l.value!==p.value,onClick:c},[d.value?(m(),v("span",D)):(m(),v("span",M,t(s(a).t("save")),1))],8,C)])])}}},I=x(P,[["__scopeId","data-v-f190e120"]]);export{I as default}; diff --git a/frontend/dist/assets/Training-DntZcGFn.js b/frontend/dist/assets/Training-CBrtrJhQ.js similarity index 97% rename from frontend/dist/assets/Training-DntZcGFn.js rename to frontend/dist/assets/Training-CBrtrJhQ.js index abd1ce1..64c5c9f 100644 --- a/frontend/dist/assets/Training-DntZcGFn.js +++ b/frontend/dist/assets/Training-CBrtrJhQ.js @@ -1 +1 @@ -import{_ as k,k as x,q as w,f as d,c as r,a as t,t as e,u as s,i as o,A as _,m,e as y,F as b,p as A,r as h,s as C,o as i,z as f}from"./index-CNkuf2ya.js";const B={class:"row",style:{"align-items":"center","margin-bottom":"16px"}},N={style:{margin:"0"}},P={style:{"margin-left":"auto"}},z={class:"primary"},T={class:"muted"},F={key:0,class:"card",style:{"min-height":"80px"}},L={key:1,class:"card empty-state"},S={key:0},V={key:1},$={class:"grid"},j={class:"card lift train-card"},q={class:"row",style:{"justify-content":"space-between"}},D={class:"muted",style:{margin:"6px 0 12px"}},E={class:"row",style:{gap:"8px"}},G={class:"muted"},I={class:"primary",style:{width:"100%","margin-top":"12px"}},M={__name:"Training",setup(H){const c=h([]),u=h(!0);function v(a){return a.sales_kit&&a.sales_kit.productName||a.input&&a.input.product||""}function g(a){return a.personas||a.persona_count||0}return x(async()=>{try{const a=(await w.listGroups()).groups||[];c.value=d.isAdmin?a:a.filter(l=>l.status==="ready")}finally{u.value=!1}}),(a,l)=>{const p=C("router-link");return i(),r("div",null,[t("div",B,[t("h2",N,"🎯 "+e(s(o).t("training")),1),t("div",P,[s(d).isAdmin?(i(),_(p,{key:0,to:"/admin/new-group"},{default:m(()=>[t("button",z,"+ "+e(s(o).t("addProduct")),1)]),_:1})):y("",!0)])]),t("p",T,e(s(o).t("trainingSubtitle")),1),u.value?(i(),r("div",F,[...l[0]||(l[0]=[t("div",{class:"skeleton",style:{height:"50px"}},null,-1)])])):c.value.length===0?(i(),r("div",L,[t("strong",null,e(s(o).t("noTraining")),1),s(d).isAdmin?(i(),r("span",S,'Click "'+e(s(o).t("addProduct"))+'" to create a persona group.',1)):(i(),r("span",V,"Ask an admin to create a persona group first."))])):y("",!0),t("div",$,[(i(!0),r(b,null,A(c.value,n=>(i(),_(p,{key:n.id,to:s(d).isAdmin?`/admin/groups/${n.id}/edit`:`/groups/${n.id}/personas`,style:{"text-decoration":"none"}},{default:m(()=>[t("div",j,[t("div",q,[t("strong",null,e(n.title),1),t("span",{class:f(["badge",n.status==="ready"?"ready":"draft"])},e(n.status),3)]),t("div",D,e(v(n)),1),t("div",E,[t("span",{class:f(["badge",n.channel||"line"])},e(n.channel||"line"),3),t("span",G,e(g(n))+" "+e(s(o).t("personas").toLowerCase()),1)]),t("button",I,e(s(d).isAdmin?n.status==="ready"?s(o).t("managePersonas"):s(o).t("analyze"):s(o).t("selectPersona")),1)])]),_:2},1032,["to"]))),128))])])}}},K=k(M,[["__scopeId","data-v-901c9d3d"]]);export{K as default}; +import{_ as k,k as x,q as w,f as d,c as r,a as t,t as e,u as s,i as o,A as _,m,e as y,F as b,p as A,r as h,s as C,o as i,z as f}from"./index-gmrXNPrQ.js";const B={class:"row",style:{"align-items":"center","margin-bottom":"16px"}},N={style:{margin:"0"}},P={style:{"margin-left":"auto"}},z={class:"primary"},T={class:"muted"},F={key:0,class:"card",style:{"min-height":"80px"}},L={key:1,class:"card empty-state"},S={key:0},V={key:1},$={class:"grid"},j={class:"card lift train-card"},q={class:"row",style:{"justify-content":"space-between"}},D={class:"muted",style:{margin:"6px 0 12px"}},E={class:"row",style:{gap:"8px"}},G={class:"muted"},I={class:"primary",style:{width:"100%","margin-top":"12px"}},M={__name:"Training",setup(H){const c=h([]),u=h(!0);function v(a){return a.sales_kit&&a.sales_kit.productName||a.input&&a.input.product||""}function g(a){return a.personas||a.persona_count||0}return x(async()=>{try{const a=(await w.listGroups()).groups||[];c.value=d.isAdmin?a:a.filter(l=>l.status==="ready")}finally{u.value=!1}}),(a,l)=>{const p=C("router-link");return i(),r("div",null,[t("div",B,[t("h2",N,"🎯 "+e(s(o).t("training")),1),t("div",P,[s(d).isAdmin?(i(),_(p,{key:0,to:"/admin/new-group"},{default:m(()=>[t("button",z,"+ "+e(s(o).t("addProduct")),1)]),_:1})):y("",!0)])]),t("p",T,e(s(o).t("trainingSubtitle")),1),u.value?(i(),r("div",F,[...l[0]||(l[0]=[t("div",{class:"skeleton",style:{height:"50px"}},null,-1)])])):c.value.length===0?(i(),r("div",L,[t("strong",null,e(s(o).t("noTraining")),1),s(d).isAdmin?(i(),r("span",S,'Click "'+e(s(o).t("addProduct"))+'" to create a persona group.',1)):(i(),r("span",V,"Ask an admin to create a persona group first."))])):y("",!0),t("div",$,[(i(!0),r(b,null,A(c.value,n=>(i(),_(p,{key:n.id,to:s(d).isAdmin?`/admin/groups/${n.id}/edit`:`/groups/${n.id}/personas`,style:{"text-decoration":"none"}},{default:m(()=>[t("div",j,[t("div",q,[t("strong",null,e(n.title),1),t("span",{class:f(["badge",n.status==="ready"?"ready":"draft"])},e(n.status),3)]),t("div",D,e(v(n)),1),t("div",E,[t("span",{class:f(["badge",n.channel||"line"])},e(n.channel||"line"),3),t("span",G,e(g(n))+" "+e(s(o).t("personas").toLowerCase()),1)]),t("button",I,e(s(d).isAdmin?n.status==="ready"?s(o).t("managePersonas"):s(o).t("analyze"):s(o).t("selectPersona")),1)])]),_:2},1032,["to"]))),128))])])}}},K=k(M,[["__scopeId","data-v-901c9d3d"]]);export{K as default}; diff --git a/frontend/dist/assets/index-CNkuf2ya.js b/frontend/dist/assets/index-gmrXNPrQ.js similarity index 91% rename from frontend/dist/assets/index-CNkuf2ya.js rename to frontend/dist/assets/index-gmrXNPrQ.js index 41ed8fe..16134b2 100644 --- a/frontend/dist/assets/index-CNkuf2ya.js +++ b/frontend/dist/assets/index-gmrXNPrQ.js @@ -1,4 +1,4 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Login-DFuS2Llc.js","assets/Login-D3svPLnW.css","assets/Setup-DwlVEQN4.js","assets/Setup-BdS_6JlN.css","assets/Analytics-hzMFeY95.js","assets/Analytics-DstNBgKK.css","assets/MyBoard-DoSeQn-O.js","assets/MyBoard-Ch6WeOlD.css","assets/Training-DntZcGFn.js","assets/Training-BcDA5IbA.css","assets/Personas-Ck-UhJ3k.js","assets/Personas-CuqA1oqu.css","assets/Chat-DPgZfhp2.js","assets/Chat-D5cDjkYb.css","assets/Settings-BcL2Fs6R.js","assets/Settings-y28ROmym.css","assets/GroupEdit-qmIH-KdK.js","assets/GroupEdit-BpqVXcH5.css"])))=>i.map(i=>d[i]); +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Login-71KwBI7P.js","assets/Login-D3svPLnW.css","assets/Setup-DofFBOwX.js","assets/Setup-BdS_6JlN.css","assets/Analytics-BothIrTb.js","assets/Analytics-ButgVyTK.css","assets/MyBoard-CjsbrOsq.js","assets/MyBoard-Ch6WeOlD.css","assets/Training-CBrtrJhQ.js","assets/Training-BcDA5IbA.css","assets/Personas-BGoC8X56.js","assets/Personas-CuqA1oqu.css","assets/Chat-CYFTB7sZ.js","assets/Chat-D5cDjkYb.css","assets/Settings-D5fpvNb-.js","assets/Settings-y28ROmym.css","assets/GroupEdit-DiRZ2lxy.js","assets/GroupEdit-BpqVXcH5.css"])))=>i.map(i=>d[i]); (function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))s(r);new MutationObserver(r=>{for(const i of r)if(i.type==="childList")for(const o of i.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&s(o)}).observe(document,{childList:!0,subtree:!0});function n(r){const i={};return r.integrity&&(i.integrity=r.integrity),r.referrerPolicy&&(i.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?i.credentials="include":r.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function s(r){if(r.ep)return;r.ep=!0;const i=n(r);fetch(r.href,i)}})();/** * @vue/shared v3.5.41 * (c) 2018-present Yuxi (Evan) You and Vue contributors @@ -24,4 +24,4 @@ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Login-DFuS2Llc. * vue-router v4.6.4 * (c) 2025 Eduardo San Martin Morote * @license MIT - */let Va=()=>location.protocol+"//"+location.host;function xo(e,t){const{pathname:n,search:s,hash:r}=t,i=e.indexOf("#");if(i>-1){let o=r.includes(e.slice(i))?e.slice(i).length:1,l=r.slice(o);return l[0]!=="/"&&(l="/"+l),Kr(l,"")}return Kr(n,e)+s+r}function Fa(e,t,n,s){let r=[],i=[],o=null;const l=({state:g})=>{const m=xo(e,location),I=n.value,R=t.value;let U=0;if(g){if(n.value=m,t.value=g,o&&o===I){o=null;return}U=R?g.position-R.position:0}else s(m);r.forEach(F=>{F(n.value,I,{delta:U,type:Ls.pop,direction:U?U>0?ys.forward:ys.back:ys.unknown})})};function c(){o=n.value}function f(g){r.push(g);const m=()=>{const I=r.indexOf(g);I>-1&&r.splice(I,1)};return i.push(m),m}function u(){if(document.visibilityState==="hidden"){const{history:g}=window;if(!g.state)return;g.replaceState(K({},g.state,{scroll:ns()}),"")}}function h(){for(const g of i)g();i=[],window.removeEventListener("popstate",l),window.removeEventListener("pagehide",u),document.removeEventListener("visibilitychange",u)}return window.addEventListener("popstate",l),window.addEventListener("pagehide",u),document.addEventListener("visibilitychange",u),{pauseListeners:c,listen:f,destroy:h}}function Jr(e,t,n,s=!1,r=!1){return{back:e,current:t,forward:n,replaced:s,position:window.history.length,scroll:r?ns():null}}function Ha(e){const{history:t,location:n}=window,s={value:xo(e,n)},r={value:t.state};r.value||i(s.value,{back:null,current:s.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function i(c,f,u){const h=e.indexOf("#"),g=h>-1?(n.host&&document.querySelector("base")?e:e.slice(h))+c:Va()+e+c;try{t[u?"replaceState":"pushState"](f,"",g),r.value=f}catch(m){console.error(m),n[u?"replace":"assign"](g)}}function o(c,f){i(c,K({},t.state,Jr(r.value.back,c,r.value.forward,!0),f,{position:r.value.position}),!0),s.value=c}function l(c,f){const u=K({},r.value,t.state,{forward:c,scroll:ns()});i(u.current,u,!0),i(c,K({},Jr(s.value,c,null),{position:u.position+1},f),!1),s.value=c}return{location:s,state:r,push:l,replace:o}}function Ua(e){e=Sa(e);const t=Ha(e),n=Fa(e,t.state,t.location,t.replace);function s(i,o=!0){o||n.pauseListeners(),history.go(i)}const r=K({location:"",base:e,go:s,createHref:wa.bind(null,e)},t,n);return Object.defineProperty(r,"location",{enumerable:!0,get:()=>t.location.value}),Object.defineProperty(r,"state",{enumerable:!0,get:()=>t.state.value}),r}let Tt=function(e){return e[e.Static=0]="Static",e[e.Param=1]="Param",e[e.Group=2]="Group",e}({});var oe=function(e){return e[e.Static=0]="Static",e[e.Param=1]="Param",e[e.ParamRegExp=2]="ParamRegExp",e[e.ParamRegExpEnd=3]="ParamRegExpEnd",e[e.EscapeNext=4]="EscapeNext",e}(oe||{});const Ba={type:Tt.Static,value:""},ja=/[a-zA-Z0-9_]/;function ka(e){if(!e)return[[]];if(e==="/")return[[Ba]];if(!e.startsWith("/"))throw new Error(`Invalid path "${e}"`);function t(m){throw new Error(`ERR (${n})/"${f}": ${m}`)}let n=oe.Static,s=n;const r=[];let i;function o(){i&&r.push(i),i=[]}let l=0,c,f="",u="";function h(){f&&(n===oe.Static?i.push({type:Tt.Static,value:f}):n===oe.Param||n===oe.ParamRegExp||n===oe.ParamRegExpEnd?(i.length>1&&(c==="*"||c==="+")&&t(`A repeatable param (${f}) must be alone in its segment. eg: '/:ids+.`),i.push({type:Tt.Param,value:f,regexp:u,repeatable:c==="*"||c==="+",optional:c==="*"||c==="?"})):t("Invalid state to consume buffer"),f="")}function g(){f+=c}for(;lt.length?t.length===1&&t[0]===me.Static+me.Segment?1:-1:0}function To(e,t){let n=0;const s=e.score,r=t.score;for(;n0&&t[t.length-1]<0}const qa={strict:!1,end:!0,sensitive:!1};function za(e,t,n){const s=Wa(ka(e.path),n),r=K(s,{record:e,parent:t,children:[],alias:[]});return t&&!r.record.aliasOf==!t.record.aliasOf&&t.children.push(r),r}function Ja(e,t){const n=[],s=new Map;t=Gr(qa,t);function r(h){return s.get(h)}function i(h,g,m){const I=!m,R=Zr(h);R.aliasOf=m&&m.record;const U=Gr(t,h),F=[R];if("alias"in h){const O=typeof h.alias=="string"?[h.alias]:h.alias;for(const Y of O)F.push(Zr(K({},R,{components:m?m.record.components:R.components,path:Y,aliasOf:m?m.record:R})))}let P,N;for(const O of F){const{path:Y}=O;if(g&&Y[0]!=="/"){const ie=g.record.path,ee=ie[ie.length-1]==="/"?"":"/";O.path=g.record.path+(Y&&ee+Y)}if(P=za(O,g,U),m?m.alias.push(P):(N=N||P,N!==P&&N.alias.push(P),I&&h.name&&!ei(P)&&o(h.name)),Po(P)&&c(P),R.children){const ie=R.children;for(let ee=0;ee{o(N)}:hn}function o(h){if(wo(h)){const g=s.get(h);g&&(s.delete(h),n.splice(n.indexOf(g),1),g.children.forEach(o),g.alias.forEach(o))}else{const g=n.indexOf(h);g>-1&&(n.splice(g,1),h.record.name&&s.delete(h.record.name),h.children.forEach(o),h.alias.forEach(o))}}function l(){return n}function c(h){const g=Xa(h,n);n.splice(g,0,h),h.record.name&&!ei(h)&&s.set(h.record.name,h)}function f(h,g){let m,I={},R,U;if("name"in h&&h.name){if(m=s.get(h.name),!m)throw zt(ne.MATCHER_NOT_FOUND,{location:h});U=m.record.name,I=K(Xr(g.params,m.keys.filter(N=>!N.optional).concat(m.parent?m.parent.keys.filter(N=>N.optional):[]).map(N=>N.name)),h.params&&Xr(h.params,m.keys.map(N=>N.name))),R=m.stringify(I)}else if(h.path!=null)R=h.path,m=n.find(N=>N.re.test(R)),m&&(I=m.parse(R),U=m.record.name);else{if(m=g.name?s.get(g.name):n.find(N=>N.re.test(g.path)),!m)throw zt(ne.MATCHER_NOT_FOUND,{location:h,currentLocation:g});U=m.record.name,I=K({},g.params,h.params),R=m.stringify(I)}const F=[];let P=m;for(;P;)F.unshift(P.record),P=P.parent;return{name:U,path:R,params:I,matched:F,meta:Qa(F)}}e.forEach(h=>i(h));function u(){n.length=0,s.clear()}return{addRoute:i,resolve:f,removeRoute:o,clearRoutes:u,getRoutes:l,getRecordMatcher:r}}function Xr(e,t){const n={};for(const s of t)s in e&&(n[s]=e[s]);return n}function Zr(e){const t={path:e.path,redirect:e.redirect,name:e.name,meta:e.meta||{},aliasOf:e.aliasOf,beforeEnter:e.beforeEnter,props:Ya(e),children:e.children||[],instances:{},leaveGuards:new Set,updateGuards:new Set,enterCallbacks:{},components:"components"in e?e.components||null:e.component&&{default:e.component}};return Object.defineProperty(t,"mods",{value:{}}),t}function Ya(e){const t={},n=e.props||!1;if("component"in e)t.default=n;else for(const s in e.components)t[s]=typeof n=="object"?n[s]:n;return t}function ei(e){for(;e;){if(e.record.aliasOf)return!0;e=e.parent}return!1}function Qa(e){return e.reduce((t,n)=>K(t,n.meta),{})}function Xa(e,t){let n=0,s=t.length;for(;n!==s;){const i=n+s>>1;To(e,t[i])<0?s=i:n=i+1}const r=Za(e);return r&&(s=t.lastIndexOf(r,s-1)),s}function Za(e){let t=e;for(;t=t.parent;)if(Po(t)&&To(e,t)===0)return t}function Po({record:e}){return!!(e.name||e.components&&Object.keys(e.components).length||e.redirect)}function ti(e){const t=Ne(ss),n=Ne(rr),s=Oe(()=>{const c=_e(e.to);return t.resolve(c)}),r=Oe(()=>{const{matched:c}=s.value,{length:f}=c,u=c[f-1],h=n.matched;if(!u||!h.length)return-1;const g=h.findIndex(qt.bind(null,u));if(g>-1)return g;const m=ni(c[f-2]);return f>1&&ni(u)===m&&h[h.length-1].path!==m?h.findIndex(qt.bind(null,c[f-2])):g}),i=Oe(()=>r.value>-1&&ru(n.params,s.value.params)),o=Oe(()=>r.value>-1&&r.value===n.matched.length-1&&Ao(n.params,s.value.params));function l(c={}){if(su(c)){const f=t[_e(e.replace)?"replace":"push"](_e(e.to)).catch(hn);return e.viewTransition&&typeof document<"u"&&"startViewTransition"in document&&document.startViewTransition(()=>f),f}return Promise.resolve()}return{route:s,href:Oe(()=>s.value.href),isActive:i,isExactActive:o,navigate:l}}function eu(e){return e.length===1?e[0]:e}const tu=Ui({name:"RouterLink",compatConfig:{MODE:3},props:{to:{type:[String,Object],required:!0},replace:Boolean,activeClass:String,exactActiveClass:String,custom:Boolean,ariaCurrentValue:{type:String,default:"page"},viewTransition:Boolean},useLink:ti,setup(e,{slots:t}){const n=Yt(ti(e)),{options:s}=Ne(ss),r=Oe(()=>({[si(e.activeClass,s.linkActiveClass,"router-link-active")]:n.isActive,[si(e.exactActiveClass,s.linkExactActiveClass,"router-link-exact-active")]:n.isExactActive}));return()=>{const i=t.default&&eu(t.default(n));return e.custom?i:ho("a",{"aria-current":n.isExactActive?e.ariaCurrentValue:null,href:n.href,onClick:n.navigate,class:r.value},i)}}}),nu=tu;function su(e){if(!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)&&!e.defaultPrevented&&!(e.button!==void 0&&e.button!==0)){if(e.currentTarget&&e.currentTarget.getAttribute){const t=e.currentTarget.getAttribute("target");if(/\b_blank\b/i.test(t))return}return e.preventDefault&&e.preventDefault(),!0}}function ru(e,t){for(const n in t){const s=t[n],r=e[n];if(typeof s=="string"){if(s!==r)return!1}else if(!Le(r)||r.length!==s.length||s.some((i,o)=>i.valueOf()!==r[o].valueOf()))return!1}return!0}function ni(e){return e?e.aliasOf?e.aliasOf.path:e.path:""}const si=(e,t,n)=>e??t??n,iu=Ui({name:"RouterView",inheritAttrs:!1,props:{name:{type:String,default:"default"},route:Object},compatConfig:{MODE:3},setup(e,{attrs:t,slots:n}){const s=Ne(Fs),r=Oe(()=>e.route||s.value),i=Ne(zr,0),o=Oe(()=>{let f=_e(i);const{matched:u}=r.value;let h;for(;(h=u[f])&&!h.components;)f++;return f}),l=Oe(()=>r.value.matched[o.value]);On(zr,Oe(()=>o.value+1)),On(Ma,l),On(Fs,r);const c=cl();return In(()=>[c.value,l.value,e.name],([f,u,h],[g,m,I])=>{u&&(u.instances[h]=f,m&&m!==u&&f&&f===g&&(u.leaveGuards.size||(u.leaveGuards=m.leaveGuards),u.updateGuards.size||(u.updateGuards=m.updateGuards))),f&&u&&(!m||!qt(u,m)||!g)&&(u.enterCallbacks[h]||[]).forEach(R=>R(f))},{flush:"post"}),()=>{const f=r.value,u=e.name,h=l.value,g=h&&h.components[u];if(!g)return ri(n.default,{Component:g,route:f});const m=h.props[u],I=m?m===!0?f.params:typeof m=="function"?m(f):m:null,U=ho(g,K({},I,t,{onVnodeUnmounted:F=>{F.component.isUnmounted&&(h.instances[u]=null)},ref:c}));return ri(n.default,{Component:U,route:f})||U}}});function ri(e,t){if(!e)return null;const n=e(t);return n.length===1?n[0]:n}const ou=iu;function lu(e){const t=Ja(e.routes,e),n=e.parseQuery||Na,s=e.stringifyQuery||qr,r=e.history,i=nn(),o=nn(),l=nn(),c=al(pt);let f=pt;Ht&&e.scrollBehavior&&"scrollRestoration"in history&&(history.scrollRestoration="manual");const u=ms.bind(null,v=>""+v),h=ms.bind(null,ga),g=ms.bind(null,bn);function m(v,C){let x,D;return wo(v)?(x=t.getRecordMatcher(v),D=C):D=v,t.addRoute(D,x)}function I(v){const C=t.getRecordMatcher(v);C&&t.removeRoute(C)}function R(){return t.getRoutes().map(v=>v.record)}function U(v){return!!t.getRecordMatcher(v)}function F(v,C){if(C=K({},C||c.value),typeof v=="string"){const p=_s(n,v,C.path),y=t.resolve({path:p.path},C),b=r.createHref(p.fullPath);return K(p,y,{params:g(y.params),hash:bn(p.hash),redirectedFrom:void 0,href:b})}let x;if(v.path!=null)x=K({},v,{path:_s(n,v.path,C.path).path});else{const p=K({},v.params);for(const y in p)p[y]==null&&delete p[y];x=K({},v,{params:h(p)}),C.params=h(C.params)}const D=t.resolve(x,C),j=v.hash||"";D.params=u(g(D.params));const a=ya(s,K({},v,{hash:da(j),path:D.path})),d=r.createHref(a);return K({fullPath:a,hash:j,query:s===qr?Da(v.query):v.query||{}},D,{redirectedFrom:void 0,href:d})}function P(v){return typeof v=="string"?_s(n,v,c.value.path):K({},v)}function N(v,C){if(f!==v)return zt(ne.NAVIGATION_CANCELLED,{from:C,to:v})}function O(v){return ee(v)}function Y(v){return O(K(P(v),{replace:!0}))}function ie(v,C){const x=v.matched[v.matched.length-1];if(x&&x.redirect){const{redirect:D}=x;let j=typeof D=="function"?D(v,C):D;return typeof j=="string"&&(j=j.includes("?")||j.includes("#")?j=P(j):{path:j},j.params={}),K({query:v.query,hash:v.hash,params:j.path!=null?{}:v.params},j)}}function ee(v,C){const x=f=F(v),D=c.value,j=v.state,a=v.force,d=v.replace===!0,p=ie(x,D);if(p)return ee(K(P(p),{state:typeof p=="object"?K({},j,p.state):j,force:a,replace:d}),C||x);const y=x;y.redirectedFrom=C;let b;return!a&&va(s,D,x)&&(b=zt(ne.NAVIGATION_DUPLICATED,{to:y,from:D}),Ue(D,D,!0,!1)),(b?Promise.resolve(b):Fe(y,D)).catch(_=>Xe(_)?Xe(_,ne.NAVIGATION_GUARD_REDIRECT)?_:ht(_):G(_,y,D)).then(_=>{if(_){if(Xe(_,ne.NAVIGATION_GUARD_REDIRECT))return ee(K({replace:d},P(_.to),{state:typeof _.to=="object"?K({},j,_.to.state):j,force:a}),C||y)}else _=bt(y,D,!0,d,j);return dt(y,D,_),_})}function Ve(v,C){const x=N(v,C);return x?Promise.reject(x):Promise.resolve()}function ft(v){const C=Dt.values().next().value;return C&&typeof C.runWithContext=="function"?C.runWithContext(v):v()}function Fe(v,C){let x;const[D,j,a]=La(v,C);x=vs(D.reverse(),"beforeRouteLeave",v,C);for(const p of D)p.leaveGuards.forEach(y=>{x.push(mt(y,v,C))});const d=Ve.bind(null,v,C);return x.push(d),xe(x).then(()=>{x=[];for(const p of i.list())x.push(mt(p,v,C));return x.push(d),xe(x)}).then(()=>{x=vs(j,"beforeRouteUpdate",v,C);for(const p of j)p.updateGuards.forEach(y=>{x.push(mt(y,v,C))});return x.push(d),xe(x)}).then(()=>{x=[];for(const p of a)if(p.beforeEnter)if(Le(p.beforeEnter))for(const y of p.beforeEnter)x.push(mt(y,v,C));else x.push(mt(p.beforeEnter,v,C));return x.push(d),xe(x)}).then(()=>(v.matched.forEach(p=>p.enterCallbacks={}),x=vs(a,"beforeRouteEnter",v,C,ft),x.push(d),xe(x))).then(()=>{x=[];for(const p of o.list())x.push(mt(p,v,C));return x.push(d),xe(x)}).catch(p=>Xe(p,ne.NAVIGATION_CANCELLED)?p:Promise.reject(p))}function dt(v,C,x){l.list().forEach(D=>ft(()=>D(v,C,x)))}function bt(v,C,x,D,j){const a=N(v,C);if(a)return a;const d=C===pt,p=Ht?history.state:{};x&&(D||d?r.replace(v.fullPath,K({scroll:d&&p&&p.scroll},j)):r.push(v.fullPath,j)),c.value=v,Ue(v,C,x,d),ht()}let He;function Qt(){He||(He=r.listen((v,C,x)=>{if(!Et.listening)return;const D=F(v),j=ie(D,Et.currentRoute.value);if(j){ee(K(j,{replace:!0,force:!0}),D).catch(hn);return}f=D;const a=c.value;Ht&&Ta($r(a.fullPath,x.delta),ns()),Fe(D,a).catch(d=>Xe(d,ne.NAVIGATION_ABORTED|ne.NAVIGATION_CANCELLED)?d:Xe(d,ne.NAVIGATION_GUARD_REDIRECT)?(ee(K(P(d.to),{force:!0}),D).then(p=>{Xe(p,ne.NAVIGATION_ABORTED|ne.NAVIGATION_DUPLICATED)&&!x.delta&&x.type===Ls.pop&&r.go(-1,!1)}).catch(hn),Promise.reject()):(x.delta&&r.go(-x.delta,!1),G(d,D,a))).then(d=>{d=d||bt(D,a,!1),d&&(x.delta&&!Xe(d,ne.NAVIGATION_CANCELLED)?r.go(-x.delta,!1):x.type===Ls.pop&&Xe(d,ne.NAVIGATION_ABORTED|ne.NAVIGATION_DUPLICATED)&&r.go(-1,!1)),dt(D,a,d)}).catch(hn)}))}let It=nn(),le=nn(),z;function G(v,C,x){ht(v);const D=le.list();return D.length?D.forEach(j=>j(v,C,x)):console.error(v),Promise.reject(v)}function Ye(){return z&&c.value!==pt?Promise.resolve():new Promise((v,C)=>{It.add([v,C])})}function ht(v){return z||(z=!v,Qt(),It.list().forEach(([C,x])=>v?x(v):C()),It.reset()),v}function Ue(v,C,x,D){const{scrollBehavior:j}=e;if(!Ht||!j)return Promise.resolve();const a=!x&&Pa($r(v.fullPath,0))||(D||!x)&&history.state&&history.state.scroll||null;return Qs().then(()=>j(v,C,a)).then(d=>d&&xa(d)).catch(d=>G(d,v,C))}const be=v=>r.go(v);let Nt;const Dt=new Set,Et={currentRoute:c,listening:!0,addRoute:m,removeRoute:I,clearRoutes:t.clearRoutes,hasRoute:U,getRoutes:R,resolve:F,options:e,push:O,replace:Y,go:be,back:()=>be(-1),forward:()=>be(1),beforeEach:i.add,beforeResolve:o.add,afterEach:l.add,onError:le.add,isReady:Ye,install(v){v.component("RouterLink",nu),v.component("RouterView",ou),v.config.globalProperties.$router=Et,Object.defineProperty(v.config.globalProperties,"$route",{enumerable:!0,get:()=>_e(c)}),Ht&&!Nt&&c.value===pt&&(Nt=!0,O(r.location).catch(D=>{}));const C={};for(const D in pt)Object.defineProperty(C,D,{get:()=>c.value[D],enumerable:!0});v.provide(ss,Et),v.provide(rr,Pi(C)),v.provide(Fs,c);const x=v.unmount;Dt.add(v),v.unmount=function(){Dt.delete(v),Dt.size<1&&(f=pt,He&&He(),He=null,c.value=pt,Nt=!1,z=!1),x()}}};function xe(v){return v.reduce((C,x)=>C.then(()=>ft(x)),Promise.resolve())}return Et}function cu(){return Ne(ss)}function Ru(e){return Ne(rr)}const Hs="st_token";function Co(){return localStorage.getItem(Hs)}function bs(e){e?localStorage.setItem(Hs,e):localStorage.removeItem(Hs)}async function te(e,t,n,s=!1){const r={},i=Co();i&&(r.Authorization=`Bearer ${i}`);let o=n;!s&&n!==void 0&&n!==null&&(r["Content-Type"]="application/json",o=JSON.stringify(n));const l=await fetch(t,{method:e,headers:r,body:o});let c=null;try{c=await l.json()}catch{}if(!l.ok){const f=c&&(c.error||c.message)||`HTTP ${l.status}`;throw new Error(f)}return c}const Es={login:(e,t)=>te("POST","/api/auth/login",{username:e,password:t}),me:()=>te("GET","/api/auth/me"),setup:e=>te("POST","/api/auth/setup",e),updateProfile:e=>te("PATCH","/api/auth/profile",e),adminCreateUser:e=>te("POST","/api/admin/users",e),adminListUsers:()=>te("GET","/api/admin/users"),adminUpdateUser:(e,t)=>te("PUT",`/api/admin/users/${e}`,t),createGroup:e=>te("POST","/api/groups",e,!0),listGroups:()=>te("GET","/api/groups"),getGroup:e=>te("GET",`/api/groups/${e}`),analyzeGroup:e=>te("POST",`/api/groups/${e}/analyze`),listPersonas:e=>te("GET",`/api/groups/${e}/personas`),getPersona:(e,t)=>te("GET",`/api/groups/${e}/personas/${t}`),updatePersona:(e,t,n)=>te("PUT",`/api/groups/${e}/personas/${t}`,n),chatStart:(e,t)=>te("POST",`/api/chat/${e}/personas/${t}/chat/start`),chatSend:(e,t,n)=>te("POST",`/api/chat/${e}/personas/${t}/chat/send`,{text:n}),chatFinish:(e,t)=>te("POST",`/api/chat/${e}/personas/${t}/chat/finish`),mySessions:()=>te("GET","/api/chat/sessions"),myBoard:()=>te("GET","/api/me/board"),weakAreas:()=>te("GET","/api/me/weak-areas"),myPersonas:()=>te("GET","/api/me/personas"),generatePersona:e=>te("POST","/api/me/personas/generate",e),analytics:(e={})=>{const t=new URLSearchParams;e.from&&t.set("from",e.from),e.to&&t.set("to",e.to);const n=t.toString();return te("GET",`/api/analytics${n?`?${n}`:""}`)}},Pe=Yt({user:null,token:Co(),mustSetup:!1,get role(){return this.user?this.user.role:null},get isAdmin(){return this.role==="admin"||this.role==="super_admin"},async load(){var e;if(!this.token)return null;try{const t=await Es.me();return this.user=t.user,this.mustSetup=!!((e=t.user)!=null&&e.must_setup),this.user}catch{return this.user=null,this.mustSetup=!1,bs(null),null}},async login(e,t){const n=await Es.login(e,t);return this.token=n.token,bs(n.token),this.user=n.user,this.mustSetup=!!n.must_setup,n.user},async finishSetup(e,t){const n=await Es.setup({username:this.user.username||this.user.id,email:e,password:t});return this.user=n.user,this.mustSetup=!1,n.user},logout(){this.user=null,this.token=null,this.mustSetup=!1,bs(null)}}),Ss={en:{app:"Sales Trainer",login:"Login",logout:"Logout",username:"Username",email:"Email",password:"Password",newPassword:"New password",confirmPassword:"Confirm password",save:"Save",passwordTooShort:"Password must be at least 4 characters",passwordMismatch:"Passwords do not match",setupTitle:"Set up your account",setupSubtitle:"First login for ",loginError:"Invalid credentials",dashboard:"Dashboard",training:"Training",myDashboard:"My dashboard",adminOverview:"Admin overview",settings:"Settings",account:"Account",profile:"Profile",readonly:"read-only",name:"Display name",saveProfile:"Save profile",changePassword:"Change password",optional:"optional",saved:"Saved",total:"Total",dateRange:"Date range",apply:"Apply",clear:"Clear",hardestPersonas:"Hardest personas",closeRate:"Close rate",managePersonas:"Manage personas",difficulty:"Difficulty",trained:"Trained",addProduct:"Add product",trainingSubtitle:"Pick a product group, then choose a persona to practice closing the sale.",noTraining:"No training groups available",groups:"Persona Groups",myTraining:"My Training",adminTools:"Admin Tools",users:"Users",analytics:"Analytics",groupBuilder:"Group Builder",create:"Create",analyze:"Analyze",manual:"Manual",edit:"Edit",product:"Product",segment:"Initial customer segment (optional)",description:"Additional description / scenario (optional)",channel:"Channel",facebook:"Facebook",line:"LINE",language:"Language",thai:"Thai",english:"English",personas:"Personas",tierA:"Tier A — Ready to buy",tierB:"Tier B — Unsure",tierC:"Tier C — Not interested but has pain",selectPersona:"Select a persona to practice",chat:"Chat",start:"Start",send:"Send",finish:"Finish & get result",debrief:"Result & Coaching",won:"Won",lost:"Lost",notTried:"Not tried",score:"Score",pain:"Pain",why:"Reason",reveal:"Revealed persona details",generatePersona:"Generate my persona",weakAreas:"My weak areas",mySessions:"My sessions",openSaleTask:"The customer did NOT message first. You must open the sale.",sellerInitiated:"You must open the sale (outbound)",customerInitiated:"The customer will message you first"},th:{app:"ตัวฝึกขาย",login:"เข้าสู่ระบบ",logout:"ออกจากระบบ",username:"ชื่อผู้ใช้",email:"อีเมล",password:"รหัสผ่าน",newPassword:"รหัสผ่านใหม่",confirmPassword:"ยืนยันรหัสผ่าน",save:"บันทึก",passwordTooShort:"รหัสผ่านต้องอย่างน้อย 4 ตัวอักษร",passwordMismatch:"รหัสผ่านไม่ตรงกัน",setupTitle:"ตั้งค่าบัญชีของคุณ",setupSubtitle:"เข้าสู่ระบบครั้งแรกสำหรับ ",loginError:"ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง",dashboard:"หน้าหลัก",training:"การฝึก",myDashboard:"แดชบอร์ดของฉัน",adminOverview:"ภาพรวม Admin",settings:"การตั้งค่า",account:"บัญชี",profile:"โปรไฟล์",readonly:"อ่านอย่างเดียว",name:"ชื่อที่แสดง",saveProfile:"บันทึกโปรไฟล์",changePassword:"เปลี่ยนรหัสผ่าน",optional:"ไม่บังคับ",saved:"บันทึกแล้ว",total:"ทั้งหมด",dateRange:"ช่วงวันที่",apply:"กรอง",clear:"ล้าง",hardestPersonas:"Persona ที่ยากสุด",closeRate:"อัตราปิดการขาย",managePersonas:"จัดการ Persona",difficulty:"ความยาก",trained:"ฝึกแล้ว",addProduct:"เพิ่มสินค้า",trainingSubtitle:"เลือกกลุ่มสินค้า แล้วเลือก persona เพื่อฝึกปิดการขาย",noTraining:"ยังไม่มีกลุ่มฝึก",groups:"กลุ่มลูกค้า (Persona)",myTraining:"การฝึกของฉัน",adminTools:"เครื่องมือ Admin",users:"ผู้ใช้",analytics:"สถิติ",groupBuilder:"สร้างกลุ่มลูกค้า",create:"สร้าง",analyze:"วิเคราะห์",manual:"กำหนดเอง",edit:"แก้ไข",product:"สินค้า/บริการ",segment:"กลุ่มลูกค้าเบื้องต้น (ไม่บังคับ)",description:"คำอธิบาย/สถานการณ์เพิ่มเติม (ไม่บังคับ)",channel:"ช่องทาง",facebook:"Facebook",line:"LINE",language:"ภาษา",thai:"ไทย",english:"อังกฤษ",personas:"Persona",tierA:"ระดับ A — ตั้งใจซื้อ",tierB:"ระดับ B — ยังไม่แน่ใจ",tierC:"ระดับ C — ไม่สนใจแต่มี pain",selectPersona:"เลือก persona เพื่อฝึก",chat:"แชท",start:"เริ่ม",send:"ส่ง",finish:"สรุปผล",debrief:"ผลลัพธ์และคำแนะนำ",won:"ขายได้",lost:"ขายไม่ได้",notTried:"ยังไม่ได้ฝึก",score:"คะแนน",pain:"Pain",why:"เหตุผล",reveal:"ข้อมูล persona ที่ถูกซ่อนไว้",generatePersona:"สร้าง persona ของฉัน",weakAreas:"จุดที่ฉันแพ้บ่อย",mySessions:"การฝึกของฉัน",openSaleTask:"ลูกค้ายังไม่ได้ทักมา คุณต้องเป็นฝ่ายเปิดการขายเอง",sellerInitiated:"คุณต้องเปิดการขาย (เชิงรุก)",customerInitiated:"ลูกค้าจะทักมาเองก่อน"}},Ze=Yt({locale:localStorage.getItem("locale")||"th",t(e){return Ss[this.locale]&&Ss[this.locale][e]||Ss.en[e]||e},set(e){this.locale=e,localStorage.setItem("locale",e)}}),au=(e,t)=>{const n=e.__vccOpts||e;for(const[s,r]of t)n[s]=r;return n},uu={class:"app"},fu={key:0,class:"topnav"},du={class:"tabs"},hu={class:"nav-right"},pu={class:"main"},gu={__name:"App",setup(e){const t=cu();function n(){Ze.set(Ze.locale==="th"?"en":"th")}function s(){Pe.logout(),t.push("/login")}return ki(()=>{Pe.token&&!Pe.user&&Pe.load()}),(r,i)=>{const o=gr("router-link"),l=gr("router-view");return rn(),Rr("div",uu,[_e(Pe).user?(rn(),Rr("nav",fu,[ue(o,{to:"/",class:"brand"},{default:Vt(()=>[Ft("🎯 "+wt(_e(Ze).t("app")),1)]),_:1}),xt("div",du,[_e(Pe).isAdmin?(rn(),Ns(o,{key:0,to:"/",class:jt(["tab",{active:r.$route.path==="/"}])},{default:Vt(()=>[Ft(wt(_e(Ze).t("adminOverview")),1)]),_:1},8,["class"])):xr("",!0),ue(o,{to:"/my/board",class:jt(["tab",{active:r.$route.path==="/my/board"}])},{default:Vt(()=>[Ft(wt(_e(Ze).t("myDashboard")),1)]),_:1},8,["class"]),ue(o,{to:"/training",class:jt(["tab",{active:r.$route.path==="/training"}])},{default:Vt(()=>[Ft(wt(_e(Ze).t("training")),1)]),_:1},8,["class"])]),xt("div",hu,[xt("button",{onClick:n,class:"lang"},wt(_e(Ze).locale==="th"?"EN":"TH"),1),ue(o,{to:"/settings",class:"icon-btn",title:"Settings"},{default:Vt(()=>[...i[0]||(i[0]=[Ft("⚙️",-1)])]),_:1}),xt("button",{onClick:s,class:"logout-btn"},"⏻ "+wt(_e(Ze).t("logout")),1)])])):xr("",!0),xt("main",pu,[(rn(),Ns(l,{key:_e(Ze).locale}))])])}}},mu=au(gu,[["__scopeId","data-v-836c19dc"]]),_u="modulepreload",yu=function(e){return"/"+e},ii={},Te=function(t,n,s){let r=Promise.resolve();if(n&&n.length>0){document.getElementsByTagName("link");const o=document.querySelector("meta[property=csp-nonce]"),l=(o==null?void 0:o.nonce)||(o==null?void 0:o.getAttribute("nonce"));r=Promise.allSettled(n.map(c=>{if(c=yu(c),c in ii)return;ii[c]=!0;const f=c.endsWith(".css"),u=f?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${c}"]${u}`))return;const h=document.createElement("link");if(h.rel=f?"stylesheet":_u,f||(h.as="script"),h.crossOrigin="",h.href=c,l&&h.setAttribute("nonce",l),document.head.appendChild(h),f)return new Promise((g,m)=>{h.addEventListener("load",g),h.addEventListener("error",()=>m(new Error(`Unable to preload CSS for ${c}`)))})}))}function i(o){const l=new Event("vite:preloadError",{cancelable:!0});if(l.payload=o,window.dispatchEvent(l),!l.defaultPrevented)throw o}return r.then(o=>{for(const l of o||[])l.status==="rejected"&&i(l.reason);return t().catch(i)})},vu=[{path:"/login",component:()=>Te(()=>import("./Login-DFuS2Llc.js"),__vite__mapDeps([0,1])),meta:{public:!0}},{path:"/setup",component:()=>Te(()=>import("./Setup-DwlVEQN4.js"),__vite__mapDeps([2,3]))},{path:"/",component:()=>Te(()=>import("./Analytics-hzMFeY95.js"),__vite__mapDeps([4,5])),meta:{admin:!0}},{path:"/my/board",component:()=>Te(()=>import("./MyBoard-DoSeQn-O.js"),__vite__mapDeps([6,7]))},{path:"/training",component:()=>Te(()=>import("./Training-DntZcGFn.js"),__vite__mapDeps([8,9]))},{path:"/groups/:gid/personas",component:()=>Te(()=>import("./Personas-Ck-UhJ3k.js"),__vite__mapDeps([10,11]))},{path:"/groups/:gid/chat/:pid",component:()=>Te(()=>import("./Chat-DPgZfhp2.js"),__vite__mapDeps([12,13]))},{path:"/settings",component:()=>Te(()=>import("./Settings-BcL2Fs6R.js"),__vite__mapDeps([14,15]))},{path:"/admin/new-group",component:()=>Te(()=>import("./GroupBuilder-CRBEizer.js"),[]),meta:{admin:!0}},{path:"/admin/groups/:gid/edit",component:()=>Te(()=>import("./GroupEdit-qmIH-KdK.js"),__vite__mapDeps([16,17])),meta:{admin:!0}},{path:"/admin/users",component:()=>Te(()=>import("./AdminUsers-C8wHHBeY.js"),[]),meta:{admin:!0}},{path:"/admin/analytics",component:()=>Te(()=>import("./Analytics-hzMFeY95.js"),__vite__mapDeps([4,5])),meta:{admin:!0}}],Oo=lu({history:Ua(),routes:vu});Oo.beforeEach(async e=>e.meta.public?!0:(Pe.user||await Pe.load(),Pe.user?Pe.mustSetup&&e.path!=="/setup"?{path:"/setup"}:e.path==="/"&&!Pe.isAdmin?{path:"/my/board"}:e.meta.admin&&!Pe.isAdmin?{path:"/my/board"}:!0:{path:"/login",query:{redirect:e.fullPath}}));Zc(mu).use(Oo).mount("#app");export{Ns as A,Qs as B,zc as C,tt as F,au as _,xt as a,wu as b,Rr as c,Au as d,xr as e,Pe as f,cu as g,Ru as h,Ze as i,Ft as j,ki as k,ue as l,Vt as m,ks as n,rn as o,Eu as p,Es as q,cl as r,gr as s,wt as t,_e as u,Ur as v,bu as w,Su as x,Oe as y,jt as z}; + */let Va=()=>location.protocol+"//"+location.host;function xo(e,t){const{pathname:n,search:s,hash:r}=t,i=e.indexOf("#");if(i>-1){let o=r.includes(e.slice(i))?e.slice(i).length:1,l=r.slice(o);return l[0]!=="/"&&(l="/"+l),Kr(l,"")}return Kr(n,e)+s+r}function Fa(e,t,n,s){let r=[],i=[],o=null;const l=({state:g})=>{const m=xo(e,location),I=n.value,R=t.value;let U=0;if(g){if(n.value=m,t.value=g,o&&o===I){o=null;return}U=R?g.position-R.position:0}else s(m);r.forEach(F=>{F(n.value,I,{delta:U,type:Ls.pop,direction:U?U>0?ys.forward:ys.back:ys.unknown})})};function c(){o=n.value}function f(g){r.push(g);const m=()=>{const I=r.indexOf(g);I>-1&&r.splice(I,1)};return i.push(m),m}function u(){if(document.visibilityState==="hidden"){const{history:g}=window;if(!g.state)return;g.replaceState(K({},g.state,{scroll:ns()}),"")}}function h(){for(const g of i)g();i=[],window.removeEventListener("popstate",l),window.removeEventListener("pagehide",u),document.removeEventListener("visibilitychange",u)}return window.addEventListener("popstate",l),window.addEventListener("pagehide",u),document.addEventListener("visibilitychange",u),{pauseListeners:c,listen:f,destroy:h}}function Jr(e,t,n,s=!1,r=!1){return{back:e,current:t,forward:n,replaced:s,position:window.history.length,scroll:r?ns():null}}function Ha(e){const{history:t,location:n}=window,s={value:xo(e,n)},r={value:t.state};r.value||i(s.value,{back:null,current:s.value,forward:null,position:t.length-1,replaced:!0,scroll:null},!0);function i(c,f,u){const h=e.indexOf("#"),g=h>-1?(n.host&&document.querySelector("base")?e:e.slice(h))+c:Va()+e+c;try{t[u?"replaceState":"pushState"](f,"",g),r.value=f}catch(m){console.error(m),n[u?"replace":"assign"](g)}}function o(c,f){i(c,K({},t.state,Jr(r.value.back,c,r.value.forward,!0),f,{position:r.value.position}),!0),s.value=c}function l(c,f){const u=K({},r.value,t.state,{forward:c,scroll:ns()});i(u.current,u,!0),i(c,K({},Jr(s.value,c,null),{position:u.position+1},f),!1),s.value=c}return{location:s,state:r,push:l,replace:o}}function Ua(e){e=Sa(e);const t=Ha(e),n=Fa(e,t.state,t.location,t.replace);function s(i,o=!0){o||n.pauseListeners(),history.go(i)}const r=K({location:"",base:e,go:s,createHref:wa.bind(null,e)},t,n);return Object.defineProperty(r,"location",{enumerable:!0,get:()=>t.location.value}),Object.defineProperty(r,"state",{enumerable:!0,get:()=>t.state.value}),r}let Tt=function(e){return e[e.Static=0]="Static",e[e.Param=1]="Param",e[e.Group=2]="Group",e}({});var oe=function(e){return e[e.Static=0]="Static",e[e.Param=1]="Param",e[e.ParamRegExp=2]="ParamRegExp",e[e.ParamRegExpEnd=3]="ParamRegExpEnd",e[e.EscapeNext=4]="EscapeNext",e}(oe||{});const Ba={type:Tt.Static,value:""},ja=/[a-zA-Z0-9_]/;function ka(e){if(!e)return[[]];if(e==="/")return[[Ba]];if(!e.startsWith("/"))throw new Error(`Invalid path "${e}"`);function t(m){throw new Error(`ERR (${n})/"${f}": ${m}`)}let n=oe.Static,s=n;const r=[];let i;function o(){i&&r.push(i),i=[]}let l=0,c,f="",u="";function h(){f&&(n===oe.Static?i.push({type:Tt.Static,value:f}):n===oe.Param||n===oe.ParamRegExp||n===oe.ParamRegExpEnd?(i.length>1&&(c==="*"||c==="+")&&t(`A repeatable param (${f}) must be alone in its segment. eg: '/:ids+.`),i.push({type:Tt.Param,value:f,regexp:u,repeatable:c==="*"||c==="+",optional:c==="*"||c==="?"})):t("Invalid state to consume buffer"),f="")}function g(){f+=c}for(;lt.length?t.length===1&&t[0]===me.Static+me.Segment?1:-1:0}function To(e,t){let n=0;const s=e.score,r=t.score;for(;n0&&t[t.length-1]<0}const qa={strict:!1,end:!0,sensitive:!1};function za(e,t,n){const s=Wa(ka(e.path),n),r=K(s,{record:e,parent:t,children:[],alias:[]});return t&&!r.record.aliasOf==!t.record.aliasOf&&t.children.push(r),r}function Ja(e,t){const n=[],s=new Map;t=Gr(qa,t);function r(h){return s.get(h)}function i(h,g,m){const I=!m,R=Zr(h);R.aliasOf=m&&m.record;const U=Gr(t,h),F=[R];if("alias"in h){const O=typeof h.alias=="string"?[h.alias]:h.alias;for(const Y of O)F.push(Zr(K({},R,{components:m?m.record.components:R.components,path:Y,aliasOf:m?m.record:R})))}let P,N;for(const O of F){const{path:Y}=O;if(g&&Y[0]!=="/"){const ie=g.record.path,ee=ie[ie.length-1]==="/"?"":"/";O.path=g.record.path+(Y&&ee+Y)}if(P=za(O,g,U),m?m.alias.push(P):(N=N||P,N!==P&&N.alias.push(P),I&&h.name&&!ei(P)&&o(h.name)),Po(P)&&c(P),R.children){const ie=R.children;for(let ee=0;ee{o(N)}:hn}function o(h){if(wo(h)){const g=s.get(h);g&&(s.delete(h),n.splice(n.indexOf(g),1),g.children.forEach(o),g.alias.forEach(o))}else{const g=n.indexOf(h);g>-1&&(n.splice(g,1),h.record.name&&s.delete(h.record.name),h.children.forEach(o),h.alias.forEach(o))}}function l(){return n}function c(h){const g=Xa(h,n);n.splice(g,0,h),h.record.name&&!ei(h)&&s.set(h.record.name,h)}function f(h,g){let m,I={},R,U;if("name"in h&&h.name){if(m=s.get(h.name),!m)throw zt(ne.MATCHER_NOT_FOUND,{location:h});U=m.record.name,I=K(Xr(g.params,m.keys.filter(N=>!N.optional).concat(m.parent?m.parent.keys.filter(N=>N.optional):[]).map(N=>N.name)),h.params&&Xr(h.params,m.keys.map(N=>N.name))),R=m.stringify(I)}else if(h.path!=null)R=h.path,m=n.find(N=>N.re.test(R)),m&&(I=m.parse(R),U=m.record.name);else{if(m=g.name?s.get(g.name):n.find(N=>N.re.test(g.path)),!m)throw zt(ne.MATCHER_NOT_FOUND,{location:h,currentLocation:g});U=m.record.name,I=K({},g.params,h.params),R=m.stringify(I)}const F=[];let P=m;for(;P;)F.unshift(P.record),P=P.parent;return{name:U,path:R,params:I,matched:F,meta:Qa(F)}}e.forEach(h=>i(h));function u(){n.length=0,s.clear()}return{addRoute:i,resolve:f,removeRoute:o,clearRoutes:u,getRoutes:l,getRecordMatcher:r}}function Xr(e,t){const n={};for(const s of t)s in e&&(n[s]=e[s]);return n}function Zr(e){const t={path:e.path,redirect:e.redirect,name:e.name,meta:e.meta||{},aliasOf:e.aliasOf,beforeEnter:e.beforeEnter,props:Ya(e),children:e.children||[],instances:{},leaveGuards:new Set,updateGuards:new Set,enterCallbacks:{},components:"components"in e?e.components||null:e.component&&{default:e.component}};return Object.defineProperty(t,"mods",{value:{}}),t}function Ya(e){const t={},n=e.props||!1;if("component"in e)t.default=n;else for(const s in e.components)t[s]=typeof n=="object"?n[s]:n;return t}function ei(e){for(;e;){if(e.record.aliasOf)return!0;e=e.parent}return!1}function Qa(e){return e.reduce((t,n)=>K(t,n.meta),{})}function Xa(e,t){let n=0,s=t.length;for(;n!==s;){const i=n+s>>1;To(e,t[i])<0?s=i:n=i+1}const r=Za(e);return r&&(s=t.lastIndexOf(r,s-1)),s}function Za(e){let t=e;for(;t=t.parent;)if(Po(t)&&To(e,t)===0)return t}function Po({record:e}){return!!(e.name||e.components&&Object.keys(e.components).length||e.redirect)}function ti(e){const t=Ne(ss),n=Ne(rr),s=Oe(()=>{const c=_e(e.to);return t.resolve(c)}),r=Oe(()=>{const{matched:c}=s.value,{length:f}=c,u=c[f-1],h=n.matched;if(!u||!h.length)return-1;const g=h.findIndex(qt.bind(null,u));if(g>-1)return g;const m=ni(c[f-2]);return f>1&&ni(u)===m&&h[h.length-1].path!==m?h.findIndex(qt.bind(null,c[f-2])):g}),i=Oe(()=>r.value>-1&&ru(n.params,s.value.params)),o=Oe(()=>r.value>-1&&r.value===n.matched.length-1&&Ao(n.params,s.value.params));function l(c={}){if(su(c)){const f=t[_e(e.replace)?"replace":"push"](_e(e.to)).catch(hn);return e.viewTransition&&typeof document<"u"&&"startViewTransition"in document&&document.startViewTransition(()=>f),f}return Promise.resolve()}return{route:s,href:Oe(()=>s.value.href),isActive:i,isExactActive:o,navigate:l}}function eu(e){return e.length===1?e[0]:e}const tu=Ui({name:"RouterLink",compatConfig:{MODE:3},props:{to:{type:[String,Object],required:!0},replace:Boolean,activeClass:String,exactActiveClass:String,custom:Boolean,ariaCurrentValue:{type:String,default:"page"},viewTransition:Boolean},useLink:ti,setup(e,{slots:t}){const n=Yt(ti(e)),{options:s}=Ne(ss),r=Oe(()=>({[si(e.activeClass,s.linkActiveClass,"router-link-active")]:n.isActive,[si(e.exactActiveClass,s.linkExactActiveClass,"router-link-exact-active")]:n.isExactActive}));return()=>{const i=t.default&&eu(t.default(n));return e.custom?i:ho("a",{"aria-current":n.isExactActive?e.ariaCurrentValue:null,href:n.href,onClick:n.navigate,class:r.value},i)}}}),nu=tu;function su(e){if(!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)&&!e.defaultPrevented&&!(e.button!==void 0&&e.button!==0)){if(e.currentTarget&&e.currentTarget.getAttribute){const t=e.currentTarget.getAttribute("target");if(/\b_blank\b/i.test(t))return}return e.preventDefault&&e.preventDefault(),!0}}function ru(e,t){for(const n in t){const s=t[n],r=e[n];if(typeof s=="string"){if(s!==r)return!1}else if(!Le(r)||r.length!==s.length||s.some((i,o)=>i.valueOf()!==r[o].valueOf()))return!1}return!0}function ni(e){return e?e.aliasOf?e.aliasOf.path:e.path:""}const si=(e,t,n)=>e??t??n,iu=Ui({name:"RouterView",inheritAttrs:!1,props:{name:{type:String,default:"default"},route:Object},compatConfig:{MODE:3},setup(e,{attrs:t,slots:n}){const s=Ne(Fs),r=Oe(()=>e.route||s.value),i=Ne(zr,0),o=Oe(()=>{let f=_e(i);const{matched:u}=r.value;let h;for(;(h=u[f])&&!h.components;)f++;return f}),l=Oe(()=>r.value.matched[o.value]);On(zr,Oe(()=>o.value+1)),On(Ma,l),On(Fs,r);const c=cl();return In(()=>[c.value,l.value,e.name],([f,u,h],[g,m,I])=>{u&&(u.instances[h]=f,m&&m!==u&&f&&f===g&&(u.leaveGuards.size||(u.leaveGuards=m.leaveGuards),u.updateGuards.size||(u.updateGuards=m.updateGuards))),f&&u&&(!m||!qt(u,m)||!g)&&(u.enterCallbacks[h]||[]).forEach(R=>R(f))},{flush:"post"}),()=>{const f=r.value,u=e.name,h=l.value,g=h&&h.components[u];if(!g)return ri(n.default,{Component:g,route:f});const m=h.props[u],I=m?m===!0?f.params:typeof m=="function"?m(f):m:null,U=ho(g,K({},I,t,{onVnodeUnmounted:F=>{F.component.isUnmounted&&(h.instances[u]=null)},ref:c}));return ri(n.default,{Component:U,route:f})||U}}});function ri(e,t){if(!e)return null;const n=e(t);return n.length===1?n[0]:n}const ou=iu;function lu(e){const t=Ja(e.routes,e),n=e.parseQuery||Na,s=e.stringifyQuery||qr,r=e.history,i=nn(),o=nn(),l=nn(),c=al(pt);let f=pt;Ht&&e.scrollBehavior&&"scrollRestoration"in history&&(history.scrollRestoration="manual");const u=ms.bind(null,v=>""+v),h=ms.bind(null,ga),g=ms.bind(null,bn);function m(v,C){let x,D;return wo(v)?(x=t.getRecordMatcher(v),D=C):D=v,t.addRoute(D,x)}function I(v){const C=t.getRecordMatcher(v);C&&t.removeRoute(C)}function R(){return t.getRoutes().map(v=>v.record)}function U(v){return!!t.getRecordMatcher(v)}function F(v,C){if(C=K({},C||c.value),typeof v=="string"){const p=_s(n,v,C.path),y=t.resolve({path:p.path},C),b=r.createHref(p.fullPath);return K(p,y,{params:g(y.params),hash:bn(p.hash),redirectedFrom:void 0,href:b})}let x;if(v.path!=null)x=K({},v,{path:_s(n,v.path,C.path).path});else{const p=K({},v.params);for(const y in p)p[y]==null&&delete p[y];x=K({},v,{params:h(p)}),C.params=h(C.params)}const D=t.resolve(x,C),j=v.hash||"";D.params=u(g(D.params));const a=ya(s,K({},v,{hash:da(j),path:D.path})),d=r.createHref(a);return K({fullPath:a,hash:j,query:s===qr?Da(v.query):v.query||{}},D,{redirectedFrom:void 0,href:d})}function P(v){return typeof v=="string"?_s(n,v,c.value.path):K({},v)}function N(v,C){if(f!==v)return zt(ne.NAVIGATION_CANCELLED,{from:C,to:v})}function O(v){return ee(v)}function Y(v){return O(K(P(v),{replace:!0}))}function ie(v,C){const x=v.matched[v.matched.length-1];if(x&&x.redirect){const{redirect:D}=x;let j=typeof D=="function"?D(v,C):D;return typeof j=="string"&&(j=j.includes("?")||j.includes("#")?j=P(j):{path:j},j.params={}),K({query:v.query,hash:v.hash,params:j.path!=null?{}:v.params},j)}}function ee(v,C){const x=f=F(v),D=c.value,j=v.state,a=v.force,d=v.replace===!0,p=ie(x,D);if(p)return ee(K(P(p),{state:typeof p=="object"?K({},j,p.state):j,force:a,replace:d}),C||x);const y=x;y.redirectedFrom=C;let b;return!a&&va(s,D,x)&&(b=zt(ne.NAVIGATION_DUPLICATED,{to:y,from:D}),Ue(D,D,!0,!1)),(b?Promise.resolve(b):Fe(y,D)).catch(_=>Xe(_)?Xe(_,ne.NAVIGATION_GUARD_REDIRECT)?_:ht(_):G(_,y,D)).then(_=>{if(_){if(Xe(_,ne.NAVIGATION_GUARD_REDIRECT))return ee(K({replace:d},P(_.to),{state:typeof _.to=="object"?K({},j,_.to.state):j,force:a}),C||y)}else _=bt(y,D,!0,d,j);return dt(y,D,_),_})}function Ve(v,C){const x=N(v,C);return x?Promise.reject(x):Promise.resolve()}function ft(v){const C=Dt.values().next().value;return C&&typeof C.runWithContext=="function"?C.runWithContext(v):v()}function Fe(v,C){let x;const[D,j,a]=La(v,C);x=vs(D.reverse(),"beforeRouteLeave",v,C);for(const p of D)p.leaveGuards.forEach(y=>{x.push(mt(y,v,C))});const d=Ve.bind(null,v,C);return x.push(d),xe(x).then(()=>{x=[];for(const p of i.list())x.push(mt(p,v,C));return x.push(d),xe(x)}).then(()=>{x=vs(j,"beforeRouteUpdate",v,C);for(const p of j)p.updateGuards.forEach(y=>{x.push(mt(y,v,C))});return x.push(d),xe(x)}).then(()=>{x=[];for(const p of a)if(p.beforeEnter)if(Le(p.beforeEnter))for(const y of p.beforeEnter)x.push(mt(y,v,C));else x.push(mt(p.beforeEnter,v,C));return x.push(d),xe(x)}).then(()=>(v.matched.forEach(p=>p.enterCallbacks={}),x=vs(a,"beforeRouteEnter",v,C,ft),x.push(d),xe(x))).then(()=>{x=[];for(const p of o.list())x.push(mt(p,v,C));return x.push(d),xe(x)}).catch(p=>Xe(p,ne.NAVIGATION_CANCELLED)?p:Promise.reject(p))}function dt(v,C,x){l.list().forEach(D=>ft(()=>D(v,C,x)))}function bt(v,C,x,D,j){const a=N(v,C);if(a)return a;const d=C===pt,p=Ht?history.state:{};x&&(D||d?r.replace(v.fullPath,K({scroll:d&&p&&p.scroll},j)):r.push(v.fullPath,j)),c.value=v,Ue(v,C,x,d),ht()}let He;function Qt(){He||(He=r.listen((v,C,x)=>{if(!Et.listening)return;const D=F(v),j=ie(D,Et.currentRoute.value);if(j){ee(K(j,{replace:!0,force:!0}),D).catch(hn);return}f=D;const a=c.value;Ht&&Ta($r(a.fullPath,x.delta),ns()),Fe(D,a).catch(d=>Xe(d,ne.NAVIGATION_ABORTED|ne.NAVIGATION_CANCELLED)?d:Xe(d,ne.NAVIGATION_GUARD_REDIRECT)?(ee(K(P(d.to),{force:!0}),D).then(p=>{Xe(p,ne.NAVIGATION_ABORTED|ne.NAVIGATION_DUPLICATED)&&!x.delta&&x.type===Ls.pop&&r.go(-1,!1)}).catch(hn),Promise.reject()):(x.delta&&r.go(-x.delta,!1),G(d,D,a))).then(d=>{d=d||bt(D,a,!1),d&&(x.delta&&!Xe(d,ne.NAVIGATION_CANCELLED)?r.go(-x.delta,!1):x.type===Ls.pop&&Xe(d,ne.NAVIGATION_ABORTED|ne.NAVIGATION_DUPLICATED)&&r.go(-1,!1)),dt(D,a,d)}).catch(hn)}))}let It=nn(),le=nn(),z;function G(v,C,x){ht(v);const D=le.list();return D.length?D.forEach(j=>j(v,C,x)):console.error(v),Promise.reject(v)}function Ye(){return z&&c.value!==pt?Promise.resolve():new Promise((v,C)=>{It.add([v,C])})}function ht(v){return z||(z=!v,Qt(),It.list().forEach(([C,x])=>v?x(v):C()),It.reset()),v}function Ue(v,C,x,D){const{scrollBehavior:j}=e;if(!Ht||!j)return Promise.resolve();const a=!x&&Pa($r(v.fullPath,0))||(D||!x)&&history.state&&history.state.scroll||null;return Qs().then(()=>j(v,C,a)).then(d=>d&&xa(d)).catch(d=>G(d,v,C))}const be=v=>r.go(v);let Nt;const Dt=new Set,Et={currentRoute:c,listening:!0,addRoute:m,removeRoute:I,clearRoutes:t.clearRoutes,hasRoute:U,getRoutes:R,resolve:F,options:e,push:O,replace:Y,go:be,back:()=>be(-1),forward:()=>be(1),beforeEach:i.add,beforeResolve:o.add,afterEach:l.add,onError:le.add,isReady:Ye,install(v){v.component("RouterLink",nu),v.component("RouterView",ou),v.config.globalProperties.$router=Et,Object.defineProperty(v.config.globalProperties,"$route",{enumerable:!0,get:()=>_e(c)}),Ht&&!Nt&&c.value===pt&&(Nt=!0,O(r.location).catch(D=>{}));const C={};for(const D in pt)Object.defineProperty(C,D,{get:()=>c.value[D],enumerable:!0});v.provide(ss,Et),v.provide(rr,Pi(C)),v.provide(Fs,c);const x=v.unmount;Dt.add(v),v.unmount=function(){Dt.delete(v),Dt.size<1&&(f=pt,He&&He(),He=null,c.value=pt,Nt=!1,z=!1),x()}}};function xe(v){return v.reduce((C,x)=>C.then(()=>ft(x)),Promise.resolve())}return Et}function cu(){return Ne(ss)}function Ru(e){return Ne(rr)}const Hs="st_token";function Co(){return localStorage.getItem(Hs)}function bs(e){e?localStorage.setItem(Hs,e):localStorage.removeItem(Hs)}async function te(e,t,n,s=!1){const r={},i=Co();i&&(r.Authorization=`Bearer ${i}`);let o=n;!s&&n!==void 0&&n!==null&&(r["Content-Type"]="application/json",o=JSON.stringify(n));const l=await fetch(t,{method:e,headers:r,body:o});let c=null;try{c=await l.json()}catch{}if(!l.ok){const f=c&&(c.error||c.message)||`HTTP ${l.status}`;throw new Error(f)}return c}const Es={login:(e,t)=>te("POST","/api/auth/login",{username:e,password:t}),me:()=>te("GET","/api/auth/me"),setup:e=>te("POST","/api/auth/setup",e),updateProfile:e=>te("PATCH","/api/auth/profile",e),adminCreateUser:e=>te("POST","/api/admin/users",e),adminListUsers:()=>te("GET","/api/admin/users"),adminUpdateUser:(e,t)=>te("PUT",`/api/admin/users/${e}`,t),createGroup:e=>te("POST","/api/groups",e,!0),listGroups:()=>te("GET","/api/groups"),getGroup:e=>te("GET",`/api/groups/${e}`),analyzeGroup:e=>te("POST",`/api/groups/${e}/analyze`),listPersonas:e=>te("GET",`/api/groups/${e}/personas`),getPersona:(e,t)=>te("GET",`/api/groups/${e}/personas/${t}`),updatePersona:(e,t,n)=>te("PUT",`/api/groups/${e}/personas/${t}`,n),chatStart:(e,t)=>te("POST",`/api/chat/${e}/personas/${t}/chat/start`),chatSend:(e,t,n)=>te("POST",`/api/chat/${e}/personas/${t}/chat/send`,{text:n}),chatFinish:(e,t)=>te("POST",`/api/chat/${e}/personas/${t}/chat/finish`),mySessions:()=>te("GET","/api/chat/sessions"),myBoard:()=>te("GET","/api/me/board"),weakAreas:()=>te("GET","/api/me/weak-areas"),myPersonas:()=>te("GET","/api/me/personas"),generatePersona:e=>te("POST","/api/me/personas/generate",e),analytics:(e={})=>{const t=new URLSearchParams;e.from&&t.set("from",e.from),e.to&&t.set("to",e.to);const n=t.toString();return te("GET",`/api/analytics${n?`?${n}`:""}`)}},Pe=Yt({user:null,token:Co(),mustSetup:!1,get role(){return this.user?this.user.role:null},get isAdmin(){return this.role==="admin"||this.role==="super_admin"},async load(){var e;if(!this.token)return null;try{const t=await Es.me();return this.user=t.user,this.mustSetup=!!((e=t.user)!=null&&e.must_setup),this.user}catch{return this.user=null,this.mustSetup=!1,bs(null),null}},async login(e,t){const n=await Es.login(e,t);return this.token=n.token,bs(n.token),this.user=n.user,this.mustSetup=!!n.must_setup,n.user},async finishSetup(e,t){const n=await Es.setup({username:this.user.username||this.user.id,email:e,password:t});return this.user=n.user,this.mustSetup=!1,n.user},logout(){this.user=null,this.token=null,this.mustSetup=!1,bs(null)}}),Ss={en:{app:"Sales Trainer",login:"Login",logout:"Logout",username:"Username",email:"Email",password:"Password",newPassword:"New password",confirmPassword:"Confirm password",save:"Save",passwordTooShort:"Password must be at least 4 characters",passwordMismatch:"Passwords do not match",setupTitle:"Set up your account",setupSubtitle:"First login for ",loginError:"Invalid credentials",dashboard:"Dashboard",training:"Training",myDashboard:"My dashboard",adminOverview:"Admin overview",settings:"Settings",account:"Account",profile:"Profile",readonly:"read-only",name:"Display name",saveProfile:"Save profile",changePassword:"Change password",optional:"optional",saved:"Saved",total:"Total",dateRange:"Date range",apply:"Apply",clear:"Clear",hardestPersonas:"Hardest personas",closeRate:"Close rate",managePersonas:"Manage personas",difficulty:"Difficulty",trained:"Trained",addProduct:"Add product",trainingSubtitle:"Pick a product group, then choose a persona to practice closing the sale.",noTraining:"No training groups available",groups:"Persona Groups",myTraining:"My Training",adminTools:"Admin Tools",users:"Users",analytics:"Analytics",groupBuilder:"Group Builder",create:"Create",analyze:"Analyze",manual:"Manual",edit:"Edit",product:"Product",segment:"Initial customer segment (optional)",description:"Additional description / scenario (optional)",channel:"Channel",facebook:"Facebook",line:"LINE",language:"Language",thai:"Thai",english:"English",personas:"Personas",tierA:"Tier A — Ready to buy",tierB:"Tier B — Unsure",tierC:"Tier C — Not interested but has pain",selectPersona:"Select a persona to practice",chat:"Chat",start:"Start",send:"Send",finish:"Finish & get result",debrief:"Result & Coaching",won:"Won",lost:"Lost",notTried:"Not tried",score:"Score",pain:"Pain",why:"Reason",reveal:"Revealed persona details",generatePersona:"Generate my persona",weakAreas:"My weak areas",mySessions:"My sessions",openSaleTask:"The customer did NOT message first. You must open the sale.",sellerInitiated:"You must open the sale (outbound)",customerInitiated:"The customer will message you first"},th:{app:"ระบบฝึกทักษะการขาย",login:"เข้าสู่ระบบ",logout:"ออกจากระบบ",username:"ชื่อผู้ใช้",email:"อีเมล",password:"รหัสผ่าน",newPassword:"รหัสผ่านใหม่",confirmPassword:"ยืนยันรหัสผ่าน",save:"บันทึก",passwordTooShort:"รหัสผ่านต้องมีความยาวอย่างน้อย 4 ตัวอักษร",passwordMismatch:"รหัสผ่านที่ยืนยันไม่ตรงกัน",setupTitle:"ตั้งค่าบัญชีของคุณ",setupSubtitle:"เข้าสู่ระบบครั้งแรกสำหรับ ",loginError:"ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง กรุณาลองอีกครั้ง",dashboard:"หน้าหลัก",training:"การฝึก",myDashboard:"ภาพรวมผลการฝึก",adminOverview:"ภาพรวมผู้ดูแล",settings:"การตั้งค่า",account:"บัญชี",profile:"ข้อมูลส่วนตัว",readonly:"อ่านอย่างเดียว",name:"ชื่อที่แสดง",saveProfile:"บันทึกข้อมูล",changePassword:"เปลี่ยนรหัสผ่าน",optional:"ไม่บังคับ",saved:"บันทึกเรียบร้อย",total:"ทั้งหมด",dateRange:"ช่วงเวลา",apply:"กรอง",clear:"ล้าง",hardestPersonas:"บุคคลต้นแบบที่ขายยากที่สุด",closeRate:"อัตราปิดการขาย",managePersonas:"จัดการบุคคลต้นแบบ",difficulty:"ระดับความยาก",trained:"ฝึกแล้ว",addProduct:"เพิ่มสินค้า",trainingSubtitle:"เลือกกลุ่มสินค้า แล้วเลือกบุคคลต้นแบบเพื่อฝึกปิดการขาย",noTraining:"ยังไม่มีกลุ่มฝึก",groups:"กลุ่มบุคคลต้นแบบลูกค้า (Persona)",myTraining:"ประวัติการฝึก",adminTools:"เครื่องมือผู้ดูแลระบบ",users:"ผู้ใช้งาน",analytics:"สถิติ",groupBuilder:"สร้างกลุ่มบุคคลต้นแบบ",create:"สร้าง",analyze:"วิเคราะห์",manual:"ระบุเอง",edit:"แก้ไข",product:"สินค้า/บริการ",segment:"กลุ่มลูกค้าเป้าหมายเบื้องต้น (ไม่บังคับ)",description:"คำอธิบายหรือรายละเอียดเพิ่มเติม (ไม่บังคับ)",channel:"ช่องทางติดต่อ",facebook:"Facebook",line:"LINE",language:"ภาษา",thai:"ไทย",english:"อังกฤษ",personas:"บุคคลต้นแบบ",tierA:"ระดับ A — พร้อมตัดสินใจซื้อ",tierB:"ระดับ B — ยังไม่แน่ใจ",tierC:"ระดับ C — ไม่สนใจแต่มีปัญหา",selectPersona:"เลือกบุคคลต้นแบบเพื่อฝึก",chat:"แชท",start:"เริ่มต้น",send:"ส่ง",finish:"สรุปผล",debrief:"ผลลัพธ์และข้อเสนอแนะ",won:"ปิดการขายได้",lost:"ปิดการขายไม่ได้",notTried:"ยังไม่ได้ฝึก",score:"คะแนน",pain:"ปัญหาของลูกค้า",why:"เหตุผล",reveal:"รายละเอียดบุคคลต้นแบบที่ถูกซ่อนไว้",generatePersona:"สร้างบุคคลต้นแบบเพิ่มเติม",weakAreas:"จุดอ่อนที่ควรฝึกเพิ่มเติม",mySessions:"ประวัติการฝึกของฉัน",openSaleTask:"ลูกค้ายังไม่ได้ทักเข้ามา คุณต้องเป็นฝ่ายเริ่มบทสนทนาการขายเอง",sellerInitiated:"คุณต้องเริ่มการขายในเชิงรุก",customerInitiated:"ลูกค้าจะติดต่อเข้ามาก่อน"}},Ze=Yt({locale:localStorage.getItem("locale")||"th",t(e){return Ss[this.locale]&&Ss[this.locale][e]||Ss.en[e]||e},set(e){this.locale=e,localStorage.setItem("locale",e)}}),au=(e,t)=>{const n=e.__vccOpts||e;for(const[s,r]of t)n[s]=r;return n},uu={class:"app"},fu={key:0,class:"topnav"},du={class:"tabs"},hu={class:"nav-right"},pu={class:"main"},gu={__name:"App",setup(e){const t=cu();function n(){Ze.set(Ze.locale==="th"?"en":"th")}function s(){Pe.logout(),t.push("/login")}return ki(()=>{Pe.token&&!Pe.user&&Pe.load()}),(r,i)=>{const o=gr("router-link"),l=gr("router-view");return rn(),Rr("div",uu,[_e(Pe).user?(rn(),Rr("nav",fu,[ue(o,{to:"/",class:"brand"},{default:Vt(()=>[Ft("🎯 "+wt(_e(Ze).t("app")),1)]),_:1}),xt("div",du,[_e(Pe).isAdmin?(rn(),Ns(o,{key:0,to:"/",class:jt(["tab",{active:r.$route.path==="/"}])},{default:Vt(()=>[Ft(wt(_e(Ze).t("adminOverview")),1)]),_:1},8,["class"])):xr("",!0),ue(o,{to:"/my/board",class:jt(["tab",{active:r.$route.path==="/my/board"}])},{default:Vt(()=>[Ft(wt(_e(Ze).t("myDashboard")),1)]),_:1},8,["class"]),ue(o,{to:"/training",class:jt(["tab",{active:r.$route.path==="/training"}])},{default:Vt(()=>[Ft(wt(_e(Ze).t("training")),1)]),_:1},8,["class"])]),xt("div",hu,[xt("button",{onClick:n,class:"lang"},wt(_e(Ze).locale==="th"?"EN":"TH"),1),ue(o,{to:"/settings",class:"icon-btn",title:"Settings"},{default:Vt(()=>[...i[0]||(i[0]=[Ft("⚙️",-1)])]),_:1}),xt("button",{onClick:s,class:"logout-btn"},"⏻ "+wt(_e(Ze).t("logout")),1)])])):xr("",!0),xt("main",pu,[(rn(),Ns(l,{key:_e(Ze).locale}))])])}}},mu=au(gu,[["__scopeId","data-v-836c19dc"]]),_u="modulepreload",yu=function(e){return"/"+e},ii={},Te=function(t,n,s){let r=Promise.resolve();if(n&&n.length>0){document.getElementsByTagName("link");const o=document.querySelector("meta[property=csp-nonce]"),l=(o==null?void 0:o.nonce)||(o==null?void 0:o.getAttribute("nonce"));r=Promise.allSettled(n.map(c=>{if(c=yu(c),c in ii)return;ii[c]=!0;const f=c.endsWith(".css"),u=f?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${c}"]${u}`))return;const h=document.createElement("link");if(h.rel=f?"stylesheet":_u,f||(h.as="script"),h.crossOrigin="",h.href=c,l&&h.setAttribute("nonce",l),document.head.appendChild(h),f)return new Promise((g,m)=>{h.addEventListener("load",g),h.addEventListener("error",()=>m(new Error(`Unable to preload CSS for ${c}`)))})}))}function i(o){const l=new Event("vite:preloadError",{cancelable:!0});if(l.payload=o,window.dispatchEvent(l),!l.defaultPrevented)throw o}return r.then(o=>{for(const l of o||[])l.status==="rejected"&&i(l.reason);return t().catch(i)})},vu=[{path:"/login",component:()=>Te(()=>import("./Login-71KwBI7P.js"),__vite__mapDeps([0,1])),meta:{public:!0}},{path:"/setup",component:()=>Te(()=>import("./Setup-DofFBOwX.js"),__vite__mapDeps([2,3]))},{path:"/",component:()=>Te(()=>import("./Analytics-BothIrTb.js"),__vite__mapDeps([4,5])),meta:{admin:!0}},{path:"/my/board",component:()=>Te(()=>import("./MyBoard-CjsbrOsq.js"),__vite__mapDeps([6,7]))},{path:"/training",component:()=>Te(()=>import("./Training-CBrtrJhQ.js"),__vite__mapDeps([8,9]))},{path:"/groups/:gid/personas",component:()=>Te(()=>import("./Personas-BGoC8X56.js"),__vite__mapDeps([10,11]))},{path:"/groups/:gid/chat/:pid",component:()=>Te(()=>import("./Chat-CYFTB7sZ.js"),__vite__mapDeps([12,13]))},{path:"/settings",component:()=>Te(()=>import("./Settings-D5fpvNb-.js"),__vite__mapDeps([14,15]))},{path:"/admin/new-group",component:()=>Te(()=>import("./GroupBuilder-CxLYlayH.js"),[]),meta:{admin:!0}},{path:"/admin/groups/:gid/edit",component:()=>Te(()=>import("./GroupEdit-DiRZ2lxy.js"),__vite__mapDeps([16,17])),meta:{admin:!0}},{path:"/admin/users",component:()=>Te(()=>import("./AdminUsers-r15xKxjs.js"),[]),meta:{admin:!0}},{path:"/admin/analytics",component:()=>Te(()=>import("./Analytics-BothIrTb.js"),__vite__mapDeps([4,5])),meta:{admin:!0}}],Oo=lu({history:Ua(),routes:vu});Oo.beforeEach(async e=>e.meta.public?!0:(Pe.user||await Pe.load(),Pe.user?Pe.mustSetup&&e.path!=="/setup"?{path:"/setup"}:e.path==="/"&&!Pe.isAdmin?{path:"/my/board"}:e.meta.admin&&!Pe.isAdmin?{path:"/my/board"}:!0:{path:"/login",query:{redirect:e.fullPath}}));Zc(mu).use(Oo).mount("#app");export{Ns as A,Qs as B,zc as C,tt as F,au as _,xt as a,wu as b,Rr as c,Au as d,xr as e,Pe as f,cu as g,Ru as h,Ze as i,Ft as j,ki as k,ue as l,Vt as m,ks as n,rn as o,Eu as p,Es as q,cl as r,gr as s,wt as t,_e as u,Ur as v,bu as w,Su as x,Oe as y,jt as z}; diff --git a/frontend/dist/index.html b/frontend/dist/index.html index 36f774d..7212452 100644 --- a/frontend/dist/index.html +++ b/frontend/dist/index.html @@ -4,7 +4,7 @@ Sales Trainer - + diff --git a/frontend/src/i18n/index.js b/frontend/src/i18n/index.js index 976e6a4..0626d1d 100644 --- a/frontend/src/i18n/index.js +++ b/frontend/src/i18n/index.js @@ -86,7 +86,7 @@ const messages = { customerInitiated: 'The customer will message you first', }, th: { - app: 'ตัวฝึกขาย', + app: 'ระบบฝึกทักษะการขาย', login: 'เข้าสู่ระบบ', logout: 'ออกจากระบบ', username: 'ชื่อผู้ใช้', @@ -95,78 +95,78 @@ const messages = { newPassword: 'รหัสผ่านใหม่', confirmPassword: 'ยืนยันรหัสผ่าน', save: 'บันทึก', - passwordTooShort: 'รหัสผ่านต้องอย่างน้อย 4 ตัวอักษร', - passwordMismatch: 'รหัสผ่านไม่ตรงกัน', + passwordTooShort: 'รหัสผ่านต้องมีความยาวอย่างน้อย 4 ตัวอักษร', + passwordMismatch: 'รหัสผ่านที่ยืนยันไม่ตรงกัน', setupTitle: 'ตั้งค่าบัญชีของคุณ', setupSubtitle: 'เข้าสู่ระบบครั้งแรกสำหรับ ', - loginError: 'ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง', + loginError: 'ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง กรุณาลองอีกครั้ง', dashboard: 'หน้าหลัก', training: 'การฝึก', - myDashboard: 'แดชบอร์ดของฉัน', - adminOverview: 'ภาพรวม Admin', + myDashboard: 'ภาพรวมผลการฝึก', + adminOverview: 'ภาพรวมผู้ดูแล', settings: 'การตั้งค่า', account: 'บัญชี', - profile: 'โปรไฟล์', + profile: 'ข้อมูลส่วนตัว', readonly: 'อ่านอย่างเดียว', name: 'ชื่อที่แสดง', - saveProfile: 'บันทึกโปรไฟล์', + saveProfile: 'บันทึกข้อมูล', changePassword: 'เปลี่ยนรหัสผ่าน', optional: 'ไม่บังคับ', - saved: 'บันทึกแล้ว', + saved: 'บันทึกเรียบร้อย', total: 'ทั้งหมด', - dateRange: 'ช่วงวันที่', + dateRange: 'ช่วงเวลา', apply: 'กรอง', clear: 'ล้าง', - hardestPersonas: 'Persona ที่ยากสุด', + hardestPersonas: 'บุคคลต้นแบบที่ขายยากที่สุด', closeRate: 'อัตราปิดการขาย', - managePersonas: 'จัดการ Persona', - difficulty: 'ความยาก', + managePersonas: 'จัดการบุคคลต้นแบบ', + difficulty: 'ระดับความยาก', trained: 'ฝึกแล้ว', addProduct: 'เพิ่มสินค้า', - trainingSubtitle: 'เลือกกลุ่มสินค้า แล้วเลือก persona เพื่อฝึกปิดการขาย', + trainingSubtitle: 'เลือกกลุ่มสินค้า แล้วเลือกบุคคลต้นแบบเพื่อฝึกปิดการขาย', noTraining: 'ยังไม่มีกลุ่มฝึก', - groups: 'กลุ่มลูกค้า (Persona)', - myTraining: 'การฝึกของฉัน', - adminTools: 'เครื่องมือ Admin', - users: 'ผู้ใช้', + groups: 'กลุ่มบุคคลต้นแบบลูกค้า (Persona)', + myTraining: 'ประวัติการฝึก', + adminTools: 'เครื่องมือผู้ดูแลระบบ', + users: 'ผู้ใช้งาน', analytics: 'สถิติ', - groupBuilder: 'สร้างกลุ่มลูกค้า', + groupBuilder: 'สร้างกลุ่มบุคคลต้นแบบ', create: 'สร้าง', analyze: 'วิเคราะห์', - manual: 'กำหนดเอง', + manual: 'ระบุเอง', edit: 'แก้ไข', product: 'สินค้า/บริการ', - segment: 'กลุ่มลูกค้าเบื้องต้น (ไม่บังคับ)', - description: 'คำอธิบาย/สถานการณ์เพิ่มเติม (ไม่บังคับ)', - channel: 'ช่องทาง', + segment: 'กลุ่มลูกค้าเป้าหมายเบื้องต้น (ไม่บังคับ)', + description: 'คำอธิบายหรือรายละเอียดเพิ่มเติม (ไม่บังคับ)', + channel: 'ช่องทางติดต่อ', facebook: 'Facebook', line: 'LINE', language: 'ภาษา', thai: 'ไทย', english: 'อังกฤษ', - personas: 'Persona', - tierA: 'ระดับ A — ตั้งใจซื้อ', + personas: 'บุคคลต้นแบบ', + tierA: 'ระดับ A — พร้อมตัดสินใจซื้อ', tierB: 'ระดับ B — ยังไม่แน่ใจ', - tierC: 'ระดับ C — ไม่สนใจแต่มี pain', - selectPersona: 'เลือก persona เพื่อฝึก', + tierC: 'ระดับ C — ไม่สนใจแต่มีปัญหา', + selectPersona: 'เลือกบุคคลต้นแบบเพื่อฝึก', chat: 'แชท', - start: 'เริ่ม', + start: 'เริ่มต้น', send: 'ส่ง', finish: 'สรุปผล', - debrief: 'ผลลัพธ์และคำแนะนำ', - won: 'ขายได้', - lost: 'ขายไม่ได้', + debrief: 'ผลลัพธ์และข้อเสนอแนะ', + won: 'ปิดการขายได้', + lost: 'ปิดการขายไม่ได้', notTried: 'ยังไม่ได้ฝึก', score: 'คะแนน', - pain: 'Pain', + pain: 'ปัญหาของลูกค้า', why: 'เหตุผล', - reveal: 'ข้อมูล persona ที่ถูกซ่อนไว้', - generatePersona: 'สร้าง persona ของฉัน', - weakAreas: 'จุดที่ฉันแพ้บ่อย', - mySessions: 'การฝึกของฉัน', - openSaleTask: 'ลูกค้ายังไม่ได้ทักมา คุณต้องเป็นฝ่ายเปิดการขายเอง', - sellerInitiated: 'คุณต้องเปิดการขาย (เชิงรุก)', - customerInitiated: 'ลูกค้าจะทักมาเองก่อน', + reveal: 'รายละเอียดบุคคลต้นแบบที่ถูกซ่อนไว้', + generatePersona: 'สร้างบุคคลต้นแบบเพิ่มเติม', + weakAreas: 'จุดอ่อนที่ควรฝึกเพิ่มเติม', + mySessions: 'ประวัติการฝึกของฉัน', + openSaleTask: 'ลูกค้ายังไม่ได้ทักเข้ามา คุณต้องเป็นฝ่ายเริ่มบทสนทนาการขายเอง', + sellerInitiated: 'คุณต้องเริ่มการขายในเชิงรุก', + customerInitiated: 'ลูกค้าจะติดต่อเข้ามาก่อน', }, } diff --git a/frontend/src/views/Analytics.vue b/frontend/src/views/Analytics.vue index 34c8237..0ec55e6 100644 --- a/frontend/src/views/Analytics.vue +++ b/frontend/src/views/Analytics.vue @@ -3,7 +3,7 @@

📊 {{ i18n.t('adminOverview') }}

- +
@@ -97,4 +97,6 @@ onMounted(load) .badge.not_tried { background: #eef2ff; color: #4338ca; } .bar { background: #eef0f5; border-radius: 999px; height: 10px; overflow: hidden; margin-top: 10px; } .bar-fill { background: linear-gradient(90deg, var(--accent), var(--accent-2)); height: 100%; border-radius: 999px; transition: width .4s ease; } +.users-btn { background: #0ea5e9; border-color: transparent; color: #fff; font-weight: 600; } +.users-btn:not(:disabled):hover { background: #0284c7; box-shadow: 0 6px 16px rgba(14,165,233,.35); }