mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
#4994 Process Handling + Schema Update
This commit is contained in:
@@ -1,10 +1,17 @@
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import { QuerySettingsDTO, QueryTokenDTO, ReceiptService } from '@generated/swagger/oms-api';
|
||||
import { map, Observable, throwError } from 'rxjs';
|
||||
import { z } from 'zod';
|
||||
import * as Schemas from './return-search.schemas';
|
||||
import { inject, Injectable } from "@angular/core";
|
||||
import { QuerySettingsDTO, ReceiptService } from "@generated/swagger/oms-api";
|
||||
import { map, Observable, throwError } from "rxjs";
|
||||
import {
|
||||
QueryTokenSchema,
|
||||
QueryTokenInput,
|
||||
} from "./schemas/query-token.schema";
|
||||
import {
|
||||
ListResponseArgs,
|
||||
ListResponseArgsSchema,
|
||||
ReceiptListItemSchema,
|
||||
} from "./schemas/receipt-list-item.schema";
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
@Injectable({ providedIn: "root" })
|
||||
export class ReturnSearchService {
|
||||
#receiptService = inject(ReceiptService);
|
||||
|
||||
@@ -12,22 +19,39 @@ export class ReturnSearchService {
|
||||
return this.#receiptService.ReceiptQueryReceiptSettings().pipe(
|
||||
map((res) => {
|
||||
if (res.error || !res.result) {
|
||||
throw new Error('Failed to fetch query settings');
|
||||
throw new Error("Failed to fetch query settings");
|
||||
}
|
||||
return res.result;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
search(queryToken: z.input<typeof Schemas.QueryTokenSchema>): Observable<any> {
|
||||
search(queryToken: QueryTokenInput): Observable<ListResponseArgs> {
|
||||
try {
|
||||
queryToken = Schemas.QueryTokenSchema.parse(queryToken);
|
||||
queryToken = QueryTokenSchema.parse(queryToken);
|
||||
} catch (error) {
|
||||
return throwError(() => error);
|
||||
}
|
||||
|
||||
return this.#receiptService.ReceiptQueryReceipt({
|
||||
queryToken,
|
||||
});
|
||||
return this.#receiptService
|
||||
.ReceiptQueryReceipt({
|
||||
queryToken,
|
||||
})
|
||||
.pipe(
|
||||
map((res) => {
|
||||
if (res.error || !res.result) {
|
||||
throw new Error("Failed to fetch receipt list items");
|
||||
}
|
||||
|
||||
return ListResponseArgsSchema.parse({
|
||||
hits: res.hits,
|
||||
skip: res.skip,
|
||||
take: res.take,
|
||||
error: res.error,
|
||||
invalidProperties: res.invalidProperties,
|
||||
result: res.result.map((res) => ReceiptListItemSchema.parse(res)),
|
||||
});
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,132 @@
|
||||
import { signalStore, withMethods } from '@ngrx/signals';
|
||||
import {} from '@ngrx/operators';
|
||||
import { withEntities } from '@ngrx/signals/entities';
|
||||
import { pipe } from 'rxjs';
|
||||
import { patchState, signalStore, type, withMethods } from "@ngrx/signals";
|
||||
import { rxMethod } from "@ngrx/signals/rxjs-interop";
|
||||
import {
|
||||
addEntity,
|
||||
entityConfig,
|
||||
updateEntity,
|
||||
withEntities,
|
||||
} from "@ngrx/signals/entities";
|
||||
import { debounceTime, distinctUntilChanged, pipe, switchMap, tap } from "rxjs";
|
||||
import { ReturnSearchService } from "./return-search.service";
|
||||
import { tapResponse } from "@ngrx/operators";
|
||||
import { inject } from "@angular/core";
|
||||
import { ReceiptListItem, QueryTokenSchema, ListResponseArgs } from "./schemas";
|
||||
|
||||
type ReturnSearuchState = {
|
||||
id: number;
|
||||
params: Record<string, string>;
|
||||
results: string[];
|
||||
hits: number;
|
||||
status: 'idle' | 'pending' | 'success' | 'error';
|
||||
error: string | null;
|
||||
enum ReturnSearchStatus {
|
||||
Idle = "idle",
|
||||
Pending = "pending",
|
||||
Success = "success",
|
||||
Error = "error",
|
||||
}
|
||||
|
||||
type ReturnSearchEntity = {
|
||||
processId: number;
|
||||
status: ReturnSearchStatus;
|
||||
params?: Record<string, string>;
|
||||
items?: ReceiptListItem[];
|
||||
hits?: number;
|
||||
error?: string | unknown;
|
||||
};
|
||||
|
||||
const config = entityConfig({
|
||||
entity: type<ReturnSearchEntity>(),
|
||||
selectId: (entity) => entity.processId,
|
||||
});
|
||||
|
||||
export const ReturnSearchStore = signalStore(
|
||||
{ providedIn: 'root' },
|
||||
withEntities<ReturnSearuchState>(),
|
||||
// withMethods((store) => ({
|
||||
// search: rxMethod<{ id: number; params: Record<string, string> }>(pipe()),
|
||||
// paging: rxMethod<{ id: number }>(pipe()),
|
||||
// })),
|
||||
{ providedIn: "root" },
|
||||
withEntities<ReturnSearchEntity>(config),
|
||||
withMethods((store) => ({
|
||||
_beforeSearch(processId: number) {
|
||||
const entity = store.entities()[processId];
|
||||
if (entity) {
|
||||
patchState(
|
||||
store,
|
||||
updateEntity(
|
||||
{ id: processId, changes: { status: ReturnSearchStatus.Pending } },
|
||||
config,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
const entity: ReturnSearchEntity = {
|
||||
processId,
|
||||
status: ReturnSearchStatus.Pending,
|
||||
};
|
||||
patchState(store, addEntity(entity, config));
|
||||
}
|
||||
},
|
||||
_handleSearchSuccess({
|
||||
processId,
|
||||
response,
|
||||
}: {
|
||||
processId: number;
|
||||
response: ListResponseArgs;
|
||||
}) {
|
||||
patchState(
|
||||
store,
|
||||
updateEntity(
|
||||
{
|
||||
id: processId,
|
||||
changes: {
|
||||
status: ReturnSearchStatus.Success,
|
||||
hits: response.hits,
|
||||
items: response.result,
|
||||
},
|
||||
},
|
||||
config,
|
||||
),
|
||||
);
|
||||
},
|
||||
_handleSearchError({
|
||||
processId,
|
||||
error,
|
||||
}: {
|
||||
processId: number;
|
||||
error: unknown;
|
||||
}) {
|
||||
patchState(
|
||||
store,
|
||||
updateEntity(
|
||||
{
|
||||
id: processId,
|
||||
changes: {
|
||||
items: [],
|
||||
hits: undefined,
|
||||
status: ReturnSearchStatus.Error,
|
||||
error,
|
||||
},
|
||||
},
|
||||
config,
|
||||
),
|
||||
);
|
||||
},
|
||||
_handleSearchComplete(processId: number) {
|
||||
patchState(
|
||||
store,
|
||||
updateEntity(
|
||||
{ id: processId, changes: { status: ReturnSearchStatus.Idle } },
|
||||
config,
|
||||
),
|
||||
);
|
||||
},
|
||||
})),
|
||||
withMethods((store, returnSearchService = inject(ReturnSearchService)) => ({
|
||||
search: rxMethod<{ processId: number; params: Record<string, string> }>(
|
||||
pipe(
|
||||
debounceTime(100),
|
||||
distinctUntilChanged(),
|
||||
tap(({ processId }) => store._beforeSearch(processId)),
|
||||
switchMap(({ processId, params }) =>
|
||||
returnSearchService.search(QueryTokenSchema.parse(params)).pipe(
|
||||
tapResponse(
|
||||
(response) => store._handleSearchSuccess({ processId, response }),
|
||||
(error) => store._handleSearchError({ processId, error }),
|
||||
() => store._handleSearchComplete(processId),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// paging: rxMethod<rxMethod<{ processId: number; params: Record<string, string> }>>(pipe()),
|
||||
})),
|
||||
);
|
||||
|
||||
3
libs/feature/return/services/src/lib/schemas/index.ts
Normal file
3
libs/feature/return/services/src/lib/schemas/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from "./receipt-list-item.schema";
|
||||
export * from "./response-args.schema";
|
||||
export * from "./query-token.schema";
|
||||
@@ -1,4 +1,4 @@
|
||||
import { z } from 'zod';
|
||||
import { z } from "zod";
|
||||
|
||||
export const QueryTokenSchema = z.object({
|
||||
filter: z.object({
|
||||
@@ -7,3 +7,5 @@ export const QueryTokenSchema = z.object({
|
||||
skip: z.number().default(0),
|
||||
take: z.number().default(25),
|
||||
});
|
||||
|
||||
export type QueryTokenInput = z.input<typeof QueryTokenSchema>;
|
||||
@@ -0,0 +1,34 @@
|
||||
import { z } from "zod";
|
||||
import { ResponseArgsSchema } from "./response-args.schema";
|
||||
|
||||
// PersonNamesDTO
|
||||
export const PersonSchema = z.object({
|
||||
firstName: z.string(),
|
||||
gender: z.string().optional(),
|
||||
lastName: z.string(),
|
||||
title: z.string().optional(),
|
||||
});
|
||||
|
||||
// AddresseeDTO
|
||||
export const BuyerSchema = z.object({
|
||||
person: PersonSchema,
|
||||
});
|
||||
|
||||
// ReceiptListItemDTO
|
||||
export const ReceiptListItemSchema = z.object({
|
||||
pId: z.string(),
|
||||
id: z.number(),
|
||||
label: z.string(),
|
||||
buyer: BuyerSchema,
|
||||
});
|
||||
|
||||
// ListResponseArgsOfReceiptListItemDTO
|
||||
export const ListResponseArgsSchema = ResponseArgsSchema.extend({
|
||||
hits: z.number(),
|
||||
skip: z.number(),
|
||||
take: z.number(),
|
||||
result: ReceiptListItemSchema.array(),
|
||||
});
|
||||
|
||||
export type ListResponseArgs = z.infer<typeof ListResponseArgsSchema>;
|
||||
export type ReceiptListItem = z.infer<typeof ReceiptListItemSchema>;
|
||||
@@ -0,0 +1,9 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const ResponseArgsSchema = z.object({
|
||||
error: z.boolean(),
|
||||
invalidProperties: z.record(z.string()).optional(),
|
||||
message: z.string().optional(),
|
||||
});
|
||||
|
||||
export type ResponseArgs = z.infer<typeof ResponseArgsSchema>;
|
||||
7874
package-lock.json
generated
7874
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user