fix(white-label): back-to-clients link points at the byra cockpit's home domain (#1973)
* fix(white-label): back-to-clients link points at the byra cockpit's home domain A byra member working a company homed on another host (e.g. a pre-byra company on canonical) got a relative /clients on the wrong host instead of their white-label cockpit. resolveCockpitHref mirrors WL-14's home rule: relative when the current host is the cockpit's home (brand domain, or canonical for a brandless byra), else an absolute URL there. Cross- host links render a plain <a> with a 'Hanteras via' hint; the hop lands on the brand host's login (per-host sessions, WL-01) and WL-14 then lands on /clients. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(white-label): show the cross-host cockpit hint as visible text CodeRabbit: title-only hints never surface on touch devices, so the expanded-sidebar and mobile external back-links now render the 'Hanteras via {domain}' line as small muted text under the label (same pattern as the switcher's foreign entries). Also corrects the comments claiming the no-company branch never renders the back-link: it can, on its cockpit/settings surfaces, where the relative fallback matches pre-change behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
a860c690ed
commit
99c94d467a
@@ -4,6 +4,7 @@ import {
|
||||
isCompanyHomedOnHost,
|
||||
isCockpitLandingRole,
|
||||
resolveLandingPath,
|
||||
resolveCockpitHref,
|
||||
type TeamBrandRef,
|
||||
} from '../home-domain'
|
||||
|
||||
@@ -200,3 +201,77 @@ describe('resolveLandingPath', () => {
|
||||
expect(resolveLandingPath({ hostBrandTeamId: 'byra-1', byraTeams: [] })).toBe('/')
|
||||
})
|
||||
})
|
||||
|
||||
describe('resolveCockpitHref', () => {
|
||||
const brandByTeam = new Map([['byra-1', siffraBrand]])
|
||||
const canonicalDomain = CANONICAL.canonicalDomain
|
||||
|
||||
it('brandless byrå on the canonical host stays relative', () => {
|
||||
expect(
|
||||
resolveCockpitHref({
|
||||
byraTeamId: 'byra-1',
|
||||
brandByTeam: new Map(),
|
||||
hostBrandTeamId: null,
|
||||
canonicalDomain,
|
||||
}),
|
||||
).toBe('/clients')
|
||||
})
|
||||
|
||||
it('branded byrå on its own brand host stays relative', () => {
|
||||
expect(
|
||||
resolveCockpitHref({
|
||||
byraTeamId: 'byra-1',
|
||||
brandByTeam,
|
||||
hostBrandTeamId: 'byra-1',
|
||||
canonicalDomain,
|
||||
}),
|
||||
).toBe('/clients')
|
||||
})
|
||||
|
||||
it('branded byrå on the canonical host points at the brand domain (problem 4)', () => {
|
||||
expect(
|
||||
resolveCockpitHref({
|
||||
byraTeamId: 'byra-1',
|
||||
brandByTeam,
|
||||
hostBrandTeamId: null,
|
||||
canonicalDomain,
|
||||
}),
|
||||
).toBe('https://app.siffra.se/clients')
|
||||
})
|
||||
|
||||
it("branded byrå on someone ELSE's brand host points at its own brand domain", () => {
|
||||
expect(
|
||||
resolveCockpitHref({
|
||||
byraTeamId: 'byra-1',
|
||||
brandByTeam,
|
||||
hostBrandTeamId: 'byra-2',
|
||||
canonicalDomain,
|
||||
}),
|
||||
).toBe('https://app.siffra.se/clients')
|
||||
})
|
||||
|
||||
it('brandless byrå on a foreign brand host points home to canonical (WL-14 symmetry)', () => {
|
||||
expect(
|
||||
resolveCockpitHref({
|
||||
byraTeamId: 'byra-1',
|
||||
brandByTeam: new Map(),
|
||||
hostBrandTeamId: 'byra-2',
|
||||
canonicalDomain,
|
||||
}),
|
||||
).toBe('https://app.gnubok.se/clients')
|
||||
})
|
||||
|
||||
it('byrå with zero client companies still resolves via its own brand entry', () => {
|
||||
// The layout adds the byrå team id to the resolveBrandsForTeams id list
|
||||
// precisely so this map entry exists even when no membership company
|
||||
// belongs to the byrå (pre-byrå companies have team_id null).
|
||||
expect(
|
||||
resolveCockpitHref({
|
||||
byraTeamId: 'byra-1',
|
||||
brandByTeam: new Map([['byra-1', siffraBrand]]),
|
||||
hostBrandTeamId: null,
|
||||
canonicalDomain,
|
||||
}),
|
||||
).toBe('https://app.siffra.se/clients')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -129,3 +129,35 @@ export function resolveLandingPath(opts: {
|
||||
// Canonical host: only a brandless byrå homes its cockpit here.
|
||||
return opts.byraTeams.some((t) => !t.hasBrand) ? '/clients' : '/'
|
||||
}
|
||||
|
||||
/**
|
||||
* Href for the pinned "Tillbaka till klienter" link: the byrå cockpit lives
|
||||
* on the byrå's home domain (its brand domain when the team has a brand, else
|
||||
* the canonical domain, same rule as WL-14's resolveLandingPath). Relative
|
||||
* '/clients' when the current host IS that home; an absolute URL otherwise,
|
||||
* so a byrå member working a company homed on a different host (e.g. a
|
||||
* pre-byrå company on canonical) is sent to their white-label cockpit.
|
||||
*
|
||||
* Navigation rule only, like everything in this file: the hop lands on the
|
||||
* brand host's login when there is no session there (per-host sessions,
|
||||
* WL-01), and WL-14 then lands the user on /clients.
|
||||
*/
|
||||
export function resolveCockpitHref(opts: {
|
||||
/** teams.id of the user's byrå team. */
|
||||
byraTeamId: string
|
||||
brandByTeam: Map<string, TeamBrandRef>
|
||||
/** teams.id of the brand serving the current host, null on canonical. */
|
||||
hostBrandTeamId: string | null
|
||||
canonicalDomain: string
|
||||
}): string {
|
||||
const brand = opts.brandByTeam.get(opts.byraTeamId)
|
||||
if (brand) {
|
||||
return opts.hostBrandTeamId === opts.byraTeamId
|
||||
? '/clients'
|
||||
: `https://${brand.domain}/clients`
|
||||
}
|
||||
// Brandless byrå: the cockpit is homed on the canonical domain.
|
||||
return opts.hostBrandTeamId === null
|
||||
? '/clients'
|
||||
: `https://${opts.canonicalDomain}/clients`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user