diff --git a/angular.json b/angular.json index b0a96f2e5..24a30d169 100644 --- a/angular.json +++ b/angular.json @@ -45,7 +45,6 @@ "node_modules/primeng/resources/primeng.min.css", "node_modules/primeicons/primeicons.css", "node_modules/primeflex/primeflex.min.css", - "node_modules/ngx-bootstrap/datepicker/bs-datepicker.css", "node_modules/ngx-spinner/animations/ball-zig-zag.css", "projects/admin/src/app/scss/styles.scss", "projects/shared/src/scss/styles.scss" @@ -282,7 +281,6 @@ "node_modules/primeng/resources/primeng.min.css", "node_modules/primeicons/primeicons.css", "node_modules/primeflex/primeflex.min.css", - "node_modules/ngx-bootstrap/datepicker/bs-datepicker.css", "projects/shared/src/scss/styles.scss" ], "scripts": [], @@ -558,6 +556,10 @@ } ], "styles": [ + "node_modules/primeng/resources/themes/bootstrap4-light-blue/theme.css", + "node_modules/primeng/resources/primeng.min.css", + "node_modules/primeicons/primeicons.css", + "node_modules/primeflex/primeflex.min.css", "projects/public-search/src/app/scss/styles.scss", "projects/shared/src/scss/styles.scss" ], @@ -860,8 +862,6 @@ } }, "cli": { - "schematicCollections": [ - "@angular-eslint/schematics" - ] + "schematicCollections": ["@angular-eslint/schematics"] } } diff --git a/package-lock.json b/package-lock.json index fd0c9dc93..e79b9c8b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "@angular/router": "^17.1.0", "@biesbjerg/ngx-translate-extract-marker": "^1.0.0", "@ng-bootstrap/ng-bootstrap": "^16.0.0", - "@ngneat/hotkeys": "^2.0.0", + "@ngneat/hotkeys": "^4.0.0", "@ngx-formly/core": "^6.3.6", "@ngx-formly/primeng": "^6.3.6", "@ngx-loading-bar/core": "^6.0.0", @@ -40,7 +40,6 @@ "lodash-es": "^4.17.21", "luxon": "^3.5.0", "marked": "^10.0.0", - "ngx-bootstrap": "^12.0.0", "ngx-spinner": "^16.0.0", "primeflex": "^3.3.1", "primeicons": "^6.0.1", @@ -3279,9 +3278,9 @@ } }, "node_modules/@ngneat/hotkeys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@ngneat/hotkeys/-/hotkeys-2.0.0.tgz", - "integrity": "sha512-AHjmEuZS/VACq9/iJG5XP0j8I2TbtS88Lvg660DkKS47K3Om7uXbI7lyi8QsisFlaArlyb9P+DxLC0cZ9a0uBA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@ngneat/hotkeys/-/hotkeys-4.0.0.tgz", + "integrity": "sha512-My5PVywrIVJDMD2j00O5hvW/70SmBwvz85v46WiJct5zyrxzQjSRh9ZD5SLH+LLEcjpiCFwCtpBD1RatzRlisQ==", "dependencies": { "tslib": "^2.0.0" } @@ -11575,6 +11574,7 @@ "version": "12.0.0", "resolved": "https://registry.npmjs.org/ngx-bootstrap/-/ngx-bootstrap-12.0.0.tgz", "integrity": "sha512-6/Hs+FT6peMc+Y2uiOm3IawG06Jh3gLQwwKRBF0U1OMlRbpx4KIyHS9GpZtMevtZaBsCRNfHKiSxwsnvn9wx0Q==", + "peer": true, "dependencies": { "tslib": "^2.3.0" }, diff --git a/package.json b/package.json index a0cdd12ea..172f0bd59 100644 --- a/package.json +++ b/package.json @@ -78,8 +78,8 @@ "@angular/platform-browser-dynamic": "^17.1.0", "@angular/router": "^17.1.0", "@biesbjerg/ngx-translate-extract-marker": "^1.0.0", + "@ngneat/hotkeys": "^4.0.0", "@ng-bootstrap/ng-bootstrap": "^16.0.0", - "@ngneat/hotkeys": "^2.0.0", "@ngx-formly/core": "^6.3.6", "@ngx-formly/primeng": "^6.3.6", "@ngx-loading-bar/core": "^6.0.0", @@ -98,7 +98,6 @@ "lodash-es": "^4.17.21", "luxon": "^3.5.0", "marked": "^10.0.0", - "ngx-bootstrap": "^12.0.0", "ngx-spinner": "^16.0.0", "primeflex": "^3.3.1", "primeicons": "^6.0.1", diff --git a/projects/admin/src/app/acquisition/acquisition.module.ts b/projects/admin/src/app/acquisition/acquisition.module.ts index d328e8017..be4270078 100644 --- a/projects/admin/src/app/acquisition/acquisition.module.ts +++ b/projects/admin/src/app/acquisition/acquisition.module.ts @@ -24,7 +24,6 @@ import { FormlyPrimeNGModule } from '@ngx-formly/primeng'; import { TranslateService } from '@ngx-translate/core'; import { ApiService, CoreModule, RecordModule } from '@rero/ng-core'; import { SharedModule } from '@rero/shared'; -import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; import { PreviewEmailModule } from '../shared/preview-email/preview-email.module'; import { PrimengImportModule } from '../shared/primeng-import/primeng-import.module'; import { AcquisitionRoutingModule } from './acquisition-routing.module'; @@ -53,7 +52,6 @@ import { registerFormlyExtension } from './formly/extension'; import { FieldDocumentBriefViewTypeComponent } from './formly/type/field-document-brief-view.type'; import { FieldRefTypeComponent } from './formly/type/field-ref.type'; import { RepeatTypeComponent } from './formly/type/repeat-section.type'; -import { SelectAccountComponent } from './formly/type/select-account/select-account.component'; import { InputNoLabelWrapperComponent } from './formly/wrapper/input-no-label.wrapper'; import { AccountAvailableAmountPipe } from './pipes/account-available-amount.pipe'; import { NegativeAmountPipe } from './pipes/negative-amount.pipe'; @@ -81,7 +79,6 @@ import { ReceptionDatesPipe } from './pipes/reception-dates.pipe'; OrderReceiptViewComponent, OrderSummaryComponent, RepeatTypeComponent, - SelectAccountComponent, SelectAccountEditorWidgetComponent, ReceiptListComponent, ReceiptSummaryComponent, @@ -94,7 +91,6 @@ import { ReceptionDatesPipe } from './pipes/reception-dates.pipe'; OrderEmailFormComponent ], imports: [ - BsDropdownModule.forRoot(), CommonModule, AcquisitionRoutingModule, FormlyModule, @@ -105,7 +101,7 @@ import { ReceptionDatesPipe } from './pipes/reception-dates.pipe'; { name: 'repeat', component: RepeatTypeComponent }, { name: 'field-document-brief-view', component: FieldDocumentBriefViewTypeComponent }, { name: 'field-ref', component: FieldRefTypeComponent }, - { name: 'select-account', component: SelectAccountComponent } + { name: 'account-select', component: SelectAccountEditorWidgetComponent } ], wrappers: [ { name: 'input-no-label', component: InputNoLabelWrapperComponent } diff --git a/projects/admin/src/app/acquisition/components/editor/widget/select-account-editor-widget/select-account-editor-widget.component.html b/projects/admin/src/app/acquisition/components/editor/widget/select-account-editor-widget/select-account-editor-widget.component.html index c2a0a763b..e24f7f6b4 100644 --- a/projects/admin/src/app/acquisition/components/editor/widget/select-account-editor-widget/select-account-editor-widget.component.html +++ b/projects/admin/src/app/acquisition/components/editor/widget/select-account-editor-widget/select-account-editor-widget.component.html @@ -15,48 +15,43 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . --> -
-
- - -
- Please select an account. -
-
+ + diff --git a/projects/admin/src/app/acquisition/components/editor/widget/select-account-editor-widget/select-account-editor-widget.component.ts b/projects/admin/src/app/acquisition/components/editor/widget/select-account-editor-widget/select-account-editor-widget.component.ts index 6d272357a..38e0a8a6a 100644 --- a/projects/admin/src/app/acquisition/components/editor/widget/select-account-editor-widget/select-account-editor-widget.component.ts +++ b/projects/admin/src/app/acquisition/components/editor/widget/select-account-editor-widget/select-account-editor-widget.component.ts @@ -15,27 +15,31 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { getCurrencySymbol } from '@angular/common'; -import { ChangeDetectorRef, Component, inject, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, OnInit } from '@angular/core'; import { IAcqAccount } from '@app/admin/acquisition/classes/account'; import { OrganisationService } from '@app/admin/service/organisation.service'; import { FieldType } from '@ngx-formly/core'; +import { TranslateService } from '@ngx-translate/core'; import { ApiService } from '@rero/ng-core'; import { UserService } from '@rero/shared'; +import { MessageService } from 'primeng/api'; import { AcqAccountApiService } from '../../../../api/acq-account-api.service'; import { orderAccountsAsTree } from '../../../../utils/account'; @Component({ selector: 'admin-select-account-editor-widget', templateUrl: './select-account-editor-widget.component.html', - styleUrls: ['../../../../acquisition.scss', './select-account-editor-widget.component.scss'] + styleUrls: ['../../../../acquisition.scss', './select-account-editor-widget.component.scss'], + changeDetection: ChangeDetectionStrategy.Default, }) export class SelectAccountEditorWidgetComponent extends FieldType implements OnInit { - + // services private acqAccountApiService: AcqAccountApiService = inject(AcqAccountApiService); private organisationService: OrganisationService = inject(OrganisationService); private apiService: ApiService = inject(ApiService); private userService: UserService = inject(UserService); + private messageService = inject(MessageService); + private translateService: TranslateService = inject(TranslateService); private changeDetectorRef: ChangeDetectorRef = inject(ChangeDetectorRef); // COMPONENT ATTRIBUTES ======================================================= @@ -43,33 +47,40 @@ export class SelectAccountEditorWidgetComponent extends FieldType implements OnI accountList: IAcqAccount[] = []; /** the selected account */ selectedAccount: IAcqAccount = null; + // loading wheels + loading: boolean = false; + // currency + defaultCurrency: string; - // GETTER & SETTER ============================================================ - /** Get the current organisation */ - get organisation(): any { - return this.organisationService.organisation; - } - - /** Get the currency symbol for the organisation */ - get currencySymbol(): any { - return getCurrencySymbol(this.organisation.default_currency, 'wide'); - } - - /** OnInit hook */ ngOnInit(): void { + this.loading = true; const libraryPid = this.userService.user.currentLibrary; - this.acqAccountApiService.getAccounts(libraryPid).subscribe((accounts: IAcqAccount[]) => { - accounts = orderAccountsAsTree(accounts); - this.accountList = accounts; + this.defaultCurrency = this.organisationService.organisation.default_currency; + this.acqAccountApiService.getAccounts(libraryPid).subscribe({ + next: (accounts: IAcqAccount[]) => { + accounts = orderAccountsAsTree(accounts); + this.accountList = accounts; - if (this.formControl.value) { - const currentPid = this.formControl.value.substring(this.formControl.value.lastIndexOf('/') + 1); - const currentAccount = this.accountList.find((account: IAcqAccount) => account.pid === currentPid); - if (currentAccount !== undefined) { - this.selectedAccount = currentAccount; - this.changeDetectorRef.markForCheck(); + if (this.formControl.value) { + const currentPid = this.formControl.value.substring(this.formControl.value.lastIndexOf('/') + 1); + const currentAccount = this.accountList.find((account: IAcqAccount) => account.pid === currentPid); + if (currentAccount !== undefined) { + this.selectedAccount = currentAccount; + } } - } + }, + error: () => + this.messageService.add({ + severity: 'error', + summary: this.translateService.instant('Acquisition accounts'), + detail: this.translateService.instant('An error has occurred. Please try again.'), + sticky: true, + closable: true, + }), + complete: () => { + this.loading = false; + this.changeDetectorRef.markForCheck(); + }, }); } @@ -78,10 +89,17 @@ export class SelectAccountEditorWidgetComponent extends FieldType implements OnI * Store the selected option, when an option is clicked in the list * @param account - The selected account. */ - selectAccount(account: IAcqAccount): void { + selectAccount(event): void { + const account: IAcqAccount = event.value; + if (account == null) { + // reset the form control value, default value cannot be used as it is already filled by ngx formly + this.formControl.reset(null); + // reset the validators but the required validator + const errors = this.formControl.errors; + this.formControl.setErrors(errors.required? {required: true}: null); + return; + } const accountRef = this.apiService.getRefEndpoint('acq_accounts', account.pid); - this.selectedAccount = account; this.formControl.patchValue(accountRef); - this.changeDetectorRef.markForCheck(); } } diff --git a/projects/admin/src/app/acquisition/components/receipt/receipt-form/order-receipt-form.ts b/projects/admin/src/app/acquisition/components/receipt/receipt-form/order-receipt-form.ts index 3182ca738..deb1ed907 100644 --- a/projects/admin/src/app/acquisition/components/receipt/receipt-form/order-receipt-form.ts +++ b/projects/admin/src/app/acquisition/components/receipt/receipt-form/order-receipt-form.ts @@ -332,7 +332,7 @@ export class OrderReceiptForm { }, { key: 'acqAccount', - type: 'select-account', + type: 'account-select', wrappers: ['form-field'], props: { placeholder: _('Select an account'), diff --git a/projects/admin/src/app/app.component.ts b/projects/admin/src/app/app.component.ts index f14388f68..fd72ec626 100644 --- a/projects/admin/src/app/app.component.ts +++ b/projects/admin/src/app/app.component.ts @@ -21,6 +21,7 @@ import { User, UserService } from '@rero/shared'; import { DialogService } from 'primeng/dynamicdialog'; import { KeyboardShortcutsService } from './service/keyboard-shortcuts.service'; import { CustomShortcutHelpComponent } from './widgets/custom-shortcut-help/custom-shortcut-help.component'; +import { TranslateService } from '@ngx-translate/core'; @Component({ selector: 'admin-root', @@ -33,6 +34,7 @@ export class AppComponent implements OnInit, AfterViewInit { private keyboardShortcutsService: KeyboardShortcutsService = inject(KeyboardShortcutsService); private hotKeysService: HotkeysService = inject(HotkeysService); private dialogService: DialogService = inject(DialogService); + private translateService: TranslateService = inject(TranslateService); /** user */ get user(): User { @@ -47,7 +49,9 @@ export class AppComponent implements OnInit, AfterViewInit { /** AfterViewInit hook */ ngAfterViewInit() { this.hotKeysService.registerHelpModal(() => { - this.dialogService.open(CustomShortcutHelpComponent, {}) + this.dialogService.open(CustomShortcutHelpComponent, { + header: this.translateService.instant('Available Shortcuts') + }) }); } } diff --git a/projects/admin/src/app/app.module.ts b/projects/admin/src/app/app.module.ts index 69de42648..7fee58ed9 100644 --- a/projects/admin/src/app/app.module.ts +++ b/projects/admin/src/app/app.module.ts @@ -23,7 +23,6 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { PrimengImportModule } from '@app/admin/shared/primeng-import/primeng-import.module'; -import { HotkeysModule, HotkeysService } from '@ngneat/hotkeys'; import { FormlyModule } from '@ngx-formly/core'; import { FormlyFieldSelect } from '@ngx-formly/primeng/select'; import { LoadingBarHttpClientModule } from '@ngx-loading-bar/http-client'; @@ -38,7 +37,6 @@ import { } from '@rero/ng-core'; import { AppSettingsService, ItemHoldingsCallNumberPipe, MainTitlePipe, SharedModule, UserService } from '@rero/shared'; import { NgxChartsModule } from '@swimlane/ngx-charts'; -import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; import { FileUploadModule } from 'primeng/fileupload'; import { MenubarModule } from 'primeng/menubar'; import { TableModule } from "primeng/table"; @@ -52,7 +50,6 @@ import { AppComponent } from './app.component'; import { IssueEmailComponent } from './components/issues/issue-email/issue-email.component'; import { ItemSwitchLocationStandaloneComponent } from './components/items/switch-location/item-switch-location-standalone/item-switch-location-standalone.component'; import { ItemSwitchLocationComponent } from './components/items/switch-location/item-switch-location/item-switch-location.component'; -import { TabOrderDirective } from './directives/tab-order.directive'; import { ErrorPageComponent } from './error/error-page/error-page.component'; import { NoCacheHeaderInterceptor } from './interceptor/no-cache-header.interceptor'; import { UserCurrentLibraryInterceptor } from './interceptor/user-current-library.interceptor'; @@ -208,6 +205,7 @@ import { FrontpageComponent } from './widgets/frontpage/frontpage.component'; import { EntityAutocompleteComponent } from './record/editor/formly/primeng/entity-autocomplete/entity-autocomplete.component'; import { RemoteAutocompleteService as UiRemoteAutocompleteService } from './record/editor/formly/primeng/remote-autocomplete/remote-autocomplete.service'; +import { HotkeysShortcutPipe } from '@ngneat/hotkeys'; /** Init application factory */ export function appInitFactory(appInitializerService: AppInitializerService): () => Observable { @@ -264,7 +262,6 @@ export function appInitFactory(appInitializerService: AppInitializerService): () DefaultHoldingItemComponent, NotesFormatPipe, MarcPipe, - TabOrderDirective, TemplatesBriefViewComponent, TemplateDetailViewComponent, CollectionBriefViewComponent, @@ -358,13 +355,13 @@ export function appInitFactory(appInitializerService: AppInitializerService): () AppRoutingModule, BrowserAnimationsModule, BrowserModule, - BsDropdownModule.forRoot(), NgxChartsModule, FormsModule, HttpClientModule, ReactiveFormsModule, RecordModule, TableModule, + HotkeysShortcutPipe, FormlyModule.forRoot({ types: [ { name: "cipo-pt-it", component: CipoPatronTypeItemTypeComponent }, @@ -386,7 +383,6 @@ export function appInitFactory(appInitializerService: AppInitializerService): () deps: [CoreConfigService, HttpClient], }, }), - HotkeysModule, SharedModule, LoadingBarHttpClientModule, PrimengImportModule, @@ -445,10 +441,6 @@ export function appInitFactory(appInitializerService: AppInitializerService): () ReceivedOrderPermissionValidator, // TODO: needed for production build, remove this after it is fixed in the // @ngneat/hotkeys library - { - provide: HotkeysService, - useClass: HotkeysService, - }, MainTitlePipe, ItemHoldingsCallNumberPipe, CountryCodeTranslatePipe, diff --git a/projects/admin/src/app/circulation/patron/main/main.component.ts b/projects/admin/src/app/circulation/patron/main/main.component.ts index ec342d886..a127e3674 100644 --- a/projects/admin/src/app/circulation/patron/main/main.component.ts +++ b/projects/admin/src/app/circulation/patron/main/main.component.ts @@ -49,42 +49,42 @@ export class MainComponent implements OnInit, OnDestroy { /** shortcuts for patron tabs */ private _shortcuts = [ { - keys: 'shift.1', + keys: '1', group: this.translateService.instant('Patron profile shortcuts'), description: this.translateService.instant('Go to "circulation" tab'), callback: ($event) => { this.router.navigate(['/circulation', 'patron', this.barcode, 'loan']); } }, { - keys: 'shift.2', + keys: '2', group: this.translateService.instant('Patron profile shortcuts'), description: this.translateService.instant('Go to "pickup" tab'), callback: ($event) => { this.router.navigate(['/circulation', 'patron', this.barcode, 'pickup']); } }, { - keys: 'shift.3', + keys: '3', group: this.translateService.instant('Patron profile shortcuts'), description: this.translateService.instant('Go to "pending" tab'), callback: ($event) => { this.router.navigate(['/circulation', 'patron', this.barcode, 'pending']); } }, { - keys: 'shift.4', + keys: '4', group: this.translateService.instant('Patron profile shortcuts'), description: this.translateService.instant('Go to "patron profile" tab'), callback: ($event) => { this.router.navigate(['/circulation', 'patron', this.barcode, 'profile']); } }, { - keys: 'shift.5', + keys: '5', group: this.translateService.instant('Patron profile shortcuts'), description: this.translateService.instant('Go to "fees" tab'), callback: ($event) => { this.router.navigate(['/circulation', 'patron', this.barcode, 'fees']); } }, { - keys: 'shift.6', + keys: '6', group: this.translateService.instant('Patron profile shortcuts'), description: this.translateService.instant('Go to "history" tab'), callback: ($event) => { diff --git a/projects/admin/src/app/service/keyboard-shortcuts.service.ts b/projects/admin/src/app/service/keyboard-shortcuts.service.ts index 808cc53d9..89d02cd48 100644 --- a/projects/admin/src/app/service/keyboard-shortcuts.service.ts +++ b/projects/admin/src/app/service/keyboard-shortcuts.service.ts @@ -44,11 +44,11 @@ export class KeyboardShortcutsService { ); this.hotKeys.addShortcut({ - keys: 'shift./', + keys: 's', group: this.translateService.instant('Global shortcuts'), description: this.translateService.instant('Set focus on the header search input') }).subscribe(e => { - const autocompleteElement = document.getElementsByClassName('rero-ils-autocomplete')[0]; + const autocompleteElement = document.getElementsByClassName('p-autocomplete')[0]; const inputField = autocompleteElement.getElementsByTagName('input')[0]; inputField.focus(); }); diff --git a/projects/admin/src/app/widgets/custom-shortcut-help/custom-shortcut-help.component.html b/projects/admin/src/app/widgets/custom-shortcut-help/custom-shortcut-help.component.html index ddb6e7d5a..daccba7ce 100644 --- a/projects/admin/src/app/widgets/custom-shortcut-help/custom-shortcut-help.component.html +++ b/projects/admin/src/app/widgets/custom-shortcut-help/custom-shortcut-help.component.html @@ -15,34 +15,28 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . --> -@if (title) { - -