feat(tabs): add helper functions for tab metadata management

This commit is contained in:
Lorenz Hilpert
2025-09-23 21:01:00 +02:00
parent 243b83bd73
commit d9ccf68314
6 changed files with 146 additions and 106 deletions

View File

@@ -0,0 +1,2 @@
export * from './models';
export * from './services';

View File

@@ -4,3 +4,4 @@ export * from './lib/schemas';
export * from './lib/tab';
export * from './lib/tab-navigation.service';
export * from './lib/tab-config';
export * from './lib/helpers';

View File

@@ -0,0 +1,29 @@
import z from 'zod';
import { Tab } from './schemas';
import { computed } from '@angular/core';
export function getTabHelper(
tabId: number,
entities: Record<number, Tab>,
): Tab | undefined {
return entities[tabId];
}
export function getMetadataHelper<T extends z.ZodTypeAny>(
tabId: number,
key: string,
schema: T,
entities: Record<number, Tab>,
): z.infer<T> | undefined {
const metadata = getTabHelper(tabId, entities)?.metadata;
if (!metadata) {
return undefined;
}
const res = schema.safeParse(metadata?.[key]);
if (res.success) {
return res.data;
}
return undefined;
}

View File

@@ -1,15 +1,15 @@
import { inject, Injectable } from '@angular/core';
import { CrmSearchService } from '../services';
import { FetchCustomerCardsInput } from '../schemas';
@Injectable({ providedIn: 'root' })
export class CustomerCardsFacade {
crmSearchService = inject(CrmSearchService);
async get(params: FetchCustomerCardsInput, abortSignal: AbortSignal) {
return await this.crmSearchService.fetchCustomerCards(
{ ...params },
abortSignal,
);
}
}
import { inject, Injectable } from '@angular/core';
import { CrmSearchService } from '../services';
import { FetchCustomerCardsInput } from '../schemas';
@Injectable({ providedIn: 'root' })
export class CustomerCardsFacade {
crmSearchService = inject(CrmSearchService);
async get(params: FetchCustomerCardsInput, abortSignal?: AbortSignal) {
return await this.crmSearchService.fetchCustomerCards(
{ ...params },
abortSignal,
);
}
}

View File

@@ -1,68 +1,75 @@
import { inject, Injectable } from '@angular/core';
import {
CustomerService,
ResponseArgsOfCustomerDTO,
ResponseArgsOfIEnumerableOfBonusCardInfoDTO,
} from '@generated/swagger/crm-api';
import {
FetchCustomerCardsInput,
FetchCustomerCardsSchema,
FetchCustomerInput,
FetchCustomerSchema,
} from '../schemas';
import {
catchResponseArgsErrorPipe,
ResponseArgs,
takeUntilAborted,
} from '@isa/common/data-access';
import { firstValueFrom } from 'rxjs';
import { BonusCardInfo, Customer } from '../models';
@Injectable({ providedIn: 'root' })
export class CrmSearchService {
#customerService = inject(CustomerService);
async fetchCustomer(
params: FetchCustomerInput,
abortSignal: AbortSignal,
): Promise<ResponseArgs<Customer>> {
const { customerId, eagerLoading } = FetchCustomerSchema.parse(params);
const req$ = this.#customerService
.CustomerGetCustomer({ customerId, eagerLoading })
.pipe(
takeUntilAborted(abortSignal),
catchResponseArgsErrorPipe<ResponseArgsOfCustomerDTO>(),
);
const res = await firstValueFrom(req$);
if (res.error) {
throw new Error(res.message);
}
return res as ResponseArgs<Customer>;
}
async fetchCustomerCards(
params: FetchCustomerCardsInput,
abortSignal: AbortSignal,
): Promise<ResponseArgs<BonusCardInfo[]>> {
const { customerId } = FetchCustomerCardsSchema.parse(params);
const req$ = this.#customerService
.CustomerGetBonuscards(customerId)
.pipe(
takeUntilAborted(abortSignal),
catchResponseArgsErrorPipe<ResponseArgsOfIEnumerableOfBonusCardInfoDTO>(),
);
const res = await firstValueFrom(req$);
if (res.error) {
throw new Error(res.message);
}
return res as ResponseArgs<BonusCardInfo[]>;
}
}
import { inject, Injectable } from '@angular/core';
import {
CustomerService,
ResponseArgsOfCustomerDTO,
ResponseArgsOfIEnumerableOfBonusCardInfoDTO,
} from '@generated/swagger/crm-api';
import {
FetchCustomerCardsInput,
FetchCustomerCardsSchema,
FetchCustomerInput,
FetchCustomerSchema,
} from '../schemas';
import {
catchResponseArgsErrorPipe,
ResponseArgs,
takeUntilAborted,
} from '@isa/common/data-access';
import { firstValueFrom } from 'rxjs';
import { BonusCardInfo, Customer } from '../models';
@Injectable({ providedIn: 'root' })
export class CrmSearchService {
#customerService = inject(CustomerService);
async fetchCustomer(
params: FetchCustomerInput,
abortSignal?: AbortSignal,
): Promise<ResponseArgs<Customer>> {
const { customerId, eagerLoading } = FetchCustomerSchema.parse(params);
let req$ = this.#customerService.CustomerGetCustomer({
customerId,
eagerLoading,
});
if (abortSignal) {
req$ = req$.pipe(takeUntilAborted(abortSignal));
}
req$ = req$.pipe(catchResponseArgsErrorPipe<ResponseArgsOfCustomerDTO>());
const res = await firstValueFrom(req$);
if (res.error) {
throw new Error(res.message);
}
return res as ResponseArgs<Customer>;
}
async fetchCustomerCards(
params: FetchCustomerCardsInput,
abortSignal?: AbortSignal,
): Promise<ResponseArgs<BonusCardInfo[]>> {
const { customerId } = FetchCustomerCardsSchema.parse(params);
let req$ = this.#customerService.CustomerGetBonuscards(customerId);
if (abortSignal) {
req$ = req$.pipe(takeUntilAborted(abortSignal));
}
req$ = req$.pipe(
catchResponseArgsErrorPipe<ResponseArgsOfIEnumerableOfBonusCardInfoDTO>(),
);
const res = await firstValueFrom(req$);
if (res.error) {
throw new Error(res.message);
}
return res as ResponseArgs<BonusCardInfo[]>;
}
}

View File

@@ -1,23 +1,24 @@
import { Injectable, inject } from '@angular/core';
import { TabService } from '@isa/core/tabs';
import { SELECTED_CUSTOMER_ID } from '../constants';
@Injectable({ providedIn: 'root' })
export class CrmTabMetadataService {
#tabService = inject(TabService);
selectedCustomerId(tabId: number): number | undefined {
return this.#metadata(tabId)?.[SELECTED_CUSTOMER_ID] as number;
}
setSelectedCustomerId(tabId: number, customerId: number | undefined) {
this.#tabService.patchTabMetadata(tabId, {
[SELECTED_CUSTOMER_ID]: customerId,
});
}
#metadata(tabId: number) {
return this.#tabService.entities().find((tab) => tab.id === tabId)
?.metadata;
}
}
import { Injectable, inject } from '@angular/core';
import { TabService, getMetadataHelper, getTabHelper } from '@isa/core/tabs';
import { SELECTED_CUSTOMER_ID } from '../constants';
import z from 'zod';
@Injectable({ providedIn: 'root' })
export class CrmTabMetadataService {
#tabService = inject(TabService);
selectedCustomerId(tabId: number): number | undefined {
return getMetadataHelper(
tabId,
SELECTED_CUSTOMER_ID,
z.number().optional(),
this.#tabService.entities(),
);
}
setSelectedCustomerId(tabId: number, customerId: number | undefined) {
this.#tabService.patchTabMetadata(tabId, {
[SELECTED_CUSTOMER_ID]: customerId,
});
}
}