Gå til innhold

Modul-sperre (module-gate)

Gjenbrukbar modul-lisens-sperre for Angular-sider og -elementer. Renderer projisert innhold når tenanten/brukeren har den nødvendige modulen, og en kontaktboks («Du har ikke denne modulen, kontakt hjelp@konti.no for å aktivere den») ellers. Brukes første gang for CRM sine Tilbud/Masterordre- menypunkter (se CRM-modulen), men er generell og kan brukes av enhver modul som trenger å vise et menypunkt/en side selv om den bakenforliggende modulen ikke er aktivert for tenanten.


Feature-tabell

Komponent/direktiv Selector Hovedfunksjon Import
ModuleGateComponent app-module-gate Content-projection-wrapper: viser innhold ELLER kontaktboks Standalone og SharedModule
ModuleGateDirective *appModuleGate Strukturell direktiv — skjul-eller-vis et enkelt element, uten meldingspanel Standalone og SharedModule
ModuleAccessService (ingen selector — injectable) hasModule()/hasModule$() — samme dual-source-sjekk som ModuleGuard providedIn: 'root'

Kildefiler

Del Sti
Komponent ui/ePortal.ui/src/app/shared/components/module-gate/module-gate.component.ts
Direktiv ui/ePortal.ui/src/app/shared/directives/module-gate.directive.ts
Service ui/ePortal.ui/src/app/services/module-access.service.ts

ModuleAccessService — tilgangskilden

Både komponenten og direktivet delegerer til ModuleAccessService.hasModule(moduleId), som er nøyaktig den samme dual-source-sjekken ModuleGuard alltid har brukt (ekstrahert til en injectable slik at også vanlige komponenter kan spørre "har denne tenanten modul X", ikke bare rutevakter):

  1. localStorage user.userAccess[] (fra innloggingens Me-respons) — treff på access.moduleID === moduleId && (access.new === true || access.new === 1).
  2. Fallback: JWT-tokenets moduleAccess-claim (array eller enkelt streng av modul-IDer).

Mangler token, eller er ingen av kildene et treff, returnerer hasModule() false (fail-closed). moduleId kan være ett tall eller en array — array betyr "har ELLER-treff på noen av dem" (samme oppførsel som ModuleGuards data: { moduleId: [28, 29] }).

hasModule$() er en reaktiv variant (v1: synkron øyeblikksbilde pakket i of(...)) for maler som binder med async — ingen server-kall, ingen caching/async-refresh i v1.


Bruk — <app-module-gate> (primær)

<app-module-gate [moduleId]="50">
  <app-subscription-offer-list></app-subscription-offer-list>
</app-module-gate>

Med tilpasset kontaktadresse og tekstnøkler:

<app-module-gate
  [moduleId]="50"
  contactEmail="support@example.com"
  messageKey="Custom.notLicensedMessage"
  titleKey="Custom.notLicensedTitle"
  variant="inline"></app-module-gate>

variant="panel" (standard) gir en sentrert kontaktboks som mirrorer external-project-no-access-mønsteret (ikon, tittel, tekst, mailto:-knapp) — egnet på side-nivå. variant="inline" gir en kompakt én-linjes variant for verktøylinjer/lister.

Inputs

Input Type Standard Beskrivelse
moduleId number \| number[] (påkrevd) Modul(er) som låser opp det projiserte innholdet. Array = ELLER-treff.
contactEmail string 'hjelp@konti.no' Adresse i meldingen og i mailto:-lenken.
messageKey string 'ModuleGate.notLicensedMessage' i18n-nøkkel for brødteksten. Interpoleres med {{ email }}.
titleKey string 'ModuleGate.notLicensedTitle' i18n-nøkkel for tittelen.
icon string 'bi-shield-lock' Bootstrap-ikonklasse for panel/inline-ikonet.
variant 'panel' \| 'inline' 'panel' panel = sentrert kort (side-nivå). inline = kompakt én-linje (verktøylinje/liste).

Bruk — *appModuleGate (skjul-uten-melding)

Lettvekts-variant for å skjule/vise et enkelt element (knapp, menyrad) uten kontaktboks-panelet:

<!-- skjul knappen helt når modulen er av -->
<button *appModuleGate="50" class="btn btn-kai-planner">Masterordre</button>

<!-- eller: gi et eget fallback-template -->
<div *appModuleGate="50; else locked"></div>
<ng-template #locked>
  <app-module-gate [moduleId]="50" variant="inline"></app-module-gate>
</ng-template>

Inputs

Input Type Beskrivelse
appModuleGate number \| number[] Modul(er) som låser opp det innkapslede viewet. Array = ELLER-treff.
appModuleGateElse TemplateRef<any> \| null Valgfritt template som vises i stedet når modulen ikke er lisensiert.

Brukseksempel — CRM Tilbud/Masterordre (referanseimplementasjon)

CrmModuleGateLandingComponent (ui/ePortal.ui/src/app/components/crm/crm-module-gate-landing/crm-module-gate-landing.component.ts) viser mønsteret for en "tynn landingsrute": CRM-gatet (modul 31) på selve ruten slik at menypunktet alltid er synlig, deretter videreført til den ekte siden når abonnementsmodulen (50) er aktiv:

<app-module-gate [moduleId]="subscriptionModuleId">
  <div class="text-center py-5">
    <div class="spinner-border" role="status">
      <span class="visually-hidden">{{ 'General.loading' | translate }}</span>
    </div>
  </div>
</app-module-gate>
ngOnInit(): void {
  const targetRoute = this.route.snapshot.data?.['targetRoute'];
  if (targetRoute && this.moduleAccessService.hasModule(this.subscriptionModuleId)) {
    this.router.navigateByUrl(targetRoute);
  }
}

Ruten registreres med canActivate: [ActivateService, ModuleGuard], data: { moduleId: 31, targetRoute: '/subscription/offers' } — CRM-gaten (31) slipper alle CRM-brukere inn på landingssiden; <app-module-gate [moduleId]="50"> avgjør om de ser innholdet (her: en kort spinner før redirect) eller kontaktboksen.


i18n

ModuleGate.*-nøklene finnes i BÅDE no.json og en.json (nytt topp-nivå-block):

"ModuleGate": {
  "notLicensedTitle": "Modulen er ikke aktivert",
  "notLicensedMessage": "Du har ikke denne modulen, kontakt {{email}} for å aktivere den.",
  "contactButton": "Kontakt oss"
}

Kjente fallgruver

Fallgruve Riktig mønster
Bygge en ny modul-tilgangssjekk et annet sted i koden Bruk ModuleAccessService.hasModule() — det er den ENESTE kilden (samme som ModuleGuard).
Forvente at hasModule() reagerer på endringer uten ny innlogging v1 er synkron/øyeblikksbilde (samme begrensning som ModuleGuard). Ingen auto-refresh.
Bruke *appModuleGate når brukeren trenger en forklaring Bruk <app-module-gate> (med panel eller inline-variant) i stedet — direktivet skjuler stille.
Hardkode kontakt-e-post i malen Bruk [contactEmail]-input (standard hjelp@konti.no) — ikke skriv adressen i HTML.
Gate hele menyoppføringen på modulen selv (skjuler menypunktet for tenants uten modulen) For "alltid synlig, vis melding hvis ikke aktivert"-mønsteret: gate RUTEN på en modul brukeren uansett har (f.eks. CRM=31), og gate INNHOLDET med <app-module-gate [moduleId]="50"> — se CRM-eksempelet over.

Relaterte sider