diff --git a/backend/app/api/group_routes.py b/backend/app/api/group_routes.py index a167c38..fbc16ea 100644 --- a/backend/app/api/group_routes.py +++ b/backend/app/api/group_routes.py @@ -338,6 +338,53 @@ def update_persona(gid: str, pid: str): return jsonify({"persona": strip_secret_fields(full)}) +@groups_bp.post("//personas//variant") +@require_auth +def create_persona_variant(gid: str, pid: str): + """Create a NEW persona cloned from an existing one (fresh identity, same core traits). + + Lets a trainee practice the SAME selling challenge repeatedly even though each persona + can only be chatted once — the variant is a different person with the same pain points / + personality / temperament, so the training repeats but never as an identical copy. + Anyone who has access to the group can create a variant (admin or trainee). + """ + s = _stores() + group = _get_owned_group(s, gid) + if group.get("status") != "ready": + raise ApiError("group not ready", 403) + src = next((p for p in group.get("personas", []) if p.get("id") == pid), None) + if src is None: + raise ApiError("persona not found", 404) + + lang = (group.get("input") or {}).get("language", "th") + try: + from ..services.persona_generator import PersonaGenerator + variant = PersonaGenerator(s["llm"]).generate_variant( + source=src, + sales_kit=group.get("sales_kit") or {}, + language=lang, + ) + except Exception as exc: + raise ApiError(f"variant failed: {exc}", 500) + + # Assign a unique id and append to the group (keeps existing personas/sessions intact). + import uuid as _uuid + variant["id"] = f"persona-{_uuid.uuid4().hex[:10]}" + variant["source_persona_id"] = pid + personas = group.get("personas", []) + [variant] + s["groups"].update(gid, personas=personas) + full = ensure_persona_shape(variant) + + actor = current_user() + if actor.get("role") == "super_admin": + persona_out = full + elif actor.get("role") == "user": + persona_out = revealable_view(full) + else: + persona_out = strip_secret_fields(full) + return jsonify({"persona": persona_out}), 201 + + @groups_bp.delete("/") @require_auth @require_roles("admin") diff --git a/backend/app/services/persona_generator.py b/backend/app/services/persona_generator.py index 492b172..645993f 100644 --- a/backend/app/services/persona_generator.py +++ b/backend/app/services/persona_generator.py @@ -87,8 +87,76 @@ class PersonaGenerator: p["special"] = "wrong_text" break - if len(normalized) < 8: - raise ValueError(f"expected ~15 personas, generated only {len(normalized)}") - # NOTE: if we're short of 15 (real LLMs occasionally return 14), we ACCEPT what we - # got rather than crashing the whole analyze — with TARGET=15 there's normally no gap. return normalized + + def generate_variant( + self, + source: dict[str, Any], + sales_kit: dict[str, Any] | None = None, + language: str = "en", + ) -> dict[str, Any]: + """Create ONE new persona that is a fresh incarnation of a source persona. + + The variant LOCKS the source's core traits — pain points, objections, negotiation + levers, tolerance (temper), and any special/recontact behavior — so it practices the + SAME selling challenge, but gets a NEW identity (name, profession, age, location, + background, personality, income, opener) so it isn't an identical copy. + + Because the seller already knows how this customer 'plays', we vary the new identity + so the trainee still has to re-read and re-adjust rather than memorizing exact answers. + """ + kit_note = ( + f"Sales Kit\\n{json.dumps(sales_kit, ensure_ascii=False)[:6000]}" + if sales_kit + else "" + ) + src = json.dumps( + { + "pains": source.get("pains", []), + "objections": source.get("objections", []), + "negotiation_levers": source.get("negotiation_levers", []), + "tolerance": source.get("tolerance", 3), + "special": source.get("special", ""), + "recontact": source.get("recontact", False), + "goal": source.get("goal", ""), + "decision_timeline": source.get("decision_timeline", ""), + "budget": source.get("budget", ""), + "difficulty": source.get("difficulty", 1), + "tier": source.get("tier", "B"), + "product_context": source.get("product_context", ""), + }, + ensure_ascii=False, + ) + lang_name = "Thai" if language == "th" else "English" + prompt = ( + f"Create ONE new, realistic customer persona that is a fresh incarnation of an existing one.\n" + f"Language: {lang_name} (all text in {lang_name})\n" + f"{kit_note}\n" + f"LOCK (keep exactly these — they drive the training): pains[], objections[], " + f"negotiation_levers[], tolerance, special, recontact, goal, decision_timeline, " + f"budget, difficulty, tier, product_context.\n" + f"VARY (make DIFFERENT so it's not a copy): name, profession, age_group, location, " + f"background, income, lifestyle, personality, communication_style, opener, and any " + f"surface small-talk. Keep it consistent with the locked traits (a customer with the " + f"same pain would believably have a different name/job/life).\n" + f"Output exactly one JSON object for the persona.\n" + ) + result = self.llm.complete_json( + PERSONA_SYSTEM, prompt, temperature=0.9, max_tokens=3000 + ) + variant = result if isinstance(result, dict) else {} + # Accept either a single persona object or a {"personas": [...]} container. + if isinstance(variant.get("personas"), list) and variant["personas"]: + variant = variant["personas"][0] + if not isinstance(variant, dict) or not variant.get("name"): + raise ValueError("variant generator returned no persona") + # Lock the core traits regardless of what the LLM chose to change. + for locked in ("pains", "objections", "negotiation_levers", "tolerance", + "special", "recontact", "goal", "decision_timeline", "budget", + "difficulty", "tier", "product_context"): + if locked in source: + variant[locked] = source.get(locked) + variant.setdefault("initiation_mode", source.get("initiation_mode", "customer")) + variant.setdefault("channel", source.get("channel", "social")) + variant.setdefault("pains", source.get("pains", [])) + return variant diff --git a/backend/scripts/test_variant.py b/backend/scripts/test_variant.py new file mode 100644 index 0000000..ec10690 --- /dev/null +++ b/backend/scripts/test_variant.py @@ -0,0 +1,54 @@ +"""Test: create a persona VARIANT from an existing persona (fresh identity, locked core traits).""" +import os, sys, tempfile, warnings +from pathlib import Path + +warnings.filterwarnings("ignore") +BACKEND = str(Path(__file__).resolve().parents[1]) +sys.path.insert(0, BACKEND) +from app.factory import create_app +from app.config import Config + +td = tempfile.mkdtemp(); Config.DATA_DIR = Path(td) +sys.path.insert(0, BACKEND + "/scripts") +from mock_llm import MockLLM + +app = create_app(); app.extensions["llm"] = MockLLM() +C = app.test_client() + +def tok(u, p): return C.post("/api/auth/login", json={"username": u, "password": p}).get_json()["token"] + +AT = tok("admin", "1234"); AH = {"Authorization": f"Bearer {AT}"} +C.post("/api/auth/setup", headers=AH, json={"username":"admin","email":"a@b.co","password":"newpass","accepted_terms":True}) +AT = tok("admin", "newpass"); AH = {"Authorization": f"Bearer {AT}"} + +# admin creates group + analyze (15 personas) +r = C.post("/api/groups", headers=AH, json={"product":"POS CRM","segment":"SME restaurants","language":"th"}) +gid = r.get_json()["group"]["id"] +C.post(f"/api/groups/{gid}/analyze", headers=AH) +ps = C.get(f"/api/groups/{gid}/personas", headers=AH).get_json()["personas"] +src = ps[0] +print("source:", src["name"], "id:", src["id"], "| pains:", len(src.get("pains", [])) if isinstance(src.get("pains"), list) else "") + +# create a variant +r = C.post(f"/api/groups/{gid}/personas/{src['id']}/variant", headers=AH) +assert r.status_code == 201, (r.status_code, r.get_json()) +var = r.get_json()["persona"] +print("[ok] variant created:", var.get("name"), "| id:", var.get("id")) + +# it's a NEW id (not the source) +assert var["id"] != src["id"], "variant must have a new id" +# core traits locked (pains present as objects w/ description) +assert isinstance(var.get("pains", []), list), "variant must keep pains" +# added to the group +ps2 = C.get(f"/api/groups/{gid}/personas", headers=AH).get_json()["personas"] +ids = [p["id"] for p in ps2] +assert var["id"] in ids, "variant must be in the group personas" +print("[ok] variant added to group (now", len(ps2), "personas)") + +# the variant can be chatted fresh (not_tried for a fresh trainee) +UT = tok("admin", "newpass"); UH = {"Authorization": f"Bearer {UT}"} +board = C.get("/api/me/board", headers=UH).get_json() +vp = next((x for x in board.get("board", []) if x["persona_id"] == var["id"]), None) +print("[ok] variant appears on my board:", (vp or {}).get("my_outcome") if vp else None) + +print("ALL VARIANT TESTS PASSED") diff --git a/frontend/dist/assets/AdminUsers-CnHWEscS.js b/frontend/dist/assets/AdminUsers-BGqSvhVH.js similarity index 98% rename from frontend/dist/assets/AdminUsers-CnHWEscS.js rename to frontend/dist/assets/AdminUsers-BGqSvhVH.js index 7f00272..fc0b6cf 100644 --- a/frontend/dist/assets/AdminUsers-CnHWEscS.js +++ b/frontend/dist/assets/AdminUsers-BGqSvhVH.js @@ -1,4 +1,4 @@ -import{c as k,_ as h,p as b,a as r,b as e,l as m,u as o,m as l,t as n,i as u,w as p,v,H as U,g as f,F as V,x as C,y as w,r as y,o as i,C as M}from"./index-yErsUbD6.js";import{U as z}from"./users-BK4yWB6N.js";/** +import{c as k,_ as h,p as b,a as r,b as e,l as m,u as o,m as l,t as n,i as u,w as p,v,H as U,g as f,F as V,x as C,y as w,r as y,o as i,C as M}from"./index-C--0e2U-.js";import{U as z}from"./users-d_q-MTMu.js";/** * @license lucide-vue-next v1.0.0 - ISC * * This source code is licensed under the ISC license. diff --git a/frontend/dist/assets/Analytics-Cdjv87WO.js b/frontend/dist/assets/Analytics-5UUWbKvU.js similarity index 97% rename from frontend/dist/assets/Analytics-Cdjv87WO.js rename to frontend/dist/assets/Analytics-5UUWbKvU.js index fdcd00c..c713b64 100644 --- a/frontend/dist/assets/Analytics-Cdjv87WO.js +++ b/frontend/dist/assets/Analytics-5UUWbKvU.js @@ -1,4 +1,4 @@ -import{c as x,_ as L,p as M,a as p,b as s,l as i,u as a,m as c,t as e,i as n,q as w,w as f,v as b,s as U,g as N,F as R,x as j,y as A,z as B,r as m,h as E,o as y}from"./index-yErsUbD6.js";import{U as P}from"./users-BK4yWB6N.js";import{P as S}from"./plus-Y1qXSgej.js";/** +import{c as x,_ as L,p as M,a as p,b as s,l as i,u as a,m as c,t as e,i as n,q as w,w as f,v as b,s as U,g as N,F as R,x as j,y as A,z as B,r as m,h as E,o as y}from"./index-C--0e2U-.js";import{U as P}from"./users-d_q-MTMu.js";import{P as S}from"./plus-DQOnWKR_.js";/** * @license lucide-vue-next v1.0.0 - ISC * * This source code is licensed under the ISC license. diff --git a/frontend/dist/assets/Chat-Dr4nNqcU.js b/frontend/dist/assets/Chat-s9Pksmwi.js similarity index 97% rename from frontend/dist/assets/Chat-Dr4nNqcU.js rename to frontend/dist/assets/Chat-s9Pksmwi.js index 48525b4..3ed584e 100644 --- a/frontend/dist/assets/Chat-Dr4nNqcU.js +++ b/frontend/dist/assets/Chat-s9Pksmwi.js @@ -1,4 +1,4 @@ -import{c as P,_ as G,p as K,y as S,a as l,l as k,q as D,u as a,b as s,t,i as n,F as j,x as T,m as g,g as m,C as L,w as R,v as $,d as q,k as H,r as u,B as J,E as O,z as U,o}from"./index-yErsUbD6.js";import{T as Y}from"./target-DmESUw9c.js";import{A as Q}from"./arrow-left-hWxF5h5m.js";/** +import{c as P,_ as G,p as K,y as S,a as l,l as k,q as D,u as a,b as s,t,i as n,F as j,x as T,m as g,g as m,C as L,w as R,v as $,d as q,k as H,r as u,B as J,E as O,z as U,o}from"./index-C--0e2U-.js";import{T as Y}from"./target-dGrJgR_B.js";import{A as Q}from"./arrow-left-C-Wn16Dy.js";/** * @license lucide-vue-next v1.0.0 - ISC * * This source code is licensed under the ISC license. diff --git a/frontend/dist/assets/GroupBuilder-Odxme5l4.js b/frontend/dist/assets/GroupBuilder-FWDh6ofr.js similarity index 98% rename from frontend/dist/assets/GroupBuilder-Odxme5l4.js rename to frontend/dist/assets/GroupBuilder-FWDh6ofr.js index 5b73961..7288cba 100644 --- a/frontend/dist/assets/GroupBuilder-Odxme5l4.js +++ b/frontend/dist/assets/GroupBuilder-FWDh6ofr.js @@ -1,4 +1,4 @@ -import{c as v,_ as M,a as k,l as u,q as z,b as e,u as l,m as o,t as r,i,w as g,v as y,H as V,g as C,z as A,r as m,y as x,j as B,o as w}from"./index-yErsUbD6.js";import{A as q}from"./arrow-left-hWxF5h5m.js";/** +import{c as v,_ as M,a as k,l as u,q as z,b as e,u as l,m as o,t as r,i,w as g,v as y,H as V,g as C,z as A,r as m,y as x,j as B,o as w}from"./index-C--0e2U-.js";import{A as q}from"./arrow-left-C-Wn16Dy.js";/** * @license lucide-vue-next v1.0.0 - ISC * * This source code is licensed under the ISC license. diff --git a/frontend/dist/assets/GroupEdit-Bzhg1xqU.js b/frontend/dist/assets/GroupEdit-BOSQCzGb.js similarity index 99% rename from frontend/dist/assets/GroupEdit-Bzhg1xqU.js rename to frontend/dist/assets/GroupEdit-BOSQCzGb.js index 367fb40..7e4a22e 100644 --- a/frontend/dist/assets/GroupEdit-Bzhg1xqU.js +++ b/frontend/dist/assets/GroupEdit-BOSQCzGb.js @@ -1,4 +1,4 @@ -import{c as q,_ as E,I as F,o as u,a as d,b as t,t as a,w as o,v as i,H as G,u as f,h as M,g as A,J as I,r as g,p as D,l as k,q as T,m as C,i as B,G as J,F as j,x as z,D as H,k as R,y as N,z as K,C as O}from"./index-yErsUbD6.js";import{U as Q}from"./users-BK4yWB6N.js";/** +import{c as q,_ as E,I as F,o as u,a as d,b as t,t as a,w as o,v as i,H as G,u as f,h as M,g as A,J as I,r as g,p as D,l as k,q as T,m as C,i as B,G as J,F as j,x as z,D as H,k as R,y as N,z as K,C as O}from"./index-C--0e2U-.js";import{U as Q}from"./users-d_q-MTMu.js";/** * @license lucide-vue-next v1.0.0 - ISC * * This source code is licensed under the ISC license. diff --git a/frontend/dist/assets/Guide-fA0ESKf-.js b/frontend/dist/assets/Guide-CdnDfIjD.js similarity index 96% rename from frontend/dist/assets/Guide-fA0ESKf-.js rename to frontend/dist/assets/Guide-CdnDfIjD.js index de3fa6a..acc4fb3 100644 --- a/frontend/dist/assets/Guide-fA0ESKf-.js +++ b/frontend/dist/assets/Guide-CdnDfIjD.js @@ -1,4 +1,4 @@ -import{c as e,a as o,b as l,l as n,u as i,m as s,t as r,i as a,G as d,o as u}from"./index-yErsUbD6.js";import{B as g}from"./book-open-Cmnj20ue.js";import{L as p}from"./layout-dashboard-DplDGQ9R.js";import{T as y}from"./target-DmESUw9c.js";/** +import{c as e,a as o,b as l,l as n,u as i,m as s,t as r,i as a,G as d,o as u}from"./index-C--0e2U-.js";import{B as g}from"./book-open-BDMN_yKI.js";import{L as p}from"./layout-dashboard-qMD4csbw.js";import{T as y}from"./target-dGrJgR_B.js";/** * @license lucide-vue-next v1.0.0 - ISC * * This source code is licensed under the ISC license. diff --git a/frontend/dist/assets/Login-Dk-IRHf2.js b/frontend/dist/assets/Login-ZlvtmZHE.js similarity index 98% rename from frontend/dist/assets/Login-Dk-IRHf2.js rename to frontend/dist/assets/Login-ZlvtmZHE.js index eb23440..6f4e628 100644 --- a/frontend/dist/assets/Login-Dk-IRHf2.js +++ b/frontend/dist/assets/Login-ZlvtmZHE.js @@ -1,4 +1,4 @@ -import{c as k,_ as x,a as y,b as e,t as l,u as a,i as n,w as h,v as M,d as w,e as B,f as _,g as E,r,h as f,j as S,k as V,o as s}from"./index-yErsUbD6.js";/** +import{c as k,_ as x,a as y,b as e,t as l,u as a,i as n,w as h,v as M,d as w,e as B,f as _,g as E,r,h as f,j as S,k as V,o as s}from"./index-C--0e2U-.js";/** * @license lucide-vue-next v1.0.0 - ISC * * This source code is licensed under the ISC license. diff --git a/frontend/dist/assets/MyBoard-DTBModgt.js b/frontend/dist/assets/MyBoard-Dc1z0Qjo.js similarity index 94% rename from frontend/dist/assets/MyBoard-DTBModgt.js rename to frontend/dist/assets/MyBoard-Dc1z0Qjo.js index 93bdaef..bafb570 100644 --- a/frontend/dist/assets/MyBoard-DTBModgt.js +++ b/frontend/dist/assets/MyBoard-Dc1z0Qjo.js @@ -1 +1 @@ -import{_ as f,p as x,y as v,a as r,b as t,l as b,u as e,m as k,t as s,i as a,g as _,w as B,A as N,F as D,x as S,r as m,B as c,o as i,C as T}from"./index-yErsUbD6.js";import{L as V}from"./layout-dashboard-DplDGQ9R.js";const C={style:{margin:"0"}},L={key:0,class:"row stat-row"},M={class:"card stat"},z={class:"card stat won"},F={class:"card stat lost"},j={class:"card stat"},A={key:1,class:"card"},E={key:2,class:"card empty-state"},G={class:"card",style:{"margin-top":"20px"}},I={style:{"margin-top":"0"}},q={__name:"MyBoard",setup(H){const o=m([]),u=m([]),p=m(!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,l)=>(i(),r("div",null,[t("div",null,[t("h2",C,[b(e(V),{size:22,"stroke-width":1.8,style:{"vertical-align":"-4px"}}),k(" "+s(e(a).t("myDashboard")),1)]),l[0]||(l[0]=t("div",{class:"muted",style:{"margin-top":"4px","margin-bottom":"16px"}},"สรุปผลการฝึกของตัวคุณเอง — ดูว่าปิดการขายได้กี่ครั้ง ยังฝึกกับใครบ้าง",-1))]),p.value?_("",!0):(i(),r("div",L,[t("div",M,[t("span",null,s(e(a).t("total")),1),t("strong",null,s(y.value),1)]),t("div",z,[t("span",null,s(e(a).t("won")),1),t("strong",null,s(g.value),1)]),t("div",F,[t("span",null,s(e(a).t("lost")),1),t("strong",null,s(h.value),1)]),t("div",j,[t("span",null,s(e(a).t("notTried")),1),t("strong",null,s(w.value),1)])])),p.value?(i(),r("div",A,[...l[1]||(l[1]=[t("div",{class:"skeleton",style:{height:"50px"}},null,-1)])])):o.value.length===0?(i(),r("div",E,[...l[2]||(l[2]=[t("strong",null,"No practice yet",-1),t("span",null,"Go to Training and try closing a sale with a persona.",-1)])])):_("",!0),B(t("div",G,[t("h3",I,s(e(a).t("mySessions")),1),(i(!0),r(D,null,S(u.value,d=>(i(),r("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:T(["badge",d.outcome])},s(d.outcome==="won"?e(a).t("won"):e(a).t("lost")),3)]))),128))],512),[[N,u.value.length]])]))}},O=f(q,[["__scopeId","data-v-6767b6b8"]]);export{O as default}; +import{_ as f,p as x,y as v,a as r,b as t,l as b,u as e,m as k,t as s,i as a,g as _,w as B,A as N,F as D,x as S,r as m,B as c,o as i,C as T}from"./index-C--0e2U-.js";import{L as V}from"./layout-dashboard-qMD4csbw.js";const C={style:{margin:"0"}},L={key:0,class:"row stat-row"},M={class:"card stat"},z={class:"card stat won"},F={class:"card stat lost"},j={class:"card stat"},A={key:1,class:"card"},E={key:2,class:"card empty-state"},G={class:"card",style:{"margin-top":"20px"}},I={style:{"margin-top":"0"}},q={__name:"MyBoard",setup(H){const o=m([]),u=m([]),p=m(!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,l)=>(i(),r("div",null,[t("div",null,[t("h2",C,[b(e(V),{size:22,"stroke-width":1.8,style:{"vertical-align":"-4px"}}),k(" "+s(e(a).t("myDashboard")),1)]),l[0]||(l[0]=t("div",{class:"muted",style:{"margin-top":"4px","margin-bottom":"16px"}},"สรุปผลการฝึกของตัวคุณเอง — ดูว่าปิดการขายได้กี่ครั้ง ยังฝึกกับใครบ้าง",-1))]),p.value?_("",!0):(i(),r("div",L,[t("div",M,[t("span",null,s(e(a).t("total")),1),t("strong",null,s(y.value),1)]),t("div",z,[t("span",null,s(e(a).t("won")),1),t("strong",null,s(g.value),1)]),t("div",F,[t("span",null,s(e(a).t("lost")),1),t("strong",null,s(h.value),1)]),t("div",j,[t("span",null,s(e(a).t("notTried")),1),t("strong",null,s(w.value),1)])])),p.value?(i(),r("div",A,[...l[1]||(l[1]=[t("div",{class:"skeleton",style:{height:"50px"}},null,-1)])])):o.value.length===0?(i(),r("div",E,[...l[2]||(l[2]=[t("strong",null,"No practice yet",-1),t("span",null,"Go to Training and try closing a sale with a persona.",-1)])])):_("",!0),B(t("div",G,[t("h3",I,s(e(a).t("mySessions")),1),(i(!0),r(D,null,S(u.value,d=>(i(),r("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:T(["badge",d.outcome])},s(d.outcome==="won"?e(a).t("won"):e(a).t("lost")),3)]))),128))],512),[[N,u.value.length]])]))}},O=f(q,[["__scopeId","data-v-6767b6b8"]]);export{O as default}; diff --git a/frontend/dist/assets/Personas-CTGLZyPW.js b/frontend/dist/assets/Personas-CTGLZyPW.js new file mode 100644 index 0000000..5f8b46b --- /dev/null +++ b/frontend/dist/assets/Personas-CTGLZyPW.js @@ -0,0 +1 @@ +import{_ as T,p as L,a as r,l as c,q as y,b as t,t as s,u as a,i as n,h as p,m as d,g as w,F as _,x as h,k as N,y as x,z as S,r as A,o as l,S as F,C,f as B}from"./index-C--0e2U-.js";import{T as j}from"./target-dGrJgR_B.js";import{A as q}from"./arrow-left-C-Wn16Dy.js";const D={class:"row",style:{"align-items":"center"}},E={style:{margin:"0"}},I={class:"muted",style:{"margin-left":"auto"}},M={key:0,class:"card guide"},R={key:1,class:"row",style:{margin:"12px 0",gap:"10px"}},G={class:"primary"},H={class:"grid"},J={class:"row",style:{"justify-content":"space-between"}},K={class:"diff"},O={class:"muted"},Q={class:"muted"},U={class:"muted"},W={class:"muted",style:{"margin-top":"6px"}},X={class:"primary",style:{width:"100%"}},Y={class:"primary",style:{width:"100%"}},Z={class:"muted",style:{"margin-top":"auto","font-size":"12px"}},tt=["onClick","disabled"],st={__name:"Personas",setup(et){const u=N().params.gid,k=A([]),z=A(!0);async function b(){try{k.value=(await x.listPersonas(u)).personas}finally{z.value=!1}}function P(o){return k.value.filter(i=>i.tier===o)}function V(o){return n.t(o==="A"?"tierA":o==="B"?"tierB":"tierC")}function v(o){return o==="won"?n.t("won"):o==="lost"?n.t("lost"):o==="not_tried"?n.t("notTried"):o||"-"}async function $(o){o._busy=!0;try{await x.createPersonaVariant(u,o.id),await b()}catch(i){alert(i.message)}finally{o._busy=!1}}return L(b),(o,i)=>{const m=S("router-link");return l(),r("div",null,[c(m,{to:"/training",class:"btn-back"},{default:y(()=>[c(a(q),{size:16,"stroke-width":2}),d(" "+s(a(n).t("training")),1)]),_:1}),t("div",D,[t("h2",E,s(a(n).t("personas")),1),t("span",I,s(a(n).t("selectPersona")),1)]),a(p).isAdmin?w("",!0):(l(),r("div",M,[t("strong",null,[c(a(j),{size:17,"stroke-width":1.8,style:{"vertical-align":"-3px"}}),i[0]||(i[0]=d(" วิธีฝึก",-1))]),i[1]||(i[1]=t("ol",{style:{margin:"8px 0 0","padding-left":"20px","line-height":"1.8"}},[t("li",null,"เลือกลูกค้าจำลอง (บุคคลต้นแบบ) คนหนึ่งที่อยากฝึกด้วย"),t("li",null,"ระดับ A ง่ายสุด → ระดับ C ยากสุด (ดูจากดาว ★ ความยาก)"),t("li",null,[d("กด "),t("strong",null,"แชท"),d(" → เลือกสถานการณ์ (โซเชียล / พบหน้า-โทร) → เริ่มคุยกับลูกค้า")]),t("li",null,"ลูกค้าจะตัดสินใจเองว่าซื้อหรือไม่ซื้อ (ฝึกได้คนละครั้งเท่านั้น)")],-1))])),a(p).isAdmin?(l(),r("div",R,[c(m,{to:`/admin/groups/${a(u)}/edit`},{default:y(()=>[t("button",G,[c(a(F),{size:18,"stroke-width":1.8}),d(" "+s(a(n).t("managePersonas")),1)])]),_:1},8,["to"]),i[2]||(i[2]=t("span",{class:"muted"},"Admin: จัดการรายละเอียดบุคคลต้นแบบได้ที่นี่",-1))])):w("",!0),(l(),r(_,null,h(["A","B","C"],f=>t("div",{key:f,style:{margin:"20px 0"}},[t("h4",null,s(V(f)),1),t("div",H,[(l(!0),r(_,null,h(P(f),e=>(l(),r("div",{key:e.id,class:"card pcard lift"},[t("div",J,[t("strong",null,s(e.name),1),t("span",{class:C(["badge",e.my_outcome])},s(v(e.my_outcome)),3)]),t("div",K,[(l(),r(_,null,h(5,g=>t("span",{key:g,class:C(["star",{on:g<=(e.difficulty||1)}])},"★",2)),64)),t("span",O,s(a(n).t("difficulty"))+" "+s(e.difficulty||1)+"/5",1)]),t("div",Q,[d(s(e.profession)+" · "+s(e.age_group)+" · "+s(e.location),1),i[3]||(i[3]=t("br",null,null,-1)),t("span",U,s(a(n).t("difficulty"))+" "+s(e.difficulty||1)+"/5",1)]),t("div",W,s(e.product_context),1),a(p).isAdmin?(l(),B(m,{key:0,to:`/groups/${a(u)}/chat/${e.id}`,style:{"margin-top":"auto"}},{default:y(()=>[t("button",X,s(a(n).t("chat")),1)]),_:1},8,["to"])):(l(),r(_,{key:1},[e.my_outcome==="not_tried"?(l(),B(m,{key:0,to:`/groups/${a(u)}/chat/${e.id}`,style:{"margin-top":"auto"}},{default:y(()=>[t("button",Y,s(a(n).t("chat")),1)]),_:1},8,["to"])):(l(),r(_,{key:1},[t("div",Z,"✓ "+s(a(n).t("trained"))+" ("+s(v(e.my_outcome))+")",1),t("button",{class:"soft",style:{width:"100%","margin-top":"8px"},onClick:g=>$(e),disabled:e._busy},s(e._busy?"กำลังสร้าง…":"สร้างบุคคลต้นแบบจากต้นแบบนี้"),9,tt)],64))],64))]))),128))])])),64))])}}},lt=T(st,[["__scopeId","data-v-20adbc50"]]);export{lt as default}; diff --git a/frontend/dist/assets/Personas-CjtqghLF.js b/frontend/dist/assets/Personas-CjtqghLF.js deleted file mode 100644 index b9d6f92..0000000 --- a/frontend/dist/assets/Personas-CjtqghLF.js +++ /dev/null @@ -1 +0,0 @@ -import{_ as T,p as $,a as l,l as u,q as _,b as t,t as s,u as e,i as n,h as g,m as d,g as x,F as y,x as p,k as L,y as N,z as V,r as w,o as a,S,C as b,f as A}from"./index-yErsUbD6.js";import{T as F}from"./target-DmESUw9c.js";import{A as j}from"./arrow-left-hWxF5h5m.js";const q={class:"row",style:{"align-items":"center"}},D={style:{margin:"0"}},E={class:"muted",style:{"margin-left":"auto"}},I={key:0,class:"card guide"},M={key:1,class:"row",style:{margin:"12px 0",gap:"10px"}},R={class:"primary"},G={class:"grid"},H={class:"row",style:{"justify-content":"space-between"}},J={class:"diff"},K={class:"muted"},O={class:"muted"},Q={class:"muted"},U={class:"muted",style:{"margin-top":"6px"}},W={class:"primary",style:{width:"100%"}},X={class:"primary",style:{width:"100%"}},Y={key:1,class:"muted",style:{"margin-top":"auto","font-size":"12px"}},Z={__name:"Personas",setup(tt){const c=L().params.gid,h=w([]),C=w(!0);async function B(){try{h.value=(await N.listPersonas(c)).personas}finally{C.value=!1}}function z(r){return h.value.filter(i=>i.tier===r)}function P(r){return n.t(r==="A"?"tierA":r==="B"?"tierB":"tierC")}function k(r){return r==="won"?n.t("won"):r==="lost"?n.t("lost"):n.t("notTried")}return $(B),(r,i)=>{const m=V("router-link");return a(),l("div",null,[u(m,{to:"/training",class:"btn-back"},{default:_(()=>[u(e(j),{size:16,"stroke-width":2}),d(" "+s(e(n).t("training")),1)]),_:1}),t("div",q,[t("h2",D,s(e(n).t("personas")),1),t("span",E,s(e(n).t("selectPersona")),1)]),e(g).isAdmin?x("",!0):(a(),l("div",I,[t("strong",null,[u(e(F),{size:17,"stroke-width":1.8,style:{"vertical-align":"-3px"}}),i[0]||(i[0]=d(" วิธีฝึก",-1))]),i[1]||(i[1]=t("ol",{style:{margin:"8px 0 0","padding-left":"20px","line-height":"1.8"}},[t("li",null,"เลือกลูกค้าจำลอง (บุคคลต้นแบบ) คนหนึ่งที่อยากฝึกด้วย"),t("li",null,"ระดับ A ง่ายสุด → ระดับ C ยากสุด (ดูจากดาว ★ ความยาก)"),t("li",null,[d("กด "),t("strong",null,"แชท"),d(" → เลือกสถานการณ์ (โซเชียล / พบหน้า-โทร) → เริ่มคุยกับลูกค้า")]),t("li",null,"ลูกค้าจะตัดสินใจเองว่าซื้อหรือไม่ซื้อ (ฝึกได้คนละครั้งเท่านั้น)")],-1))])),e(g).isAdmin?(a(),l("div",M,[u(m,{to:`/admin/groups/${e(c)}/edit`},{default:_(()=>[t("button",R,[u(e(S),{size:18,"stroke-width":1.8}),d(" "+s(e(n).t("managePersonas")),1)])]),_:1},8,["to"]),i[2]||(i[2]=t("span",{class:"muted"},"Admin: จัดการรายละเอียดบุคคลต้นแบบได้ที่นี่",-1))])):x("",!0),(a(),l(y,null,p(["A","B","C"],f=>t("div",{key:f,style:{margin:"20px 0"}},[t("h4",null,s(P(f)),1),t("div",G,[(a(!0),l(y,null,p(z(f),o=>(a(),l("div",{key:o.id,class:"card pcard lift"},[t("div",H,[t("strong",null,s(o.name),1),t("span",{class:b(["badge",o.my_outcome])},s(k(o.my_outcome)),3)]),t("div",J,[(a(),l(y,null,p(5,v=>t("span",{key:v,class:b(["star",{on:v<=(o.difficulty||1)}])},"★",2)),64)),t("span",K,s(e(n).t("difficulty"))+" "+s(o.difficulty||1)+"/5",1)]),t("div",O,[d(s(o.profession)+" · "+s(o.age_group)+" · "+s(o.location),1),i[3]||(i[3]=t("br",null,null,-1)),t("span",Q,s(e(n).t("difficulty"))+" "+s(o.difficulty||1)+"/5",1)]),t("div",U,s(o.product_context),1),e(g).isAdmin?(a(),A(m,{key:0,to:`/groups/${e(c)}/chat/${o.id}`,style:{"margin-top":"auto"}},{default:_(()=>[t("button",W,s(e(n).t("chat")),1)]),_:1},8,["to"])):(a(),l(y,{key:1},[o.my_outcome==="not_tried"?(a(),A(m,{key:0,to:`/groups/${e(c)}/chat/${o.id}`,style:{"margin-top":"auto"}},{default:_(()=>[t("button",X,s(e(n).t("chat")),1)]),_:1},8,["to"])):(a(),l("div",Y,"✓ "+s(e(n).t("trained"))+" ("+s(k(o.my_outcome))+")",1))],64))]))),128))])])),64))])}}},at=T(Z,[["__scopeId","data-v-ec851b01"]]);export{at as default}; diff --git a/frontend/dist/assets/Personas-CmLjB15L.css b/frontend/dist/assets/Personas-CmLjB15L.css new file mode 100644 index 0000000..d3cd029 --- /dev/null +++ b/frontend/dist/assets/Personas-CmLjB15L.css @@ -0,0 +1 @@ +.grid[data-v-20adbc50]{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:14px}.pcard[data-v-20adbc50]{display:flex;flex-direction:column;min-height:190px}.diff[data-v-20adbc50]{margin:8px 0}.star[data-v-20adbc50]{color:#d8dbe3}.star.on[data-v-20adbc50]{color:#f59e0b}.badge.won[data-v-20adbc50]{background:#dcfce7;color:#166534}.badge.lost[data-v-20adbc50]{background:#fee2e2;color:#991b1b}.badge.not_tried[data-v-20adbc50]{background:#eef2ff;color:#4338ca}.guide[data-v-20adbc50]{background:#eef2ff;border-color:#c7d2fe;margin:12px 0 16px} diff --git a/frontend/dist/assets/Personas-cgqlaBh7.css b/frontend/dist/assets/Personas-cgqlaBh7.css deleted file mode 100644 index 88d8edb..0000000 --- a/frontend/dist/assets/Personas-cgqlaBh7.css +++ /dev/null @@ -1 +0,0 @@ -.grid[data-v-ec851b01]{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:14px}.pcard[data-v-ec851b01]{display:flex;flex-direction:column;min-height:190px}.diff[data-v-ec851b01]{margin:8px 0}.star[data-v-ec851b01]{color:#d8dbe3}.star.on[data-v-ec851b01]{color:#f59e0b}.badge.won[data-v-ec851b01]{background:#dcfce7;color:#166534}.badge.lost[data-v-ec851b01]{background:#fee2e2;color:#991b1b}.badge.not_tried[data-v-ec851b01]{background:#eef2ff;color:#4338ca}.guide[data-v-ec851b01]{background:#eef2ff;border-color:#c7d2fe;margin:12px 0 16px} diff --git a/frontend/dist/assets/Settings-sM2KFjew.js b/frontend/dist/assets/Settings-DTl0HJtQ.js similarity index 98% rename from frontend/dist/assets/Settings-sM2KFjew.js rename to frontend/dist/assets/Settings-DTl0HJtQ.js index d012f03..05ee708 100644 --- a/frontend/dist/assets/Settings-sM2KFjew.js +++ b/frontend/dist/assets/Settings-DTl0HJtQ.js @@ -1,4 +1,4 @@ -import{c as U,_ as T,r as c,h as u,a as h,b as e,l as k,u as a,S as $,m as v,t as o,i as s,w as b,v as x,g as V,C as S,y as M,o as g}from"./index-yErsUbD6.js";import{L as D}from"./lock-CCBV2bwv.js";/** +import{c as U,_ as T,r as c,h as u,a as h,b as e,l as k,u as a,S as $,m as v,t as o,i as s,w as b,v as x,g as V,C as S,y as M,o as g}from"./index-C--0e2U-.js";import{L as D}from"./lock-CdhbyMuc.js";/** * @license lucide-vue-next v1.0.0 - ISC * * This source code is licensed under the ISC license. diff --git a/frontend/dist/assets/Setup-BWzXOByZ.js b/frontend/dist/assets/Setup-CFifwHLU.js similarity index 94% rename from frontend/dist/assets/Setup-BWzXOByZ.js rename to frontend/dist/assets/Setup-CFifwHLU.js index ea90fa2..2d19aa3 100644 --- a/frontend/dist/assets/Setup-BWzXOByZ.js +++ b/frontend/dist/assets/Setup-CFifwHLU.js @@ -1 +1 @@ -import{_ as U,a as v,b as e,l as K,u as s,m,t as a,i as l,h as _,w,v as b,d as h,n as N,g as T,r,j as B,o as f}from"./index-yErsUbD6.js";import{L as C}from"./lock-CCBV2bwv.js";const M={class:"setup-wrap"},D={class:"card setup-card"},L={class:"muted"},P={class:"terms"},j={key:0,class:"error",role:"alert"},z=["disabled"],E={key:0,class:"spinner"},I={key:1},V="/legal",R={__name:"Setup",setup(q){const S=B(),i=r(""),o=r(""),p=r(""),y=r(!1),u=r(""),d=r(!1);async function c(){if(u.value="",o.value.length<4){u.value=l.t("passwordTooShort");return}if(o.value!==p.value){u.value=l.t("passwordMismatch");return}d.value=!0;try{await _.finishSetup(i.value.trim(),o.value,!0),S.push("/")}catch(k){u.value=k.message}finally{d.value=!1}}return(k,t)=>{var g,x;return f(),v("div",M,[e("div",D,[e("h1",null,[K(s(C),{size:22,"stroke-width":1.8,style:{"vertical-align":"-4px"}}),m(" "+a(s(l).t("setupTitle")),1)]),e("p",L,[m(a(s(l).t("setupSubtitle"))+" ",1),e("strong",null,a(((g=s(_).user)==null?void 0:g.name)||((x=s(_).user)==null?void 0:x.username)),1)]),e("label",null,a(s(l).t("email")),1),w(e("input",{"onUpdate:modelValue":t[0]||(t[0]=n=>i.value=n),type:"email",autocomplete:"email",class:"wide",onKeyup:h(c,["enter"])},null,544),[[b,i.value]]),e("label",null,a(s(l).t("newPassword")),1),w(e("input",{"onUpdate:modelValue":t[1]||(t[1]=n=>o.value=n),type:"password",autocomplete:"new-password",class:"wide",onKeyup:h(c,["enter"])},null,544),[[b,o.value]]),e("label",null,a(s(l).t("confirmPassword")),1),w(e("input",{"onUpdate:modelValue":t[2]||(t[2]=n=>p.value=n),type:"password",autocomplete:"new-password",class:"wide",onKeyup:h(c,["enter"])},null,544),[[b,p.value]]),e("label",P,[w(e("input",{"onUpdate:modelValue":t[3]||(t[3]=n=>y.value=n),type:"checkbox"},null,512),[[N,y.value]]),e("span",null,[t[4]||(t[4]=m("ฉันยอมรับ ",-1)),e("a",{href:V,target:"_blank",rel:"noopener"},"ข้อกำหนดการใช้งาน"),t[5]||(t[5]=m(" และ ",-1)),e("a",{href:V,target:"_blank",rel:"noopener"},"นโยบายความเป็นส่วนตัว")])]),u.value?(f(),v("div",j,a(u.value),1)):T("",!0),e("button",{class:"primary",style:{width:"100%","margin-top":"16px"},disabled:d.value||!i.value||!o.value||o.value!==p.value||!y.value,onClick:c},[d.value?(f(),v("span",E)):(f(),v("span",I,a(s(l).t("save")),1))],8,z)])])}}},G=U(R,[["__scopeId","data-v-a3748c0a"]]);export{G as default}; +import{_ as U,a as v,b as e,l as K,u as s,m,t as a,i as l,h as _,w,v as b,d as h,n as N,g as T,r,j as B,o as f}from"./index-C--0e2U-.js";import{L as C}from"./lock-CdhbyMuc.js";const M={class:"setup-wrap"},D={class:"card setup-card"},L={class:"muted"},P={class:"terms"},j={key:0,class:"error",role:"alert"},z=["disabled"],E={key:0,class:"spinner"},I={key:1},V="/legal",R={__name:"Setup",setup(q){const S=B(),i=r(""),o=r(""),p=r(""),y=r(!1),u=r(""),d=r(!1);async function c(){if(u.value="",o.value.length<4){u.value=l.t("passwordTooShort");return}if(o.value!==p.value){u.value=l.t("passwordMismatch");return}d.value=!0;try{await _.finishSetup(i.value.trim(),o.value,!0),S.push("/")}catch(k){u.value=k.message}finally{d.value=!1}}return(k,t)=>{var g,x;return f(),v("div",M,[e("div",D,[e("h1",null,[K(s(C),{size:22,"stroke-width":1.8,style:{"vertical-align":"-4px"}}),m(" "+a(s(l).t("setupTitle")),1)]),e("p",L,[m(a(s(l).t("setupSubtitle"))+" ",1),e("strong",null,a(((g=s(_).user)==null?void 0:g.name)||((x=s(_).user)==null?void 0:x.username)),1)]),e("label",null,a(s(l).t("email")),1),w(e("input",{"onUpdate:modelValue":t[0]||(t[0]=n=>i.value=n),type:"email",autocomplete:"email",class:"wide",onKeyup:h(c,["enter"])},null,544),[[b,i.value]]),e("label",null,a(s(l).t("newPassword")),1),w(e("input",{"onUpdate:modelValue":t[1]||(t[1]=n=>o.value=n),type:"password",autocomplete:"new-password",class:"wide",onKeyup:h(c,["enter"])},null,544),[[b,o.value]]),e("label",null,a(s(l).t("confirmPassword")),1),w(e("input",{"onUpdate:modelValue":t[2]||(t[2]=n=>p.value=n),type:"password",autocomplete:"new-password",class:"wide",onKeyup:h(c,["enter"])},null,544),[[b,p.value]]),e("label",P,[w(e("input",{"onUpdate:modelValue":t[3]||(t[3]=n=>y.value=n),type:"checkbox"},null,512),[[N,y.value]]),e("span",null,[t[4]||(t[4]=m("ฉันยอมรับ ",-1)),e("a",{href:V,target:"_blank",rel:"noopener"},"ข้อกำหนดการใช้งาน"),t[5]||(t[5]=m(" และ ",-1)),e("a",{href:V,target:"_blank",rel:"noopener"},"นโยบายความเป็นส่วนตัว")])]),u.value?(f(),v("div",j,a(u.value),1)):T("",!0),e("button",{class:"primary",style:{width:"100%","margin-top":"16px"},disabled:d.value||!i.value||!o.value||o.value!==p.value||!y.value,onClick:c},[d.value?(f(),v("span",E)):(f(),v("span",I,a(s(l).t("save")),1))],8,z)])])}}},G=U(R,[["__scopeId","data-v-a3748c0a"]]);export{G as default}; diff --git a/frontend/dist/assets/Training-6jie9iTF.js b/frontend/dist/assets/Training-B5ukgpN-.js similarity index 95% rename from frontend/dist/assets/Training-6jie9iTF.js rename to frontend/dist/assets/Training-B5ukgpN-.js index 4c02b68..132cfe9 100644 --- a/frontend/dist/assets/Training-6jie9iTF.js +++ b/frontend/dist/assets/Training-B5ukgpN-.js @@ -1,4 +1,4 @@ -import{c as x,_ as b,p as C,y as f,h as l,a as d,b as s,l as c,u as t,m,t as o,i as n,q as _,f as A,g as h,F as z,x as M,r as v,z as T,o as r,C as B,D as N}from"./index-yErsUbD6.js";import{T as P}from"./target-DmESUw9c.js";import{B as V}from"./book-open-Cmnj20ue.js";import{P as $}from"./plus-Y1qXSgej.js";/** +import{c as x,_ as b,p as C,y as f,h as l,a as d,b as s,l as c,u as t,m,t as o,i as n,q as _,f as A,g as h,F as z,x as M,r as v,z as T,o as r,C as B,D as N}from"./index-C--0e2U-.js";import{T as P}from"./target-dGrJgR_B.js";import{B as V}from"./book-open-BDMN_yKI.js";import{P as $}from"./plus-DQOnWKR_.js";/** * @license lucide-vue-next v1.0.0 - ISC * * This source code is licensed under the ISC license. diff --git a/frontend/dist/assets/arrow-left-hWxF5h5m.js b/frontend/dist/assets/arrow-left-C-Wn16Dy.js similarity index 86% rename from frontend/dist/assets/arrow-left-hWxF5h5m.js rename to frontend/dist/assets/arrow-left-C-Wn16Dy.js index 2027936..8814c0f 100644 --- a/frontend/dist/assets/arrow-left-hWxF5h5m.js +++ b/frontend/dist/assets/arrow-left-C-Wn16Dy.js @@ -1,4 +1,4 @@ -import{c as e}from"./index-yErsUbD6.js";/** +import{c as e}from"./index-C--0e2U-.js";/** * @license lucide-vue-next v1.0.0 - ISC * * This source code is licensed under the ISC license. diff --git a/frontend/dist/assets/book-open-Cmnj20ue.js b/frontend/dist/assets/book-open-BDMN_yKI.js similarity index 90% rename from frontend/dist/assets/book-open-Cmnj20ue.js rename to frontend/dist/assets/book-open-BDMN_yKI.js index 9a460cf..00937b4 100644 --- a/frontend/dist/assets/book-open-Cmnj20ue.js +++ b/frontend/dist/assets/book-open-BDMN_yKI.js @@ -1,4 +1,4 @@ -import{c as a}from"./index-yErsUbD6.js";/** +import{c as a}from"./index-C--0e2U-.js";/** * @license lucide-vue-next v1.0.0 - ISC * * This source code is licensed under the ISC license. diff --git a/frontend/dist/assets/index-yErsUbD6.js b/frontend/dist/assets/index-C--0e2U-.js similarity index 73% rename from frontend/dist/assets/index-yErsUbD6.js rename to frontend/dist/assets/index-C--0e2U-.js index 24457f4..16dd339 100644 --- a/frontend/dist/assets/index-yErsUbD6.js +++ b/frontend/dist/assets/index-C--0e2U-.js @@ -1,4 +1,4 @@ -const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Login-Dk-IRHf2.js","assets/Login-j4sHK_z1.css","assets/Setup-BWzXOByZ.js","assets/lock-CCBV2bwv.js","assets/Setup-BHyRmSn1.css","assets/Analytics-Cdjv87WO.js","assets/users-BK4yWB6N.js","assets/plus-Y1qXSgej.js","assets/Analytics-CQgwlaXy.css","assets/MyBoard-DTBModgt.js","assets/layout-dashboard-DplDGQ9R.js","assets/MyBoard-B7ypQ1JT.css","assets/Training-6jie9iTF.js","assets/target-DmESUw9c.js","assets/book-open-Cmnj20ue.js","assets/Training-Cb1U9s84.css","assets/Personas-CjtqghLF.js","assets/arrow-left-hWxF5h5m.js","assets/Personas-cgqlaBh7.css","assets/Chat-Dr4nNqcU.js","assets/Chat-pa8hnBQD.css","assets/Settings-sM2KFjew.js","assets/Settings-BCN2EZQ5.css","assets/Guide-fA0ESKf-.js","assets/GroupBuilder-Odxme5l4.js","assets/GroupBuilder-7-9ZskJo.css","assets/GroupEdit-Bzhg1xqU.js","assets/GroupEdit-sOm6hJOC.css","assets/AdminUsers-CnHWEscS.js","assets/AdminUsers-B0sl0uHS.css"])))=>i.map(i=>d[i]); +const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Login-ZlvtmZHE.js","assets/Login-j4sHK_z1.css","assets/Setup-CFifwHLU.js","assets/lock-CdhbyMuc.js","assets/Setup-BHyRmSn1.css","assets/Analytics-5UUWbKvU.js","assets/users-d_q-MTMu.js","assets/plus-DQOnWKR_.js","assets/Analytics-CQgwlaXy.css","assets/MyBoard-Dc1z0Qjo.js","assets/layout-dashboard-qMD4csbw.js","assets/MyBoard-B7ypQ1JT.css","assets/Training-B5ukgpN-.js","assets/target-dGrJgR_B.js","assets/book-open-BDMN_yKI.js","assets/Training-Cb1U9s84.css","assets/Personas-CTGLZyPW.js","assets/arrow-left-C-Wn16Dy.js","assets/Personas-CmLjB15L.css","assets/Chat-s9Pksmwi.js","assets/Chat-pa8hnBQD.css","assets/Settings-DTl0HJtQ.js","assets/Settings-BCN2EZQ5.css","assets/Guide-CdnDfIjD.js","assets/GroupBuilder-FWDh6ofr.js","assets/GroupBuilder-7-9ZskJo.css","assets/GroupEdit-BOSQCzGb.js","assets/GroupEdit-sOm6hJOC.css","assets/AdminUsers-BGqSvhVH.js","assets/AdminUsers-B0sl0uHS.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 @@ -7,7 +7,7 @@ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Login-Dk-IRHf2. * @vue/reactivity v3.5.41 * (c) 2018-present Yuxi (Evan) You and Vue contributors * @license MIT -**/let fe;class Wo{constructor(t=!1){this.detached=t,this._active=!0,this._on=0,this.effects=[],this.cleanups=[],this._isPaused=!1,this._warnOnRun=!0,this.__v_skip=!0,!t&&fe&&(fe.active?(this.parent=fe,this.index=(fe.scopes||(fe.scopes=[])).push(this)-1):(this._active=!1,this._warnOnRun=!1))}get active(){return this._active}pause(){if(this._active){this._isPaused=!0;let t,n;if(this.scopes){const s=this.scopes.slice();for(t=0,n=s.length;t0&&--this._on===0){if(fe===this)fe=this.prevScope;else{let t=fe;for(;t;){if(t.prevScope===this){t.prevScope=this.prevScope;break}t=t.prevScope}}this.prevScope=void 0}}stop(t){if(this._active){this._active=!1;let n,s;for(n=0,s=this.effects.length;n0)return;if(un){let t=un;for(un=void 0;t;){const n=t.next;t.next=void 0,t.flags&=-9,t=n}}let e;for(;an;){let t=an;for(an=void 0;t;){const n=t.next;if(t.next=void 0,t.flags&=-9,t.flags&1)try{t.trigger()}catch(s){e||(e=s)}t=n}}if(e)throw e}function Ei(e){for(let t=e.deps;t;t=t.nextDep)t.version=-1,t.prevActiveLink=t.dep.activeLink,t.dep.activeLink=t}function wi(e){let t,n=e.depsTail,s=n;for(;s;){const r=s.prevDep;s.version===-1?(s===n&&(n=r),zs(s),zo(s)):t=s,s.dep.activeLink=s.prevActiveLink,s.prevActiveLink=void 0,s=r}e.deps=t,e.depsTail=n}function Rs(e){for(let t=e.deps;t;t=t.nextDep)if(t.dep.version!==t.version||t.dep.computed&&(Si(t.dep.computed)||t.dep.version!==t.version))return!0;return!!e._dirty}function Si(e){if(e.flags&4&&!(e.flags&16)||(e.flags&=-17,e.globalVersion===gn)||(e.globalVersion=gn,!e.isSSR&&e.flags&128&&(!e.deps&&!e._dirty||!Rs(e))))return;e.flags|=2;const t=e.dep,n=Z,s=Ie;Z=e,Ie=!0;try{Ei(e);const r=e.fn(e._value);(t.version===0||ze(r,e._value))&&(e.flags|=128,e._value=r,t.version++)}catch(r){throw t.version++,r}finally{Z=n,Ie=s,wi(e),e.flags&=-3}}function zs(e,t=!1){const{dep:n,prevSub:s,nextSub:r}=e;if(s&&(s.nextSub=r,e.prevSub=void 0),r&&(r.prevSub=s,e.nextSub=void 0),n.subs===e&&(n.subs=s,!s&&n.computed)){n.computed.flags&=-5;for(let i=n.computed.deps;i;i=i.nextDep)zs(i,!0)}!t&&!--n.sc&&n.map&&n.map.delete(n.key)}function zo(e){const{prevDep:t,nextDep:n}=e;t&&(t.nextDep=n,e.prevDep=void 0),n&&(n.prevDep=t,e.nextDep=void 0)}let Ie=!0;const Ai=[];function ot(){Ai.push(Ie),Ie=!1}function lt(){const e=Ai.pop();Ie=e===void 0?!0:e}function dr(e){const{cleanup:t}=e;if(e.cleanup=void 0,t){const n=Z;Z=void 0;try{t()}finally{Z=n}}}let gn=0;class Jo{constructor(t,n){this.sub=t,this.dep=n,this.version=n.version,this.nextDep=this.prevDep=this.nextSub=this.prevSub=this.prevActiveLink=void 0}}class Js{constructor(t){this.computed=t,this.version=0,this.activeLink=void 0,this.subs=void 0,this.map=void 0,this.key=void 0,this.sc=0,this.__v_skip=!0}track(t){if(!Z||!Ie||Z===this.computed)return;let n=this.activeLink;if(n===void 0||n.sub!==Z)n=this.activeLink=new Jo(Z,this),Z.deps?(n.prevDep=Z.depsTail,Z.depsTail.nextDep=n,Z.depsTail=n):Z.deps=Z.depsTail=n,Ri(n);else if(n.version===-1&&(n.version=this.version,n.nextDep)){const s=n.nextDep;s.prevDep=n.prevDep,n.prevDep&&(n.prevDep.nextDep=s),n.prevDep=Z.depsTail,n.nextDep=void 0,Z.depsTail.nextDep=n,Z.depsTail=n,Z.deps===n&&(Z.deps=s)}return n}trigger(t){this.version++,gn++,this.notify(t)}notify(t){Ws();try{for(let n=this.subs;n;n=n.prevSub)n.sub.notify()&&n.sub.dep.notify()}finally{qs()}}}function Ri(e){if(e.dep.sc++,e.sub.flags&4){const t=e.dep.computed;if(t&&!e.dep.subs){t.flags|=20;for(let s=t.deps;s;s=s.nextDep)Ri(s)}const n=e.dep.subs;n!==e&&(e.prevSub=n,n&&(n.nextSub=e)),e.dep.subs=e}}const xs=new WeakMap,Ct=Symbol(""),Ts=Symbol(""),mn=Symbol("");function he(e,t,n){if(Ie&&Z){let s=xs.get(e);s||xs.set(e,s=new Map);let r=s.get(n);r||(s.set(n,r=new Js),r.map=s,r.key=n),r.track()}}function st(e,t,n,s,r,i){const o=xs.get(e);if(!o){gn++;return}const l=c=>{c&&c.trigger()};if(Ws(),t==="clear")o.forEach(l);else{const c=V(e),f=c&&Gs(n);if(c&&n==="length"){const u=Number(s);o.forEach((h,g)=>{(g==="length"||g===mn||!Ye(g)&&g>=u)&&l(h)})}else switch((n!==void 0||o.has(void 0))&&l(o.get(n)),f&&l(o.get(mn)),t){case"add":c?f&&l(o.get("length")):(l(o.get(Ct)),Bt(e)&&l(o.get(Ts)));break;case"delete":c||(l(o.get(Ct)),Bt(e)&&l(o.get(Ts)));break;case"set":Bt(e)&&l(o.get(Ct));break}}qs()}function Dt(e){const t=$(e);return t===e?t:(he(t,"iterate",mn),Pe(e)?t:t.map(Me))}function Xn(e){return he(e=$(e),"iterate",mn),e}function We(e,t){return ct(e)?Kt(Pt(e)?Me(t):t):Me(t)}const Yo={__proto__:null,[Symbol.iterator](){return us(this,Symbol.iterator,e=>We(this,e))},concat(...e){return Dt(this).concat(...e.map(t=>V(t)?Dt(t):t))},entries(){return us(this,"entries",e=>(e[1]=We(this,e[1]),e))},every(e,t){return Xe(this,"every",e,t,void 0,arguments)},filter(e,t){return Xe(this,"filter",e,t,n=>n.map(s=>We(this,s)),arguments)},find(e,t){return Xe(this,"find",e,t,n=>We(this,n),arguments)},findIndex(e,t){return Xe(this,"findIndex",e,t,void 0,arguments)},findLast(e,t){return Xe(this,"findLast",e,t,n=>We(this,n),arguments)},findLastIndex(e,t){return Xe(this,"findLastIndex",e,t,void 0,arguments)},forEach(e,t){return Xe(this,"forEach",e,t,void 0,arguments)},includes(...e){return fs(this,"includes",e)},indexOf(...e){return fs(this,"indexOf",e)},join(e){return Dt(this).join(e)},lastIndexOf(...e){return fs(this,"lastIndexOf",e)},map(e,t){return Xe(this,"map",e,t,void 0,arguments)},pop(){return Zt(this,"pop")},push(...e){return Zt(this,"push",e)},reduce(e,...t){return hr(this,"reduce",e,t)},reduceRight(e,...t){return hr(this,"reduceRight",e,t)},shift(){return Zt(this,"shift")},some(e,t){return Xe(this,"some",e,t,void 0,arguments)},splice(...e){return Zt(this,"splice",e)},toReversed(){return Dt(this).toReversed()},toSorted(e){return Dt(this).toSorted(e)},toSpliced(...e){return Dt(this).toSpliced(...e)},unshift(...e){return Zt(this,"unshift",e)},values(){return us(this,"values",e=>We(this,e))}};function us(e,t,n){const s=Xn(e),r=s[t]();return s!==e&&!Pe(e)&&(r._next=r.next,r.next=()=>{const i=r._next();return i.done||(i.value=n(i.value)),i}),r}const Qo=Array.prototype;function Xe(e,t,n,s,r,i){const o=Xn(e),l=o!==e&&!Pe(e),c=o[t];if(c!==Qo[t]){const h=c.apply(e,i);return l?Me(h):h}let f=n;o!==e&&(l?f=function(h,g){return n.call(this,We(e,h),g,e)}:n.length>2&&(f=function(h,g){return n.call(this,h,g,e)}));const u=c.call(o,f,s);return l&&r?r(u):u}function hr(e,t,n,s){const r=Xn(e),i=r!==e&&!Pe(e);let o=n,l=!1;r!==e&&(i?(l=s.length===0,o=function(f,u,h){return l&&(l=!1,f=We(e,f)),n.call(this,f,We(e,u),h,e)}):n.length>3&&(o=function(f,u,h){return n.call(this,f,u,h,e)}));const c=r[t](o,...s);return l?We(e,c):c}function fs(e,t,n){const s=$(e);he(s,"iterate",mn);const r=s[t](...n);return(r===-1||r===!1)&&Xs(n[0])?(n[0]=$(n[0]),s[t](...n)):r}function Zt(e,t,n=[]){ot(),Ws();const s=$(e)[t].apply(e,n);return qs(),lt(),s}const Xo=js("__proto__,__v_isRef,__isVue"),xi=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(Ye));function Zo(e){Ye(e)||(e=String(e));const t=$(this);return he(t,"has",e),t.hasOwnProperty(e)}class Ti{constructor(t=!1,n=!1){this._isReadonly=t,this._isShallow=n}get(t,n,s){if(n==="__v_skip")return t.__v_skip;const r=this._isReadonly,i=this._isShallow;if(n==="__v_isReactive")return!r;if(n==="__v_isReadonly")return r;if(n==="__v_isShallow")return i;if(n==="__v_raw")return s===(r?i?al:Ii:i?Oi:Pi).get(t)||Object.getPrototypeOf(t)===Object.getPrototypeOf(s)?t:void 0;const o=V(t);if(!r){let c;if(o&&(c=Yo[n]))return c;if(n==="hasOwnProperty")return Zo}const l=Reflect.get(t,n,ge(t)?t:s);if((Ye(n)?xi.has(n):Xo(n))||(r||he(t,"get",n),i))return l;if(ge(l)){const c=o&&Gs(n)?l:l.value;return r&&q(c)?Ps(c):c}return q(l)?r?Ps(l):Yt(l):l}}class Ci extends Ti{constructor(t=!1){super(!1,t)}set(t,n,s,r){let i=t[n];const o=V(t)&&Gs(n);if(!this._isShallow){const f=ct(i);if(!Pe(s)&&!ct(s)&&(i=$(i),s=$(s)),!o&&ge(i)&&!ge(s))return f||(i.value=s),!0}const l=o?Number(n)e,xn=e=>Reflect.getPrototypeOf(e);function rl(e,t,n){return function(...s){const r=this.__v_raw,i=$(r),o=Bt(i),l=e==="entries"||e===Symbol.iterator&&o,c=e==="keys"&&o,f=r[e](...s),u=n?Cs:t?Kt:Me;return!t&&he(i,"iterate",c?Ts:Ct),de(Object.create(f),{next(){const{value:h,done:g}=f.next();return g?{value:h,done:g}:{value:l?[u(h[0]),u(h[1])]:u(h),done:g}}})}}function Tn(e){return function(...t){return e==="delete"?!1:e==="clear"?void 0:this}}function il(e,t){const n={get(r){const i=this.__v_raw,o=$(i),l=$(r);e||(ze(r,l)&&he(o,"get",r),he(o,"get",l));const{has:c}=xn(o),f=t?Cs:e?Kt:Me;if(c.call(o,r))return f(i.get(r));if(c.call(o,l))return f(i.get(l));i!==o&&i.get(r)},get size(){const r=this.__v_raw;return!e&&he($(r),"iterate",Ct),r.size},has(r){const i=this.__v_raw,o=$(i),l=$(r);return e||(ze(r,l)&&he(o,"has",r),he(o,"has",l)),r===l?i.has(r):i.has(r)||i.has(l)},forEach(r,i){const o=this,l=o.__v_raw,c=$(l),f=t?Cs:e?Kt:Me;return!e&&he(c,"iterate",Ct),l.forEach((u,h)=>r.call(i,f(u),f(h),o))}};return de(n,e?{add:Tn("add"),set:Tn("set"),delete:Tn("delete"),clear:Tn("clear")}:{add(r){const i=$(this),o=xn(i),l=$(r),c=!t&&!Pe(r)&&!ct(r)?l:r;return o.has.call(i,c)||ze(r,c)&&o.has.call(i,r)||ze(l,c)&&o.has.call(i,l)||(i.add(c),st(i,"add",c,c)),this},set(r,i){!t&&!Pe(i)&&!ct(i)&&(i=$(i));const o=$(this),{has:l,get:c}=xn(o);let f=l.call(o,r);f||(r=$(r),f=l.call(o,r));const u=c.call(o,r);return o.set(r,i),f?ze(i,u)&&st(o,"set",r,i):st(o,"add",r,i),this},delete(r){const i=$(this),{has:o,get:l}=xn(i);let c=o.call(i,r);c||(r=$(r),c=o.call(i,r)),l&&l.call(i,r);const f=i.delete(r);return c&&st(i,"delete",r,void 0),f},clear(){const r=$(this),i=r.size!==0,o=r.clear();return i&&st(r,"clear",void 0,void 0),o}}),["keys","values","entries",Symbol.iterator].forEach(r=>{n[r]=rl(r,e,t)}),n}function Ys(e,t){const n=il(e,t);return(s,r,i)=>r==="__v_isReactive"?!e:r==="__v_isReadonly"?e:r==="__v_raw"?s:Reflect.get(W(n,r)&&r in s?n:s,r,i)}const ol={get:Ys(!1,!1)},ll={get:Ys(!1,!0)},cl={get:Ys(!0,!1)};const Pi=new WeakMap,Oi=new WeakMap,Ii=new WeakMap,al=new WeakMap;function ul(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function Yt(e){return ct(e)?e:Qs(e,!1,tl,ol,Pi)}function Ni(e){return Qs(e,!1,sl,ll,Oi)}function Ps(e){return Qs(e,!0,nl,cl,Ii)}function Qs(e,t,n,s,r){if(!q(e)||e.__v_raw&&!(t&&e.__v_isReactive)||e.__v_skip||!Object.isExtensible(e))return e;const i=r.get(e);if(i)return i;const o=ul(Vo(e));if(o===0)return e;const l=new Proxy(e,o===2?s:n);return r.set(e,l),l}function Pt(e){return ct(e)?Pt(e.__v_raw):!!(e&&e.__v_isReactive)}function ct(e){return!!(e&&e.__v_isReadonly)}function Pe(e){return!!(e&&e.__v_isShallow)}function Xs(e){return e?!!e.__v_raw:!1}function $(e){const t=e&&e.__v_raw;return t?$(t):e}function fl(e){return!W(e,"__v_skip")&&Object.isExtensible(e)&&pi(e,"__v_skip",!0),e}const Me=e=>q(e)?Yt(e):e,Kt=e=>q(e)?Ps(e):e;function ge(e){return e?e.__v_isRef===!0:!1}function dl(e){return Mi(e,!1)}function hl(e){return Mi(e,!0)}function Mi(e,t){return ge(e)?e:new pl(e,t)}class pl{constructor(t,n){this.dep=new Js,this.__v_isRef=!0,this.__v_isShallow=!1,this._rawValue=n?t:$(t),this._value=n?t:Me(t),this.__v_isShallow=n}get value(){return this.dep.track(),this._value}set value(t){const n=this._rawValue,s=this.__v_isShallow||Pe(t)||ct(t);t=s?t:$(t),ze(t,n)&&(this._rawValue=t,this._value=s?t:Me(t),this.dep.trigger())}}function ae(e){return ge(e)?e.value:e}const gl={get:(e,t,n)=>t==="__v_raw"?e:ae(Reflect.get(e,t,n)),set:(e,t,n,s)=>{const r=e[t];return ge(r)&&!ge(n)?(r.value=n,!0):Reflect.set(e,t,n,s)}};function Di(e){return Pt(e)?e:new Proxy(e,gl)}class ml{constructor(t,n,s){this.fn=t,this.setter=n,this._value=void 0,this.dep=new Js(this),this.__v_isRef=!0,this.deps=void 0,this.depsTail=void 0,this.flags=16,this.globalVersion=gn-1,this.next=void 0,this.effect=this,this.__v_isReadonly=!n,this.isSSR=s}notify(){if(this.flags|=16,!(this.flags&8)&&Z!==this)return bi(this,!0),!0}get value(){const t=this.dep.track();return Si(this),t&&(t.version=this.dep.version),this._value}set value(t){this.setter&&this.setter(t)}}function _l(e,t,n=!1){let s,r;return B(e)?s=e:(s=e.get,r=e.set),new ml(s,r,n)}const Cn={},Vn=new WeakMap;let xt;function yl(e,t=!1,n=xt){if(n){let s=Vn.get(n);s||Vn.set(n,s=[]),s.push(e)}}function vl(e,t,n=X){const{immediate:s,deep:r,once:i,scheduler:o,augmentJob:l,call:c}=n,f=O=>r?O:Pe(O)||r===!1||r===0?rt(O,1):rt(O);let u,h,g,m,I=!1,R=!1;if(ge(e)?(h=()=>e.value,I=Pe(e)):Pt(e)?(h=()=>f(e),I=!0):V(e)?(R=!0,I=e.some(O=>Pt(O)||Pe(O)),h=()=>e.map(O=>{if(ge(O))return O.value;if(Pt(O))return f(O);if(B(O))return c?c(O,2):O()})):B(e)?t?h=c?()=>c(e,2):e:h=()=>{if(g){ot();try{g()}finally{lt()}}const O=xt;xt=u;try{return c?c(e,3,[m]):e(m)}finally{xt=O}}:h=Je,t&&r){const O=h,Y=r===!0?1/0:r;h=()=>rt(O(),Y)}const U=qo(),F=()=>{u.stop(),U&&U.active&&ks(U.effects,u)};if(i&&t){const O=t;t=(...Y)=>{const oe=O(...Y);return F(),oe}}let C=R?new Array(e.length).fill(Cn):Cn;const N=O=>{if(!(!(u.flags&1)||!u.dirty&&!O))if(t){const Y=u.run();if(O||r||I||(R?Y.some((oe,te)=>ze(oe,C[te])):ze(Y,C))){g&&g();const oe=xt;xt=u;try{const te=[Y,C===Cn?void 0:R&&C[0]===Cn?[]:C,m];C=Y,c?c(t,3,te):t(...te)}finally{xt=oe}}}else u.run()};return l&&l(N),u=new yi(h),u.scheduler=o?()=>o(N,!1):N,m=O=>yl(O,!1,u),g=u.onStop=()=>{const O=Vn.get(u);if(O){if(c)c(O,4);else for(const Y of O)Y();Vn.delete(u)}},t?s?N(!0):C=u.run():o?o(N.bind(null,!0),!0):u.run(),F.pause=u.pause.bind(u),F.resume=u.resume.bind(u),F.stop=F,F}function rt(e,t=1/0,n){if(t<=0||!q(e)||e.__v_skip||(n=n||new Map,(n.get(e)||0)>=t))return e;if(n.set(e,t),t--,ge(e))rt(e.value,t,n);else if(V(e))for(let s=0;s{rt(s,t,n)});else if(hi(e)){for(const s in e)rt(e[s],t,n);for(const s of Object.getOwnPropertySymbols(e))Object.prototype.propertyIsEnumerable.call(e,s)&&rt(e[s],t,n)}return e}/** +**/let fe;class Wo{constructor(t=!1){this.detached=t,this._active=!0,this._on=0,this.effects=[],this.cleanups=[],this._isPaused=!1,this._warnOnRun=!0,this.__v_skip=!0,!t&&fe&&(fe.active?(this.parent=fe,this.index=(fe.scopes||(fe.scopes=[])).push(this)-1):(this._active=!1,this._warnOnRun=!1))}get active(){return this._active}pause(){if(this._active){this._isPaused=!0;let t,n;if(this.scopes){const s=this.scopes.slice();for(t=0,n=s.length;t0&&--this._on===0){if(fe===this)fe=this.prevScope;else{let t=fe;for(;t;){if(t.prevScope===this){t.prevScope=this.prevScope;break}t=t.prevScope}}this.prevScope=void 0}}stop(t){if(this._active){this._active=!1;let n,s;for(n=0,s=this.effects.length;n0)return;if(un){let t=un;for(un=void 0;t;){const n=t.next;t.next=void 0,t.flags&=-9,t=n}}let e;for(;an;){let t=an;for(an=void 0;t;){const n=t.next;if(t.next=void 0,t.flags&=-9,t.flags&1)try{t.trigger()}catch(s){e||(e=s)}t=n}}if(e)throw e}function Ei(e){for(let t=e.deps;t;t=t.nextDep)t.version=-1,t.prevActiveLink=t.dep.activeLink,t.dep.activeLink=t}function wi(e){let t,n=e.depsTail,s=n;for(;s;){const r=s.prevDep;s.version===-1?(s===n&&(n=r),zs(s),zo(s)):t=s,s.dep.activeLink=s.prevActiveLink,s.prevActiveLink=void 0,s=r}e.deps=t,e.depsTail=n}function Rs(e){for(let t=e.deps;t;t=t.nextDep)if(t.dep.version!==t.version||t.dep.computed&&(Si(t.dep.computed)||t.dep.version!==t.version))return!0;return!!e._dirty}function Si(e){if(e.flags&4&&!(e.flags&16)||(e.flags&=-17,e.globalVersion===gn)||(e.globalVersion=gn,!e.isSSR&&e.flags&128&&(!e.deps&&!e._dirty||!Rs(e))))return;e.flags|=2;const t=e.dep,n=ee,s=Ie;ee=e,Ie=!0;try{Ei(e);const r=e.fn(e._value);(t.version===0||ze(r,e._value))&&(e.flags|=128,e._value=r,t.version++)}catch(r){throw t.version++,r}finally{ee=n,Ie=s,wi(e),e.flags&=-3}}function zs(e,t=!1){const{dep:n,prevSub:s,nextSub:r}=e;if(s&&(s.nextSub=r,e.prevSub=void 0),r&&(r.prevSub=s,e.nextSub=void 0),n.subs===e&&(n.subs=s,!s&&n.computed)){n.computed.flags&=-5;for(let i=n.computed.deps;i;i=i.nextDep)zs(i,!0)}!t&&!--n.sc&&n.map&&n.map.delete(n.key)}function zo(e){const{prevDep:t,nextDep:n}=e;t&&(t.nextDep=n,e.prevDep=void 0),n&&(n.prevDep=t,e.nextDep=void 0)}let Ie=!0;const Ai=[];function ot(){Ai.push(Ie),Ie=!1}function lt(){const e=Ai.pop();Ie=e===void 0?!0:e}function dr(e){const{cleanup:t}=e;if(e.cleanup=void 0,t){const n=ee;ee=void 0;try{t()}finally{ee=n}}}let gn=0;class Jo{constructor(t,n){this.sub=t,this.dep=n,this.version=n.version,this.nextDep=this.prevDep=this.nextSub=this.prevSub=this.prevActiveLink=void 0}}class Js{constructor(t){this.computed=t,this.version=0,this.activeLink=void 0,this.subs=void 0,this.map=void 0,this.key=void 0,this.sc=0,this.__v_skip=!0}track(t){if(!ee||!Ie||ee===this.computed)return;let n=this.activeLink;if(n===void 0||n.sub!==ee)n=this.activeLink=new Jo(ee,this),ee.deps?(n.prevDep=ee.depsTail,ee.depsTail.nextDep=n,ee.depsTail=n):ee.deps=ee.depsTail=n,Ri(n);else if(n.version===-1&&(n.version=this.version,n.nextDep)){const s=n.nextDep;s.prevDep=n.prevDep,n.prevDep&&(n.prevDep.nextDep=s),n.prevDep=ee.depsTail,n.nextDep=void 0,ee.depsTail.nextDep=n,ee.depsTail=n,ee.deps===n&&(ee.deps=s)}return n}trigger(t){this.version++,gn++,this.notify(t)}notify(t){Ws();try{for(let n=this.subs;n;n=n.prevSub)n.sub.notify()&&n.sub.dep.notify()}finally{qs()}}}function Ri(e){if(e.dep.sc++,e.sub.flags&4){const t=e.dep.computed;if(t&&!e.dep.subs){t.flags|=20;for(let s=t.deps;s;s=s.nextDep)Ri(s)}const n=e.dep.subs;n!==e&&(e.prevSub=n,n&&(n.nextSub=e)),e.dep.subs=e}}const xs=new WeakMap,Ct=Symbol(""),Ts=Symbol(""),mn=Symbol("");function he(e,t,n){if(Ie&&ee){let s=xs.get(e);s||xs.set(e,s=new Map);let r=s.get(n);r||(s.set(n,r=new Js),r.map=s,r.key=n),r.track()}}function st(e,t,n,s,r,i){const o=xs.get(e);if(!o){gn++;return}const l=c=>{c&&c.trigger()};if(Ws(),t==="clear")o.forEach(l);else{const c=V(e),f=c&&Gs(n);if(c&&n==="length"){const u=Number(s);o.forEach((h,g)=>{(g==="length"||g===mn||!Ye(g)&&g>=u)&&l(h)})}else switch((n!==void 0||o.has(void 0))&&l(o.get(n)),f&&l(o.get(mn)),t){case"add":c?f&&l(o.get("length")):(l(o.get(Ct)),Bt(e)&&l(o.get(Ts)));break;case"delete":c||(l(o.get(Ct)),Bt(e)&&l(o.get(Ts)));break;case"set":Bt(e)&&l(o.get(Ct));break}}qs()}function Dt(e){const t=$(e);return t===e?t:(he(t,"iterate",mn),Pe(e)?t:t.map(Me))}function Xn(e){return he(e=$(e),"iterate",mn),e}function We(e,t){return ct(e)?Kt(Pt(e)?Me(t):t):Me(t)}const Yo={__proto__:null,[Symbol.iterator](){return us(this,Symbol.iterator,e=>We(this,e))},concat(...e){return Dt(this).concat(...e.map(t=>V(t)?Dt(t):t))},entries(){return us(this,"entries",e=>(e[1]=We(this,e[1]),e))},every(e,t){return Xe(this,"every",e,t,void 0,arguments)},filter(e,t){return Xe(this,"filter",e,t,n=>n.map(s=>We(this,s)),arguments)},find(e,t){return Xe(this,"find",e,t,n=>We(this,n),arguments)},findIndex(e,t){return Xe(this,"findIndex",e,t,void 0,arguments)},findLast(e,t){return Xe(this,"findLast",e,t,n=>We(this,n),arguments)},findLastIndex(e,t){return Xe(this,"findLastIndex",e,t,void 0,arguments)},forEach(e,t){return Xe(this,"forEach",e,t,void 0,arguments)},includes(...e){return fs(this,"includes",e)},indexOf(...e){return fs(this,"indexOf",e)},join(e){return Dt(this).join(e)},lastIndexOf(...e){return fs(this,"lastIndexOf",e)},map(e,t){return Xe(this,"map",e,t,void 0,arguments)},pop(){return Zt(this,"pop")},push(...e){return Zt(this,"push",e)},reduce(e,...t){return hr(this,"reduce",e,t)},reduceRight(e,...t){return hr(this,"reduceRight",e,t)},shift(){return Zt(this,"shift")},some(e,t){return Xe(this,"some",e,t,void 0,arguments)},splice(...e){return Zt(this,"splice",e)},toReversed(){return Dt(this).toReversed()},toSorted(e){return Dt(this).toSorted(e)},toSpliced(...e){return Dt(this).toSpliced(...e)},unshift(...e){return Zt(this,"unshift",e)},values(){return us(this,"values",e=>We(this,e))}};function us(e,t,n){const s=Xn(e),r=s[t]();return s!==e&&!Pe(e)&&(r._next=r.next,r.next=()=>{const i=r._next();return i.done||(i.value=n(i.value)),i}),r}const Qo=Array.prototype;function Xe(e,t,n,s,r,i){const o=Xn(e),l=o!==e&&!Pe(e),c=o[t];if(c!==Qo[t]){const h=c.apply(e,i);return l?Me(h):h}let f=n;o!==e&&(l?f=function(h,g){return n.call(this,We(e,h),g,e)}:n.length>2&&(f=function(h,g){return n.call(this,h,g,e)}));const u=c.call(o,f,s);return l&&r?r(u):u}function hr(e,t,n,s){const r=Xn(e),i=r!==e&&!Pe(e);let o=n,l=!1;r!==e&&(i?(l=s.length===0,o=function(f,u,h){return l&&(l=!1,f=We(e,f)),n.call(this,f,We(e,u),h,e)}):n.length>3&&(o=function(f,u,h){return n.call(this,f,u,h,e)}));const c=r[t](o,...s);return l?We(e,c):c}function fs(e,t,n){const s=$(e);he(s,"iterate",mn);const r=s[t](...n);return(r===-1||r===!1)&&Xs(n[0])?(n[0]=$(n[0]),s[t](...n)):r}function Zt(e,t,n=[]){ot(),Ws();const s=$(e)[t].apply(e,n);return qs(),lt(),s}const Xo=js("__proto__,__v_isRef,__isVue"),xi=new Set(Object.getOwnPropertyNames(Symbol).filter(e=>e!=="arguments"&&e!=="caller").map(e=>Symbol[e]).filter(Ye));function Zo(e){Ye(e)||(e=String(e));const t=$(this);return he(t,"has",e),t.hasOwnProperty(e)}class Ti{constructor(t=!1,n=!1){this._isReadonly=t,this._isShallow=n}get(t,n,s){if(n==="__v_skip")return t.__v_skip;const r=this._isReadonly,i=this._isShallow;if(n==="__v_isReactive")return!r;if(n==="__v_isReadonly")return r;if(n==="__v_isShallow")return i;if(n==="__v_raw")return s===(r?i?al:Ii:i?Oi:Pi).get(t)||Object.getPrototypeOf(t)===Object.getPrototypeOf(s)?t:void 0;const o=V(t);if(!r){let c;if(o&&(c=Yo[n]))return c;if(n==="hasOwnProperty")return Zo}const l=Reflect.get(t,n,ge(t)?t:s);if((Ye(n)?xi.has(n):Xo(n))||(r||he(t,"get",n),i))return l;if(ge(l)){const c=o&&Gs(n)?l:l.value;return r&&q(c)?Ps(c):c}return q(l)?r?Ps(l):Yt(l):l}}class Ci extends Ti{constructor(t=!1){super(!1,t)}set(t,n,s,r){let i=t[n];const o=V(t)&&Gs(n);if(!this._isShallow){const f=ct(i);if(!Pe(s)&&!ct(s)&&(i=$(i),s=$(s)),!o&&ge(i)&&!ge(s))return f||(i.value=s),!0}const l=o?Number(n)e,xn=e=>Reflect.getPrototypeOf(e);function rl(e,t,n){return function(...s){const r=this.__v_raw,i=$(r),o=Bt(i),l=e==="entries"||e===Symbol.iterator&&o,c=e==="keys"&&o,f=r[e](...s),u=n?Cs:t?Kt:Me;return!t&&he(i,"iterate",c?Ts:Ct),de(Object.create(f),{next(){const{value:h,done:g}=f.next();return g?{value:h,done:g}:{value:l?[u(h[0]),u(h[1])]:u(h),done:g}}})}}function Tn(e){return function(...t){return e==="delete"?!1:e==="clear"?void 0:this}}function il(e,t){const n={get(r){const i=this.__v_raw,o=$(i),l=$(r);e||(ze(r,l)&&he(o,"get",r),he(o,"get",l));const{has:c}=xn(o),f=t?Cs:e?Kt:Me;if(c.call(o,r))return f(i.get(r));if(c.call(o,l))return f(i.get(l));i!==o&&i.get(r)},get size(){const r=this.__v_raw;return!e&&he($(r),"iterate",Ct),r.size},has(r){const i=this.__v_raw,o=$(i),l=$(r);return e||(ze(r,l)&&he(o,"has",r),he(o,"has",l)),r===l?i.has(r):i.has(r)||i.has(l)},forEach(r,i){const o=this,l=o.__v_raw,c=$(l),f=t?Cs:e?Kt:Me;return!e&&he(c,"iterate",Ct),l.forEach((u,h)=>r.call(i,f(u),f(h),o))}};return de(n,e?{add:Tn("add"),set:Tn("set"),delete:Tn("delete"),clear:Tn("clear")}:{add(r){const i=$(this),o=xn(i),l=$(r),c=!t&&!Pe(r)&&!ct(r)?l:r;return o.has.call(i,c)||ze(r,c)&&o.has.call(i,r)||ze(l,c)&&o.has.call(i,l)||(i.add(c),st(i,"add",c,c)),this},set(r,i){!t&&!Pe(i)&&!ct(i)&&(i=$(i));const o=$(this),{has:l,get:c}=xn(o);let f=l.call(o,r);f||(r=$(r),f=l.call(o,r));const u=c.call(o,r);return o.set(r,i),f?ze(i,u)&&st(o,"set",r,i):st(o,"add",r,i),this},delete(r){const i=$(this),{has:o,get:l}=xn(i);let c=o.call(i,r);c||(r=$(r),c=o.call(i,r)),l&&l.call(i,r);const f=i.delete(r);return c&&st(i,"delete",r,void 0),f},clear(){const r=$(this),i=r.size!==0,o=r.clear();return i&&st(r,"clear",void 0,void 0),o}}),["keys","values","entries",Symbol.iterator].forEach(r=>{n[r]=rl(r,e,t)}),n}function Ys(e,t){const n=il(e,t);return(s,r,i)=>r==="__v_isReactive"?!e:r==="__v_isReadonly"?e:r==="__v_raw"?s:Reflect.get(W(n,r)&&r in s?n:s,r,i)}const ol={get:Ys(!1,!1)},ll={get:Ys(!1,!0)},cl={get:Ys(!0,!1)};const Pi=new WeakMap,Oi=new WeakMap,Ii=new WeakMap,al=new WeakMap;function ul(e){switch(e){case"Object":case"Array":return 1;case"Map":case"Set":case"WeakMap":case"WeakSet":return 2;default:return 0}}function Yt(e){return ct(e)?e:Qs(e,!1,tl,ol,Pi)}function Ni(e){return Qs(e,!1,sl,ll,Oi)}function Ps(e){return Qs(e,!0,nl,cl,Ii)}function Qs(e,t,n,s,r){if(!q(e)||e.__v_raw&&!(t&&e.__v_isReactive)||e.__v_skip||!Object.isExtensible(e))return e;const i=r.get(e);if(i)return i;const o=ul(Vo(e));if(o===0)return e;const l=new Proxy(e,o===2?s:n);return r.set(e,l),l}function Pt(e){return ct(e)?Pt(e.__v_raw):!!(e&&e.__v_isReactive)}function ct(e){return!!(e&&e.__v_isReadonly)}function Pe(e){return!!(e&&e.__v_isShallow)}function Xs(e){return e?!!e.__v_raw:!1}function $(e){const t=e&&e.__v_raw;return t?$(t):e}function fl(e){return!W(e,"__v_skip")&&Object.isExtensible(e)&&pi(e,"__v_skip",!0),e}const Me=e=>q(e)?Yt(e):e,Kt=e=>q(e)?Ps(e):e;function ge(e){return e?e.__v_isRef===!0:!1}function dl(e){return Mi(e,!1)}function hl(e){return Mi(e,!0)}function Mi(e,t){return ge(e)?e:new pl(e,t)}class pl{constructor(t,n){this.dep=new Js,this.__v_isRef=!0,this.__v_isShallow=!1,this._rawValue=n?t:$(t),this._value=n?t:Me(t),this.__v_isShallow=n}get value(){return this.dep.track(),this._value}set value(t){const n=this._rawValue,s=this.__v_isShallow||Pe(t)||ct(t);t=s?t:$(t),ze(t,n)&&(this._rawValue=t,this._value=s?t:Me(t),this.dep.trigger())}}function ae(e){return ge(e)?e.value:e}const gl={get:(e,t,n)=>t==="__v_raw"?e:ae(Reflect.get(e,t,n)),set:(e,t,n,s)=>{const r=e[t];return ge(r)&&!ge(n)?(r.value=n,!0):Reflect.set(e,t,n,s)}};function Di(e){return Pt(e)?e:new Proxy(e,gl)}class ml{constructor(t,n,s){this.fn=t,this.setter=n,this._value=void 0,this.dep=new Js(this),this.__v_isRef=!0,this.deps=void 0,this.depsTail=void 0,this.flags=16,this.globalVersion=gn-1,this.next=void 0,this.effect=this,this.__v_isReadonly=!n,this.isSSR=s}notify(){if(this.flags|=16,!(this.flags&8)&&ee!==this)return bi(this,!0),!0}get value(){const t=this.dep.track();return Si(this),t&&(t.version=this.dep.version),this._value}set value(t){this.setter&&this.setter(t)}}function _l(e,t,n=!1){let s,r;return B(e)?s=e:(s=e.get,r=e.set),new ml(s,r,n)}const Cn={},Vn=new WeakMap;let xt;function yl(e,t=!1,n=xt){if(n){let s=Vn.get(n);s||Vn.set(n,s=[]),s.push(e)}}function vl(e,t,n=X){const{immediate:s,deep:r,once:i,scheduler:o,augmentJob:l,call:c}=n,f=O=>r?O:Pe(O)||r===!1||r===0?rt(O,1):rt(O);let u,h,g,m,I=!1,R=!1;if(ge(e)?(h=()=>e.value,I=Pe(e)):Pt(e)?(h=()=>f(e),I=!0):V(e)?(R=!0,I=e.some(O=>Pt(O)||Pe(O)),h=()=>e.map(O=>{if(ge(O))return O.value;if(Pt(O))return f(O);if(B(O))return c?c(O,2):O()})):B(e)?t?h=c?()=>c(e,2):e:h=()=>{if(g){ot();try{g()}finally{lt()}}const O=xt;xt=u;try{return c?c(e,3,[m]):e(m)}finally{xt=O}}:h=Je,t&&r){const O=h,Y=r===!0?1/0:r;h=()=>rt(O(),Y)}const U=qo(),F=()=>{u.stop(),U&&U.active&&ks(U.effects,u)};if(i&&t){const O=t;t=(...Y)=>{const oe=O(...Y);return F(),oe}}let C=R?new Array(e.length).fill(Cn):Cn;const N=O=>{if(!(!(u.flags&1)||!u.dirty&&!O))if(t){const Y=u.run();if(O||r||I||(R?Y.some((oe,te)=>ze(oe,C[te])):ze(Y,C))){g&&g();const oe=xt;xt=u;try{const te=[Y,C===Cn?void 0:R&&C[0]===Cn?[]:C,m];C=Y,c?c(t,3,te):t(...te)}finally{xt=oe}}}else u.run()};return l&&l(N),u=new yi(h),u.scheduler=o?()=>o(N,!1):N,m=O=>yl(O,!1,u),g=u.onStop=()=>{const O=Vn.get(u);if(O){if(c)c(O,4);else for(const Y of O)Y();Vn.delete(u)}},t?s?N(!0):C=u.run():o?o(N.bind(null,!0),!0):u.run(),F.pause=u.pause.bind(u),F.resume=u.resume.bind(u),F.stop=F,F}function rt(e,t=1/0,n){if(t<=0||!q(e)||e.__v_skip||(n=n||new Map,(n.get(e)||0)>=t))return e;if(n.set(e,t),t--,ge(e))rt(e.value,t,n);else if(V(e))for(let s=0;s{rt(s,t,n)});else if(hi(e)){for(const s in e)rt(e[s],t,n);for(const s of Object.getOwnPropertySymbols(e))Object.prototype.propertyIsEnumerable.call(e,s)&&rt(e[s],t,n)}return e}/** * @vue/runtime-core v3.5.41 * (c) 2018-present Yuxi (Evan) You and Vue contributors * @license MIT @@ -79,4 +79,4 @@ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/Login-Dk-IRHf2. * * This source code is licensed under the ISC license. * See the LICENSE file in the root directory of this source tree. - */const Eu=No("settings",[["path",{d:"M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915",key:"1i5ecw"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]]),Bs="st_token";function Mo(){return localStorage.getItem(Bs)}function ws(e){e?localStorage.setItem(Bs,e):localStorage.removeItem(Bs)}async function ee(e,t,n,s=!1){const r={},i=Mo();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 Ss={login:(e,t)=>ee("POST","/api/auth/login",{username:e,password:t}),me:()=>ee("GET","/api/auth/me"),setup:e=>ee("POST","/api/auth/setup",e),updateProfile:e=>ee("PATCH","/api/auth/profile",e),adminCreateUser:e=>ee("POST","/api/admin/users",e),adminListUsers:()=>ee("GET","/api/admin/users"),adminUpdateUser:(e,t)=>ee("PUT",`/api/admin/users/${e}`,t),createGroup:e=>ee("POST","/api/groups",e,!0),listGroups:()=>ee("GET","/api/groups"),getGroup:e=>ee("GET",`/api/groups/${e}`),deleteGroup:e=>ee("DELETE",`/api/groups/${e}`),analyzeGroup:(e,t={})=>ee("POST",`/api/groups/${e}/analyze${t.append?"?append=true":""}`),listPersonas:e=>ee("GET",`/api/groups/${e}/personas`),getPersona:(e,t)=>ee("GET",`/api/groups/${e}/personas/${t}`),updatePersona:(e,t,n)=>ee("PUT",`/api/groups/${e}/personas/${t}`,n),chatStart:(e,t,n,s)=>ee("POST",`/api/chat/${e}/personas/${t}/chat/start`,{scenario:n,locale:s}),chatResume:(e,t)=>ee("GET",`/api/chat/${e}/personas/${t}/chat/resume`),chatSend:(e,t,n)=>ee("POST",`/api/chat/${e}/personas/${t}/chat/send`,{text:n}),chatFinish:(e,t)=>ee("POST",`/api/chat/${e}/personas/${t}/chat/finish`),mySessions:()=>ee("GET","/api/chat/sessions"),myBoard:()=>ee("GET","/api/me/board"),weakAreas:()=>ee("GET","/api/me/weak-areas"),myPersonas:()=>ee("GET","/api/me/personas"),generatePersona:e=>ee("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 ee("GET",`/api/analytics${n?`?${n}`:""}`)}},Ce=Yt({user:null,token:Mo(),mustSetup:!1,get role(){return this.user?this.user.role:null},get isAdmin(){return this.role==="admin"||this.role==="super_admin"},get isSuperAdmin(){return this.role==="super_admin"},async load(){var e;if(!this.token)return null;try{const t=await Ss.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,ws(null),null}},async login(e,t){const n=await Ss.login(e,t);return this.token=n.token,ws(n.token),this.user=n.user,this.mustSetup=!!n.must_setup,n.user},async finishSetup(e,t,n=!1){const s=await Ss.setup({username:this.user.username||this.user.id,email:e,password:t,accepted_terms:n});return this.user=s.user,this.mustSetup=!1,s.user},logout(){this.user=null,this.token=null,this.mustSetup=!1,ws(null)}}),As={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",guideTitle:"How to use / คู่มือใช้งาน",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",chooseScenario:"Choose a scenario",chatGuideTitle:"How to practice",chatGuideText:'You are playing the salesperson. Chat with this customer and try to close the sale. Ask about their needs, solve their pain, and handle their objections. When you are done, press "Finish & get result" to see your score and coaching.',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:"เลือกบุคคลต้นแบบเพื่อฝึก",chooseScenario:"เลือกสถานการณ์",chatGuideTitle:"วิธีฝึก",chatGuideText:'คุณรับบทเป็นพนักงานขาย พูดคุยกับลูกค้าคนนี้เพื่อพยายามปิดการขายให้ได้ สอบถามความต้องการ แก้ไขปัญหาของลูกค้า และรับมือกับข้อโต้แย้ง เมื่อพอใจแล้วกด "สรุปผล" เพื่อดูคะแนนและข้อเสนอแนะ',chat:"แชท",start:"เริ่มต้น",send:"ส่ง",finish:"สรุปผล",debrief:"ผลลัพธ์และข้อเสนอแนะ",won:"ปิดการขายได้",lost:"ปิดการขายไม่ได้",notTried:"ยังไม่ได้ฝึก",score:"คะแนน",pain:"ปัญหาของลูกค้า",why:"เหตุผล",reveal:"รายละเอียดบุคคลต้นแบบที่ถูกซ่อนไว้",generatePersona:"สร้างบุคคลต้นแบบเพิ่มเติม",weakAreas:"จุดอ่อนที่ควรฝึกเพิ่มเติม",mySessions:"ประวัติการฝึกของฉัน",openSaleTask:"ลูกค้ายังไม่ได้ทักเข้ามา คุณต้องเป็นฝ่ายเริ่มบทสนทนาการขายเอง",sellerInitiated:"คุณต้องเริ่มการขายในเชิงรุก",customerInitiated:"ลูกค้าจะติดต่อเข้ามาก่อน"}},Ke=Yt({locale:localStorage.getItem("locale")||"th",t(e){return As[this.locale]&&As[this.locale][e]||As.en[e]||e},set(e){this.locale=e,localStorage.setItem("locale",e)}}),wu=(e,t)=>{const n=e.__vccOpts||e;for(const[s,r]of t)n[s]=r;return n},Su={class:"app"},Au={key:0,class:"topnav"},Ru={class:"tabs"},xu={class:"nav-right"},Tu={class:"txt"},Cu={class:"main"},Pu={__name:"App",setup(e){const t=pu();function n(){Ke.set(Ke.locale==="th"?"en":"th")}function s(){Ce.logout(),t.push("/login")}return Wi(()=>{Ce.token&&!Ce.user&&Ce.load()}),(r,i)=>{const o=_r("router-link"),l=_r("router-view");return on(),Tr("div",Su,[ae(Ce).user?(on(),Tr("nav",Au,[ie(o,{to:"/",class:"brand"},{default:Vt(()=>[Ft(Rt(ae(Ke).t("app")),1)]),_:1}),mt("div",Ru,[ae(Ce).isAdmin?(on(),Ds(o,{key:0,to:"/",class:jt(["tab",{active:r.$route.path==="/"}])},{default:Vt(()=>[Ft(Rt(ae(Ke).t("adminOverview")),1)]),_:1},8,["class"])):Cr("",!0),ie(o,{to:"/my/board",class:jt(["tab",{active:r.$route.path==="/my/board"}])},{default:Vt(()=>[Ft(Rt(ae(Ke).t("myDashboard")),1)]),_:1},8,["class"]),ie(o,{to:"/training",class:jt(["tab",{active:r.$route.path==="/training"}])},{default:Vt(()=>[Ft(Rt(ae(Ke).t("training")),1)]),_:1},8,["class"])]),mt("div",xu,[mt("button",{onClick:n,class:"lang"},Rt(ae(Ke).locale==="th"?"EN":"TH"),1),ie(o,{to:"/settings",class:"icon-btn",title:ae(Ke).t("settings")},{default:Vt(()=>[ie(ae(Eu),{size:20,"stroke-width":1.8})]),_:1},8,["title"]),mt("button",{onClick:s,class:"logout-btn"},[ie(ae(bu),{size:18,"stroke-width":1.8}),i[0]||(i[0]=Ft()),mt("span",Tu,Rt(ae(Ke).t("logout")),1)])])])):Cr("",!0),mt("main",Cu,[(on(),Ds(l,{key:ae(Ke).locale}))])])}}},Ou=wu(Pu,[["__scopeId","data-v-f29a3a4f"]]),Iu="modulepreload",Nu=function(e){return"/"+e},ai={},Se=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=Nu(c),c in ai)return;ai[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":Iu,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)})},Mu=[{path:"/login",component:()=>Se(()=>import("./Login-Dk-IRHf2.js"),__vite__mapDeps([0,1])),meta:{public:!0}},{path:"/setup",component:()=>Se(()=>import("./Setup-BWzXOByZ.js"),__vite__mapDeps([2,3,4]))},{path:"/",component:()=>Se(()=>import("./Analytics-Cdjv87WO.js"),__vite__mapDeps([5,6,7,8])),meta:{admin:!0}},{path:"/my/board",component:()=>Se(()=>import("./MyBoard-DTBModgt.js"),__vite__mapDeps([9,10,11]))},{path:"/training",component:()=>Se(()=>import("./Training-6jie9iTF.js"),__vite__mapDeps([12,13,14,7,15]))},{path:"/groups/:gid/personas",component:()=>Se(()=>import("./Personas-CjtqghLF.js"),__vite__mapDeps([16,13,17,18]))},{path:"/groups/:gid/chat/:pid",component:()=>Se(()=>import("./Chat-Dr4nNqcU.js"),__vite__mapDeps([19,13,17,20]))},{path:"/settings",component:()=>Se(()=>import("./Settings-sM2KFjew.js"),__vite__mapDeps([21,3,22]))},{path:"/guide",component:()=>Se(()=>import("./Guide-fA0ESKf-.js"),__vite__mapDeps([23,14,10,13]))},{path:"/admin/new-group",component:()=>Se(()=>import("./GroupBuilder-Odxme5l4.js"),__vite__mapDeps([24,17,25])),meta:{admin:!0}},{path:"/admin/groups/:gid/edit",component:()=>Se(()=>import("./GroupEdit-Bzhg1xqU.js"),__vite__mapDeps([26,6,27])),meta:{admin:!0}},{path:"/admin/users",component:()=>Se(()=>import("./AdminUsers-CnHWEscS.js"),__vite__mapDeps([28,6,29])),meta:{admin:!0}},{path:"/admin/analytics",component:()=>Se(()=>import("./Analytics-Cdjv87WO.js"),__vite__mapDeps([5,6,7,8])),meta:{admin:!0}}],Do=hu({history:$a(),routes:Mu});Do.beforeEach(async e=>e.meta.public?!0:(Ce.user||await Ce.load(),Ce.user?Ce.mustSetup&&e.path!=="/setup"?{path:"/setup"}:e.path==="/"&&!Ce.isAdmin?{path:"/my/board"}:e.meta.admin&&!Ce.isAdmin?{path:"/my/board"}:!0:{path:"/login",query:{redirect:e.fullPath}}));ia(Ou).use(Do).mount("#app");export{Fu as A,Oe as B,jt as C,Uu as D,Zs as E,tt as F,Vu as G,Xc as H,Mn as I,Yt as J,Eu as S,wu as _,Tr as a,mt as b,No as c,Bu as d,Hu as e,Ds as f,Cr as g,Ce as h,Ke as i,pu as j,ju as k,ie as l,Ft as m,Yc as n,on as o,Wi as p,Vt as q,dl as r,Ks as s,Rt as t,ae as u,jr as v,Du as w,Lu as x,Ss as y,_r as z}; + */const Eu=No("settings",[["path",{d:"M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915",key:"1i5ecw"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]]),Bs="st_token";function Mo(){return localStorage.getItem(Bs)}function ws(e){e?localStorage.setItem(Bs,e):localStorage.removeItem(Bs)}async function Z(e,t,n,s=!1){const r={},i=Mo();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 Ss={login:(e,t)=>Z("POST","/api/auth/login",{username:e,password:t}),me:()=>Z("GET","/api/auth/me"),setup:e=>Z("POST","/api/auth/setup",e),updateProfile:e=>Z("PATCH","/api/auth/profile",e),adminCreateUser:e=>Z("POST","/api/admin/users",e),adminListUsers:()=>Z("GET","/api/admin/users"),adminUpdateUser:(e,t)=>Z("PUT",`/api/admin/users/${e}`,t),createGroup:e=>Z("POST","/api/groups",e,!0),listGroups:()=>Z("GET","/api/groups"),getGroup:e=>Z("GET",`/api/groups/${e}`),deleteGroup:e=>Z("DELETE",`/api/groups/${e}`),analyzeGroup:(e,t={})=>Z("POST",`/api/groups/${e}/analyze${t.append?"?append=true":""}`),listPersonas:e=>Z("GET",`/api/groups/${e}/personas`),getPersona:(e,t)=>Z("GET",`/api/groups/${e}/personas/${t}`),createPersonaVariant:(e,t)=>Z("POST",`/api/groups/${e}/personas/${t}/variant`),updatePersona:(e,t,n)=>Z("PUT",`/api/groups/${e}/personas/${t}`,n),chatStart:(e,t,n,s)=>Z("POST",`/api/chat/${e}/personas/${t}/chat/start`,{scenario:n,locale:s}),chatResume:(e,t)=>Z("GET",`/api/chat/${e}/personas/${t}/chat/resume`),chatSend:(e,t,n)=>Z("POST",`/api/chat/${e}/personas/${t}/chat/send`,{text:n}),chatFinish:(e,t)=>Z("POST",`/api/chat/${e}/personas/${t}/chat/finish`),mySessions:()=>Z("GET","/api/chat/sessions"),myBoard:()=>Z("GET","/api/me/board"),weakAreas:()=>Z("GET","/api/me/weak-areas"),myPersonas:()=>Z("GET","/api/me/personas"),generatePersona:e=>Z("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 Z("GET",`/api/analytics${n?`?${n}`:""}`)}},Ce=Yt({user:null,token:Mo(),mustSetup:!1,get role(){return this.user?this.user.role:null},get isAdmin(){return this.role==="admin"||this.role==="super_admin"},get isSuperAdmin(){return this.role==="super_admin"},async load(){var e;if(!this.token)return null;try{const t=await Ss.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,ws(null),null}},async login(e,t){const n=await Ss.login(e,t);return this.token=n.token,ws(n.token),this.user=n.user,this.mustSetup=!!n.must_setup,n.user},async finishSetup(e,t,n=!1){const s=await Ss.setup({username:this.user.username||this.user.id,email:e,password:t,accepted_terms:n});return this.user=s.user,this.mustSetup=!1,s.user},logout(){this.user=null,this.token=null,this.mustSetup=!1,ws(null)}}),As={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",guideTitle:"How to use / คู่มือใช้งาน",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",chooseScenario:"Choose a scenario",chatGuideTitle:"How to practice",chatGuideText:'You are playing the salesperson. Chat with this customer and try to close the sale. Ask about their needs, solve their pain, and handle their objections. When you are done, press "Finish & get result" to see your score and coaching.',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:"เลือกบุคคลต้นแบบเพื่อฝึก",chooseScenario:"เลือกสถานการณ์",chatGuideTitle:"วิธีฝึก",chatGuideText:'คุณรับบทเป็นพนักงานขาย พูดคุยกับลูกค้าคนนี้เพื่อพยายามปิดการขายให้ได้ สอบถามความต้องการ แก้ไขปัญหาของลูกค้า และรับมือกับข้อโต้แย้ง เมื่อพอใจแล้วกด "สรุปผล" เพื่อดูคะแนนและข้อเสนอแนะ',chat:"แชท",start:"เริ่มต้น",send:"ส่ง",finish:"สรุปผล",debrief:"ผลลัพธ์และข้อเสนอแนะ",won:"ปิดการขายได้",lost:"ปิดการขายไม่ได้",notTried:"ยังไม่ได้ฝึก",score:"คะแนน",pain:"ปัญหาของลูกค้า",why:"เหตุผล",reveal:"รายละเอียดบุคคลต้นแบบที่ถูกซ่อนไว้",generatePersona:"สร้างบุคคลต้นแบบเพิ่มเติม",weakAreas:"จุดอ่อนที่ควรฝึกเพิ่มเติม",mySessions:"ประวัติการฝึกของฉัน",openSaleTask:"ลูกค้ายังไม่ได้ทักเข้ามา คุณต้องเป็นฝ่ายเริ่มบทสนทนาการขายเอง",sellerInitiated:"คุณต้องเริ่มการขายในเชิงรุก",customerInitiated:"ลูกค้าจะติดต่อเข้ามาก่อน"}},Ke=Yt({locale:localStorage.getItem("locale")||"th",t(e){return As[this.locale]&&As[this.locale][e]||As.en[e]||e},set(e){this.locale=e,localStorage.setItem("locale",e)}}),wu=(e,t)=>{const n=e.__vccOpts||e;for(const[s,r]of t)n[s]=r;return n},Su={class:"app"},Au={key:0,class:"topnav"},Ru={class:"tabs"},xu={class:"nav-right"},Tu={class:"txt"},Cu={class:"main"},Pu={__name:"App",setup(e){const t=pu();function n(){Ke.set(Ke.locale==="th"?"en":"th")}function s(){Ce.logout(),t.push("/login")}return Wi(()=>{Ce.token&&!Ce.user&&Ce.load()}),(r,i)=>{const o=_r("router-link"),l=_r("router-view");return on(),Tr("div",Su,[ae(Ce).user?(on(),Tr("nav",Au,[ie(o,{to:"/",class:"brand"},{default:Vt(()=>[Ft(Rt(ae(Ke).t("app")),1)]),_:1}),mt("div",Ru,[ae(Ce).isAdmin?(on(),Ds(o,{key:0,to:"/",class:jt(["tab",{active:r.$route.path==="/"}])},{default:Vt(()=>[Ft(Rt(ae(Ke).t("adminOverview")),1)]),_:1},8,["class"])):Cr("",!0),ie(o,{to:"/my/board",class:jt(["tab",{active:r.$route.path==="/my/board"}])},{default:Vt(()=>[Ft(Rt(ae(Ke).t("myDashboard")),1)]),_:1},8,["class"]),ie(o,{to:"/training",class:jt(["tab",{active:r.$route.path==="/training"}])},{default:Vt(()=>[Ft(Rt(ae(Ke).t("training")),1)]),_:1},8,["class"])]),mt("div",xu,[mt("button",{onClick:n,class:"lang"},Rt(ae(Ke).locale==="th"?"EN":"TH"),1),ie(o,{to:"/settings",class:"icon-btn",title:ae(Ke).t("settings")},{default:Vt(()=>[ie(ae(Eu),{size:20,"stroke-width":1.8})]),_:1},8,["title"]),mt("button",{onClick:s,class:"logout-btn"},[ie(ae(bu),{size:18,"stroke-width":1.8}),i[0]||(i[0]=Ft()),mt("span",Tu,Rt(ae(Ke).t("logout")),1)])])])):Cr("",!0),mt("main",Cu,[(on(),Ds(l,{key:ae(Ke).locale}))])])}}},Ou=wu(Pu,[["__scopeId","data-v-f29a3a4f"]]),Iu="modulepreload",Nu=function(e){return"/"+e},ai={},Se=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=Nu(c),c in ai)return;ai[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":Iu,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)})},Mu=[{path:"/login",component:()=>Se(()=>import("./Login-ZlvtmZHE.js"),__vite__mapDeps([0,1])),meta:{public:!0}},{path:"/setup",component:()=>Se(()=>import("./Setup-CFifwHLU.js"),__vite__mapDeps([2,3,4]))},{path:"/",component:()=>Se(()=>import("./Analytics-5UUWbKvU.js"),__vite__mapDeps([5,6,7,8])),meta:{admin:!0}},{path:"/my/board",component:()=>Se(()=>import("./MyBoard-Dc1z0Qjo.js"),__vite__mapDeps([9,10,11]))},{path:"/training",component:()=>Se(()=>import("./Training-B5ukgpN-.js"),__vite__mapDeps([12,13,14,7,15]))},{path:"/groups/:gid/personas",component:()=>Se(()=>import("./Personas-CTGLZyPW.js"),__vite__mapDeps([16,13,17,18]))},{path:"/groups/:gid/chat/:pid",component:()=>Se(()=>import("./Chat-s9Pksmwi.js"),__vite__mapDeps([19,13,17,20]))},{path:"/settings",component:()=>Se(()=>import("./Settings-DTl0HJtQ.js"),__vite__mapDeps([21,3,22]))},{path:"/guide",component:()=>Se(()=>import("./Guide-CdnDfIjD.js"),__vite__mapDeps([23,14,10,13]))},{path:"/admin/new-group",component:()=>Se(()=>import("./GroupBuilder-FWDh6ofr.js"),__vite__mapDeps([24,17,25])),meta:{admin:!0}},{path:"/admin/groups/:gid/edit",component:()=>Se(()=>import("./GroupEdit-BOSQCzGb.js"),__vite__mapDeps([26,6,27])),meta:{admin:!0}},{path:"/admin/users",component:()=>Se(()=>import("./AdminUsers-BGqSvhVH.js"),__vite__mapDeps([28,6,29])),meta:{admin:!0}},{path:"/admin/analytics",component:()=>Se(()=>import("./Analytics-5UUWbKvU.js"),__vite__mapDeps([5,6,7,8])),meta:{admin:!0}}],Do=hu({history:$a(),routes:Mu});Do.beforeEach(async e=>e.meta.public?!0:(Ce.user||await Ce.load(),Ce.user?Ce.mustSetup&&e.path!=="/setup"?{path:"/setup"}:e.path==="/"&&!Ce.isAdmin?{path:"/my/board"}:e.meta.admin&&!Ce.isAdmin?{path:"/my/board"}:!0:{path:"/login",query:{redirect:e.fullPath}}));ia(Ou).use(Do).mount("#app");export{Fu as A,Oe as B,jt as C,Uu as D,Zs as E,tt as F,Vu as G,Xc as H,Mn as I,Yt as J,Eu as S,wu as _,Tr as a,mt as b,No as c,Bu as d,Hu as e,Ds as f,Cr as g,Ce as h,Ke as i,pu as j,ju as k,ie as l,Ft as m,Yc as n,on as o,Wi as p,Vt as q,dl as r,Ks as s,Rt as t,ae as u,jr as v,Du as w,Lu as x,Ss as y,_r as z}; diff --git a/frontend/dist/assets/layout-dashboard-DplDGQ9R.js b/frontend/dist/assets/layout-dashboard-qMD4csbw.js similarity index 91% rename from frontend/dist/assets/layout-dashboard-DplDGQ9R.js rename to frontend/dist/assets/layout-dashboard-qMD4csbw.js index 45e69a8..2be2a7f 100644 --- a/frontend/dist/assets/layout-dashboard-DplDGQ9R.js +++ b/frontend/dist/assets/layout-dashboard-qMD4csbw.js @@ -1,4 +1,4 @@ -import{c as t}from"./index-yErsUbD6.js";/** +import{c as t}from"./index-C--0e2U-.js";/** * @license lucide-vue-next v1.0.0 - ISC * * This source code is licensed under the ISC license. diff --git a/frontend/dist/assets/lock-CCBV2bwv.js b/frontend/dist/assets/lock-CdhbyMuc.js similarity index 88% rename from frontend/dist/assets/lock-CCBV2bwv.js rename to frontend/dist/assets/lock-CdhbyMuc.js index 711a29f..dcdd2e4 100644 --- a/frontend/dist/assets/lock-CCBV2bwv.js +++ b/frontend/dist/assets/lock-CdhbyMuc.js @@ -1,4 +1,4 @@ -import{c as e}from"./index-yErsUbD6.js";/** +import{c as e}from"./index-C--0e2U-.js";/** * @license lucide-vue-next v1.0.0 - ISC * * This source code is licensed under the ISC license. diff --git a/frontend/dist/assets/plus-Y1qXSgej.js b/frontend/dist/assets/plus-DQOnWKR_.js similarity index 86% rename from frontend/dist/assets/plus-Y1qXSgej.js rename to frontend/dist/assets/plus-DQOnWKR_.js index 0094a36..9dd08ad 100644 --- a/frontend/dist/assets/plus-Y1qXSgej.js +++ b/frontend/dist/assets/plus-DQOnWKR_.js @@ -1,4 +1,4 @@ -import{c as e}from"./index-yErsUbD6.js";/** +import{c as e}from"./index-C--0e2U-.js";/** * @license lucide-vue-next v1.0.0 - ISC * * This source code is licensed under the ISC license. diff --git a/frontend/dist/assets/target-DmESUw9c.js b/frontend/dist/assets/target-dGrJgR_B.js similarity index 90% rename from frontend/dist/assets/target-DmESUw9c.js rename to frontend/dist/assets/target-dGrJgR_B.js index 5709f8b..cedc23c 100644 --- a/frontend/dist/assets/target-DmESUw9c.js +++ b/frontend/dist/assets/target-dGrJgR_B.js @@ -1,4 +1,4 @@ -import{c}from"./index-yErsUbD6.js";/** +import{c}from"./index-C--0e2U-.js";/** * @license lucide-vue-next v1.0.0 - ISC * * This source code is licensed under the ISC license. diff --git a/frontend/dist/assets/users-BK4yWB6N.js b/frontend/dist/assets/users-d_q-MTMu.js similarity index 90% rename from frontend/dist/assets/users-BK4yWB6N.js rename to frontend/dist/assets/users-d_q-MTMu.js index 57d7671..0fd772e 100644 --- a/frontend/dist/assets/users-BK4yWB6N.js +++ b/frontend/dist/assets/users-d_q-MTMu.js @@ -1,4 +1,4 @@ -import{c as e}from"./index-yErsUbD6.js";/** +import{c as e}from"./index-C--0e2U-.js";/** * @license lucide-vue-next v1.0.0 - ISC * * This source code is licensed under the ISC license. diff --git a/frontend/dist/index.html b/frontend/dist/index.html index d753a1a..762b1c2 100644 --- a/frontend/dist/index.html +++ b/frontend/dist/index.html @@ -4,7 +4,7 @@ Sales Trainer - + diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js index 10aaac8..6323ec9 100644 --- a/frontend/src/api/index.js +++ b/frontend/src/api/index.js @@ -47,6 +47,7 @@ export const api = { analyzeGroup: (id, opts = {}) => request('POST', `/api/groups/${id}/analyze${opts.append ? '?append=true' : ''}`), listPersonas: (gid) => request('GET', `/api/groups/${gid}/personas`), getPersona: (gid, pid) => request('GET', `/api/groups/${gid}/personas/${pid}`), + createPersonaVariant: (gid, pid) => request('POST', `/api/groups/${gid}/personas/${pid}/variant`), updatePersona: (gid, pid, b) => request('PUT', `/api/groups/${gid}/personas/${pid}`, b), chatStart: (gid, pid, scenario, locale) => request('POST', `/api/chat/${gid}/personas/${pid}/chat/start`, { scenario, locale }), chatResume: (gid, pid) => request('GET', `/api/chat/${gid}/personas/${pid}/chat/resume`), diff --git a/frontend/src/views/Personas.vue b/frontend/src/views/Personas.vue index 50b494f..f4ded39 100644 --- a/frontend/src/views/Personas.vue +++ b/frontend/src/views/Personas.vue @@ -48,7 +48,12 @@ -
✓ {{ i18n.t('trained') }} ({{ outcomeLabel(p.my_outcome) }})
+ @@ -76,7 +81,19 @@ async function load() { function byTier(t) { return personas.value.filter((p) => p.tier === t) } function tierLabel(t) { return i18n.t(t === 'A' ? 'tierA' : t === 'B' ? 'tierB' : 'tierC') } function outcomeLabel(o) { - return o === 'won' ? i18n.t('won') : o === 'lost' ? i18n.t('lost') : i18n.t('notTried') + return o === 'won' ? i18n.t('won') : o === 'lost' ? i18n.t('lost') : o === 'not_tried' ? i18n.t('notTried') : o || '-' +} + +async function makeVariant(p) { + p._busy = true + try { + await api.createPersonaVariant(gid, p.id) + await load() // reload so the new variant shows up in the list + } catch (e) { + alert(e.message) + } finally { + p._busy = false + } } onMounted(load)