Files
tehran_tala/apps/user-app-v2/dist/assets/ChildOrdersView-cR_RyD4X.js
T
s.esmaeiliandClaude Opus 5 5ad1083aee parity(apps+api): complete_profile in both apps [ref: henza_server Major/CustomerController::complete]
Ports "تکمیل پروفایل" end to end (D22).

API
- POST customer/me/complete-profile — three required document ids, the
  customer taken from the token, verification step set to the reference's
  LIVE value (approved outright; its `= 1` line is commented out at :83 in
  favour of `= 2` at :85). Both SMS messages byte-identical and non-blocking
  per D20.
- POST customer/me/documents — the reference let the app upload through the
  same file/create the admin used, inside its auth:api-customer group
  (routes/api.php:95); the target's copy is admin-guarded, so the page could
  not have uploaded at all. Reuses AdminUploadsService unchanged, so both
  paths share one size limit, MIME whitelist and naming scheme (UPL-01).
- PROFILE_ADMIN_MOBILES replaces the reference's four hardcoded personal
  numbers; blank means nobody is notified and the upload still succeeds.

Three reference behaviours deliberately NOT ported, all in ISSUES.md:
- SEC-14: `$customer->update($request->all())` mass-assigned the whole request
  body, letting the app write its own credit limit, making charge, gold debt,
  active flag or mobile. Replaced with a three-field whitelist.
- SEC-15: four real personal mobiles hardcoded in the source.
- APP-03: refresh()'s unterminated setInterval page reload.

Apps (both, template+script byte-identical, per-app styling only)
- CompleteProfileView + SingleImageUploader
- route /complete_profile, redirecting home once the documents are in, as the
  reference's guard did (router/index.ts:266)
- the entry point on the profile screen, shown only while they are missing
  (profile.vue:96-102)

Also (D23): JWT_CUSTOMER_SECRET now warns loudly at boot when unset. It falls
back to JWT_SECRET, which signs app and admin tokens with the same key and
leaves the `typ` check as the only barrier — and an expert's app token carries
their AdminUser id in `sub`. Warn rather than refuse to boot (D19, lowest
risk); DELIVERY.md lists it as the first pre-release step (REL-03).

Verified: build 5/5 · jest 45/45 · complete-profile 38/38 (new) ·
expert login 36/36 · apps smoke 43/43 · admin smoke 43/43 ·
B2B scan 34 ok/0 broken · typecheck clean on all four apps.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 01:42:07 +03:30

2 lines
5.1 KiB
JavaScript

import{d as R,o as U,a as $,c as r,l as a,s as f,u as N,g as l,p as j,f as d,b as e,F as P,r as M,e as y,I,t as n,v as T,D as A,_ as L}from"./index-D7u32dbn.js";import{P as q}from"./PageBar-CihrRnwd.js";import{a as G}from"./Spinner.vue_vue_type_style_index_0_lang-Ce4r_sA4.js";import{S as H}from"./SearchInput-CPHlMOl1.js";import{j as J}from"./filters-CLL9nGZ2.js";import{D as K}from"./index-CGMkzVe8.js";import{P as Q}from"./index-B7hk2Rd_.js";import"./_commonjsHelpers-Cpj98o6Y.js";import"./classCallCheck-BIPEroH2.js";const W={class:"cho"},X={class:"cho__barExtra"},Y={class:"cho__list"},Z=["onClick"],ee={class:"cho__top"},se={class:"cho__left"},te={class:"cho__num"},oe={class:"cho__meta"},ne={class:"cho__strong"},le={class:"cho__right"},ae={class:"cho__meta"},ie={class:"cho__strong"},re={class:"cho__bottom"},de={class:"cho__customer"},ue={key:0,class:"cho__more"},ce={key:1,class:"cho__empty"},_e={key:2,class:"cho__empty"},ve={key:0,class:"cho__detail"},he={class:"cho__detailTitle"},fe={class:"cho__rows"},me={class:"cho__row"},pe={class:"cho__row"},ge={dir:"ltr"},ye={class:"cho__row"},be={dir:"ltr"},we={class:"cho__row"},ke={class:"cho__row"},xe=R({__name:"ChildOrdersView",setup(Ce){const u=l([]),c=l(!1),b=l(!1),m=l(!1),w=l(null),k=l(1),p=l(!0),g=l(!1),i=l(null);function O(t){const s=Number(t??0);return Number.isFinite(s)?s.toFixed(3):"0.000"}async function x(){if(!(c.value||!p.value)){c.value=!0,m.value=!1;try{const t=await j.getExpertChildOrders(k.value,w.value),s=t.rows??[];u.value=[...u.value,...s],s.length<(t.limit??20)?p.value=!1:k.value+=1}catch{m.value=!0,p.value=!1}finally{c.value=!1}}}function S(){u.value=[],k.value=1,p.value=!0,m.value=!1}async function C(){S(),await x()}async function B(t){w.value=t!=null&&t.trim()?t.trim():null,await C()}async function D(){await C(),b.value=!1}function F(t){i.value=t,g.value=!0}const V=l(null);let _=null;return U(async()=>{await x(),typeof IntersectionObserver<"u"&&(_=new IntersectionObserver(t=>{t.some(s=>s.isIntersecting)&&x()}),V.value&&_.observe(V.value))}),$(()=>_==null?void 0:_.disconnect()),(t,s)=>{const z=T("container");return d(),r("div",W,[a(q,{title:"سفارشات مشتریان","back-to":"userPage::hasSubRoute"},{below:f(()=>[e("div",X,[a(H,{onSearch:B,"place-holder":"جستجو"})])]),_:1}),a(G,{spinning:c.value&&!u.value.length,tip:"درحال دریافت اطلاعات"},{default:f(()=>[a(N(Q),{modelValue:b.value,"onUpdate:modelValue":s[0]||(s[0]=o=>b.value=o),onRefresh:D},{default:f(()=>[a(z,{class:"cho__body"},{default:f(()=>[u.value.length?(d(),r(P,{key:0},[e("div",Y,[(d(!0),r(P,null,M(u.value,o=>{var v,h;return d(),r("article",{key:o.id,class:"cho__card",onClick:E=>F(o)},[e("div",ee,[e("div",se,[e("div",te,[s[3]||(s[3]=e("span",{class:"cho__muted"},"سفارش :",-1)),A(" "+n(o.orderNumber),1)]),e("div",oe,[e("span",ne,n(((v=o.items)==null?void 0:v.length)??0),1),s[4]||(s[4]=e("span",{class:"cho__unit"},"آیتم",-1))])]),e("div",le,[s[6]||(s[6]=e("span",{class:"cho__status"},"تحویل مسئول فروش",-1)),e("div",ae,[e("span",ie,n(O(o.w)),1),s[5]||(s[5]=e("span",{class:"cho__unit"},"گرم",-1))])])]),s[7]||(s[7]=e("div",{class:"cho__divider"},null,-1)),e("div",re,[e("div",de," نام مشتری : "+n(((h=o.customer)==null?void 0:h.name)??"—"),1),a(I,{icon:"vuesax-linear:arrow-left-1",size:"20"})])],8,Z)}),128))]),c.value?(d(),r("div",ue,"در حال دریافت…")):y("",!0)],64)):c.value?y("",!0):(d(),r("section",ce,[a(I,{icon:"vuesax-linear:box",size:"26"}),e("p",null,n(w.value?"سفارشی با این مشخصات پیدا نشد.":"هنوز سفارشی ثبت نشده است."),1)])),m.value?(d(),r("section",_e,[a(I,{icon:"vuesax-linear:danger",size:"26"}),s[8]||(s[8]=e("p",null,"دریافت اطلاعات با خطا روبه‌رو شد.",-1)),e("button",{type:"button",class:"cho__retry",onClick:C},"تلاش دوباره")])):y("",!0),e("div",{ref_key:"sentinel",ref:V,class:"cho__sentinel"},null,512)]),_:1})]),_:1},8,["modelValue"])]),_:1},8,["spinning"]),a(N(K),{open:g.value,"onUpdate:open":s[2]||(s[2]=o=>g.value=o),placement:"bottom",height:"auto",closable:!1,"body-style":{padding:"0"}},{default:f(()=>{var o,v,h;return[i.value?(d(),r("div",ve,[e("h2",he,n(i.value.orderNumber),1),e("dl",fe,[e("div",me,[s[9]||(s[9]=e("dt",null,"نام مشتری",-1)),e("dd",null,n(((o=i.value.customer)==null?void 0:o.name)??"—"),1)]),e("div",pe,[s[10]||(s[10]=e("dt",null,"شماره تماس",-1)),e("dd",ge,n(((v=i.value.customer)==null?void 0:v.mobile)??"—"),1)]),e("div",ye,[s[11]||(s[11]=e("dt",null,"وزن کل",-1)),e("dd",be,n(O(i.value.w))+" گرم",1)]),e("div",we,[s[12]||(s[12]=e("dt",null,"تعداد آیتم‌ها",-1)),e("dd",null,n(((h=i.value.items)==null?void 0:h.length)??0),1)]),e("div",ke,[s[13]||(s[13]=e("dt",null,"تاریخ ثبت",-1)),e("dd",null,n(N(J)(i.value.createdAt)),1)]),s[14]||(s[14]=e("div",{class:"cho__row"},[e("dt",null,"وضعیت"),e("dd",null,"تحویل مسئول فروش")],-1))]),e("button",{type:"button",class:"cho__close",onClick:s[1]||(s[1]=E=>g.value=!1)},"بستن")])):y("",!0)]}),_:1},8,["open"])])}}}),ze=L(xe,[["__scopeId","data-v-b76e0ead"]]);export{ze as default};