refactor(portal): partner-mode customer switcher on real tenants
Migrate the partner-mode customer switcher, in-customer banner, sidebar tile and the team invite/teammate panels off the data/customers fixture onto the real /api/partner/tenants list (shared key, gated to partner-staff so the global shell doesn't 403 for other users). Active customer resolves by tenant _id (the key the customers page already passes to partnerMode.enter); partner-identity labels now use the real partner name from useMe. Removes the now-unused customers + CustomerOrg-list fixture export and the dead setCustomer helper. Verified in UI: switcher + enter/exit show real Baslund Test / Baslund Research ApS.
This commit is contained in:
@@ -2,13 +2,25 @@
|
||||
// Portal topbar: workspace label, optional org switcher (partner admins), global
|
||||
// search, app launcher, notifications, profile menu.
|
||||
|
||||
import { customers } from '~/data/customers'
|
||||
import type { PartnerTenantDoc } from '~/types/partner'
|
||||
|
||||
const launcher = useAppLauncher()
|
||||
const drawer = useNotificationDrawer()
|
||||
const partnerMode = usePartnerMode()
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const { partner, isPartnerStaff } = useMe()
|
||||
|
||||
// Real customer tenants drive the org switcher. Shared 'partner-tenants' key
|
||||
// dedupes with the sidebar + customers page; gated to partner-staff so the
|
||||
// global shell doesn't 403 the partner-scoped endpoint for end-users/admins.
|
||||
const { data: tenants } = useFetch<PartnerTenantDoc[]>('/api/partner/tenants', {
|
||||
key: 'partner-tenants',
|
||||
default: () => [],
|
||||
immediate: isPartnerStaff.value,
|
||||
})
|
||||
const PLAN_LABEL: Record<string, string> = { mvp: 'Starter', pro: 'Business', enterprise: 'Enterprise' }
|
||||
const partnerLabel = computed(() => partner.value?.name ?? 'Partner')
|
||||
|
||||
// Section context is URL-driven (same rule as the sidebar). The org switcher
|
||||
// only appears in the partner section or when acting-as a customer.
|
||||
@@ -24,7 +36,7 @@ const showOrgSwitcher = computed(() =>
|
||||
)
|
||||
|
||||
const activeCustomer = computed(() =>
|
||||
customers.find((c) => c.id === partnerMode.activeCustomerId.value) || null,
|
||||
(tenants.value ?? []).find((c) => c._id === partnerMode.activeCustomerId.value) || null,
|
||||
)
|
||||
|
||||
const orgSwitcherOpen = ref(false)
|
||||
@@ -57,7 +69,7 @@ const searchValue = ref('')
|
||||
>
|
||||
{{ (activeCustomer?.name || 'NordicMSP').slice(0, 1) }}
|
||||
</span>
|
||||
<span class="org-name">{{ activeCustomer?.name || 'NordicMSP · Partner view' }}</span>
|
||||
<span class="org-name">{{ activeCustomer?.name || `${partnerLabel} · Partner view` }}</span>
|
||||
<UiIcon name="chevDown" :size="12" />
|
||||
</button>
|
||||
|
||||
@@ -89,10 +101,10 @@ const searchValue = ref('')
|
||||
<div v-if="orgSwitcherOpen" class="org-drop-scrim" @click="orgSwitcherOpen = false" />
|
||||
<div v-if="orgSwitcherOpen" class="org-drop">
|
||||
<div class="org-drop-head">
|
||||
<Eyebrow>NordicMSP · {{ customers.length }} customers</Eyebrow>
|
||||
<Eyebrow>{{ partnerLabel }} · {{ (tenants?.length ?? 0) }} customers</Eyebrow>
|
||||
</div>
|
||||
<button class="org-drop-row" :class="{ on: !partnerMode.isActive.value }" @click="leaveCustomerMode">
|
||||
<span class="org-drop-chip" style="background: #0A0A0A">N</span>
|
||||
<span class="org-drop-chip" style="background: #0A0A0A">{{ partnerLabel.charAt(0).toUpperCase() }}</span>
|
||||
<div class="org-drop-meta">
|
||||
<div class="org-drop-name">Partner view</div>
|
||||
<Mono dim>portfolio overview</Mono>
|
||||
@@ -100,16 +112,16 @@ const searchValue = ref('')
|
||||
</button>
|
||||
<div class="org-drop-divider" />
|
||||
<button
|
||||
v-for="c in customers"
|
||||
:key="c.id"
|
||||
v-for="c in tenants"
|
||||
:key="c._id"
|
||||
class="org-drop-row"
|
||||
:class="{ on: partnerMode.activeCustomerId.value === c.id }"
|
||||
@click="pickCustomer(c.id)"
|
||||
:class="{ on: partnerMode.activeCustomerId.value === c._id }"
|
||||
@click="pickCustomer(c._id)"
|
||||
>
|
||||
<span class="org-drop-chip" :style="{ background: c.brandColor }">{{ c.name.slice(0, 1) }}</span>
|
||||
<span class="org-drop-chip" :style="{ background: c.brandColor || '#0A0A0A' }">{{ c.name.slice(0, 1) }}</span>
|
||||
<div class="org-drop-meta">
|
||||
<div class="org-drop-name">{{ c.name }}</div>
|
||||
<Mono dim>{{ c.domain }} · {{ c.plan }}</Mono>
|
||||
<Mono dim>{{ c.domains?.[0] || c.slug }} · {{ PLAN_LABEL[c.plan ?? 'pro'] }}</Mono>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user