feat: editable new-order poll interval in admin settings
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -32,4 +32,23 @@
|
|||||||
<span class="saved-message" *ngIf="showSavedMessage()">{{ 'adminSettings.currencyRatesSaved' | translate }}</span>
|
<span class="saved-message" *ngIf="showSavedMessage()">{{ 'adminSettings.currencyRatesSaved' | translate }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-card">
|
||||||
|
<h2>{{ 'adminSettings.notificationInterval' | translate }}</h2>
|
||||||
|
<p class="settings-explain">{{ 'adminSettings.notificationIntervalExplain' | translate }}</p>
|
||||||
|
<div class="rate-row">
|
||||||
|
<input
|
||||||
|
class="rate-input"
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
step="1"
|
||||||
|
[ngModel]="notificationIntervalSecondsDraft()"
|
||||||
|
(ngModelChange)="notificationIntervalSecondsDraft.set($event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="rate-actions">
|
||||||
|
<button type="button" class="save-button" (click)="saveNotificationInterval()">{{ 'adminSettings.notificationIntervalSave' | translate }}</button>
|
||||||
|
<span class="saved-message" *ngIf="showNotificationIntervalSaved()">{{ 'adminSettings.notificationIntervalSaved' | translate }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
import { provideRouter } from '@angular/router';
|
||||||
|
import { signal } from '@angular/core';
|
||||||
|
import { AdminSettingsPageComponent } from './admin-settings-page.component';
|
||||||
|
import { AdminOrderWatcherService } from '../../shell/services/admin-order-watcher.service';
|
||||||
|
|
||||||
|
describe('AdminSettingsPageComponent notification interval', () => {
|
||||||
|
let watcherStub: {
|
||||||
|
intervalMs: ReturnType<typeof signal<number>>;
|
||||||
|
setIntervalSeconds: jasmine.Spy;
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
watcherStub = {
|
||||||
|
intervalMs: signal(15000),
|
||||||
|
setIntervalSeconds: jasmine.createSpy('setIntervalSeconds'),
|
||||||
|
};
|
||||||
|
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [AdminSettingsPageComponent],
|
||||||
|
providers: [
|
||||||
|
provideRouter([]),
|
||||||
|
{ provide: AdminOrderWatcherService, useValue: watcherStub },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('initializes the draft from the current interval in seconds', () => {
|
||||||
|
const fixture = TestBed.createComponent(AdminSettingsPageComponent);
|
||||||
|
expect(fixture.componentInstance.notificationIntervalSecondsDraft()).toBe(15);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('saveNotificationInterval calls setIntervalSeconds with the draft value', () => {
|
||||||
|
const fixture = TestBed.createComponent(AdminSettingsPageComponent);
|
||||||
|
const component = fixture.componentInstance;
|
||||||
|
|
||||||
|
component.notificationIntervalSecondsDraft.set(30);
|
||||||
|
component.saveNotificationInterval();
|
||||||
|
|
||||||
|
expect(watcherStub.setIntervalSeconds).toHaveBeenCalledWith(30);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -6,6 +6,7 @@ import { TranslatePipe } from '../../../../i18n/translate.pipe';
|
|||||||
import { ToggleComponent } from '../../../../shared/ui/toggle/toggle.component';
|
import { ToggleComponent } from '../../../../shared/ui/toggle/toggle.component';
|
||||||
import { CurrencyRatesService } from '../../../../services/currency-rates.service';
|
import { CurrencyRatesService } from '../../../../services/currency-rates.service';
|
||||||
import { LanguageService } from '../../../../services/language.service';
|
import { LanguageService } from '../../../../services/language.service';
|
||||||
|
import { AdminOrderWatcherService } from '../../shell/services/admin-order-watcher.service';
|
||||||
|
|
||||||
const SAVED_MESSAGE_DURATION_MS = 2000;
|
const SAVED_MESSAGE_DURATION_MS = 2000;
|
||||||
|
|
||||||
@@ -25,6 +26,16 @@ export class AdminSettingsPageComponent {
|
|||||||
readonly rateDrafts = signal<Record<string, number>>({ ...this.currencyRates.rates() });
|
readonly rateDrafts = signal<Record<string, number>>({ ...this.currencyRates.rates() });
|
||||||
readonly showSavedMessage = signal(false);
|
readonly showSavedMessage = signal(false);
|
||||||
|
|
||||||
|
readonly orderWatcher = inject(AdminOrderWatcherService);
|
||||||
|
readonly notificationIntervalSecondsDraft = signal(Math.round(this.orderWatcher.intervalMs() / 1000));
|
||||||
|
readonly showNotificationIntervalSaved = signal(false);
|
||||||
|
|
||||||
|
saveNotificationInterval(): void {
|
||||||
|
this.orderWatcher.setIntervalSeconds(this.notificationIntervalSecondsDraft());
|
||||||
|
this.showNotificationIntervalSaved.set(true);
|
||||||
|
setTimeout(() => this.showNotificationIntervalSaved.set(false), SAVED_MESSAGE_DURATION_MS);
|
||||||
|
}
|
||||||
|
|
||||||
onCompactToggle(compact: boolean): void {
|
onCompactToggle(compact: boolean): void {
|
||||||
this.preferences.setDensity(compact ? 'compact' : 'comfortable');
|
this.preferences.setDensity(compact ? 'compact' : 'comfortable');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1951,6 +1951,10 @@ export const en: Translations = {
|
|||||||
currencyRatesExplain: 'Rates relative to 1 RUB, used to convert storefront prices while the backend does not return prices per currency.',
|
currencyRatesExplain: 'Rates relative to 1 RUB, used to convert storefront prices while the backend does not return prices per currency.',
|
||||||
currencyRatesSave: 'Save rates',
|
currencyRatesSave: 'Save rates',
|
||||||
currencyRatesSaved: 'Rates saved',
|
currencyRatesSaved: 'Rates saved',
|
||||||
|
notificationInterval: 'New-order check interval (seconds)',
|
||||||
|
notificationIntervalExplain: 'How often the admin panel polls for new orders to show a notification.',
|
||||||
|
notificationIntervalSave: 'Save interval',
|
||||||
|
notificationIntervalSaved: 'Interval saved',
|
||||||
},
|
},
|
||||||
adminAnalytics: {
|
adminAnalytics: {
|
||||||
topProductsEmptyTitle: 'No product sales in this period',
|
topProductsEmptyTitle: 'No product sales in this period',
|
||||||
|
|||||||
@@ -1946,6 +1946,10 @@ export const hy: Translations = {
|
|||||||
currencyRatesExplain: 'Փոխարժեքներ՝ 1 RUB-ի նկատմամբ, օգտագործվում են կայքի գները փոխարկելու համար, քանի դեռ բեքենդը գներ չի վերադարձնում ըստ արժույթի։',
|
currencyRatesExplain: 'Փոխարժեքներ՝ 1 RUB-ի նկատմամբ, օգտագործվում են կայքի գները փոխարկելու համար, քանի դեռ բեքենդը գներ չի վերադարձնում ըստ արժույթի։',
|
||||||
currencyRatesSave: 'Պահպանել փոխարժեքները',
|
currencyRatesSave: 'Պահպանել փոխարժեքները',
|
||||||
currencyRatesSaved: 'Փոխարժեքները պահպանվեցին',
|
currencyRatesSaved: 'Փոխարժեքները պահպանվեցին',
|
||||||
|
notificationInterval: 'Նոր պատվերների ստուգման ինտերվալ (վրկ)',
|
||||||
|
notificationIntervalExplain: 'Որքան հաճախ է ադմին վահանակը ստուգում նոր պատվերներ ծանուցման համար։',
|
||||||
|
notificationIntervalSave: 'Պահպանել ինտերվալը',
|
||||||
|
notificationIntervalSaved: 'Ինտերվալը պահպանվեց',
|
||||||
},
|
},
|
||||||
adminAnalytics: {
|
adminAnalytics: {
|
||||||
topProductsEmptyTitle: 'Այս ժամանակահատվածում ապրանքների վաճառք չկա',
|
topProductsEmptyTitle: 'Այս ժամանակահատվածում ապրանքների վաճառք չկա',
|
||||||
|
|||||||
@@ -1946,6 +1946,10 @@ export const ru: Translations = {
|
|||||||
currencyRatesExplain: 'Курсы относительно 1 RUB, используются для конвертации цен на сайте, пока бэкенд не возвращает цены в разных валютах.',
|
currencyRatesExplain: 'Курсы относительно 1 RUB, используются для конвертации цен на сайте, пока бэкенд не возвращает цены в разных валютах.',
|
||||||
currencyRatesSave: 'Сохранить курсы',
|
currencyRatesSave: 'Сохранить курсы',
|
||||||
currencyRatesSaved: 'Курсы сохранены',
|
currencyRatesSaved: 'Курсы сохранены',
|
||||||
|
notificationInterval: 'Интервал проверки новых заказов (сек)',
|
||||||
|
notificationIntervalExplain: 'Как часто админ-панель проверяет новые заказы для уведомления.',
|
||||||
|
notificationIntervalSave: 'Сохранить интервал',
|
||||||
|
notificationIntervalSaved: 'Интервал сохранён',
|
||||||
},
|
},
|
||||||
adminAnalytics: {
|
adminAnalytics: {
|
||||||
topProductsEmptyTitle: 'Нет продаж товаров за этот период',
|
topProductsEmptyTitle: 'Нет продаж товаров за этот период',
|
||||||
|
|||||||
@@ -1959,6 +1959,10 @@ export interface Translations {
|
|||||||
currencyRatesExplain: string;
|
currencyRatesExplain: string;
|
||||||
currencyRatesSave: string;
|
currencyRatesSave: string;
|
||||||
currencyRatesSaved: string;
|
currencyRatesSaved: string;
|
||||||
|
notificationInterval: string;
|
||||||
|
notificationIntervalExplain: string;
|
||||||
|
notificationIntervalSave: string;
|
||||||
|
notificationIntervalSaved: string;
|
||||||
};
|
};
|
||||||
adminAnalytics: {
|
adminAnalytics: {
|
||||||
topProductsEmptyTitle: string;
|
topProductsEmptyTitle: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user