+
@if (!dialogData || !dialogData.partyId) {
}
diff --git a/src/components/create-shop-dialog/create-shop-dialog.component.ts b/src/components/create-shop-dialog/create-shop-dialog.component.ts
index 29ad71da5..259d5df3b 100644
--- a/src/components/create-shop-dialog/create-shop-dialog.component.ts
+++ b/src/components/create-shop-dialog/create-shop-dialog.component.ts
@@ -2,7 +2,7 @@ import { BehaviorSubject } from 'rxjs';
import { ValuesType } from 'utility-types';
import { CommonModule } from '@angular/common';
-import { Component, DestroyRef, inject, signal } from '@angular/core';
+import { Component, DestroyRef, OnInit, effect, inject, signal } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { ReactiveFormsModule } from '@angular/forms';
import { FormField, form, required } from '@angular/forms/signals';
@@ -19,12 +19,14 @@ import {
DialogSuperclass,
InputFieldModule,
NotifyLogService,
+ Option,
+ SelectFieldModule,
getNoTimeZoneIsoString,
progressTo,
} from '@vality/matez';
import { DomainService } from '~/api/domain-config';
-import { ConfigService } from '~/services';
+import { ConfigService, DEFAULT_PRESET, PRESETS, Preset } from '~/services';
import { AccountFieldComponent, CurrencyAccount } from '../account-field';
import { MerchantFieldModule } from '../merchant-field';
@@ -41,16 +43,20 @@ import { CreateDomainObjectDialogComponent, DomainObjectFieldComponent } from '.
DomainObjectFieldComponent,
FormField,
InputFieldModule,
+ SelectFieldModule,
AccountFieldComponent,
],
templateUrl: './create-shop-dialog.component.html',
})
-export class CreateShopDialogComponent extends DialogSuperclass<
- CreateShopDialogComponent,
- {
- partyId?: PartyConfigRef['id'];
- } | void
-> {
+export class CreateShopDialogComponent
+ extends DialogSuperclass<
+ CreateShopDialogComponent,
+ {
+ partyId?: PartyConfigRef['id'];
+ } | void
+ >
+ implements OnInit
+{
private domainService = inject(DomainService);
private destroyRef = inject(DestroyRef);
private log = inject(NotifyLogService);
@@ -63,11 +69,13 @@ export class CreateShopDialogComponent extends DialogSuperclass<
};
shopModel = signal<{
+ preset: Preset;
partyId: PartyConfigRef['id'] | null;
termsetId: TermSetHierarchyRef['id'] | null;
name: ShopConfig['name'] | null;
account: CurrencyAccount | null;
}>({
+ preset: DEFAULT_PRESET,
partyId: (this.dialogData && this.dialogData?.partyId) ?? null,
termsetId: null,
name: null,
@@ -80,9 +88,20 @@ export class CreateShopDialogComponent extends DialogSuperclass<
required(schemaPath.termsetId);
required(schemaPath.account);
});
+ presets: Option
[] = [...PRESETS];
progress$ = new BehaviorSubject(0);
isReview = false;
+ ngOnInit() {
+ effect(() => {
+ this.shopModel.update((v) => ({
+ ...v,
+ termsetId:
+ this.configService.config.value().default[this.shopModel().preset].termset,
+ }));
+ });
+ }
+
create() {
const insert: InsertOp = {
object: {
@@ -101,8 +120,9 @@ export class CreateShopDialogComponent extends DialogSuperclass<
}
private getShopConfig(): ShopConfig {
- const defaultConfig = this.configService.config.value().default;
const value = this.shopModel();
+ const defaultConfig = this.configService.config.value().default;
+ const shopDefaultConfig = defaultConfig[value.preset] || defaultConfig[DEFAULT_PRESET];
return {
name: value.name,
@@ -116,14 +136,14 @@ export class CreateShopDialogComponent extends DialogSuperclass<
block: {
unblocked: {
- reason: 'prod',
+ reason: value.preset,
since: getNoTimeZoneIsoString(new Date()),
},
},
suspension: { active: { since: getNoTimeZoneIsoString(new Date()) } },
- payment_institution: { id: defaultConfig.paymentInstitution },
+ payment_institution: { id: shopDefaultConfig.paymentInstitution },
location: { url: 'none' },
- category: { id: defaultConfig.category },
+ category: { id: shopDefaultConfig.category },
};
}
diff --git a/src/services/config/index.ts b/src/services/config/index.ts
index 90392254a..293b57bea 100644
--- a/src/services/config/index.ts
+++ b/src/services/config/index.ts
@@ -1 +1,2 @@
export * from './config.service';
+export * from './types/app-config';
diff --git a/src/services/config/types/app-config.ts b/src/services/config/types/app-config.ts
index 93c5ce2ee..34e5a7971 100644
--- a/src/services/config/types/app-config.ts
+++ b/src/services/config/types/app-config.ts
@@ -5,13 +5,29 @@ interface Endpoint {
https?: boolean;
}
+interface PresetConfig {
+ paymentInstitution: number;
+ category: number;
+ termset?: number;
+}
+
+export const PRESETS = [
+ {
+ label: 'Production',
+ value: 'prod',
+ },
+ {
+ label: 'Test',
+ value: 'test',
+ },
+] as const satisfies readonly { label: string; value: string }[];
+export const DEFAULT_PRESET = PRESETS[0].value;
+export type Preset = (typeof PRESETS)[number]['value'];
+
export interface AppConfig {
api: {
wachter: Endpoint;
};
checkout: Endpoint;
- default: {
- paymentInstitution: number;
- category: number;
- };
+ default: Record;
}
From e07fbc713064647ba6ee0f9619a36218a0653e06 Mon Sep 17 00:00:00 2001
From: Ray <11846445+A77AY@users.noreply.github.com>
Date: Mon, 29 Jun 2026 17:15:10 +0400
Subject: [PATCH 15/18] feat: refactor CreateShopDialogComponent to remove
OnInit and update termsetId handling
---
.../create-shop-dialog.component.ts | 58 +++++++++----------
1 file changed, 28 insertions(+), 30 deletions(-)
diff --git a/src/components/create-shop-dialog/create-shop-dialog.component.ts b/src/components/create-shop-dialog/create-shop-dialog.component.ts
index 259d5df3b..996ba15bd 100644
--- a/src/components/create-shop-dialog/create-shop-dialog.component.ts
+++ b/src/components/create-shop-dialog/create-shop-dialog.component.ts
@@ -2,7 +2,7 @@ import { BehaviorSubject } from 'rxjs';
import { ValuesType } from 'utility-types';
import { CommonModule } from '@angular/common';
-import { Component, DestroyRef, OnInit, effect, inject, signal } from '@angular/core';
+import { Component, DestroyRef, computed, effect, inject, signal } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { ReactiveFormsModule } from '@angular/forms';
import { FormField, form, required } from '@angular/forms/signals';
@@ -48,15 +48,12 @@ import { CreateDomainObjectDialogComponent, DomainObjectFieldComponent } from '.
],
templateUrl: './create-shop-dialog.component.html',
})
-export class CreateShopDialogComponent
- extends DialogSuperclass<
- CreateShopDialogComponent,
- {
- partyId?: PartyConfigRef['id'];
- } | void
- >
- implements OnInit
-{
+export class CreateShopDialogComponent extends DialogSuperclass<
+ CreateShopDialogComponent,
+ {
+ partyId?: PartyConfigRef['id'];
+ } | void
+> {
private domainService = inject(DomainService);
private destroyRef = inject(DestroyRef);
private log = inject(NotifyLogService);
@@ -91,14 +88,17 @@ export class CreateShopDialogComponent
presets: Option[] = [...PRESETS];
progress$ = new BehaviorSubject(0);
isReview = false;
+ preset = computed(() => {
+ const defaultConfig = this.configService.config.value().default;
+ return defaultConfig[this.shopModel().preset] || defaultConfig[DEFAULT_PRESET];
+ });
- ngOnInit() {
+ constructor() {
+ super();
effect(() => {
- this.shopModel.update((v) => ({
- ...v,
- termsetId:
- this.configService.config.value().default[this.shopModel().preset].termset,
- }));
+ if (this.configService.config.value()) {
+ this.shopForm.termsetId().value.set(this.preset().termset ?? null);
+ }
});
}
@@ -119,10 +119,18 @@ export class CreateShopDialogComponent
});
}
+ editFull() {
+ this.closeWithCancellation();
+ this.dialogService.open(CreateDomainObjectDialogComponent, {
+ objectType: 'shop_config',
+ noType: true,
+ initValue: this.getShopConfig(),
+ noNavigate: true,
+ });
+ }
+
private getShopConfig(): ShopConfig {
const value = this.shopModel();
- const defaultConfig = this.configService.config.value().default;
- const shopDefaultConfig = defaultConfig[value.preset] || defaultConfig[DEFAULT_PRESET];
return {
name: value.name,
@@ -141,19 +149,9 @@ export class CreateShopDialogComponent
},
},
suspension: { active: { since: getNoTimeZoneIsoString(new Date()) } },
- payment_institution: { id: shopDefaultConfig.paymentInstitution },
+ payment_institution: { id: this.preset().paymentInstitution },
location: { url: 'none' },
- category: { id: shopDefaultConfig.category },
+ category: { id: this.preset().category },
};
}
-
- editFull() {
- this.closeWithCancellation();
- this.dialogService.open(CreateDomainObjectDialogComponent, {
- objectType: 'shop_config',
- noType: true,
- initValue: this.getShopConfig(),
- noNavigate: true,
- });
- }
}
From 6ddf1f55ce4dd2f6c46eaa03a76b9cecdde2687c Mon Sep 17 00:00:00 2001
From: Ray <11846445+A77AY@users.noreply.github.com>
Date: Mon, 29 Jun 2026 20:04:50 +0400
Subject: [PATCH 16/18] feat: add description field to CreateShopDialog and
update form handling
---
.../create-shop-dialog/create-shop-dialog.component.html | 1 +
.../create-shop-dialog/create-shop-dialog.component.ts | 5 ++++-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/components/create-shop-dialog/create-shop-dialog.component.html b/src/components/create-shop-dialog/create-shop-dialog.component.html
index 6201957aa..2b35930f6 100644
--- a/src/components/create-shop-dialog/create-shop-dialog.component.html
+++ b/src/components/create-shop-dialog/create-shop-dialog.component.html
@@ -9,6 +9,7 @@
}
+
({
preset: DEFAULT_PRESET,
partyId: (this.dialogData && this.dialogData?.partyId) ?? null,
termsetId: null,
- name: null,
+ name: '',
+ description: '',
account: null,
});
@@ -134,6 +136,7 @@ export class CreateShopDialogComponent extends DialogSuperclass<
return {
name: value.name,
+ description: value.description,
party_ref: { id: value.partyId },
terms: { id: value.termsetId },
account: {
From ee6a83ca2079e2b7456162649d2659b4e4ba61ba Mon Sep 17 00:00:00 2001
From: Ray <11846445+A77AY@users.noreply.github.com>
Date: Mon, 29 Jun 2026 20:11:24 +0400
Subject: [PATCH 17/18] feat: implement CreateWalletDialog component and
integrate with WalletsComponent
---
src/app/wallets/wallets.component.html | 3 +
src/app/wallets/wallets.component.ts | 26 ++-
.../create-wallet-dialog.component.html | 34 ++++
.../create-wallet-dialog.component.ts | 156 ++++++++++++++++++
src/components/create-wallet-dialog/index.ts | 1 +
5 files changed, 218 insertions(+), 2 deletions(-)
create mode 100644 src/components/create-wallet-dialog/create-wallet-dialog.component.html
create mode 100644 src/components/create-wallet-dialog/create-wallet-dialog.component.ts
create mode 100644 src/components/create-wallet-dialog/index.ts
diff --git a/src/app/wallets/wallets.component.html b/src/app/wallets/wallets.component.html
index c355dd1bf..3c0dfd5b4 100644
--- a/src/app/wallets/wallets.component.html
+++ b/src/app/wallets/wallets.component.html
@@ -1,3 +1,6 @@
+
+
+
diff --git a/src/app/wallets/wallets.component.ts b/src/app/wallets/wallets.component.ts
index 348b31c82..260dea567 100644
--- a/src/app/wallets/wallets.component.ts
+++ b/src/app/wallets/wallets.component.ts
@@ -1,8 +1,12 @@
-import { map } from 'rxjs/operators';
+import { first, map, switchMap } from 'rxjs/operators';
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
+import { MatButtonModule } from '@angular/material/button';
+
+import { DialogService } from '@vality/matez';
import { DomainObjectsStoreService } from '~/api/domain-config';
+import { CreateWalletDialogComponent } from '~/components/create-wallet-dialog';
import { PageLayoutModule } from '~/components/page-layout';
import { WalletsTableComponent } from '~/components/wallets-table';
@@ -13,11 +17,12 @@ import { PartyStoreService } from '../parties/party';
templateUrl: './wallets.component.html',
providers: [PartyStoreService],
changeDetection: ChangeDetectionStrategy.Eager,
- imports: [PageLayoutModule, WalletsTableComponent],
+ imports: [MatButtonModule, PageLayoutModule, WalletsTableComponent],
})
export class WalletsComponent {
private domainObjectsStoreService = inject(DomainObjectsStoreService);
private partyStoreService = inject(PartyStoreService);
+ private dialog = inject(DialogService);
wallets = this.domainObjectsStoreService
.getObjects('wallet_config')
@@ -30,4 +35,21 @@ export class WalletsComponent {
),
),
);
+
+ create() {
+ this.partyStoreService.id$
+ .pipe(
+ first(),
+ switchMap((partyId) =>
+ this.dialog
+ .open(CreateWalletDialogComponent, partyId ? { partyId } : undefined)
+ .afterClosed(),
+ ),
+ )
+ .subscribe((res) => {
+ if (res?.status === 'success') {
+ this.wallets.reload();
+ }
+ });
+ }
}
diff --git a/src/components/create-wallet-dialog/create-wallet-dialog.component.html b/src/components/create-wallet-dialog/create-wallet-dialog.component.html
new file mode 100644
index 000000000..79938bba8
--- /dev/null
+++ b/src/components/create-wallet-dialog/create-wallet-dialog.component.html
@@ -0,0 +1,34 @@
+
+
+
+ @if (!dialogData || !dialogData.partyId) {
+
+ }
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/create-wallet-dialog/create-wallet-dialog.component.ts b/src/components/create-wallet-dialog/create-wallet-dialog.component.ts
new file mode 100644
index 000000000..4a2894f48
--- /dev/null
+++ b/src/components/create-wallet-dialog/create-wallet-dialog.component.ts
@@ -0,0 +1,156 @@
+import { BehaviorSubject } from 'rxjs';
+import { ValuesType } from 'utility-types';
+
+import { CommonModule } from '@angular/common';
+import { Component, DestroyRef, computed, effect, inject, signal } from '@angular/core';
+import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
+import { ReactiveFormsModule } from '@angular/forms';
+import { FormField, form, required } from '@angular/forms/signals';
+import { MatButtonModule } from '@angular/material/button';
+
+import { PartyConfigRef, TermSetHierarchyRef, WalletConfig } from '@vality/domain-proto/domain';
+import { InsertOp } from '@vality/domain-proto/domain_config_v2';
+import {
+ DEFAULT_DIALOG_CONFIG,
+ DEFAULT_DIALOG_CONFIG_FULL_HEIGHT,
+ DialogConfig,
+ DialogModule,
+ DialogService,
+ DialogSuperclass,
+ InputFieldModule,
+ NotifyLogService,
+ Option,
+ SelectFieldModule,
+ getNoTimeZoneIsoString,
+ progressTo,
+} from '@vality/matez';
+
+import { DomainService } from '~/api/domain-config';
+import { ConfigService, DEFAULT_PRESET, PRESETS, Preset } from '~/services';
+
+import { AccountFieldComponent, CurrencyAccount } from '../account-field';
+import { MerchantFieldModule } from '../merchant-field';
+import { CreateDomainObjectDialogComponent, DomainObjectFieldComponent } from '../thrift-api-crud';
+
+@Component({
+ selector: 'cc-create-wallet-dialog',
+ imports: [
+ CommonModule,
+ DialogModule,
+ MatButtonModule,
+ ReactiveFormsModule,
+ MerchantFieldModule,
+ DomainObjectFieldComponent,
+ FormField,
+ InputFieldModule,
+ SelectFieldModule,
+ AccountFieldComponent,
+ ],
+ templateUrl: './create-wallet-dialog.component.html',
+})
+export class CreateWalletDialogComponent extends DialogSuperclass<
+ CreateWalletDialogComponent,
+ {
+ partyId?: PartyConfigRef['id'];
+ } | void
+> {
+ private domainService = inject(DomainService);
+ private destroyRef = inject(DestroyRef);
+ private log = inject(NotifyLogService);
+ private configService = inject(ConfigService);
+ private dialogService = inject(DialogService);
+
+ static override defaultDialogConfig: ValuesType = {
+ ...DEFAULT_DIALOG_CONFIG.large,
+ minHeight: DEFAULT_DIALOG_CONFIG_FULL_HEIGHT,
+ };
+
+ walletModel = signal<{
+ preset: Preset;
+ partyId: PartyConfigRef['id'] | null;
+ termsetId: TermSetHierarchyRef['id'] | null;
+ name: WalletConfig['name'] | null;
+ description: WalletConfig['description'] | null;
+ account: CurrencyAccount | null;
+ }>({
+ preset: DEFAULT_PRESET,
+ partyId: (this.dialogData && this.dialogData?.partyId) ?? null,
+ termsetId: null,
+ name: '',
+ description: '',
+ account: null,
+ });
+
+ walletForm = form(this.walletModel, (schemaPath) => {
+ required(schemaPath.name);
+ required(schemaPath.partyId);
+ required(schemaPath.termsetId);
+ required(schemaPath.account);
+ });
+ presets: Option[] = [...PRESETS];
+ progress$ = new BehaviorSubject(0);
+ preset = computed(() => {
+ const defaultConfig = this.configService.config.value().default;
+ return defaultConfig[this.walletModel().preset] || defaultConfig[DEFAULT_PRESET];
+ });
+
+ constructor() {
+ super();
+ effect(() => {
+ if (this.configService.config.value()) {
+ this.walletForm.termsetId().value.set(this.preset().termset ?? null);
+ }
+ });
+ }
+
+ create() {
+ const insert: InsertOp = {
+ object: {
+ wallet_config: {
+ ...this.getWalletConfig(),
+ },
+ },
+ };
+ this.domainService
+ .commit([{ insert }])
+ .pipe(progressTo(this.progress$), takeUntilDestroyed(this.destroyRef))
+ .subscribe(() => {
+ this.log.successOperation('create', 'wallet');
+ this.closeWithSuccess();
+ });
+ }
+
+ editFull() {
+ this.closeWithCancellation();
+ this.dialogService.open(CreateDomainObjectDialogComponent, {
+ objectType: 'wallet_config',
+ noType: true,
+ initValue: this.getWalletConfig(),
+ noNavigate: true,
+ });
+ }
+
+ private getWalletConfig(): WalletConfig {
+ const value = this.walletModel();
+
+ return {
+ name: value.name,
+ description: value.description,
+ party_ref: { id: value.partyId },
+ terms: { id: value.termsetId },
+ account: {
+ currency: { symbolic_code: value.account.currency },
+ settlement: value.account.accounts[0],
+ },
+
+ block: {
+ unblocked: {
+ reason: value.preset,
+ since: getNoTimeZoneIsoString(new Date()),
+ },
+ },
+ suspension: { active: { since: getNoTimeZoneIsoString(new Date()) } },
+ payment_institution: { id: this.preset().paymentInstitution },
+ };
+ }
+}
diff --git a/src/components/create-wallet-dialog/index.ts b/src/components/create-wallet-dialog/index.ts
new file mode 100644
index 000000000..46354ca2c
--- /dev/null
+++ b/src/components/create-wallet-dialog/index.ts
@@ -0,0 +1 @@
+export * from './create-wallet-dialog.component';
From 38141b836e1368a1d5ed80c363721ebd3300e3f5 Mon Sep 17 00:00:00 2001
From: Ray <11846445+A77AY@users.noreply.github.com>
Date: Mon, 29 Jun 2026 22:36:04 +0400
Subject: [PATCH 18/18] feat: update @vality/domain-proto version in
package.json and package-lock.json
---
package-lock.json | 8 ++++----
package.json | 2 +-
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 0b3491dee..41f92b472 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,7 +22,7 @@
"@angular/router": "^22.0.1",
"@ngneat/input-mask": "^6.1.0",
"@tailwindcss/postcss": "^4.3.1",
- "@vality/domain-proto": "^2.0.2-dcd6682.0",
+ "@vality/domain-proto": "^2.0.2-c529750.0",
"@vality/fistful-proto": "^2.0.1-9864622.0",
"@vality/machinegun-proto": "^1.0.1-273f2f3.0",
"@vality/magista-proto": "^2.0.2-bd58cea.0",
@@ -6135,9 +6135,9 @@
]
},
"node_modules/@vality/domain-proto": {
- "version": "2.0.2-dcd6682.0",
- "resolved": "https://registry.npmjs.org/@vality/domain-proto/-/domain-proto-2.0.2-dcd6682.0.tgz",
- "integrity": "sha512-Kme4MZQIOvudB7haeYc7EJBIPamn4j97EEjGY7YgoEZvXttGTC5mN1EGbdgFb9Aqt9dGIYZCJxk9g+62N/5eKg==",
+ "version": "2.0.2-c529750.0",
+ "resolved": "https://registry.npmjs.org/@vality/domain-proto/-/domain-proto-2.0.2-c529750.0.tgz",
+ "integrity": "sha512-VheZVAGXfWGjxYlNORwnHJAY3f+41/HIPW+swgMolpiSHH57gc9RNYooKZSQkKTrTSH/jMzoNtZrSgm1iXtoTw==",
"license": "Apache-2.0"
},
"node_modules/@vality/fistful-proto": {
diff --git a/package.json b/package.json
index d6360c435..0b6d5f02c 100644
--- a/package.json
+++ b/package.json
@@ -37,7 +37,7 @@
"@angular/router": "^22.0.1",
"@ngneat/input-mask": "^6.1.0",
"@tailwindcss/postcss": "^4.3.1",
- "@vality/domain-proto": "^2.0.2-dcd6682.0",
+ "@vality/domain-proto": "^2.0.2-c529750.0",
"@vality/fistful-proto": "^2.0.1-9864622.0",
"@vality/machinegun-proto": "^1.0.1-273f2f3.0",
"@vality/magista-proto": "^2.0.2-bd58cea.0",