feat(ui): 3-tab UI per spec — admin dashboard + date filter, personal dashboard, training w/ difficulty, settings profile

Tab 1 Admin overview (/): aggregate stats + DATE FILTER (?from&to), hardest personas,
admin quick actions (Users / + Add product).
Tab 2 My dashboard (/my/board): per-user win/lose/session summary (works for admin too).
Tab 3 Training (/training): product list w/ status + persona count; admins see all groups
(draft->analyze/edit), trainees see ready->personas; persona list shows DIFFICULTY (1-5
stars); admins get a Manage-personas button.
Settings (/settings): profile (name/email) via new PATCH /api/auth/profile + change
password + language.
Backend: analytics date filter; profile endpoint; /api/me/board + /api/chat/sessions
opened to any authed user.
Rebuilt frontend/dist.
This commit is contained in:
Macky
2026-08-07 22:35:49 +07:00
parent ac35be8906
commit b05907ae62
40 changed files with 319 additions and 88 deletions

View File

@@ -0,0 +1 @@
import{_ as f,k as x,p as v,c as l,a as t,t as s,u as e,i as a,e as m,w as k,s as b,F as B,n as S,r as _,x as c,o as r,y as D}from"./index-Hx407ukZ.js";const M={key:0,class:"row stat-row"},N={class:"card stat"},T={class:"card stat won"},C={class:"card stat lost"},F={class:"card stat"},V={key:1,class:"card"},j={key:2,class:"card empty-state"},z={class:"card",style:{"margin-top":"20px"}},E={style:{"margin-top":"0"}},G={__name:"MyBoard",setup(I){const o=_([]),u=_([]),p=_(!0),y=c(()=>o.value.length),g=c(()=>o.value.filter(n=>n.my_outcome==="won").length),h=c(()=>o.value.filter(n=>n.my_outcome==="lost").length),w=c(()=>o.value.filter(n=>n.my_outcome==="not_tried").length);return x(async()=>{try{o.value=(await v.myBoard()).board||[],u.value=(await v.mySessions()).sessions||[]}finally{p.value=!1}}),(n,i)=>(r(),l("div",null,[t("h2",null,"📊 "+s(e(a).t("myDashboard")),1),p.value?m("",!0):(r(),l("div",M,[t("div",N,[t("span",null,s(e(a).t("total")),1),t("strong",null,s(y.value),1)]),t("div",T,[t("span",null,s(e(a).t("won")),1),t("strong",null,s(g.value),1)]),t("div",C,[t("span",null,s(e(a).t("lost")),1),t("strong",null,s(h.value),1)]),t("div",F,[t("span",null,s(e(a).t("notTried")),1),t("strong",null,s(w.value),1)])])),p.value?(r(),l("div",V,[...i[0]||(i[0]=[t("div",{class:"skeleton",style:{height:"50px"}},null,-1)])])):o.value.length===0?(r(),l("div",j,[...i[1]||(i[1]=[t("strong",null,"No practice yet",-1),t("span",null,"Go to Training and try closing a sale with a persona.",-1)])])):m("",!0),k(t("div",z,[t("h3",E,s(e(a).t("mySessions")),1),(r(!0),l(B,null,S(u.value,d=>(r(),l("div",{key:d.id,style:{display:"flex","justify-content":"space-between",padding:"8px 0","border-bottom":"1px solid var(--border)"}},[t("span",null,s(d.persona_name),1),t("span",{class:D(["badge",d.outcome])},s(d.outcome==="won"?e(a).t("won"):e(a).t("lost")),3)]))),128))],512),[[b,u.value.length]])]))}},q=f(G,[["__scopeId","data-v-1f6ea068"]]);export{q as default};