mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
chore: update dependencies and add vitest configuration
- Added @analogjs/vite-plugin-angular and @analogjs/vitest-angular to devDependencies. - Updated @nx/vite to version 20.1.4. - Added @vitest/coverage-v8 and @vitest/ui to devDependencies. - Added jsdom to devDependencies. - Added vite and vitest to devDependencies. - Updated tsconfig.base.json to include new paths for shared libraries. - Created vitest.workspace.ts for vitest configuration. Refs: #5135
This commit is contained in:
9
.claude/settings.local.json
Normal file
9
.claude/settings.local.json
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"mcp__context7__resolve-library-id",
|
||||||
|
"mcp__context7__get-library-docs"
|
||||||
|
],
|
||||||
|
"deny": []
|
||||||
|
}
|
||||||
|
}
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -66,3 +66,5 @@ storybook-static
|
|||||||
.github\instructions\nx.instructions.md
|
.github\instructions\nx.instructions.md
|
||||||
.cursor/rules/nx-rules.mdc
|
.cursor/rules/nx-rules.mdc
|
||||||
.github/instructions/nx.instructions.md
|
.github/instructions/nx.instructions.md
|
||||||
|
|
||||||
|
vite.config.*.timestamp*
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
"tabWidth": 2,
|
"tabWidth": 2,
|
||||||
"bracketSpacing": true,
|
"bracketSpacing": true,
|
||||||
"printWidth": 80,
|
"printWidth": 80,
|
||||||
"endOfLine": "crlf",
|
"endOfLine": "auto",
|
||||||
"arrowParens": "always",
|
"arrowParens": "always",
|
||||||
"quoteProps": "consistent",
|
"quoteProps": "consistent",
|
||||||
"overrides": [
|
"overrides": [
|
||||||
|
|||||||
@@ -4,5 +4,6 @@
|
|||||||
@use "../../../libs/ui/input-controls/src/input-controls.scss";
|
@use "../../../libs/ui/input-controls/src/input-controls.scss";
|
||||||
@use "../../../libs/ui/menu/src/menu.scss";
|
@use "../../../libs/ui/menu/src/menu.scss";
|
||||||
@use "../../../libs/ui/progress-bar/src/lib/progress-bar.scss";
|
@use "../../../libs/ui/progress-bar/src/lib/progress-bar.scss";
|
||||||
|
@use "../../../libs/ui/search-bar/src/search-bar.scss";
|
||||||
@use "../../../libs/ui/skeleton-loader/src/skeleton-loader.scss";
|
@use "../../../libs/ui/skeleton-loader/src/skeleton-loader.scss";
|
||||||
@use "../../../libs/ui/tooltip/src/tooltip.scss";
|
@use "../../../libs/ui/tooltip/src/tooltip.scss";
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
export * from './lib/services';
|
export * from './lib/services';
|
||||||
|
export * from './lib/schemas';
|
||||||
export * from './lib/models';
|
export * from './lib/models';
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { AvailabilityDTO } from '@generated/swagger/cat-search-api';
|
||||||
|
import { Price } from './price';
|
||||||
|
|
||||||
|
export interface Availability extends AvailabilityDTO {
|
||||||
|
price: Price;
|
||||||
|
}
|
||||||
@@ -1,2 +1,5 @@
|
|||||||
|
export * from './availability';
|
||||||
export * from './item';
|
export * from './item';
|
||||||
|
export * from './price-value';
|
||||||
|
export * from './price';
|
||||||
export * from './product';
|
export * from './product';
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { ItemDTO } from '@generated/swagger/cat-search-api';
|
import { ItemDTO } from '@generated/swagger/cat-search-api';
|
||||||
import { Product } from './product';
|
import { Product } from './product';
|
||||||
|
import { Availability } from './availability';
|
||||||
|
|
||||||
export interface Item extends ItemDTO {
|
export interface Item extends ItemDTO {
|
||||||
id: number;
|
id: number;
|
||||||
product: Product;
|
product: Product;
|
||||||
|
catalogAvailability: Availability;
|
||||||
}
|
}
|
||||||
|
|||||||
5
libs/catalogue/data-access/src/lib/models/price-value.ts
Normal file
5
libs/catalogue/data-access/src/lib/models/price-value.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { PriceValueDTO } from '@generated/swagger/cat-search-api';
|
||||||
|
|
||||||
|
export interface PriceValue extends PriceValueDTO {
|
||||||
|
value: number;
|
||||||
|
}
|
||||||
6
libs/catalogue/data-access/src/lib/models/price.ts
Normal file
6
libs/catalogue/data-access/src/lib/models/price.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { PriceDTO } from '@generated/swagger/cat-search-api';
|
||||||
|
import { PriceValue } from './price-value';
|
||||||
|
|
||||||
|
export interface Price extends PriceDTO {
|
||||||
|
value: PriceValue;
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
export const SearchByTermParamsSchema = z.object({
|
export const SearchByTermSchema = z.object({
|
||||||
term: z.string().min(1, 'Search term must not be empty'),
|
searchTerm: z.string().min(1, 'Search term must not be empty'),
|
||||||
skip: z.number().int().min(0).default(0),
|
skip: z.number().int().min(0).default(0),
|
||||||
take: z.number().int().min(1).max(100).default(20),
|
take: z.number().int().min(1).max(100).default(20),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type SearchByTermParams = z.infer<typeof SearchByTermParamsSchema>;
|
export type SearchByTerm = z.infer<typeof SearchByTermSchema>;
|
||||||
|
|
||||||
|
export type SearchByTermInput = z.input<typeof SearchByTermSchema>;
|
||||||
|
|||||||
@@ -4,9 +4,10 @@ import { firstValueFrom, map, Observable } from 'rxjs';
|
|||||||
import { takeUntilAborted } from '@isa/common/data-access';
|
import { takeUntilAborted } from '@isa/common/data-access';
|
||||||
import { Item } from '../models';
|
import { Item } from '../models';
|
||||||
import {
|
import {
|
||||||
SearchByTermParams,
|
SearchByTermInput,
|
||||||
SearchByTermParamsSchema,
|
SearchByTermSchema,
|
||||||
} from '../schemas/catalouge-search.schemas';
|
} from '../schemas/catalouge-search.schemas';
|
||||||
|
import { ListResponseArgs } from '@isa/common/data-access';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class CatalougeSearchService {
|
export class CatalougeSearchService {
|
||||||
@@ -25,15 +26,15 @@ export class CatalougeSearchService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async searchByTerm(
|
async searchByTerm(
|
||||||
params: SearchByTermParams,
|
params: SearchByTermInput,
|
||||||
abortSignal: AbortSignal,
|
abortSignal: AbortSignal,
|
||||||
): Promise<Item[]> {
|
): Promise<ListResponseArgs<Item>> {
|
||||||
const { term, skip, take } = SearchByTermParamsSchema.parse(params);
|
const { searchTerm, skip, take } = SearchByTermSchema.parse(params);
|
||||||
|
|
||||||
const req$ = this.#searchService
|
const req$ = this.#searchService
|
||||||
.SearchSearch({
|
.SearchSearch({
|
||||||
filter: {
|
filter: {
|
||||||
qs: term,
|
qs: searchTerm,
|
||||||
},
|
},
|
||||||
skip,
|
skip,
|
||||||
take,
|
take,
|
||||||
@@ -46,6 +47,6 @@ export class CatalougeSearchService {
|
|||||||
throw new Error(res.message);
|
throw new Error(res.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.result as Item[];
|
return res as ListResponseArgs<Item>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
export * from './lib/errors';
|
export * from './lib/errors';
|
||||||
|
export * from './lib/helpers';
|
||||||
export * from './lib/models';
|
export * from './lib/models';
|
||||||
export * from './lib/operators';
|
export * from './lib/operators';
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
export * from './data-access.error';
|
export * from './data-access.error';
|
||||||
export * from './property-is-empty.error';
|
export * from './property-is-empty.error';
|
||||||
export * from './property-is-null-or-undefined.error';
|
export * from './property-is-null-or-undefined.error';
|
||||||
|
export * from './response-args.error';
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { ResponseArgs } from '../models';
|
||||||
|
import { DataAccessError } from './data-access.error';
|
||||||
|
|
||||||
|
function invalidPropertyErrorMessage(
|
||||||
|
invalidProperties: Record<string, string> | undefined,
|
||||||
|
): string | undefined {
|
||||||
|
if (!invalidProperties || Object.keys(invalidProperties).length === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Object.entries(invalidProperties)
|
||||||
|
.map(([key, value]) => `${key}: ${value}`)
|
||||||
|
.join('; ');
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ResponseArgsError<
|
||||||
|
T,
|
||||||
|
> extends DataAccessError<'RESPONSE_ARGS_ERROR'> {
|
||||||
|
constructor(public readonly responseArgs: Omit<ResponseArgs<T>, 'result'>) {
|
||||||
|
super(
|
||||||
|
'RESPONSE_ARGS_ERROR',
|
||||||
|
responseArgs.message ||
|
||||||
|
invalidPropertyErrorMessage(responseArgs.invalidProperties) ||
|
||||||
|
'An error occurred while processing response arguments',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
export function createEscAbortControllerHelper(): AbortController {
|
||||||
|
const escAbortController = new AbortController();
|
||||||
|
const escKeyHandler = (event: KeyboardEvent) => {
|
||||||
|
if (event.key === 'Escape') {
|
||||||
|
escAbortController.abort();
|
||||||
|
document.removeEventListener('keydown', escKeyHandler);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('keydown', escKeyHandler);
|
||||||
|
|
||||||
|
return escAbortController;
|
||||||
|
}
|
||||||
1
libs/common/data-access/src/lib/helpers/index.ts
Normal file
1
libs/common/data-access/src/lib/helpers/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './create-esc-abort-controller.helper';
|
||||||
@@ -15,7 +15,7 @@ export interface ResponseArgs<T> {
|
|||||||
* Map of property names to error messages for validation failures
|
* Map of property names to error messages for validation failures
|
||||||
* Keys represent property names, values contain validation error messages
|
* Keys represent property names, values contain validation error messages
|
||||||
*/
|
*/
|
||||||
invalidProperties: Record<string, string>;
|
invalidProperties?: Record<string, string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optional message providing additional information about the response
|
* Optional message providing additional information about the response
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import { PrintDialogComponent } from '../print-dialog/print-dialog.component';
|
|||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class PrintService {
|
export class PrintService {
|
||||||
#printService = inject(PrintApiService);
|
#printService = inject(PrintApiService);
|
||||||
#printDailog = injectDialog(PrintDialogComponent, 'Drucken');
|
#printDailog = injectDialog(PrintDialogComponent, { title: 'Drucken' });
|
||||||
#platform = inject(Platform);
|
#platform = inject(Platform);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ export function hash(obj: object | string): string {
|
|||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
const str = JSON.stringify(obj, Object.keys(obj).sort());
|
const str = JSON.stringify(obj);
|
||||||
let hash = 0;
|
let hash = 0;
|
||||||
for (let i = 0; i < str.length; i++) {
|
for (let i = 0; i < str.length; i++) {
|
||||||
hash = (hash << 5) - hash + str.charCodeAt(i);
|
hash = (hash << 5) - hash + str.charCodeAt(i);
|
||||||
|
|||||||
@@ -4,12 +4,15 @@ import { z } from 'zod';
|
|||||||
import { OAuthService } from 'angular-oauth2-oidc';
|
import { OAuthService } from 'angular-oauth2-oidc';
|
||||||
import { hash } from './hash.utils';
|
import { hash } from './hash.utils';
|
||||||
|
|
||||||
export const USER_SUB = new InjectionToken<() => string>('core.storage.user-sub', {
|
export const USER_SUB = new InjectionToken<() => string>(
|
||||||
factory: () => {
|
'core.storage.user-sub',
|
||||||
const auth = inject(OAuthService, { optional: true });
|
{
|
||||||
return () => auth?.getIdentityClaims()?.['sub'] ?? 'anonymous';
|
factory: () => {
|
||||||
|
const auth = inject(OAuthService, { optional: true });
|
||||||
|
return () => auth?.getIdentityClaims()?.['sub'] ?? 'anonymous';
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
);
|
||||||
|
|
||||||
export class Storage {
|
export class Storage {
|
||||||
private readonly userSub = inject(USER_SUB);
|
private readonly userSub = inject(USER_SUB);
|
||||||
@@ -25,7 +28,10 @@ export class Storage {
|
|||||||
return this.storageProvider.set(this.getKey(token), value);
|
return this.storageProvider.set(this.getKey(token), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
async get<T>(token: string | object, schema?: z.ZodType<T>): Promise<T | unknown> {
|
async get<T>(
|
||||||
|
token: string | object,
|
||||||
|
schema?: z.ZodType<T>,
|
||||||
|
): Promise<T | unknown> {
|
||||||
const data = await this.storageProvider.get(this.getKey(token));
|
const data = await this.storageProvider.get(this.getKey(token));
|
||||||
if (schema) {
|
if (schema) {
|
||||||
return schema.parse(data);
|
return schema.parse(data);
|
||||||
|
|||||||
@@ -11,10 +11,9 @@ export class UncompletedTasksGuard
|
|||||||
implements CanDeactivate<ReturnReviewComponent>
|
implements CanDeactivate<ReturnReviewComponent>
|
||||||
{
|
{
|
||||||
#returnTaskListStore = inject(ReturnTaskListStore);
|
#returnTaskListStore = inject(ReturnTaskListStore);
|
||||||
#confirmationDialog = injectDialog(
|
#confirmationDialog = injectDialog(ConfirmationDialogComponent, {
|
||||||
ConfirmationDialogComponent,
|
title: 'Aufgaben erledigen',
|
||||||
'Aufgaben erledigen',
|
});
|
||||||
);
|
|
||||||
|
|
||||||
processId = injectActivatedTabId();
|
processId = injectActivatedTabId();
|
||||||
|
|
||||||
|
|||||||
@@ -2,5 +2,4 @@ import { PriceValueDTO } from '@generated/swagger/inventory-api';
|
|||||||
|
|
||||||
export interface PriceValue extends PriceValueDTO {
|
export interface PriceValue extends PriceValueDTO {
|
||||||
value: number;
|
value: number;
|
||||||
currency: string;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { z } from 'zod';
|
||||||
|
|
||||||
|
export const FetchReturnReasonSchema = z.object({
|
||||||
|
stockId: z.number(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type FetchReturnReason = z.infer<typeof FetchReturnReasonSchema>;
|
||||||
|
|
||||||
|
export type FetchReturnReasonParams = z.input<typeof FetchReturnReasonSchema>;
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
|
export * from './fetch-product-groups.schema';
|
||||||
|
export * from './fetch-query-settings.schema';
|
||||||
|
export * from './fetch-return-reason.schema';
|
||||||
export * from './fetch-stock-in-stock.schema';
|
export * from './fetch-stock-in-stock.schema';
|
||||||
export * from './fetch-suppliers.schema';
|
export * from './fetch-suppliers.schema';
|
||||||
export * from './fetch-query-settings.schema';
|
|
||||||
export * from './query-token.schema';
|
export * from './query-token.schema';
|
||||||
export * from './fetch-product-groups.schema';
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
export * from './remission-stock.service';
|
|
||||||
export * from './remission-product-group.service';
|
export * from './remission-product-group.service';
|
||||||
|
export * from './remission-reason.service';
|
||||||
export * from './remission-search.service';
|
export * from './remission-search.service';
|
||||||
|
export * from './remission-stock.service';
|
||||||
export * from './remission-supplier.service';
|
export * from './remission-supplier.service';
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { inject, Injectable } from '@angular/core';
|
||||||
|
import { ReturnService } from '@generated/swagger/inventory-api';
|
||||||
|
import { FetchReturnReasonParams, FetchReturnReasonSchema } from '../schemas';
|
||||||
|
import { ResponseArgsError, takeUntilAborted } from '@isa/common/data-access';
|
||||||
|
import { firstValueFrom } from 'rxjs';
|
||||||
|
import { KeyValueStringAndString } from '../models';
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class RemissionReasonService {
|
||||||
|
#returnService = inject(ReturnService);
|
||||||
|
|
||||||
|
async fetchReturnReasons(
|
||||||
|
params: FetchReturnReasonParams,
|
||||||
|
abortSignal?: AbortSignal,
|
||||||
|
): Promise<KeyValueStringAndString[]> {
|
||||||
|
const { stockId } = FetchReturnReasonSchema.parse(params);
|
||||||
|
|
||||||
|
let req$ = this.#returnService.ReturnGetReturnReasons({ stockId });
|
||||||
|
|
||||||
|
if (abortSignal) {
|
||||||
|
req$ = req$.pipe(takeUntilAborted(abortSignal));
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await firstValueFrom(req$);
|
||||||
|
|
||||||
|
if (res.error) {
|
||||||
|
throw new ResponseArgsError(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.result as KeyValueStringAndString[];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,13 +5,14 @@ import { Stock, StockInfo } from '../models';
|
|||||||
import { FetchStockInStock, FetchStockInStockSchema } from '../schemas';
|
import { FetchStockInStock, FetchStockInStockSchema } from '../schemas';
|
||||||
import { injectStorage, MemoryStorageProvider } from '@isa/core/storage';
|
import { injectStorage, MemoryStorageProvider } from '@isa/core/storage';
|
||||||
import { ASSIGNED_STOCK_STORAGE_KEY } from '../constants';
|
import { ASSIGNED_STOCK_STORAGE_KEY } from '../constants';
|
||||||
|
import { ResponseArgsError, takeUntilAborted } from '@isa/common/data-access';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class RemissionStockService {
|
export class RemissionStockService {
|
||||||
#stockService = inject(StockService);
|
#stockService = inject(StockService);
|
||||||
#memoryStorage = injectStorage(MemoryStorageProvider);
|
#memoryStorage = injectStorage(MemoryStorageProvider);
|
||||||
|
|
||||||
async fetchAssignedStock(): Promise<Stock> {
|
async fetchAssignedStock(abortSignal?: AbortSignal): Promise<Stock> {
|
||||||
const cached = await this.#memoryStorage.get(ASSIGNED_STOCK_STORAGE_KEY);
|
const cached = await this.#memoryStorage.get(ASSIGNED_STOCK_STORAGE_KEY);
|
||||||
|
|
||||||
if (cached) {
|
if (cached) {
|
||||||
@@ -20,10 +21,14 @@ export class RemissionStockService {
|
|||||||
|
|
||||||
const req$ = this.#stockService.StockCurrentStock();
|
const req$ = this.#stockService.StockCurrentStock();
|
||||||
|
|
||||||
|
if (abortSignal) {
|
||||||
|
req$.pipe(takeUntilAborted(abortSignal));
|
||||||
|
}
|
||||||
|
|
||||||
const res = await firstValueFrom(req$);
|
const res = await firstValueFrom(req$);
|
||||||
|
|
||||||
if (res.error || !res.result) {
|
if (res.error || !res.result) {
|
||||||
throw new Error(res.message || 'Failed to fetch CurrentStock data');
|
throw new ResponseArgsError(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#memoryStorage.set(ASSIGNED_STOCK_STORAGE_KEY, res.result);
|
this.#memoryStorage.set(ASSIGNED_STOCK_STORAGE_KEY, res.result);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||||
import { ButtonComponent } from '@isa/ui/buttons';
|
import { ButtonComponent } from '@isa/ui/buttons';
|
||||||
|
import { injectDialog } from '@isa/ui/dialog';
|
||||||
|
import { SearchItemToRemitDialogComponent } from '@isa/remission/shared/search-item-to-remit-dialog';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'remission-feature-remission-start-card',
|
selector: 'remission-feature-remission-start-card',
|
||||||
@@ -9,7 +11,9 @@ import { ButtonComponent } from '@isa/ui/buttons';
|
|||||||
imports: [ButtonComponent],
|
imports: [ButtonComponent],
|
||||||
})
|
})
|
||||||
export class RemissionStartCardComponent {
|
export class RemissionStartCardComponent {
|
||||||
|
searchItemToRemitDialog = injectDialog(SearchItemToRemitDialogComponent);
|
||||||
|
|
||||||
startRemission() {
|
startRemission() {
|
||||||
console.log('Start');
|
this.searchItemToRemitDialog({ data: { searchTerm: 'Pokemon' } });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# remission-shared-search-item-to-remit-dialog
|
||||||
|
|
||||||
|
This library was generated with [Nx](https://nx.dev).
|
||||||
|
|
||||||
|
## Running unit tests
|
||||||
|
|
||||||
|
Run `nx test remission-shared-search-item-to-remit-dialog` to execute the unit tests.
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
const nx = require('@nx/eslint-plugin');
|
||||||
|
const baseConfig = require('../../../../eslint.config.js');
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
...baseConfig,
|
||||||
|
...nx.configs['flat/angular'],
|
||||||
|
...nx.configs['flat/angular-template'],
|
||||||
|
{
|
||||||
|
files: ['**/*.ts'],
|
||||||
|
rules: {
|
||||||
|
'@angular-eslint/directive-selector': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
type: 'attribute',
|
||||||
|
prefix: 'remi',
|
||||||
|
style: 'camelCase',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'@angular-eslint/component-selector': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
type: 'element',
|
||||||
|
prefix: 'remi',
|
||||||
|
style: 'kebab-case',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['**/*.html'],
|
||||||
|
// Override or add rules here
|
||||||
|
rules: {},
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "remission-shared-search-item-to-remit-dialog",
|
||||||
|
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
|
||||||
|
"sourceRoot": "libs/remission/shared/search-item-to-remit-dialog/src",
|
||||||
|
"prefix": "remi",
|
||||||
|
"projectType": "library",
|
||||||
|
"tags": [],
|
||||||
|
"targets": {
|
||||||
|
"test": {
|
||||||
|
"executor": "@nx/vite:test",
|
||||||
|
"outputs": ["{options.reportsDirectory}"],
|
||||||
|
"options": {
|
||||||
|
"reportsDirectory": "../../../../coverage/libs/remission/shared/search-item-to-remit-dialog"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"executor": "@nx/eslint:lint"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './lib/search-item-to-remit-dialog.component';
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { Item } from '@isa/catalogue/data-access';
|
||||||
|
import { ListResponseArgs } from '@isa/common/data-access';
|
||||||
|
|
||||||
|
export const DEFAULT_LIST_RESPONSE_ARGS_OF_ITEM: ListResponseArgs<Item> = {
|
||||||
|
error: false,
|
||||||
|
hits: 0,
|
||||||
|
result: [],
|
||||||
|
skip: 0,
|
||||||
|
take: 0,
|
||||||
|
invalidProperties: {},
|
||||||
|
};
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<div class="isa-text-body-1-bold">Menge {{ position() }}</div>
|
||||||
|
<div class="-mr-4">
|
||||||
|
<ui-dropdown [(ngModel)]="quantity" class="border-none">
|
||||||
|
<ui-dropdown-option [value]="1">1</ui-dropdown-option>
|
||||||
|
<ui-dropdown-option [value]="2">2</ui-dropdown-option>
|
||||||
|
<ui-dropdown-option [value]="3">3</ui-dropdown-option>
|
||||||
|
<ui-dropdown-option [value]="4">4</ui-dropdown-option>
|
||||||
|
<ui-dropdown-option [value]="5">5</ui-dropdown-option>
|
||||||
|
</ui-dropdown>
|
||||||
|
<ui-dropdown [(ngModel)]="reason" class="border-none">
|
||||||
|
@if (reasonResource.value(); as reasons) {
|
||||||
|
@for (reson of reasons; track reson.key) {
|
||||||
|
<ui-dropdown-option [value]="reson.value">
|
||||||
|
{{ reson.value }}
|
||||||
|
</ui-dropdown-option>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<ui-dropdown-option [value]="1">1</ui-dropdown-option>
|
||||||
|
</ui-dropdown>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
:host {
|
||||||
|
@apply grid grid-cols-[1fr,auto] items-center justify-between px-4 py-[.44rem] border border-isa-neutral-400 rounded-lg;
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import {
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
Component,
|
||||||
|
inject,
|
||||||
|
input,
|
||||||
|
linkedSignal,
|
||||||
|
model,
|
||||||
|
resource,
|
||||||
|
} from '@angular/core';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import {
|
||||||
|
RemissionReasonService,
|
||||||
|
RemissionStockService,
|
||||||
|
} from '@isa/remission/data-access';
|
||||||
|
import {
|
||||||
|
DropdownButtonComponent,
|
||||||
|
DropdownOptionComponent,
|
||||||
|
} from '@isa/ui/input-controls';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'remi-quantity-and-reason-item',
|
||||||
|
templateUrl: './quantity-and-reason-item.component.html',
|
||||||
|
styleUrls: ['./quantity-and-reason-item.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
standalone: true,
|
||||||
|
imports: [DropdownButtonComponent, DropdownOptionComponent, FormsModule],
|
||||||
|
})
|
||||||
|
export class QuantityAndReasonItemComponent {
|
||||||
|
#reasonService = inject(RemissionReasonService);
|
||||||
|
#stockService = inject(RemissionStockService);
|
||||||
|
|
||||||
|
position = input.required<number>();
|
||||||
|
|
||||||
|
quantity = linkedSignal(() => 1);
|
||||||
|
|
||||||
|
reason = linkedSignal(() => {
|
||||||
|
const returnReasons = this.reasonResource.value();
|
||||||
|
if (!returnReasons || returnReasons.length === 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return returnReasons[0].value;
|
||||||
|
});
|
||||||
|
|
||||||
|
assignedStockResource = resource({
|
||||||
|
loader: ({ abortSignal }) =>
|
||||||
|
this.#stockService.fetchAssignedStock(abortSignal),
|
||||||
|
});
|
||||||
|
|
||||||
|
reasonResource = resource({
|
||||||
|
params: this.assignedStockResource.value,
|
||||||
|
loader: async ({ abortSignal, params }) => {
|
||||||
|
if (!params || !params.id) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.#reasonService.fetchReturnReasons(
|
||||||
|
{
|
||||||
|
stockId: params.id,
|
||||||
|
},
|
||||||
|
abortSignal,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
@if (item()) {
|
||||||
|
<remi-select-remi-quantity-and-reason></remi-select-remi-quantity-and-reason>
|
||||||
|
} @else {
|
||||||
|
<button
|
||||||
|
class="absolute top-1 right-[1.33rem]"
|
||||||
|
type="button"
|
||||||
|
uiTextButton
|
||||||
|
siez="small"
|
||||||
|
color="subtle"
|
||||||
|
(click)="close(undefined)"
|
||||||
|
>
|
||||||
|
Schließen
|
||||||
|
</button>
|
||||||
|
<remi-search-item-to-remit-list></remi-search-item-to-remit-list>
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
:host {
|
||||||
|
@apply block h-full;
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import {
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
Component,
|
||||||
|
effect,
|
||||||
|
isSignal,
|
||||||
|
linkedSignal,
|
||||||
|
signal,
|
||||||
|
Signal,
|
||||||
|
} from '@angular/core';
|
||||||
|
import { DialogContentDirective } from '@isa/ui/dialog';
|
||||||
|
import { Item } from '@isa/catalogue/data-access';
|
||||||
|
import { TextButtonComponent } from '@isa/ui/buttons';
|
||||||
|
import { provideIcons } from '@ng-icons/core';
|
||||||
|
import { isaActionSearch } from '@isa/icons';
|
||||||
|
import { SearchItemToRemitListComponent } from './search-item-to-remit-list.component';
|
||||||
|
import { SelectRemiQuantityAndReasonComponent } from './select-remi-quantity-and-reason.component';
|
||||||
|
|
||||||
|
export type SearchItemToRemitDialogData = {
|
||||||
|
searchTerm: string | Signal<string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'remi-search-item-to-remit-dialog',
|
||||||
|
templateUrl: './search-item-to-remit-dialog.component.html',
|
||||||
|
styleUrls: ['./search-item-to-remit-dialog.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
TextButtonComponent,
|
||||||
|
SearchItemToRemitListComponent,
|
||||||
|
SelectRemiQuantityAndReasonComponent,
|
||||||
|
],
|
||||||
|
providers: [provideIcons({ isaActionSearch })],
|
||||||
|
})
|
||||||
|
export class SearchItemToRemitDialogComponent extends DialogContentDirective<
|
||||||
|
SearchItemToRemitDialogData,
|
||||||
|
Item | undefined
|
||||||
|
> {
|
||||||
|
searchTerm = linkedSignal(() =>
|
||||||
|
isSignal(this.data.searchTerm)
|
||||||
|
? this.data.searchTerm()
|
||||||
|
: this.data.searchTerm,
|
||||||
|
);
|
||||||
|
|
||||||
|
item = signal<Item | undefined>(undefined);
|
||||||
|
|
||||||
|
itemEffect = effect(() => {
|
||||||
|
const item = this.item();
|
||||||
|
this.dialogRef.updateSize(item ? '36rem' : 'auto');
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<ui-search-bar appearance="main" class="bg-isa-neutral-100 w-full">
|
||||||
|
<input
|
||||||
|
[(ngModel)]="host.searchTerm"
|
||||||
|
type="text"
|
||||||
|
placeholder="Rechnungsnummer, E-Mail, Kundenkarte, Name..."
|
||||||
|
(keydown.enter)="triggerSearch()"
|
||||||
|
/>
|
||||||
|
<ui-search-bar-clear></ui-search-bar-clear>
|
||||||
|
<ui-icon-button
|
||||||
|
type="submit"
|
||||||
|
name="isaActionSearch"
|
||||||
|
color="brand"
|
||||||
|
(click)="triggerSearch()"
|
||||||
|
[pending]="searchResource.isLoading()"
|
||||||
|
></ui-icon-button>
|
||||||
|
</ui-search-bar>
|
||||||
|
<p
|
||||||
|
class="text-isa-neutral-600 isa-text-body-1-regular pb-4 border-b border-b-isa-neutral-300"
|
||||||
|
>
|
||||||
|
Sie können Artikel die nicht auf der Remi Liste stehen direkt zum
|
||||||
|
Warenbegleitschein hinzufügen.
|
||||||
|
</p>
|
||||||
|
<div class="overflow-y-auto">
|
||||||
|
@if (searchResource.value()?.result; as items) {
|
||||||
|
@for (item of items; track item.id) {
|
||||||
|
@defer {
|
||||||
|
<remi-search-item-to-remit [item]="item"></remi-search-item-to-remit>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
:host {
|
||||||
|
@apply grid grid-rows-[auto,auto,1fr] gap-6 h-full;
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
import {
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
Component,
|
||||||
|
inject,
|
||||||
|
OnInit,
|
||||||
|
resource,
|
||||||
|
signal,
|
||||||
|
} from '@angular/core';
|
||||||
|
import { isaActionSearch } from '@isa/icons';
|
||||||
|
import { IconButtonComponent } from '@isa/ui/buttons';
|
||||||
|
import {
|
||||||
|
UiSearchBarClearComponent,
|
||||||
|
UiSearchBarComponent,
|
||||||
|
} from '@isa/ui/search-bar';
|
||||||
|
import { provideIcons } from '@ng-icons/core';
|
||||||
|
import { SearchItemToRemitComponent } from './search-item-to-remit.component';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { DEFAULT_LIST_RESPONSE_ARGS_OF_ITEM } from './constants';
|
||||||
|
import {
|
||||||
|
CatalougeSearchService,
|
||||||
|
SearchByTermInput,
|
||||||
|
Item,
|
||||||
|
} from '@isa/catalogue/data-access';
|
||||||
|
import {
|
||||||
|
ListResponseArgs,
|
||||||
|
createEscAbortControllerHelper,
|
||||||
|
} from '@isa/common/data-access';
|
||||||
|
import { injectStorage, MemoryStorageProvider } from '@isa/core/storage';
|
||||||
|
import { SearchItemToRemitDialogComponent } from './search-item-to-remit-dialog.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'remi-search-item-to-remit-list',
|
||||||
|
templateUrl: './search-item-to-remit-list.component.html',
|
||||||
|
styleUrls: ['./search-item-to-remit-list.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
UiSearchBarClearComponent,
|
||||||
|
UiSearchBarComponent,
|
||||||
|
IconButtonComponent,
|
||||||
|
FormsModule,
|
||||||
|
SearchItemToRemitComponent,
|
||||||
|
],
|
||||||
|
providers: [provideIcons({ isaActionSearch })],
|
||||||
|
})
|
||||||
|
export class SearchItemToRemitListComponent implements OnInit {
|
||||||
|
host = inject(SearchItemToRemitDialogComponent);
|
||||||
|
#catalougeSearchService = inject(CatalougeSearchService);
|
||||||
|
#memoryStorage = injectStorage(MemoryStorageProvider);
|
||||||
|
|
||||||
|
searchParams = signal<SearchByTermInput | undefined>(undefined);
|
||||||
|
|
||||||
|
#setSearchResourceCache(
|
||||||
|
params: SearchByTermInput,
|
||||||
|
data: ListResponseArgs<Item>,
|
||||||
|
): Promise<void> {
|
||||||
|
return this.#memoryStorage.set(
|
||||||
|
{
|
||||||
|
component: 'SearchItemToRemitDialogComponent',
|
||||||
|
params,
|
||||||
|
},
|
||||||
|
data,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#getSearchResourceCache(
|
||||||
|
params: SearchByTermInput,
|
||||||
|
): Promise<ListResponseArgs<Item> | undefined> {
|
||||||
|
return this.#memoryStorage.get({
|
||||||
|
component: 'SearchItemToRemitDialogComponent',
|
||||||
|
params,
|
||||||
|
}) as Promise<ListResponseArgs<Item> | undefined>;
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerSearch(): void {
|
||||||
|
this.searchParams.set({
|
||||||
|
searchTerm: this.host.searchTerm(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
searchResource = resource({
|
||||||
|
params: this.searchParams,
|
||||||
|
loader: async ({ abortSignal, params }) => {
|
||||||
|
if (params === undefined) {
|
||||||
|
return DEFAULT_LIST_RESPONSE_ARGS_OF_ITEM;
|
||||||
|
}
|
||||||
|
let result = await this.#getSearchResourceCache(params);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const escAbortController = createEscAbortControllerHelper();
|
||||||
|
|
||||||
|
try {
|
||||||
|
result = await this.#catalougeSearchService.searchByTerm(
|
||||||
|
params,
|
||||||
|
AbortSignal.any([abortSignal, escAbortController.signal]),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.#setSearchResourceCache(params, result);
|
||||||
|
} catch (error) {
|
||||||
|
const message =
|
||||||
|
error instanceof Error ? error.message : 'Unknown error';
|
||||||
|
result = {
|
||||||
|
...DEFAULT_LIST_RESPONSE_ARGS_OF_ITEM,
|
||||||
|
error: true,
|
||||||
|
message,
|
||||||
|
};
|
||||||
|
} finally {
|
||||||
|
escAbortController.abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.host.dialog.title.set('');
|
||||||
|
if (this.host.searchTerm().length) {
|
||||||
|
this.triggerSearch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<remi-product-info
|
||||||
|
[item]="{
|
||||||
|
product: item().product,
|
||||||
|
retailPrice: item().catalogAvailability.price,
|
||||||
|
}"
|
||||||
|
></remi-product-info>
|
||||||
|
<div class="text-right">
|
||||||
|
<button
|
||||||
|
class="-mr-5"
|
||||||
|
type="button"
|
||||||
|
uiTextButton
|
||||||
|
color="strong"
|
||||||
|
(click)="host.item.set(item())"
|
||||||
|
>
|
||||||
|
Remimenge auswählen
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
:host {
|
||||||
|
@apply grid grid-flow-row border-b border-b-isa-neutral-300 pt-6 pb-4 gap-4;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import {
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
Component,
|
||||||
|
inject,
|
||||||
|
input,
|
||||||
|
} from '@angular/core';
|
||||||
|
import { Item } from '@isa/catalogue/data-access';
|
||||||
|
import { ProductInfoComponent } from '@isa/remission/shared/product';
|
||||||
|
import { TextButtonComponent } from '@isa/ui/buttons';
|
||||||
|
import { SearchItemToRemitDialogComponent } from './search-item-to-remit-dialog.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'remi-search-item-to-remit',
|
||||||
|
templateUrl: './search-item-to-remit.component.html',
|
||||||
|
styleUrls: ['./search-item-to-remit.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
imports: [ProductInfoComponent, TextButtonComponent],
|
||||||
|
})
|
||||||
|
export class SearchItemToRemitComponent {
|
||||||
|
host = inject(SearchItemToRemitDialogComponent);
|
||||||
|
|
||||||
|
item = input.required<Item>();
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<p class="text-isa-neutral-600 isa-text-body-1-regular">
|
||||||
|
Wie viele Exemplare können remittiert werden?
|
||||||
|
</p>
|
||||||
|
<div>
|
||||||
|
<remi-quantity-and-reason-item [position]="1"></remi-quantity-and-reason-item>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="flex items-center gap-2 -ml-5"
|
||||||
|
uiTextButton
|
||||||
|
color="strong"
|
||||||
|
>
|
||||||
|
<ng-icon name="isaActionPlus" size="1.5rem"></ng-icon>
|
||||||
|
<div>Menge hinzufügen</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div></div>
|
||||||
|
<div class="grid grid-cols-2 items-center gap-2">
|
||||||
|
<button type="button" color="secondary" size="large" uiButton>Zurück</button>
|
||||||
|
<button type="button" color="primary" size="large" uiButton>Speichern</button>
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
:host {
|
||||||
|
@apply grid grid-flow-row gap-6;
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import {
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
Component,
|
||||||
|
inject,
|
||||||
|
OnInit,
|
||||||
|
} from '@angular/core';
|
||||||
|
import { SearchItemToRemitDialogComponent } from './search-item-to-remit-dialog.component';
|
||||||
|
import { QuantityAndReasonItemComponent } from './quantity-and-reason-item.component';
|
||||||
|
import { ButtonComponent, TextButtonComponent } from '@isa/ui/buttons';
|
||||||
|
import { NgIcon, provideIcons } from '@ng-icons/core';
|
||||||
|
import { isaActionPlus } from '@isa/icons';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'remi-select-remi-quantity-and-reason',
|
||||||
|
templateUrl: './select-remi-quantity-and-reason.component.html',
|
||||||
|
styleUrls: ['./select-remi-quantity-and-reason.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
standalone: true,
|
||||||
|
imports: [
|
||||||
|
QuantityAndReasonItemComponent,
|
||||||
|
TextButtonComponent,
|
||||||
|
NgIcon,
|
||||||
|
ButtonComponent,
|
||||||
|
],
|
||||||
|
providers: [provideIcons({ isaActionPlus })],
|
||||||
|
})
|
||||||
|
export class SelectRemiQuantityAndReasonComponent implements OnInit {
|
||||||
|
host = inject(SearchItemToRemitDialogComponent);
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.host.dialog.title.set('Dieser Artikel steht nicht auf der Remi Liste');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import '@analogjs/vitest-angular/setup-zone';
|
||||||
|
|
||||||
|
import {
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting,
|
||||||
|
} from '@angular/platform-browser-dynamic/testing';
|
||||||
|
import { getTestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
getTestBed().initTestEnvironment(
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting(),
|
||||||
|
);
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es2022",
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"noPropertyAccessFromIndexSignature": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
|
},
|
||||||
|
"files": [],
|
||||||
|
"include": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.lib.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"extends": "../../../../tsconfig.base.json",
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
"enableI18nLegacyMessageIdFormat": false,
|
||||||
|
"strictInjectionParameters": true,
|
||||||
|
"strictInputAccessModifiers": true,
|
||||||
|
"strictTemplates": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../../../dist/out-tsc",
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"inlineSources": true,
|
||||||
|
"types": []
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/test-setup.ts",
|
||||||
|
"jest.config.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"vite.config.ts",
|
||||||
|
"vite.config.mts",
|
||||||
|
"vitest.config.ts",
|
||||||
|
"vitest.config.mts",
|
||||||
|
"src/**/*.test.tsx",
|
||||||
|
"src/**/*.spec.tsx",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.jsx",
|
||||||
|
"src/**/*.spec.jsx",
|
||||||
|
"src/test-setup.ts"
|
||||||
|
],
|
||||||
|
"include": ["src/**/*.ts"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../../../dist/out-tsc",
|
||||||
|
"types": [
|
||||||
|
"vitest/globals",
|
||||||
|
"vitest/importMeta",
|
||||||
|
"vite/client",
|
||||||
|
"node",
|
||||||
|
"vitest"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"vite.config.ts",
|
||||||
|
"vite.config.mts",
|
||||||
|
"vitest.config.ts",
|
||||||
|
"vitest.config.mts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.tsx",
|
||||||
|
"src/**/*.spec.tsx",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.jsx",
|
||||||
|
"src/**/*.spec.jsx",
|
||||||
|
"src/**/*.d.ts"
|
||||||
|
],
|
||||||
|
"files": ["src/test-setup.ts"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/// <reference types='vitest' />
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import angular from '@analogjs/vite-plugin-angular';
|
||||||
|
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||||
|
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
root: __dirname,
|
||||||
|
cacheDir:
|
||||||
|
'../../../../node_modules/.vite/libs/remission/shared/search-item-to-remit-dialog',
|
||||||
|
plugins: [angular(), nxViteTsPaths(), nxCopyAssetsPlugin(['*.md'])],
|
||||||
|
// Uncomment this if you are using workers.
|
||||||
|
// worker: {
|
||||||
|
// plugins: [ nxViteTsPaths() ],
|
||||||
|
// },
|
||||||
|
test: {
|
||||||
|
watch: false,
|
||||||
|
globals: true,
|
||||||
|
environment: 'jsdom',
|
||||||
|
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||||
|
setupFiles: ['src/test-setup.ts'],
|
||||||
|
reporters: ['default'],
|
||||||
|
coverage: {
|
||||||
|
reportsDirectory:
|
||||||
|
'../../../../coverage/libs/remission/shared/search-item-to-remit-dialog',
|
||||||
|
provider: 'v8',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# remission-shared-select-remission-quantity-and-reason-dialog
|
||||||
|
|
||||||
|
This library was generated with [Nx](https://nx.dev).
|
||||||
|
|
||||||
|
## Running unit tests
|
||||||
|
|
||||||
|
Run `nx test remission-shared-select-remission-quantity-and-reason-dialog` to execute the unit tests.
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
const nx = require('@nx/eslint-plugin');
|
||||||
|
const baseConfig = require('../../../../eslint.config.js');
|
||||||
|
|
||||||
|
module.exports = [
|
||||||
|
...baseConfig,
|
||||||
|
...nx.configs['flat/angular'],
|
||||||
|
...nx.configs['flat/angular-template'],
|
||||||
|
{
|
||||||
|
files: ['**/*.ts'],
|
||||||
|
rules: {
|
||||||
|
'@angular-eslint/directive-selector': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
type: 'attribute',
|
||||||
|
prefix: 'remi',
|
||||||
|
style: 'camelCase',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'@angular-eslint/component-selector': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
type: 'element',
|
||||||
|
prefix: 'remi',
|
||||||
|
style: 'kebab-case',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: ['**/*.html'],
|
||||||
|
// Override or add rules here
|
||||||
|
rules: {},
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "remission-shared-select-remission-quantity-and-reason-dialog",
|
||||||
|
"$schema": "../../../../node_modules/nx/schemas/project-schema.json",
|
||||||
|
"sourceRoot": "libs/remission/shared/select-remission-quantity-and-reason-dialog/src",
|
||||||
|
"prefix": "remi",
|
||||||
|
"projectType": "library",
|
||||||
|
"tags": [],
|
||||||
|
"targets": {
|
||||||
|
"test": {
|
||||||
|
"executor": "@nx/vite:test",
|
||||||
|
"outputs": ["{options.reportsDirectory}"],
|
||||||
|
"options": {
|
||||||
|
"reportsDirectory": "../../../../coverage/libs/remission/shared/select-remission-quantity-and-reason-dialog"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"executor": "@nx/eslint:lint"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './lib/remission-shared-select-remission-quantity-and-reason-dialog/remission-shared-select-remission-quantity-and-reason-dialog.component';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
<p>remission-shared-select-remission-quantity-and-reason-dialog works!</p>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { RemissionSharedSelectRemissionQuantityAndReasonDialogComponent } from './remission-shared-select-remission-quantity-and-reason-dialog.component';
|
||||||
|
|
||||||
|
describe('RemissionSharedSelectRemissionQuantityAndReasonDialogComponent', () => {
|
||||||
|
let component: RemissionSharedSelectRemissionQuantityAndReasonDialogComponent;
|
||||||
|
let fixture: ComponentFixture<RemissionSharedSelectRemissionQuantityAndReasonDialogComponent>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [RemissionSharedSelectRemissionQuantityAndReasonDialogComponent],
|
||||||
|
}).compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(
|
||||||
|
RemissionSharedSelectRemissionQuantityAndReasonDialogComponent,
|
||||||
|
);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'remi-remission-shared-select-remission-quantity-and-reason-dialog',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule],
|
||||||
|
templateUrl:
|
||||||
|
'./remission-shared-select-remission-quantity-and-reason-dialog.component.html',
|
||||||
|
styleUrl:
|
||||||
|
'./remission-shared-select-remission-quantity-and-reason-dialog.component.css',
|
||||||
|
})
|
||||||
|
export class RemissionSharedSelectRemissionQuantityAndReasonDialogComponent {}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import '@analogjs/vitest-angular/setup-zone';
|
||||||
|
|
||||||
|
import {
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting,
|
||||||
|
} from '@angular/platform-browser-dynamic/testing';
|
||||||
|
import { getTestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
getTestBed().initTestEnvironment(
|
||||||
|
BrowserDynamicTestingModule,
|
||||||
|
platformBrowserDynamicTesting(),
|
||||||
|
);
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es2022",
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"noPropertyAccessFromIndexSignature": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
|
},
|
||||||
|
"files": [],
|
||||||
|
"include": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.lib.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"extends": "../../../../tsconfig.base.json",
|
||||||
|
"angularCompilerOptions": {
|
||||||
|
"enableI18nLegacyMessageIdFormat": false,
|
||||||
|
"strictInjectionParameters": true,
|
||||||
|
"strictInputAccessModifiers": true,
|
||||||
|
"strictTemplates": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../../../dist/out-tsc",
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"inlineSources": true,
|
||||||
|
"types": []
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/test-setup.ts",
|
||||||
|
"jest.config.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"vite.config.ts",
|
||||||
|
"vite.config.mts",
|
||||||
|
"vitest.config.ts",
|
||||||
|
"vitest.config.mts",
|
||||||
|
"src/**/*.test.tsx",
|
||||||
|
"src/**/*.spec.tsx",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.jsx",
|
||||||
|
"src/**/*.spec.jsx",
|
||||||
|
"src/test-setup.ts"
|
||||||
|
],
|
||||||
|
"include": ["src/**/*.ts"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "../../../../dist/out-tsc",
|
||||||
|
"types": [
|
||||||
|
"vitest/globals",
|
||||||
|
"vitest/importMeta",
|
||||||
|
"vite/client",
|
||||||
|
"node",
|
||||||
|
"vitest"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"vite.config.ts",
|
||||||
|
"vite.config.mts",
|
||||||
|
"vitest.config.ts",
|
||||||
|
"vitest.config.mts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.tsx",
|
||||||
|
"src/**/*.spec.tsx",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.jsx",
|
||||||
|
"src/**/*.spec.jsx",
|
||||||
|
"src/**/*.d.ts"
|
||||||
|
],
|
||||||
|
"files": ["src/test-setup.ts"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/// <reference types='vitest' />
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import angular from '@analogjs/vite-plugin-angular';
|
||||||
|
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||||
|
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
root: __dirname,
|
||||||
|
cacheDir:
|
||||||
|
'../../../../node_modules/.vite/libs/remission/shared/select-remission-quantity-and-reason-dialog',
|
||||||
|
plugins: [angular(), nxViteTsPaths(), nxCopyAssetsPlugin(['*.md'])],
|
||||||
|
// Uncomment this if you are using workers.
|
||||||
|
// worker: {
|
||||||
|
// plugins: [ nxViteTsPaths() ],
|
||||||
|
// },
|
||||||
|
test: {
|
||||||
|
watch: false,
|
||||||
|
globals: true,
|
||||||
|
environment: 'jsdom',
|
||||||
|
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||||
|
setupFiles: ['src/test-setup.ts'],
|
||||||
|
reporters: ['default'],
|
||||||
|
coverage: {
|
||||||
|
reportsDirectory:
|
||||||
|
'../../../../coverage/libs/remission/shared/select-remission-quantity-and-reason-dialog',
|
||||||
|
provider: 'v8',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -37,7 +37,6 @@ import { isaLoading } from '@isa/icons';
|
|||||||
'[tabindex]': 'tabIndex()',
|
'[tabindex]': 'tabIndex()',
|
||||||
'[attr.aria-disabled]': 'disabled()',
|
'[attr.aria-disabled]': 'disabled()',
|
||||||
'[attr.aria-label]': 'name()',
|
'[attr.aria-label]': 'name()',
|
||||||
'[attr.aria-hidden]': 'pending()',
|
|
||||||
'[attr.aria-busy]': 'pending()',
|
'[attr.aria-busy]': 'pending()',
|
||||||
'[attr.role]': 'pending() ? "progressbar" : "button"',
|
'[attr.role]': 'pending() ? "progressbar" : "button"',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
.ui-dialog {
|
.ui-dialog {
|
||||||
@apply bg-isa-white p-8 flex gap-8 items-start rounded-[2rem] flex-col text-isa-neutral-900;
|
@apply bg-isa-white p-8 grid gap-8 items-start rounded-[2rem] grid-flow-row text-isa-neutral-900 relative;
|
||||||
|
@apply max-h-[90vh] max-w-[90vw] overflow-hidden;
|
||||||
|
grid-template-rows: auto 1fr;
|
||||||
|
|
||||||
.ui-dialog-title {
|
.ui-dialog-title {
|
||||||
@apply isa-text-subtitle-1-bold;
|
@apply isa-text-subtitle-1-bold;
|
||||||
|
@apply flex-shrink-0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ui-dialog-content {
|
.ui-dialog-content {
|
||||||
@apply flex flex-col gap-8;
|
@apply flex flex-col gap-8;
|
||||||
|
@apply overflow-y-auto overflow-x-hidden;
|
||||||
|
@apply min-h-0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { DIALOG_DATA, DialogRef } from '@angular/cdk/dialog';
|
import { DIALOG_DATA, DialogRef } from '@angular/cdk/dialog';
|
||||||
import { Directive, inject } from '@angular/core';
|
import { Directive, inject } from '@angular/core';
|
||||||
|
import { DialogComponent } from './dialog.component';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base directive for dialog content components
|
* Base directive for dialog content components
|
||||||
@@ -14,6 +15,8 @@ import { Directive, inject } from '@angular/core';
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
export abstract class DialogContentDirective<D, R> {
|
export abstract class DialogContentDirective<D, R> {
|
||||||
|
readonly dialog = inject(DialogComponent<D, R, DialogContentDirective<D, R>>);
|
||||||
|
|
||||||
/** Reference to the dialog instance */
|
/** Reference to the dialog instance */
|
||||||
readonly dialogRef = inject(DialogRef<R, DialogContentDirective<D, R>>);
|
readonly dialogRef = inject(DialogRef<R, DialogContentDirective<D, R>>);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<h2 class="ui-dialog-title" data-what="title">
|
<h2 class="ui-dialog-title" data-what="title">
|
||||||
{{ title }}
|
{{ title() }}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<ng-container *ngComponentOutlet="component"> </ng-container>
|
<ng-container *ngComponentOutlet="component"> </ng-container>
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
|
import {
|
||||||
|
ChangeDetectionStrategy,
|
||||||
|
Component,
|
||||||
|
inject,
|
||||||
|
signal,
|
||||||
|
} from '@angular/core';
|
||||||
import { DialogContentDirective } from './dialog-content.directive';
|
import { DialogContentDirective } from './dialog-content.directive';
|
||||||
import { DIALOG_CONTENT, DIALOG_TITLE } from './tokens';
|
import { DIALOG_CONTENT, DIALOG_TITLE } from './tokens';
|
||||||
import { ComponentType } from '@angular/cdk/portal';
|
import { ComponentType } from '@angular/cdk/portal';
|
||||||
@@ -23,7 +28,7 @@ import { NgComponentOutlet } from '@angular/common';
|
|||||||
})
|
})
|
||||||
export class DialogComponent<D, R, C extends DialogContentDirective<D, R>> {
|
export class DialogComponent<D, R, C extends DialogContentDirective<D, R>> {
|
||||||
/** The title to display at the top of the dialog */
|
/** The title to display at the top of the dialog */
|
||||||
title = inject(DIALOG_TITLE);
|
title = signal(inject(DIALOG_TITLE));
|
||||||
|
|
||||||
/** The component type to instantiate as the dialog content */
|
/** The component type to instantiate as the dialog content */
|
||||||
readonly component = inject(DIALOG_CONTENT) as ComponentType<C>;
|
readonly component = inject(DIALOG_CONTENT) as ComponentType<C>;
|
||||||
|
|||||||
@@ -7,13 +7,40 @@ import { DialogComponent } from './dialog.component';
|
|||||||
import { DIALOG_CONTENT, DIALOG_TITLE } from './tokens';
|
import { DIALOG_CONTENT, DIALOG_TITLE } from './tokens';
|
||||||
import { MessageDialogComponent } from './message-dialog/message-dialog.component';
|
import { MessageDialogComponent } from './message-dialog/message-dialog.component';
|
||||||
|
|
||||||
|
export interface InjectDialogOptions {
|
||||||
|
/** Optional title override for the dialog */
|
||||||
|
title?: string;
|
||||||
|
|
||||||
|
/** Optional width for the dialog */
|
||||||
|
width?: string;
|
||||||
|
|
||||||
|
/** Optional height for the dialog */
|
||||||
|
height?: string;
|
||||||
|
|
||||||
|
/** Optional minWidth for the dialog */
|
||||||
|
minWidth?: string;
|
||||||
|
|
||||||
|
/** Optional maxWidth for the dialog */
|
||||||
|
maxWidth?: string;
|
||||||
|
|
||||||
|
/** Optional minHeight for the dialog */
|
||||||
|
minHeight?: string;
|
||||||
|
|
||||||
|
/** Optional maxHeight for the dialog */
|
||||||
|
maxHeight?: string;
|
||||||
|
|
||||||
|
/** Optional hasBackdrop for the dialog */
|
||||||
|
hasBackdrop?: boolean;
|
||||||
|
|
||||||
|
/** Optional disableClose for the dialog */
|
||||||
|
disableClose?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options for opening a dialog using injectDialog function
|
* Options for opening a dialog using injectDialog function
|
||||||
* @template D The type of data passed to the dialog
|
* @template D The type of data passed to the dialog
|
||||||
*/
|
*/
|
||||||
export interface OpenDialogOptions<D> {
|
export interface OpenDialogOptions<D> extends InjectDialogOptions {
|
||||||
/** Optional title override for the dialog */
|
|
||||||
title?: string;
|
|
||||||
/** Data to pass to the dialog component */
|
/** Data to pass to the dialog component */
|
||||||
data: D;
|
data: D;
|
||||||
}
|
}
|
||||||
@@ -29,7 +56,7 @@ export interface OpenDialogOptions<D> {
|
|||||||
*/
|
*/
|
||||||
export function injectDialog<C extends DialogContentDirective<any, any>>(
|
export function injectDialog<C extends DialogContentDirective<any, any>>(
|
||||||
componentType: ComponentType<C>,
|
componentType: ComponentType<C>,
|
||||||
title?: string,
|
injectOptions?: InjectDialogOptions,
|
||||||
) {
|
) {
|
||||||
type D = C extends DialogContentDirective<infer D, any> ? D : never;
|
type D = C extends DialogContentDirective<infer D, any> ? D : never;
|
||||||
type R = C extends DialogContentDirective<any, infer R> ? R : never;
|
type R = C extends DialogContentDirective<any, infer R> ? R : never;
|
||||||
@@ -37,7 +64,7 @@ export function injectDialog<C extends DialogContentDirective<any, any>>(
|
|||||||
const cdkDialog = inject(Dialog);
|
const cdkDialog = inject(Dialog);
|
||||||
const injector = inject(Injector);
|
const injector = inject(Injector);
|
||||||
|
|
||||||
return (options?: OpenDialogOptions<D>) => {
|
return (openOptions?: OpenDialogOptions<D>) => {
|
||||||
const dialogInjector = Injector.create({
|
const dialogInjector = Injector.create({
|
||||||
parent: injector,
|
parent: injector,
|
||||||
providers: [
|
providers: [
|
||||||
@@ -47,7 +74,7 @@ export function injectDialog<C extends DialogContentDirective<any, any>>(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
provide: DIALOG_TITLE,
|
provide: DIALOG_TITLE,
|
||||||
useValue: options?.title ?? title,
|
useValue: openOptions?.title ?? injectOptions?.title,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
@@ -55,11 +82,18 @@ export function injectDialog<C extends DialogContentDirective<any, any>>(
|
|||||||
const dialogRef = cdkDialog.open<R, D, DialogComponent<D, R, C>>(
|
const dialogRef = cdkDialog.open<R, D, DialogComponent<D, R, C>>(
|
||||||
DialogComponent<D, R, C>,
|
DialogComponent<D, R, C>,
|
||||||
{
|
{
|
||||||
data: options?.data,
|
data: openOptions?.data,
|
||||||
injector: dialogInjector,
|
injector: dialogInjector,
|
||||||
width: '30rem',
|
width: openOptions?.width ?? injectOptions?.width,
|
||||||
hasBackdrop: true,
|
height: openOptions?.height ?? injectOptions?.height,
|
||||||
disableClose: true,
|
minWidth: openOptions?.minWidth ?? injectOptions?.minWidth ?? '30rem',
|
||||||
|
maxWidth: openOptions?.maxWidth ?? injectOptions?.maxWidth,
|
||||||
|
minHeight: openOptions?.minHeight ?? injectOptions?.minHeight,
|
||||||
|
maxHeight: openOptions?.maxHeight ?? injectOptions?.maxHeight,
|
||||||
|
hasBackdrop:
|
||||||
|
openOptions?.hasBackdrop ?? injectOptions?.hasBackdrop ?? true,
|
||||||
|
disableClose:
|
||||||
|
openOptions?.disableClose ?? injectOptions?.disableClose ?? true,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ export type SearchbarAppearance =
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'ui-search-bar',
|
selector: 'ui-search-bar',
|
||||||
templateUrl: './search-bar.component.html',
|
templateUrl: './search-bar.component.html',
|
||||||
styleUrl: './search-bar.component.scss',
|
|
||||||
encapsulation: ViewEncapsulation.None,
|
encapsulation: ViewEncapsulation.None,
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
host: {
|
host: {
|
||||||
|
|||||||
@@ -5,13 +5,13 @@
|
|||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:has(input[type='text']:placeholder-shown) {
|
&:has(input[type="text"]:placeholder-shown) {
|
||||||
.ui-search-bar__action__close {
|
.ui-search-bar__action__close {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type='text'] {
|
input[type="text"] {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 1.25rem; /* 142.857% */
|
line-height: 1.25rem; /* 142.857% */
|
||||||
@apply text-isa-neutral-900;
|
background-color: inherit;
|
||||||
|
|
||||||
&::placeholder {
|
&::placeholder {
|
||||||
@apply text-isa-neutral-500;
|
@apply text-isa-neutral-500;
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
@apply pr-4;
|
@apply pr-4;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:has(input[type='text']:placeholder-shown) {
|
&:has(input[type="text"]:placeholder-shown) {
|
||||||
@apply pl-0;
|
@apply pl-0;
|
||||||
|
|
||||||
button[prefix][uiIconButton] {
|
button[prefix][uiIconButton] {
|
||||||
@@ -65,10 +65,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:has(input[type='text']) {
|
&:has(input[type="text"]) {
|
||||||
@apply pl-4;
|
@apply pl-4;
|
||||||
|
|
||||||
input[type='text'] {
|
input[type="text"] {
|
||||||
@apply pr-4 whitespace-nowrap overflow-hidden overflow-ellipsis;
|
@apply pr-4 whitespace-nowrap overflow-hidden overflow-ellipsis;
|
||||||
}
|
}
|
||||||
|
|
||||||
4
nx.json
4
nx.json
@@ -52,6 +52,10 @@
|
|||||||
"cache": true,
|
"cache": true,
|
||||||
"dependsOn": ["^build"],
|
"dependsOn": ["^build"],
|
||||||
"inputs": ["production", "^production"]
|
"inputs": ["production", "^production"]
|
||||||
|
},
|
||||||
|
"@nx/vite:test": {
|
||||||
|
"cache": true,
|
||||||
|
"inputs": ["default", "^production"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"defaultBase": "develop",
|
"defaultBase": "develop",
|
||||||
|
|||||||
3074
package-lock.json
generated
3074
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
@@ -58,6 +58,8 @@
|
|||||||
"zone.js": "~0.15.0"
|
"zone.js": "~0.15.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@analogjs/vite-plugin-angular": "~1.9.1",
|
||||||
|
"@analogjs/vitest-angular": "~1.9.1",
|
||||||
"@angular-devkit/build-angular": "20.0.3",
|
"@angular-devkit/build-angular": "20.0.3",
|
||||||
"@angular-devkit/core": "20.0.2",
|
"@angular-devkit/core": "20.0.2",
|
||||||
"@angular-devkit/schematics": "20.0.2",
|
"@angular-devkit/schematics": "20.0.2",
|
||||||
@@ -73,6 +75,7 @@
|
|||||||
"@nx/jest": "21.2.0",
|
"@nx/jest": "21.2.0",
|
||||||
"@nx/js": "21.2.0",
|
"@nx/js": "21.2.0",
|
||||||
"@nx/storybook": "21.2.0",
|
"@nx/storybook": "21.2.0",
|
||||||
|
"@nx/vite": "20.1.4",
|
||||||
"@nx/web": "21.2.0",
|
"@nx/web": "21.2.0",
|
||||||
"@nx/workspace": "21.2.0",
|
"@nx/workspace": "21.2.0",
|
||||||
"@schematics/angular": "20.0.2",
|
"@schematics/angular": "20.0.2",
|
||||||
@@ -88,6 +91,8 @@
|
|||||||
"@types/node": "18.16.9",
|
"@types/node": "18.16.9",
|
||||||
"@types/uuid": "^10.0.0",
|
"@types/uuid": "^10.0.0",
|
||||||
"@typescript-eslint/utils": "^8.19.0",
|
"@typescript-eslint/utils": "^8.19.0",
|
||||||
|
"@vitest/coverage-v8": "^1.0.4",
|
||||||
|
"@vitest/ui": "^1.3.1",
|
||||||
"angular-eslint": "^19.2.0",
|
"angular-eslint": "^19.2.0",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"eslint": "^9.8.0",
|
"eslint": "^9.8.0",
|
||||||
@@ -99,6 +104,7 @@
|
|||||||
"jest-environment-node": "^29.7.0",
|
"jest-environment-node": "^29.7.0",
|
||||||
"jest-junit": "^16.0.0",
|
"jest-junit": "^16.0.0",
|
||||||
"jest-preset-angular": "14.6.0",
|
"jest-preset-angular": "14.6.0",
|
||||||
|
"jsdom": "~22.1.0",
|
||||||
"jsonc-eslint-parser": "^2.1.0",
|
"jsonc-eslint-parser": "^2.1.0",
|
||||||
"ng-mocks": "14.13.5",
|
"ng-mocks": "14.13.5",
|
||||||
"ng-packagr": "20.0.1",
|
"ng-packagr": "20.0.1",
|
||||||
@@ -113,7 +119,9 @@
|
|||||||
"ts-jest": "^29.1.0",
|
"ts-jest": "^29.1.0",
|
||||||
"ts-node": "10.9.1",
|
"ts-node": "10.9.1",
|
||||||
"typescript": "5.8.3",
|
"typescript": "5.8.3",
|
||||||
"typescript-eslint": "^8.19.0"
|
"typescript-eslint": "^8.19.0",
|
||||||
|
"vite": "^5.0.0",
|
||||||
|
"vitest": "^1.3.1"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@esbuild/linux-x64": "^0.25.5"
|
"@esbuild/linux-x64": "^0.25.5"
|
||||||
|
|||||||
@@ -75,11 +75,17 @@
|
|||||||
],
|
],
|
||||||
"@isa/remission/helpers": ["libs/remission/helpers/src/index.ts"],
|
"@isa/remission/helpers": ["libs/remission/helpers/src/index.ts"],
|
||||||
"@isa/remission/shared": ["libs/remission/shared/src/index.ts"],
|
"@isa/remission/shared": ["libs/remission/shared/src/index.ts"],
|
||||||
|
"@isa/remission/shared/product": [
|
||||||
|
"libs/remission/shared/product/src/index.ts"
|
||||||
|
],
|
||||||
"@isa/remission/shared/product-details": [
|
"@isa/remission/shared/product-details": [
|
||||||
"libs/remission/shared/product-details/src/index.ts"
|
"libs/remission/shared/product-details/src/index.ts"
|
||||||
],
|
],
|
||||||
"@isa/remission/shared/product": [
|
"@isa/remission/shared/search-item-to-remit-dialog": [
|
||||||
"libs/remission/shared/product/src/index.ts"
|
"libs/remission/shared/search-item-to-remit-dialog/src/index.ts"
|
||||||
|
],
|
||||||
|
"@isa/remission/shared/select-remission-quantity-and-reason-dialog": [
|
||||||
|
"libs/remission/shared/select-remission-quantity-and-reason-dialog/src/index.ts"
|
||||||
],
|
],
|
||||||
"@isa/shared/filter": ["libs/shared/filter/src/index.ts"],
|
"@isa/shared/filter": ["libs/shared/filter/src/index.ts"],
|
||||||
"@isa/shared/product-foramt": ["libs/shared/product-format/src/index.ts"],
|
"@isa/shared/product-foramt": ["libs/shared/product-format/src/index.ts"],
|
||||||
|
|||||||
1
vitest.workspace.ts
Normal file
1
vitest.workspace.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export default ['**/*/vite.config.{ts,mts}', '**/*/vitest.config.{ts,mts}'];
|
||||||
Reference in New Issue
Block a user