Files
tehran_taj/apps/user-app-v2/dist/assets/ProfileView-P18v07q9.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
2.6 KiB
JavaScript

import{d as y,E as T,o as b,p as k,c as l,l as i,s as V,g as p,v as P,f as n,b as e,I as d,t as a,e as r,i as g,u as B,h as f,x as C,_ as D}from"./index-D7u32dbn.js";import{P as N}from"./PageBar-CihrRnwd.js";import{S as h}from"./SectionHead-CZ7O6-xd.js";const x={class:"prof"},R={class:"prof__identity"},F={class:"prof__avatar","aria-hidden":"true"},M={class:"prof__name"},w={key:0,class:"prof__mobile"},O={key:0,class:"prof__block"},U={class:"prof__specs"},z={class:"prof__spec"},L={class:"prof__spec"},A={class:"prof__spec"},W={class:"prof__spec"},H={key:1,class:"prof__empty"},$=y({__name:"ProfileView",setup(j){const _={UNVERIFIED:"احراز نشده",STEP_ONE_SUBMITTED:"مرحله اول ثبت شده",STEP_TWO_SUBMITTED:"مرحله دوم ثبت شده",VERIFIED:"تایید شده"},v=T(),s=p(null),u=p(!1),m=f(()=>{var t;return((t=s.value)==null?void 0:t.verificationStep)==="VERIFIED"}),E=f(()=>{var o;const t=(o=s.value)==null?void 0:o.verificationStep;return!!t&&t!=="VERIFIED"&&t!=="STEP_TWO_SUBMITTED"}),S=C();return b(async()=>{if(v.isLoggedIn){u.value=!0;try{s.value=await k.getMe()}finally{u.value=!1}}}),(t,o)=>{const I=P("container");return n(),l("div",x,[i(N,{title:"اطلاعات کاربری","back-to":"userPage::hasSubRoute"}),i(I,{class:"prof__body"},{default:V(()=>{var c;return[e("section",R,[e("div",F,[i(d,{icon:"vuesax-linear:user",size:"30"})]),e("h2",M,a(((c=s.value)==null?void 0:c.fullName)??"—"),1),s.value?(n(),l("p",w,a(s.value.mobile),1)):r("",!0),s.value?(n(),l("span",{key:1,class:g(["prof__seal",m.value?"is-ok":"is-pending"])},a(_[s.value.verificationStep]??s.value.verificationStep),3)):r("",!0)]),s.value?(n(),l("section",O,[i(h,{title:"مشخصات",subtitle:"اطلاعات ثبت‌شده حساب شما"}),e("dl",U,[e("div",z,[o[1]||(o[1]=e("dt",null,"نام و نام خانوادگی",-1)),e("dd",null,a(s.value.fullName),1)]),e("div",L,[o[2]||(o[2]=e("dt",null,"تلفن همراه",-1)),e("dd",null,a(s.value.mobile),1)]),e("div",A,[o[3]||(o[3]=e("dt",null,"کد ملی",-1)),e("dd",null,a(s.value.nationalCode),1)]),e("div",W,[o[4]||(o[4]=e("dt",null,"وضعیت احراز هویت",-1)),e("dd",null,a(_[s.value.verificationStep]??s.value.verificationStep),1)])])])):u.value?r("",!0):(n(),l("section",H,[i(d,{icon:"vuesax-linear:user",size:"26"}),o[5]||(o[5]=e("p",null,"اطلاعات حساب در دسترس نیست.",-1))])),E.value?(n(),l("button",{key:2,type:"button",class:"prof__complete",onClick:o[0]||(o[0]=q=>B(S).push({name:"completeProfile"}))}," تکمیل پروفایل ")):r("",!0)]}),_:1})])}}}),Q=D($,[["__scopeId","data-v-33e6f62c"]]);export{Q as default};