1import{b5 as W,at as G,j as e,b6 as K,b7 as Q,b8 as X,Q as J,b9 as Z,M as V,O as j,aE as H,U as ee,aa as R,aA as z,r as h,a as se,z as N,ba as ae,bb as te,bc as re,bd as oe}from"./entry-Do74TiKF.js";import{M as n,d as x,u as v,c as ie}from"./index-DJijX_33.js";import{g as ne,M as le,u as de}from"./use-update-my-profile-Dp1ujLG8.js";import{B as T,I as B,S as ce}from"./index-BZII-Bkc.js";import{z as $,u as q,f as Y}from"./useForm-Ce-jLSnp.js";import{u as pe,h as fe,f as ue}from"./PageHeaderSlot-Br21m3sy.js";import"./chat-session-context-B4L4YnRG.js";import{u as me}from"./use-page-context-BGXeyuTT.js";import{u as ge}from"./use-logout-Hcs7AiWF.js";import{L as he}from"./log-out-Bqo2zMFP.js";import{u as xe}from"./use-mobile-D7b4MNm1.js";import{S as F}from"./skeleton-DGzORg1U.js";import{C as we}from"./circle-alert-CTUQKP2n.js";import"./with-selector-BECvcOMO.js";import"./eye-CFF0i2TW.js";import"./ChatMessageItem-1FyHwZ-1.js";import"./check-CuBV3tGh.js";import"./copy-BXCSOQ4Q.js";import"./chevron-right-DO02ttya.js";import"./mock-members-Bfilma6e.js";import"./parseISO-BJ8NA1Tw.js";import"./dumbbell-DqI5xzH3.js";import"./clock-C8UNSBRI.js";import"./chart-column-DxCyIWMA.js";import"./map-pinned-BP5Dk_Pr.js";import"./popover-B819a5UE.js";import"./zap-BImvJgYE.js";function Me(s){const a=new Map;for(const t of s){if(!W(t.role_name))continue;const i=`${t.partner_id??"portal"}:${t.role_name}`,o=a.get(i)??{key:i,roleName:t.role_name,partnerName:t.partner_name??null,locationNames:[]};t.location_id?o.locationNames&&t.location_name&&o.locationNames.push(t.location_name):o.locationNames=null,a.set(i,o)}return[...a.values()].sort((t,i)=>(t.partnerName??"").localeCompare(i.partnerName??""))}function ye(){return G({queryKey:le,queryFn:ne})}function be(){const s=ge();return e.jsx(T,{type:"button",variant:"secondary",size:"md",className:"self-start bg-bg-100 text-danger",leftIcon:e.jsx(he,{className:"size-4","aria-hidden":!0}),onClick:()=>{s()},children:e.jsx(n,{id:"portal.settings.session.logout",defaultMessage:"Log out",description:"Button that signs the user out of the portal."})})}const Pe="https://partner-api.zing.coach",S={INVALID_CURRENT_PASSWORD:"invalid_current_password",SAME_AS_CURRENT:"same_as_current",ACCOUNT_LOCKED:"account_locked"};class A extends Error{constructor(a,t){super(a),this.code=a,this.status=t,this.name="ChangePasswordError"}}async function je(s){const a=()=>K(()=>fetch(`${Pe}/api/v1/auth/change-password`,Z({method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)})));let t=await a();if(t.status===401&&await Q()==="refreshed"&&(t=await a()),t.ok){const o=await t.json().catch(()=>null);typeof(o==null?void 0:o.expires_in)=="number"&&X(o.expires_in);return}const i=await t.json().catch(()=>({}));throw new A(J(i)??String(t.status),t.status)}const E=8,O=128,b=x({currentRequired:{id:"portal.profile.password.error.currentRequired",defaultMessage:"Enter your current password.",description:"Validation error when the current password field is empty."},tooShort:{id:"portal.profile.password.error.tooShort",defaultMessage:"Use at least {min} characters.",description:"Validation error when the new password is too short. {min} is the minimum length."},tooLong:{id:"portal.profile.password.error.tooLong",defaultMessage:"Use {max} characters or fewer.",description:"Validation error when the new password is too long. {max} is the maximum length."},sameAsCurrent:{id:"portal.profile.password.error.sameAsCurrent",defaultMessage:"Choose a password different from your current one.",description:"Validation error when the new password equals the current password."},mismatch:{id:"portal.profile.password.error.mismatch",defaultMessage:"The passwords don't match.",description:"Validation error when the password confirmation differs from the new password."}}),Ne={currentPassword:"",newPassword:"",confirmPassword:""};function ve(s){return V({currentPassword:j().min(1,s.formatMessage(b.currentRequired)),newPassword:j().min(E,s.formatMessage(b.tooShort,{min:E})).max(O,s.formatMessage(b.tooLong,{max:O})),confirmPassword:j()}).superRefine((a,t)=>{a.newPassword&&a.newPassword===a.currentPassword&&t.addIssue({code:H.custom,path:["newPassword"],message:s.formatMessage(b.sameAsCurrent)}),a.confirmPassword!==a.newPassword&&t.addIssue({code:H.custom,path:["confirmPassword"],message:s.formatMessage(b.mismatch)})})}const Le=/^[a-z][a-z0-9_]*$/;function Se(){return ee({mutationFn:je,onSuccess:()=>R({entity:"password",action:"update",result:"success"}),onError:s=>R({entity:"password",action:"update",result:"failure",error_code:s instanceof A?Le.test(s.code)?s.code:String(s.status):"network"})})}const d=x({currentLabel:{id:"portal.profile.password.currentLabel",defaultMessage:"Current password",description:"Label for the current password input on the My Profile page."},newLabel:{id:"portal.profile.password.newLabel",defaultMessage:"New password",description:"Label for the new password input on the My Profile page."},newHint:{id:"portal.profile.password.newHint",defaultMessage:"At least {min} characters.",description:"Help text under the new password input. {min} is the minimum length."},confirmLabel:{id:"portal.profile.password.confirmLabel",defaultMessage:"Confirm new password",description:"Label for the new password confirmation input on the My Profile page."},submit:{id:"portal.profile.password.submit",defaultMessage:"Change password",description:"Button that changes the user's password on the My Profile page."},wrongCurrent:{id:"portal.profile.password.error.wrongCurrent",defaultMessage:"That's not your current password.",description:"Error under the current password input when the server rejects it."},sameAsCurrent:{id:"portal.profile.password.error.sameAsCurrentServer",defaultMessage:"Choose a password different from your current one.",description:"Error under the new password input when the server says it equals the current one."},changedTitle:{id:"portal.profile.password.changedTitle",defaultMessage:"Password changed",description:"Toast title after the user changes their password."},changedBody:{id:"portal.profile.password.changedBody",defaultMessage:"You're still signed in here. Your other devices have been signed out.",description:"Toast body after the user changes their password."},lockedTitle:{id:"portal.profile.password.lockedTitle",defaultMessage:"Too many attempts",description:"Toast title when the account is locked after repeated wrong passwords."},lockedBody:{id:"portal.profile.password.lockedBody",defaultMessage:"Your account is locked for a while. Try again later or reset your password.",description:"Toast body when the account is locked after repeated wrong passwords."},failedTitle:{id:"portal.profile.password.failedTitle",defaultMessage:"Couldn't change your password",description:"Toast title when changing the password fails for an unexpected reason."},failedBody:{id:"portal.profile.password.failedBody",defaultMessage:"Check your connection and try again.",description:"Toast body when changing the password fails for an unexpected reason."}}),Ce=[{name:"currentPassword",label:d.currentLabel,autoComplete:"current-password"},{name:"newPassword",label:d.newLabel,autoComplete:"new-password"},{name:"confirmPassword",label:d.confirmLabel,autoComplete:"new-password"}];function _e(){const s=v(),{toast:a}=z(),{mutate:t,isPending:i}=Se(),[o,m]=h.useState(null),M=h.useMemo(()=>ve(s),[s]),y=h.useMemo(()=>$(M),[M]),g=q({defaultValues:Ne,validators:{onChange:y,onSubmit:y},onSubmit:({value:r})=>{m(null),t({current_password:r.currentPassword,new_password:r.newPassword},{onSuccess:()=>{g.reset(),a({title:s.formatMessage(d.changedTitle),description:s.formatMessage(d.changedBody)})},onError:p=>{const f=p instanceof A?p.code:null;if(f===S.INVALID_CURRENT_PASSWORD){m({field:"currentPassword",message:s.formatMessage(d.wrongCurrent)});return}if(f===S.SAME_AS_CURRENT){m({field:"newPassword",message:s.formatMessage(d.sameAsCurrent)});return}const c=f===S.ACCOUNT_LOCKED;a({title:s.formatMessage(c?d.lockedTitle:d.failedTitle),description:s.formatMessage(c?d.lockedBody:d.failedBody),variant:"destructive"})}})}});return e.jsxs("form",{noValidate:!0,className:"flex flex-col gap-4",onSubmit:r=>{r.preventDefault(),g.handleSubmit()},children:[e.jsx("div",{className:"grid gap-4 md:grid-cols-2",children:Ce.map(({name:r,label:p,autoComplete:f})=>e.jsx(g.Field,{name:r,children:c=>{const w=Y(c.state.meta)??((o==null?void 0:o.field)===r?o.message:void 0);return e.jsxs("div",{className:se("flex min-w-0 flex-col gap-2",r==="newPassword"&&"md:col-start-1"),children:[e.jsx(N,{htmlFor:`password-${r}`,children:s.formatMessage(p)}),e.jsx(pe,{size:"lg",id:`password-${r}
1`,autoComplete:f,invalid:!!w,value:c.state.value,onChange:L=>{(o==null?void 0:o.field)===r&&m(null),c.handleChange(L.target.value)},onBlur:c.handleBlur}),e.jsx("div",{className:"min-h-5","aria-live":"polite",children:w?e.jsx("p",{className:"text-body-sm text-danger",children:w}):r==="newPassword"?e.jsx("p",{className:"text-body-sm text-text-secondary",children:s.formatMessage(d.newHint,{min:E})}):null})]})}},r))}),e.jsx(T,{type:"submit",variant:"secondary",size:"md",className:"self-start",disabled:i,children:s.formatMessage(d.submit)})]})}const C=100,k=x({nameRequired:{id:"portal.profile.details.error.nameRequired",defaultMessage:"Enter your full name.",description:"Validation error when the full name on the My Profile page is empty."},nameTooLong:{id:"portal.profile.details.error.nameTooLong",defaultMessage:"Use {max} characters or fewer.",description:"Validation error when a name on the My Profile page is too long. {max} is the character limit."}});function D(s){return{name:s.name??"",preferredName:s.preferred_name??""}}function Ee(s){const a=s.formatMessage(k.nameTooLong,{max:C});return V({name:j().trim().min(1,s.formatMessage(k.nameRequired)).max(C,a),preferredName:j().trim().max(C,a)})}function I(s,a){const t={},i=a.name.trim(),o=a.preferredName.trim();return i!==s.name.trim()&&(t.name=i),o!==s.preferredName.trim()&&(t.preferred_name=o||null),t}const u=x({nameLabel:{id:"portal.profile.details.nameLabel",defaultMessage:"Full name",description:"Label for the full name input on the My Profile page."},preferredNameLabel:{id:"portal.profile.details.preferredNameLabel",defaultMessage:"Preferred name (optional)",description:"Label for the optional preferred name input on the My Profile page."},preferredNameHint:{id:"portal.profile.details.preferredNameHint",defaultMessage:"What the portal calls you in greetings.",description:"Help text under the preferred name input on the My Profile page."},emailLabel:{id:"portal.profile.details.emailLabel",defaultMessage:"Email",description:"Label for the read-only email field on the My Profile page."},emailHint:{id:"portal.profile.details.emailHint",defaultMessage:"This is the email you sign in with.",description:"Help text under the read-only email field on the My Profile page."},save:{id:"portal.profile.details.save",defaultMessage:"Save changes",description:"Button that saves the name changes on the My Profile page."},saved:{id:"portal.profile.details.saved",defaultMessage:"Profile saved",description:"Toast title after the user saves their profile."},saveFailedTitle:{id:"portal.profile.details.saveFailedTitle",defaultMessage:"Couldn't save your profile",description:"Toast title when saving the profile fails."},saveFailedBody:{id:"portal.profile.details.saveFailedBody",defaultMessage:"Check your connection and try again.",description:"Toast body when saving the profile fails."}}),Te=[{name:"name",label:u.nameLabel},{name:"preferredName",label:u.preferredNameLabel,hint:u.preferredNameHint}];function Ae({profile:s}){const a=v(),{toast:t}=z(),{mutate:i,isPending:o}=de(),m=h.useMemo(()=>D(s),[s]),M=h.useMemo(()=>Ee(a),[a]),y=h.useMemo(()=>$(M),[M]),g=q({defaultValues:m,validators:{onChange:y,onSubmit:y},onSubmit:({value:r})=>{const p=I(m,r);Object.keys(p).length!==0&&i(p,{onSuccess:f=>{g.reset(D(f)),t({title:a.formatMessage(u.saved)})},onError:()=>t({title:a.formatMessage(u.saveFailedTitle),description:a.formatMessage(u.saveFailedBody),variant:"destructive"})})}});return e.jsxs("form",{noValidate:!0,className:"flex flex-col gap-4",onSubmit:r=>{r.preventDefault(),g.handleSubmit()},children:[e.jsx("div",{className:"grid gap-4 md:grid-cols-2",children:Te.map(({name:r,label:p,hint:f})=>e.jsx(g.Field,{name:r,children:c=>{const w=Y(c.state.meta);return e.jsxs("div",{className:"flex min-w-0 flex-col gap-2",children:[e.jsx(N,{htmlFor:`profile-${r}`,children:a.formatMessage(p)}),e.jsx(B,{size:"lg",id:`profile-${r}`,autoComplete:r==="name"?"name":"nickname",maxLength:100,invalid:!!w,value:c.state.value,onChange:L=>c.handleChange(L.target.value),onBlur:c.handleBlur}),e.jsx("div",{className:"min-h-5","aria-live":"polite",children:w?e.jsx("p",{className:"text-body-sm text-danger",children:w}):f?e.jsx("p",{className:"text-body-sm text-text-secondary",children:a.formatMessage(f)}):null})]})}},r))}),e.jsxs("div",{className:"flex min-w-0 flex-col gap-2",children:[e.jsx(N,{htmlFor:"profile-email",children:a.formatMessage(u.emailLabel)}),e.jsx(B,{size:"lg",id:"profile-email",value:s.email,readOnly:!0,disabled:!0}),e.jsx("p",{className:"text-body-sm text-text-secondary",children:a.formatMessage(u.emailHint)})]}),e.jsx(g.Subscribe,{selector:r=>r.values,children:r=>{const p=Object.keys(I(m,r)).length>0;return e.jsx(T,{type:"submit",variant:"primary",size:"md",className:"self-start",disabled:!p||o,children:a.formatMessage(u.save)})}})]})}const U=x({label:{id:"portal.settings.language.label",defaultMessage:"Language",description:"Label for the portal language selector on the My Profile page."},description:{id:"portal.settings.language.description",defaultMessage:"Choose the language the partner portal is shown in. It applies on every device you sign in on.",description:"Help text under the language selector on the My Profile page."}}),He=re.map(s=>({value:s,label:oe[s]}));function Re(){const s=v(),{locale:a,setLocale:t}=ae(),i=h.useMemo(()=>o=>{te(o)&&t(o)},[t]);return e.jsxs("div",{className:"flex max-w-xs flex-col gap-2",children:[e.jsx(N,{htmlFor:"profile-language",children:s.formatMessage(U.label)}),e.jsx(ce,{id:"profile-language",size:"lg",searchable:!1,options:He,value:a,onValueChange:i,containerClassName:"w-full"}),e.jsx("p",{className:"text-body-sm text-text-secondary",children:s.formatMessage(U.description)})]})}const Be=x({portal_admin:{id:"portal.profile.access.role.portalAdmin",defaultMessage:"Portal admin",description:"Role name in the Access list on the My Profile page."},partner_admin:{id:"portal.profile.access.role.partnerAdmin",defaultMessage:"Administrator",description:"Role name in the Access list on the My Profile page."},partner_manager:{id:"portal.profile.access.role.partnerManager",defaultMessage:"Manager",description:"Role name in the Access list on the My Profile page."},partner_trainer:{id:"portal.profile.access.role.partnerTrainer",defaultMessage:"Trainer",description:"Role name in the Access list on the My Profile page."},partner_contractor_trainer:{id:"portal.profile.access.role.partnerContractorTrainer",defaultMessage:"Contractor trainer",description:"Role name in the Access list on the My Profile page."}}),_=x({allLocations:{id:"portal.profile.access.allLocations",defaultMessage:"All locations",description:"Shown in the Access list when the role covers every location of the partner."},allPartners:{id:"portal.profile.access.allPartners",defaultMessage:"All partners",description:"Shown in the Access list for a portal admin, whose role is not tied to one partner."},none:{id:"portal.profile.access.none",defaultMessage:"You don't have a role in any partner yet.",description:"Shown in the Access list when the account has no roles."}});function Fe({entries:s}){return s.length===0?e.jsx("p",{className:"text-body-md text-on-surface-muted",children:e.jsx(n,{..._.none})}):e.jsx("ul",{className:"flex flex-col divide-y divide-border-subtle",children:s.map(a=>e.jsxs("li",{className:"flex min-w-0 flex-col gap-1 py-3 first:pt-0 last:pb-0 sm:flex-row sm:items-baseline sm:justify-between sm:gap-4",children:[e.jsx("span",{className:"min-w-0 text-body-md-semi text-on-surface",children:a.partnerName??e.jsx(n,{..._.allPartners})}),e.jsxs("span",{className:"min-w-0 text-body-sm text-text-secondary sm:text-right",children:[e.jsx(n,{...Be[a.roleName]})," · ",a.locationNames&&a.locationNames.length>0?e.jsx(ie,{type:"conjunction",value:a.locationNames}):e.jsx(n,{..._.allLocations})]})]},a.key))})}function P({id:s,title:a,description:t,children:i}){return e.jsxs("section",{"aria-labelledby":s,className:"flex flex-col gap-2",children:[e.jsx("h2",{id:s,className:"text-body-caption-uppercase text-on-surface-muted",children:a}),e.jsxs(fe,{children:[t?e.jsx("p",{className:"text-body-sm text-text-secondary",children:t}):null,i]})]})}
1const l=x({title:{id:"portal.profile.page.title",defaultMessage:"My profile",description:"Heading of the My Profile page."},subtitle:{id:"portal.profile.page.subtitle",defaultMessage:"Your name, language and password. Changes apply only to your own account.",description:"Subtitle under the My Profile page heading (desktop only)."},detailsHeading:{id:"portal.profile.details.heading",defaultMessage:"Profile",description:"Heading of the name and email section on the My Profile page."},accessHeading:{id:"portal.profile.access.heading",defaultMessage:"Access",description:"Heading of the section listing the user's roles and locations on the My Profile page."},accessDescription:{id:"portal.profile.access.description",defaultMessage:"Your role and the locations you can see in each partner.",description:"Help text of the Access section on the My Profile page."},preferencesHeading:{id:"portal.profile.preferences.heading",defaultMessage:"Preferences",description:"Heading of the preferences section on the My Profile page."},securityHeading:{id:"portal.profile.password.heading",defaultMessage:"Password",description:"Heading of the change password section on the My Profile page."},securityDescription:{id:"portal.profile.password.description",defaultMessage:"Changing your password signs you out on every other device.",description:"Help text of the change password section on the My Profile page."},sessionHeading:{id:"portal.profile.session.heading",defaultMessage:"Session",description:"Heading of the log out section on the My Profile page."},sessionDescription:{id:"portal.profile.session.description",defaultMessage:"Sign out of the partner portal on this device.",description:"Help text above the log out button on the My Profile page."},loading:{id:"portal.profile.page.loading",defaultMessage:"Loading your profile...",description:"Accessible label for the My Profile loading skeleton."},loadErrorTitle:{id:"portal.profile.page.loadErrorTitle",defaultMessage:"Could not load your profile",description:"Title shown when the My Profile page fails to load."},loadErrorBody:{id:"portal.profile.page.loadErrorBody",defaultMessage:"Try refreshing the page.",description:"Help text shown when the My Profile page fails to load."}});function Oe(){const s=v();return e.jsxs("div",{className:"flex flex-col gap-6",role:"status","aria-label":s.formatMessage(l.loading),children:[e.jsx(F,{className:"h-64 w-full rounded-[16px]"}),e.jsx(F,{className:"h-24 w-full rounded-[16px]"})]})}function ke(){return e.jsxs("div",{role:"alert",className:"flex flex-col items-center gap-2 rounded-[16px] bg-surface-base px-4 py-12 text-center",children:[e.jsx(we,{className:"size-8 text-on-surface-muted","aria-hidden":"true"}),e.jsx("p",{className:"text-body-lg-semi text-on-surface",children:e.jsx(n,{...l.loadErrorTitle})}),e.jsx("p",{className:"text-body-md text-on-surface-muted",children:e.jsx(n,{...l.loadErrorBody})})]})}function fs(){const s=xe(),{data:a,isError:t}=ye(),i=h.useMemo(()=>Me((a==null?void 0:a.roles)??[]),[a==null?void 0:a.roles]);return me({type:"settings",label:"My profile"}),e.jsxs("div",{className:"flex w-full max-w-3xl flex-col gap-8",children:[s?e.jsx(ue,{children:e.jsx("h1",{className:"truncate font-brand text-heading-h4-semi text-on-surface-heading",children:e.jsx(n,{...l.title})})}):e.jsxs("header",{className:"flex flex-col gap-1",children:[e.jsx("h1",{className:"font-brand text-heading-h2 text-on-surface-heading",children:e.jsx(n,{...l.title})}),e.jsx("p",{className:"text-sm text-on-surface-muted",children:e.jsx(n,{...l.subtitle})})]}),t?e.jsx(ke,{}):a?e.jsxs(e.Fragment,{children:[e.jsx(P,{id:"profile-details",title:e.jsx(n,{...l.detailsHeading}),children:e.jsx(Ae,{profile:a})}),e.jsx(P,{id:"profile-access",title:e.jsx(n,{...l.accessHeading}),description:e.jsx(n,{...l.accessDescription}),children:e.jsx(Fe,{entries:i})})]}):e.jsx(Oe,{}),e.jsx(P,{id:"profile-preferences",title:e.jsx(n,{...l.preferencesHeading}),children:e.jsx(Re,{})}),e.jsx(P,{id:"profile-password",title:e.jsx(n,{...l.securityHeading}),description:e.jsx(n,{...l.securityDescription}),children:e.jsx(_e,{})}),e.jsx(P,{id:"profile-session",title:e.jsx(n,{...l.sessionHeading}),description:e.jsx(n,{...l.sessionDescription}),children:e.jsx(be,{})})]})}export{fs as ProfilePage};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.