diff --git a/libs/common/data-access/src/lib/operators/index.ts b/libs/common/data-access/src/lib/operators/index.ts index 5c6ce6584..a87853fef 100644 --- a/libs/common/data-access/src/lib/operators/index.ts +++ b/libs/common/data-access/src/lib/operators/index.ts @@ -1 +1,2 @@ export * from './take-until-aborted'; +export * from './take-unitl-keydown'; diff --git a/libs/common/data-access/src/lib/operators/take-unitl-keydown.ts b/libs/common/data-access/src/lib/operators/take-unitl-keydown.ts new file mode 100644 index 000000000..5b0f1d5f1 --- /dev/null +++ b/libs/common/data-access/src/lib/operators/take-unitl-keydown.ts @@ -0,0 +1,14 @@ +import { filter, fromEvent, Observable, takeUntil } from 'rxjs'; + +export const takeUntilKeydown = + (key: string) => + (source: Observable): Observable => { + const keydownEvent$ = fromEvent(document, 'keydown').pipe( + // Filter for the specific key + filter((event) => event.key === key), + ); + + return source.pipe(takeUntil(keydownEvent$)); + }; + +export const takeUntilKeydownEscape = () => takeUntilKeydown('Escape'); diff --git a/libs/common/data-access/src/lib/operators/take-until-aborted.ts b/libs/common/data-access/src/lib/operators/take-until-aborted.ts index a2461f805..334010943 100644 --- a/libs/common/data-access/src/lib/operators/take-until-aborted.ts +++ b/libs/common/data-access/src/lib/operators/take-until-aborted.ts @@ -1,4 +1,4 @@ -import { Observable, fromEvent } from 'rxjs'; +import { Observable } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; /** @@ -19,7 +19,6 @@ export const fromAbortSignal = (signal: AbortSignal): Observable => { return new Observable((subscriber) => { const abortHandler = () => { subscriber.next(); - subscriber.complete(); }; // Listen for the 'abort' event diff --git a/libs/oms/data-access/src/lib/stores/return-search.store.ts b/libs/oms/data-access/src/lib/stores/return-search.store.ts index b4bd6f957..27ca800c3 100644 --- a/libs/oms/data-access/src/lib/stores/return-search.store.ts +++ b/libs/oms/data-access/src/lib/stores/return-search.store.ts @@ -18,7 +18,11 @@ import { ReturnSearchService } from '../services'; import { tapResponse } from '@ngrx/operators'; import { effect, inject } from '@angular/core'; import { QueryTokenSchema } from '../schemas'; -import { Callback, ListResponseArgs } from '@isa/common/data-access'; +import { + Callback, + ListResponseArgs, + takeUntilKeydownEscape, +} from '@isa/common/data-access'; import { ReceiptListItem } from '../models'; import { Query } from '@isa/shared/filter'; import { SessionStorageProvider, withStorage } from '@isa/core/storage'; @@ -191,6 +195,26 @@ export const ReturnSearchStore = signalStore( ), ); }, + handleSearchCompleted(processId: number) { + const entity = store.getEntity(processId); + + if (entity?.status !== ReturnSearchStatus.Pending) { + return; + } + + patchState( + store, + updateEntity( + { + id: processId, // Assuming we want to update the first entity + changes: { + status: ReturnSearchStatus.Idle, + }, + }, + config, + ), + ); + }, })), withMethods((store, returnSearchService = inject(ReturnSearchService)) => ({ /** @@ -219,6 +243,7 @@ export const ReturnSearchStore = signalStore( }), ) .pipe( + takeUntilKeydownEscape(), tapResponse( (response) => { store.handleSearchSuccess({ processId, response }); @@ -228,6 +253,9 @@ export const ReturnSearchStore = signalStore( store.handleSearchError({ processId, error }); cb?.({ error }); }, + () => { + store.handleSearchCompleted(processId); + }, ), ), ), diff --git a/libs/oms/feature/return-process/src/lib/return-process-questions/return-process-product-question/return-process-product-question.component.ts b/libs/oms/feature/return-process/src/lib/return-process-questions/return-process-product-question/return-process-product-question.component.ts index a964edf2a..6716b3f08 100644 --- a/libs/oms/feature/return-process/src/lib/return-process-questions/return-process-product-question/return-process-product-question.component.ts +++ b/libs/oms/feature/return-process/src/lib/return-process-questions/return-process-product-question/return-process-product-question.component.ts @@ -34,7 +34,7 @@ import { tapResponse } from '@ngrx/operators'; import { ProductImageDirective } from '@isa/shared/product-image'; import { provideIcons } from '@ng-icons/core'; import { isaActionScanner } from '@isa/icons'; -import { ScannerButtonComponent } from '@isa/core/scanner'; +import { ScannerButtonComponent } from '@isa/shared/scanner'; import { ProductRouterLinkDirective } from '@isa/shared/product-router-link'; const eanValidator: ValidatorFn = ( diff --git a/libs/oms/feature/return-search/src/lib/return-search-result/return-search-result.component.html b/libs/oms/feature/return-search/src/lib/return-search-result/return-search-result.component.html index 22a5f4bc5..cf7691482 100644 --- a/libs/oms/feature/return-search/src/lib/return-search-result/return-search-result.component.html +++ b/libs/oms/feature/return-search/src/lib/return-search-result/return-search-result.component.html @@ -14,14 +14,13 @@ > @if (mobileBreakpoint()) { - + > } @else { } diff --git a/libs/oms/feature/return-search/src/lib/return-search-result/return-search-result.component.ts b/libs/oms/feature/return-search/src/lib/return-search-result/return-search-result.component.ts index fb5336f8a..960062cc5 100644 --- a/libs/oms/feature/return-search/src/lib/return-search-result/return-search-result.component.ts +++ b/libs/oms/feature/return-search/src/lib/return-search-result/return-search-result.component.ts @@ -18,7 +18,7 @@ import { import { IconButtonComponent } from '@isa/ui/buttons'; import { EmptyStateComponent } from '@isa/ui/empty-state'; -import { NgIconComponent, provideIcons } from '@ng-icons/core'; +import { provideIcons } from '@ng-icons/core'; import { isaActionSort, isaActionFilter } from '@isa/icons'; import { ReceiptListItem, @@ -55,7 +55,6 @@ import { breakpoint } from '@isa/ui/layout'; EmptyStateComponent, FilterMenuButtonComponent, InViewportDirective, - NgIconComponent, ], providers: [provideIcons({ isaActionSort, isaActionFilter })], }) diff --git a/libs/shared/filter/src/lib/inputs/search-bar-input/search-bar-input.component.ts b/libs/shared/filter/src/lib/inputs/search-bar-input/search-bar-input.component.ts index 20a979a88..904db74cd 100644 --- a/libs/shared/filter/src/lib/inputs/search-bar-input/search-bar-input.component.ts +++ b/libs/shared/filter/src/lib/inputs/search-bar-input/search-bar-input.component.ts @@ -20,7 +20,7 @@ import { isaActionSearch, isaActionScanner } from '@isa/icons'; import { FilterService, TextFilterInput } from '../../core'; import { InputType } from '../../types'; import { toSignal } from '@angular/core/rxjs-interop'; -import { ScannerButtonComponent } from '@isa/core/scanner'; +import { ScannerButtonComponent } from '@isa/shared/scanner'; @Component({ selector: 'filter-search-bar-input', diff --git a/libs/core/scanner/README.md b/libs/shared/scanner/README.md similarity index 91% rename from libs/core/scanner/README.md rename to libs/shared/scanner/README.md index 2b1ab8da3..8dcd3876d 100644 --- a/libs/core/scanner/README.md +++ b/libs/shared/scanner/README.md @@ -28,6 +28,7 @@ The Scanner library provides barcode scanning capabilities for the ISA applicati A button component that integrates with the scanner service to trigger barcode scanning. It implements `OnDestroy` to properly clean up resources. **Features:** + - Only appears when scanner is ready - Can be disabled through binding - Configurable size @@ -42,18 +43,19 @@ import { ScannerButtonComponent } from '@isa/core/scanner'; @Component({ selector: 'app-my-component', template: ` - + `, imports: [ScannerButtonComponent], - standalone: true + standalone: true, }) export class MyComponent { isDisabled = false; - + onScan(value: string | null) { console.log('Scanned barcode:', value); } @@ -65,6 +67,7 @@ export class MyComponent { A structural directive (`*sharedScannerReady`) that conditionally renders its content based on the scanner's ready state. Similar to `*ngIf`, but specifically tied to scanner readiness. **Features:** + - Only renders content when the scanner is ready - Supports an optional else template for when the scanner is not ready - Uses Angular's effect system for reactive updates @@ -82,19 +85,19 @@ import { ScannerReadyDirective } from '@isa/core/scanner';

Scanner is ready to use

- +

Scanner is ready

- +

Scanner is not yet ready

`, imports: [ScannerReadyDirective], - standalone: true + standalone: true, }) export class MyComponent { // Component logic @@ -106,6 +109,7 @@ export class MyComponent { Internal component used by ScannerService to render the camera view and process barcode scanning. **Features:** + - Integrates with Scandit SDK - Handles camera setup and barcode detection - Emits scanned values @@ -118,6 +122,7 @@ Internal component used by ScannerService to render the camera view and process Core service that provides barcode scanning functionality. **Features:** + - Initializes and configures Scandit SDK - Checks platform compatibility - Manages scanner lifecycle @@ -136,19 +141,19 @@ import { Component, inject } from '@angular/core';
Last Scan: {{ result }}
`, - standalone: true + standalone: true, }) export class MyComponent { private scannerService = inject(ScannerService); isReady = this.scannerService.ready; result: string | null = null; - + async scan() { const options: ScannerInputs = { // Optional configuration // symbologies: [...] // Specify barcode types }; - + try { this.result = await this.scannerService.open(options); } catch (error) { @@ -169,27 +174,24 @@ The scanner module uses injection tokens for configuration: **Custom Configuration Example:** ```typescript -import { - SCANDIT_LICENSE, - SCANDIT_LIBRARY_LOCATION -} from '@isa/core/scanner'; +import { SCANDIT_LICENSE, SCANDIT_LIBRARY_LOCATION } from '@isa/core/scanner'; import { Symbology } from 'scandit-web-datacapture-barcode'; @NgModule({ providers: [ // Custom license key - { - provide: SCANDIT_LICENSE, - useValue: 'YOUR-SCANDIT-LICENSE-KEY' + { + provide: SCANDIT_LICENSE, + useValue: 'YOUR-SCANDIT-LICENSE-KEY', }, // Custom library location - { - provide: SCANDIT_LIBRARY_LOCATION, - useValue: 'https://cdn.example.com/scandit/' - } - ] + { + provide: SCANDIT_LIBRARY_LOCATION, + useValue: 'https://cdn.example.com/scandit/', + }, + ], }) -export class AppModule { } +export class AppModule {} ``` ## Error Handling diff --git a/libs/core/scanner/eslint.config.mjs b/libs/shared/scanner/eslint.config.mjs similarity index 100% rename from libs/core/scanner/eslint.config.mjs rename to libs/shared/scanner/eslint.config.mjs diff --git a/libs/core/scanner/jest.config.ts b/libs/shared/scanner/jest.config.ts similarity index 86% rename from libs/core/scanner/jest.config.ts rename to libs/shared/scanner/jest.config.ts index d496c25cf..163a28fa0 100644 --- a/libs/core/scanner/jest.config.ts +++ b/libs/shared/scanner/jest.config.ts @@ -1,8 +1,8 @@ export default { - displayName: 'core-scanner', + displayName: 'shared-scanner', preset: '../../../jest.preset.js', setupFilesAfterEnv: ['/src/test-setup.ts'], - coverageDirectory: '../../../coverage/libs/core/scanner', + coverageDirectory: '../../../coverage/libs/shared/scanner', transform: { '^.+\\.(ts|mjs|js|html)$': [ 'jest-preset-angular', diff --git a/libs/core/scanner/project.json b/libs/shared/scanner/project.json similarity index 73% rename from libs/core/scanner/project.json rename to libs/shared/scanner/project.json index bbdafccc2..06b626b98 100644 --- a/libs/core/scanner/project.json +++ b/libs/shared/scanner/project.json @@ -1,7 +1,7 @@ { - "name": "core-scanner", + "name": "shared-scanner", "$schema": "../../../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "libs/core/scanner/src", + "sourceRoot": "libs/shared/scanner/src", "prefix": "shared", "projectType": "library", "tags": [], @@ -10,7 +10,7 @@ "executor": "@nx/jest:jest", "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], "options": { - "jestConfig": "libs/core/scanner/jest.config.ts" + "jestConfig": "libs/shared/scanner/jest.config.ts" } }, "lint": { diff --git a/libs/core/scanner/src/index.ts b/libs/shared/scanner/src/index.ts similarity index 100% rename from libs/core/scanner/src/index.ts rename to libs/shared/scanner/src/index.ts diff --git a/libs/core/scanner/src/lib/errors/index.ts b/libs/shared/scanner/src/lib/errors/index.ts similarity index 100% rename from libs/core/scanner/src/lib/errors/index.ts rename to libs/shared/scanner/src/lib/errors/index.ts diff --git a/libs/core/scanner/src/lib/errors/platform-not-supported.error.ts b/libs/shared/scanner/src/lib/errors/platform-not-supported.error.ts similarity index 100% rename from libs/core/scanner/src/lib/errors/platform-not-supported.error.ts rename to libs/shared/scanner/src/lib/errors/platform-not-supported.error.ts diff --git a/libs/core/scanner/src/lib/render-if-scanner-is-ready.directive.spec.ts b/libs/shared/scanner/src/lib/render-if-scanner-is-ready.directive.spec.ts similarity index 100% rename from libs/core/scanner/src/lib/render-if-scanner-is-ready.directive.spec.ts rename to libs/shared/scanner/src/lib/render-if-scanner-is-ready.directive.spec.ts diff --git a/libs/core/scanner/src/lib/render-if-scanner-is-ready.directive.ts b/libs/shared/scanner/src/lib/render-if-scanner-is-ready.directive.ts similarity index 100% rename from libs/core/scanner/src/lib/render-if-scanner-is-ready.directive.ts rename to libs/shared/scanner/src/lib/render-if-scanner-is-ready.directive.ts diff --git a/libs/core/scanner/src/lib/scanner-button.component.html b/libs/shared/scanner/src/lib/scanner-button.component.html similarity index 100% rename from libs/core/scanner/src/lib/scanner-button.component.html rename to libs/shared/scanner/src/lib/scanner-button.component.html diff --git a/libs/core/scanner/src/lib/scanner-button.component.scss b/libs/shared/scanner/src/lib/scanner-button.component.scss similarity index 100% rename from libs/core/scanner/src/lib/scanner-button.component.scss rename to libs/shared/scanner/src/lib/scanner-button.component.scss diff --git a/libs/core/scanner/src/lib/scanner-button.component.ts b/libs/shared/scanner/src/lib/scanner-button.component.ts similarity index 100% rename from libs/core/scanner/src/lib/scanner-button.component.ts rename to libs/shared/scanner/src/lib/scanner-button.component.ts diff --git a/libs/core/scanner/src/lib/scanner.component.html b/libs/shared/scanner/src/lib/scanner.component.html similarity index 100% rename from libs/core/scanner/src/lib/scanner.component.html rename to libs/shared/scanner/src/lib/scanner.component.html diff --git a/libs/core/scanner/src/lib/scanner.component.scss b/libs/shared/scanner/src/lib/scanner.component.scss similarity index 100% rename from libs/core/scanner/src/lib/scanner.component.scss rename to libs/shared/scanner/src/lib/scanner.component.scss diff --git a/libs/core/scanner/src/lib/scanner.component.ts b/libs/shared/scanner/src/lib/scanner.component.ts similarity index 100% rename from libs/core/scanner/src/lib/scanner.component.ts rename to libs/shared/scanner/src/lib/scanner.component.ts diff --git a/libs/core/scanner/src/lib/scanner.service.spec.ts b/libs/shared/scanner/src/lib/scanner.service.spec.ts similarity index 100% rename from libs/core/scanner/src/lib/scanner.service.spec.ts rename to libs/shared/scanner/src/lib/scanner.service.spec.ts diff --git a/libs/core/scanner/src/lib/scanner.service.ts b/libs/shared/scanner/src/lib/scanner.service.ts similarity index 96% rename from libs/core/scanner/src/lib/scanner.service.ts rename to libs/shared/scanner/src/lib/scanner.service.ts index 7cd1631b0..a6657869a 100644 --- a/libs/core/scanner/src/lib/scanner.service.ts +++ b/libs/shared/scanner/src/lib/scanner.service.ts @@ -174,14 +174,21 @@ export class ScannerService { libraryLocation: this.#libraryLocation, moduleLoaders: [barcodeCaptureLoader()], }); + + this.#status.set(ScannerStatus.Ready); + this.#logger.info('Scanner ready'); } catch (error) { + if (error instanceof PlatformNotSupportedError) { + this.#logger.warn(error.message, () => ({ + error, + })); + return; + } + this.#status.set(ScannerStatus.Error); this.#logger.error('Failed to configure Scandit', error); throw error; } - - this.#status.set(ScannerStatus.Ready); - this.#logger.info('Scanner ready'); } /** diff --git a/libs/core/scanner/src/test-setup.ts b/libs/shared/scanner/src/test-setup.ts similarity index 100% rename from libs/core/scanner/src/test-setup.ts rename to libs/shared/scanner/src/test-setup.ts diff --git a/libs/core/scanner/tsconfig.json b/libs/shared/scanner/tsconfig.json similarity index 100% rename from libs/core/scanner/tsconfig.json rename to libs/shared/scanner/tsconfig.json diff --git a/libs/core/scanner/tsconfig.lib.json b/libs/shared/scanner/tsconfig.lib.json similarity index 100% rename from libs/core/scanner/tsconfig.lib.json rename to libs/shared/scanner/tsconfig.lib.json diff --git a/libs/core/scanner/tsconfig.spec.json b/libs/shared/scanner/tsconfig.spec.json similarity index 100% rename from libs/core/scanner/tsconfig.spec.json rename to libs/shared/scanner/tsconfig.spec.json diff --git a/tsconfig.base.json b/tsconfig.base.json index ad1f2a150..7ebf0940a 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -46,7 +46,6 @@ "@isa/core/logging": ["libs/core/logging/src/index.ts"], "@isa/core/notifications": ["libs/core/notifications/src/index.ts"], "@isa/core/process": ["libs/core/process/src/index.ts"], - "@isa/core/scanner": ["libs/core/scanner/src/index.ts"], "@isa/core/storage": ["libs/core/storage/src/index.ts"], "@isa/icons": ["libs/icons/src/index.ts"], "@isa/oms/data-access": ["libs/oms/data-access/src/index.ts"], @@ -75,6 +74,7 @@ "@isa/shared/product-router-link": [ "libs/shared/product-router-link/src/index.ts" ], + "@isa/shared/scanner": ["libs/shared/scanner/src/index.ts"], "@isa/ui/buttons": ["libs/ui/buttons/src/index.ts"], "@isa/ui/datepicker": ["libs/ui/datepicker/src/index.ts"], "@isa/ui/dialog": ["libs/ui/dialog/src/index.ts"],