TD-693: Update Prettier, ESLint (#141)

This commit is contained in:
Rinat Arsaev 2023-08-14 15:38:33 +04:00 committed by GitHub
parent 125d70bec1
commit eb3c5c6b32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
898 changed files with 9995 additions and 6407 deletions

View File

@ -1,8 +1,8 @@
name: Init name: Init
description: Init description: Init
runs: runs:
using: composite using: composite
steps: steps:
- uses: valitydev/action-frontend/setup@v0.1 - uses: valitydev/action-frontend/setup@v0.1
- run: npm ci --force # TODO: Remove "--force" after updating Angular in external libraries (@vality) - run: npm ci --force # TODO: Remove "--force" after updating Angular in external libraries (@vality)
shell: bash shell: bash

View File

@ -1,18 +1,18 @@
name: Main name: Main
on: on:
push: push:
branches: ['master', 'main'] branches: ['master', 'main']
jobs: jobs:
build: build:
name: Build name: Build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: ./.github/actions/init - uses: ./.github/actions/init
- name: Build - name: Build
run: npm run build run: npm run build
- name: Deploy image - name: Deploy image
uses: valitydev/action-deploy-docker@v2 uses: valitydev/action-deploy-docker@v2
with: with:
registry-username: ${{ github.actor }} registry-username: ${{ github.actor }}
registry-access-token: ${{ secrets.GITHUB_TOKEN }} registry-access-token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,69 +1,69 @@
name: PR name: PR
on: on:
pull_request: pull_request:
branches: ['*'] branches: ['*']
jobs: jobs:
init: init:
name: Initialization name: Initialization
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
- uses: ./.github/actions/init - uses: ./.github/actions/init
- name: Cache all - name: Cache all
uses: actions/cache@v3 uses: actions/cache@v3
id: cache id: cache
with: with:
path: ./* path: ./*
key: ${{ github.sha }} key: ${{ github.sha }}
prettier: prettier:
name: Prettier check name: Format check
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [init] needs: [init]
steps: steps:
- name: Cache all - name: Cache all
uses: actions/cache@v3 uses: actions/cache@v3
id: cache id: cache
with: with:
path: ./* path: ./*
key: ${{ github.sha }} key: ${{ github.sha }}
- name: Check - name: Check
run: npm run prettier run: npm run format
eslint: eslint:
name: ESLint check name: ESLint check
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [init] needs: [init]
steps: steps:
- name: Cache all - name: Cache all
uses: actions/cache@v3 uses: actions/cache@v3
id: cache id: cache
with: with:
path: ./* path: ./*
key: ${{ github.sha }} key: ${{ github.sha }}
- name: Check - name: Check
run: npm run lint run: npm run lint
i18n: i18n:
name: Translation keys check name: Translation keys check
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [init] needs: [init]
steps: steps:
- name: Cache all - name: Cache all
uses: actions/cache@v3 uses: actions/cache@v3
id: cache id: cache
with: with:
path: ./* path: ./*
key: ${{ github.sha }} key: ${{ github.sha }}
- name: Check - name: Check
run: npm run i18n:check run: npm run i18n:check
build: build:
name: Build name: Build
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: [init] needs: [init]
steps: steps:
- name: Cache all - name: Cache all
uses: actions/cache@v3 uses: actions/cache@v3
id: cache id: cache
with: with:
path: ./* path: ./*
key: ${{ github.sha }} key: ${{ github.sha }}
- name: Build - name: Build
run: npm run build run: npm run build

View File

@ -1,16 +0,0 @@
{
"printWidth": 120,
"singleQuote": true,
"tabWidth": 4,
"endOfLine": "auto",
"overrides": [
{
"files": "*.svg",
"options": { "parser": "html" }
},
{
"files": ".prettierrc",
"options": { "parser": "json" }
}
]
}

1
.prettierrc.js Normal file
View File

@ -0,0 +1 @@
module.exports = require("@vality/prettier-config");

5836
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
"scripts": { "scripts": {
"start": "ng serve --proxy-config proxy.conf.js --port 8000", "start": "ng serve --proxy-config proxy.conf.js --port 8000",
"stage": "cross-env NODE_ENV=stage ng serve --proxy-config proxy.conf.js --port 8001 --configuration=stage", "stage": "cross-env NODE_ENV=stage ng serve --proxy-config proxy.conf.js --port 8001 --configuration=stage",
"fix": "npm run lint:fix && npm run prettier-fix", "fix": "npm run lint:fix && npm run format:fix",
"build": "ng build && transloco-optimize dist/assets/i18n", "build": "ng build && transloco-optimize dist/assets/i18n",
"test": "ng test", "test": "ng test",
"i18n:extract": "transloco-keys-manager extract", "i18n:extract": "transloco-keys-manager extract",
@ -15,32 +15,31 @@
"lint": "ng lint --max-warnings=0", "lint": "ng lint --max-warnings=0",
"lint:fix": "ng lint --fix", "lint:fix": "ng lint --fix",
"lint:errors": "ng lint --quiet", "lint:errors": "ng lint --quiet",
"prettier-cmd": "prettier \"**/*.{html,js,ts,css,scss,md,json,prettierrc,svg,yaml,yml}\"", "format": "prettier * --list-different",
"prettier": "npm run prettier-cmd -- --check", "format:fix": "prettier * --write --loglevel warn",
"prettier-fix": "npm run prettier-cmd -- --write",
"tools-cmd": "ts-node --project tools/tsconfig.json", "tools-cmd": "ts-node --project tools/tsconfig.json",
"icons-list-gen": "npm run tools-cmd -- tools/gen-icons-list.ts", "icons-list-gen": "npm run tools-cmd -- tools/gen-icons-list.ts",
"icons-ids-gen": "npm run tools-cmd -- tools/gen-icons-ids.ts", "icons-ids-gen": "npm run tools-cmd -- tools/gen-icons-ids.ts",
"ci:test": "npm run test -- --configuration=ci" "ci:test": "npm run test -- --configuration=ci"
}, },
"dependencies": { "dependencies": {
"@angular/animations": "^16.1.2", "@angular/animations": "^16.2.0",
"@angular/cdk": "~16.1.2", "@angular/cdk": "~16.2.0",
"@angular/common": "^16.1.2", "@angular/common": "^16.2.0",
"@angular/compiler": "^16.1.2", "@angular/compiler": "^16.2.0",
"@angular/core": "^16.1.2", "@angular/core": "^16.2.0",
"@angular/flex-layout": "15.0.0-beta.42", "@angular/flex-layout": "^15.0.0-beta.42",
"@angular/forms": "^16.1.2", "@angular/forms": "^16.2.0",
"@angular/material": "~16.1.2", "@angular/material": "~16.2.0",
"@angular/material-moment-adapter": "^16.1.2", "@angular/material-moment-adapter": "^16.2.0",
"@angular/platform-browser": "^16.1.2", "@angular/platform-browser": "^16.2.0",
"@angular/platform-browser-dynamic": "^16.1.2", "@angular/platform-browser-dynamic": "^16.2.0",
"@angular/router": "^16.1.2", "@angular/router": "^16.2.0",
"@ngneat/transloco": "^4.3.0", "@ngneat/transloco": "^4.3.0",
"@ngneat/until-destroy": "^9.0.0", "@ngneat/until-destroy": "^9.0.0",
"@sentry/angular": "^7.56.0", "@sentry/angular-ivy": "^7.63.0",
"@sentry/integrations": "^7.56.0", "@sentry/integrations": "^7.63.0",
"@sentry/tracing": "^7.56.0", "@sentry/tracing": "^7.63.0",
"@vality/ng-core": "^16.2.1-pr-33-c999544.0", "@vality/ng-core": "^16.2.1-pr-33-c999544.0",
"@vality/swag-anapi-v2": "2.0.0", "@vality/swag-anapi-v2": "2.0.0",
"@vality/swag-api-keys-v2": "^0.1.2-870c41d.0", "@vality/swag-api-keys-v2": "^0.1.2-870c41d.0",
@ -71,12 +70,12 @@
}, },
"devDependencies": { "devDependencies": {
"@angular-builders/custom-webpack": "^16.0.0", "@angular-builders/custom-webpack": "^16.0.0",
"@angular-devkit/build-angular": "16.1.1", "@angular-devkit/build-angular": "^16.2.0",
"@angular-eslint/builder": "16.0.3", "@angular-eslint/builder": "^16.1.0",
"@angular-eslint/schematics": "16.0.3", "@angular-eslint/schematics": "^16.1.0",
"@angular/cli": "16.1.1", "@angular/cli": "^16.2.0",
"@angular/compiler-cli": "16.1.2", "@angular/compiler-cli": "^16.2.0",
"@angular/language-service": "16.1.2", "@angular/language-service": "^16.2.0",
"@ngneat/transloco-keys-manager": "^3.7.0", "@ngneat/transloco-keys-manager": "^3.7.0",
"@ngneat/transloco-optimize": "^3.0.2", "@ngneat/transloco-optimize": "^3.0.2",
"@types/d3": "^5.7.0", "@types/d3": "^5.7.0",
@ -86,11 +85,12 @@
"@types/jwt-decode": "^3.1.0", "@types/jwt-decode": "^3.1.0",
"@types/lodash-es": "4.17.6", "@types/lodash-es": "4.17.6",
"@types/moment": "2.13.0", "@types/moment": "2.13.0",
"@types/prettier": "2.4.3", "@types/prettier": "^3.0.0",
"@vality/eslint-config": "0.1.1-2a1b72f.0", "@vality/eslint-config": "^8.0.1-pr-33-52841c7.0",
"@vality/prettier-config": "3.0.1-pr-33-52841c7.0",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"dotenv": "^16.0.3", "dotenv": "^16.0.3",
"eslint": "^8.39.0", "eslint": "^8.47.0",
"glob": "^7.1.6", "glob": "^7.1.6",
"jasmine-core": "~3.7.0", "jasmine-core": "~3.7.0",
"jasmine-marbles": "0.9.2", "jasmine-marbles": "0.9.2",
@ -100,7 +100,7 @@
"karma-jasmine": "~4.0.0", "karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0", "karma-jasmine-html-reporter": "^1.5.0",
"karma-spec-reporter": "0.0.32", "karma-spec-reporter": "0.0.32",
"prettier": "^2.8.7", "prettier": "^3.0.1",
"ts-mockito": "^2.6.1", "ts-mockito": "^2.6.1",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",
"typescript": "~5.1.3" "typescript": "~5.1.3"

View File

@ -13,34 +13,94 @@ export class AnapiDictionaryService {
paymentTool$ = this.dictionaryService.create(() => ({ paymentTool$ = this.dictionaryService.create(() => ({
bank_card: this.t.translate('anapi.paymentTool.bank_card', null, 'dictionary'), bank_card: this.t.translate('anapi.paymentTool.bank_card', null, 'dictionary'),
digital_wallet: this.t.translate('anapi.paymentTool.digital_wallet', null, 'dictionary'), digital_wallet: this.t.translate('anapi.paymentTool.digital_wallet', null, 'dictionary'),
payment_terminal: this.t.translate('anapi.paymentTool.payment_terminal', null, 'dictionary'), payment_terminal: this.t.translate(
'anapi.paymentTool.payment_terminal',
null,
'dictionary',
),
})); }));
errorCode$ = this.dictionaryService.create(() => ({ errorCode$ = this.dictionaryService.create(() => ({
account_limit_exceeded: this.t.translate('anapi.errorCode.account_limit_exceeded', null, 'dictionary'), account_limit_exceeded: this.t.translate(
account_not_found: this.t.translate('anapi.errorCode.account_not_found', null, 'dictionary'), 'anapi.errorCode.account_limit_exceeded',
null,
'dictionary',
),
account_not_found: this.t.translate(
'anapi.errorCode.account_not_found',
null,
'dictionary',
),
amount: this.t.translate('anapi.errorCode.amount', null, 'dictionary'), amount: this.t.translate('anapi.errorCode.amount', null, 'dictionary'),
authorization_failed: this.t.translate('anapi.errorCode.authorization_failed', null, 'dictionary'), authorization_failed: this.t.translate(
bank_card_rejected: this.t.translate('anapi.errorCode.bank_card_rejected', null, 'dictionary'), 'anapi.errorCode.authorization_failed',
null,
'dictionary',
),
bank_card_rejected: this.t.translate(
'anapi.errorCode.bank_card_rejected',
null,
'dictionary',
),
card_expired: this.t.translate('anapi.errorCode.card_expired', null, 'dictionary'), card_expired: this.t.translate('anapi.errorCode.card_expired', null, 'dictionary'),
card_number_invalid: this.t.translate('anapi.errorCode.card_number_invalid', null, 'dictionary'), card_number_invalid: this.t.translate(
insufficient_funds: this.t.translate('anapi.errorCode.insufficient_funds', null, 'dictionary'), 'anapi.errorCode.card_number_invalid',
null,
'dictionary',
),
insufficient_funds: this.t.translate(
'anapi.errorCode.insufficient_funds',
null,
'dictionary',
),
no_route_found: this.t.translate('anapi.errorCode.no_route_found', null, 'dictionary'), no_route_found: this.t.translate('anapi.errorCode.no_route_found', null, 'dictionary'),
number: this.t.translate('anapi.errorCode.number', null, 'dictionary'), number: this.t.translate('anapi.errorCode.number', null, 'dictionary'),
operation_blocked: this.t.translate('anapi.errorCode.operation_blocked', null, 'dictionary'), operation_blocked: this.t.translate(
operation_timeout: this.t.translate('anapi.errorCode.operation_timeout', null, 'dictionary'), 'anapi.errorCode.operation_blocked',
payment_tool_rejected: this.t.translate('anapi.errorCode.payment_tool_rejected', null, 'dictionary'), null,
preauthorization_failed: this.t.translate('anapi.errorCode.preauthorization_failed', null, 'dictionary'), 'dictionary',
),
operation_timeout: this.t.translate(
'anapi.errorCode.operation_timeout',
null,
'dictionary',
),
payment_tool_rejected: this.t.translate(
'anapi.errorCode.payment_tool_rejected',
null,
'dictionary',
),
preauthorization_failed: this.t.translate(
'anapi.errorCode.preauthorization_failed',
null,
'dictionary',
),
processing_deadline_reached: this.t.translate( processing_deadline_reached: this.t.translate(
'anapi.errorCode.processing_deadline_reached', 'anapi.errorCode.processing_deadline_reached',
null, null,
'dictionary' 'dictionary',
),
rejected_by_issuer: this.t.translate(
'anapi.errorCode.rejected_by_issuer',
null,
'dictionary',
),
risk_score_is_too_high: this.t.translate(
'anapi.errorCode.risk_score_is_too_high',
null,
'dictionary',
),
security_policy_violated: this.t.translate(
'anapi.errorCode.security_policy_violated',
null,
'dictionary',
), ),
rejected_by_issuer: this.t.translate('anapi.errorCode.rejected_by_issuer', null, 'dictionary'),
risk_score_is_too_high: this.t.translate('anapi.errorCode.risk_score_is_too_high', null, 'dictionary'),
security_policy_violated: this.t.translate('anapi.errorCode.security_policy_violated', null, 'dictionary'),
three_ds_failed: this.t.translate('anapi.errorCode.three_ds_failed', null, 'dictionary'), three_ds_failed: this.t.translate('anapi.errorCode.three_ds_failed', null, 'dictionary'),
three_ds_not_finished: this.t.translate('anapi.errorCode.three_ds_not_finished', null, 'dictionary'), three_ds_not_finished: this.t.translate(
'anapi.errorCode.three_ds_not_finished',
null,
'dictionary',
),
other: this.t.translate('anapi.errorCode.other', null, 'dictionary'), other: this.t.translate('anapi.errorCode.other', null, 'dictionary'),
})); }));
@ -62,9 +122,17 @@ export class AnapiDictionaryService {
})); }));
reportType$ = this.dictionaryService.create<Report.ReportTypeEnum>(() => ({ reportType$ = this.dictionaryService.create<Report.ReportTypeEnum>(() => ({
provisionOfService: this.t.translate('anapi.reportType.provisionOfService', null, 'dictionary'), provisionOfService: this.t.translate(
'anapi.reportType.provisionOfService',
null,
'dictionary',
),
paymentRegistry: this.t.translate('anapi.reportType.paymentRegistry', null, 'dictionary'), paymentRegistry: this.t.translate('anapi.reportType.paymentRegistry', null, 'dictionary'),
paymentRegistryByPayout: this.t.translate('anapi.reportType.paymentRegistryByPayout', null, 'dictionary'), paymentRegistryByPayout: this.t.translate(
'anapi.reportType.paymentRegistryByPayout',
null,
'dictionary',
),
})); }));
reportStatus$ = this.dictionaryService.create<Report.StatusEnum>(() => ({ reportStatus$ = this.dictionaryService.create<Report.StatusEnum>(() => ({
@ -78,14 +146,22 @@ export class AnapiDictionaryService {
dankort: this.t.translate('anapi.bankCardPaymentSystem.dankort', null, 'dictionary'), dankort: this.t.translate('anapi.bankCardPaymentSystem.dankort', null, 'dictionary'),
dinersclub: this.t.translate('anapi.bankCardPaymentSystem.dinersclub', null, 'dictionary'), dinersclub: this.t.translate('anapi.bankCardPaymentSystem.dinersclub', null, 'dictionary'),
discover: this.t.translate('anapi.bankCardPaymentSystem.discover', null, 'dictionary'), discover: this.t.translate('anapi.bankCardPaymentSystem.discover', null, 'dictionary'),
forbrugsforeningen: this.t.translate('anapi.bankCardPaymentSystem.forbrugsforeningen', null, 'dictionary'), forbrugsforeningen: this.t.translate(
'anapi.bankCardPaymentSystem.forbrugsforeningen',
null,
'dictionary',
),
jcb: this.t.translate('anapi.bankCardPaymentSystem.jcb', null, 'dictionary'), jcb: this.t.translate('anapi.bankCardPaymentSystem.jcb', null, 'dictionary'),
maestro: this.t.translate('anapi.bankCardPaymentSystem.maestro', null, 'dictionary'), maestro: this.t.translate('anapi.bankCardPaymentSystem.maestro', null, 'dictionary'),
mastercard: this.t.translate('anapi.bankCardPaymentSystem.mastercard', null, 'dictionary'), mastercard: this.t.translate('anapi.bankCardPaymentSystem.mastercard', null, 'dictionary'),
nspkmir: this.t.translate('anapi.bankCardPaymentSystem.nspkmir', null, 'dictionary'), nspkmir: this.t.translate('anapi.bankCardPaymentSystem.nspkmir', null, 'dictionary'),
unionpay: this.t.translate('anapi.bankCardPaymentSystem.unionpay', null, 'dictionary'), unionpay: this.t.translate('anapi.bankCardPaymentSystem.unionpay', null, 'dictionary'),
visa: this.t.translate('anapi.bankCardPaymentSystem.visa', null, 'dictionary'), visa: this.t.translate('anapi.bankCardPaymentSystem.visa', null, 'dictionary'),
visaelectron: this.t.translate('anapi.bankCardPaymentSystem.visaelectron', null, 'dictionary'), visaelectron: this.t.translate(
'anapi.bankCardPaymentSystem.visaelectron',
null,
'dictionary',
),
elo: this.t.translate('anapi.bankCardPaymentSystem.elo', null, 'dictionary'), elo: this.t.translate('anapi.bankCardPaymentSystem.elo', null, 'dictionary'),
rupay: this.t.translate('anapi.bankCardPaymentSystem.rupay', null, 'dictionary'), rupay: this.t.translate('anapi.bankCardPaymentSystem.rupay', null, 'dictionary'),
dummy: this.t.translate('anapi.bankCardPaymentSystem.dummy', null, 'dictionary'), dummy: this.t.translate('anapi.bankCardPaymentSystem.dummy', null, 'dictionary'),
@ -105,5 +181,8 @@ export class AnapiDictionaryService {
failed: this.t.translate('anapi.refundStatus.failed', null, 'dictionary'), failed: this.t.translate('anapi.refundStatus.failed', null, 'dictionary'),
})); }));
constructor(private t: TranslocoService, private dictionaryService: DictionaryService) {} constructor(
private t: TranslocoService,
private dictionaryService: DictionaryService,
) {}
} }

View File

@ -13,5 +13,8 @@ export class ApiKeysDictionaryService {
revoked: this.t.translate('api-keys.ApiKeyStatus.revoked', null, 'dictionary'), revoked: this.t.translate('api-keys.ApiKeyStatus.revoked', null, 'dictionary'),
})); }));
constructor(private t: TranslocoService, private dictionaryService: DictionaryService) {} constructor(
private t: TranslocoService,
private dictionaryService: DictionaryService,
) {}
} }

View File

@ -12,7 +12,7 @@ export class ApiKeysService extends createApi(ApiService, [PartyIdExtension]) {
super(injector); super(injector);
this.requestRevokeApiKey = partyIdPatchMethodService.patch( this.requestRevokeApiKey = partyIdPatchMethodService.patch(
this.requestRevokeApiKey, this.requestRevokeApiKey,
(params, partyId) => (params.partyId = partyId) (params, partyId) => (params.partyId = partyId),
); );
} }
} }

View File

@ -12,10 +12,17 @@ export class ClaimManagementDictionaryService {
accepted: this.t.translate('claimManagement.claimStatus.accepted', null, 'dictionary'), accepted: this.t.translate('claimManagement.claimStatus.accepted', null, 'dictionary'),
denied: this.t.translate('claimManagement.claimStatus.denied', null, 'dictionary'), denied: this.t.translate('claimManagement.claimStatus.denied', null, 'dictionary'),
pending: this.t.translate('claimManagement.claimStatus.pending', null, 'dictionary'), pending: this.t.translate('claimManagement.claimStatus.pending', null, 'dictionary'),
pendingAcceptance: this.t.translate('claimManagement.claimStatus.pendingAcceptance', null, 'dictionary'), pendingAcceptance: this.t.translate(
'claimManagement.claimStatus.pendingAcceptance',
null,
'dictionary',
),
review: this.t.translate('claimManagement.claimStatus.review', null, 'dictionary'), review: this.t.translate('claimManagement.claimStatus.review', null, 'dictionary'),
revoked: this.t.translate('claimManagement.claimStatus.revoked', null, 'dictionary'), revoked: this.t.translate('claimManagement.claimStatus.revoked', null, 'dictionary'),
})); }));
constructor(private t: TranslocoService, private dictionaryService: DictionaryService) {} constructor(
private t: TranslocoService,
private dictionaryService: DictionaryService,
) {}
} }

View File

@ -12,7 +12,10 @@ import { PartyIdExtension } from '../utils/extensions';
}) })
export class ClaimsService extends createApi(ApiClaimsService, [PartyIdExtension]) { export class ClaimsService extends createApi(ApiClaimsService, [PartyIdExtension]) {
requestReviewClaimByIDWithRevisionCheck = ( requestReviewClaimByIDWithRevisionCheck = (
params: ApiMethodParams<ApiClaimsService['requestReviewClaimByID'], 'xRequestID' | 'partyID'> params: ApiMethodParams<
ApiClaimsService['requestReviewClaimByID'],
'xRequestID' | 'partyID'
>,
) => { ) => {
return this.requestReviewClaimByID(params).pipe( return this.requestReviewClaimByID(params).pipe(
catchError((err) => { catchError((err) => {
@ -22,11 +25,11 @@ export class ClaimsService extends createApi(ApiClaimsService, [PartyIdExtension
this.requestReviewClaimByID({ this.requestReviewClaimByID({
...params, ...params,
claimRevision: claim.revision, claimRevision: claim.revision,
}) }),
) ),
); );
return throwError(err); return throwError(err);
}) }),
); );
}; };
} }

View File

@ -1,12 +1,16 @@
import { ContractModificationUnit, PartyModification, PartyModificationType } from '@vality/swag-claim-management'; import {
ContractModificationUnit,
PartyModification,
PartyModificationType,
} from '@vality/swag-claim-management';
import { PARTY_MODIFICATION } from '../consts'; import { PARTY_MODIFICATION } from '../consts';
import PartyModificationTypeEnum = PartyModificationType.PartyModificationTypeEnum; import PartyModificationTypeEnum = PartyModificationType.PartyModificationTypeEnum;
export function createBaseContractModification<M extends Omit<ContractModificationUnit, 'partyModificationType'>>( export function createBaseContractModification<
modification: M M extends Omit<ContractModificationUnit, 'partyModificationType'>,
): PartyModification { >(modification: M): PartyModification {
return { return {
...PARTY_MODIFICATION, ...PARTY_MODIFICATION,
partyModificationType: { partyModificationType: {

View File

@ -1,10 +1,14 @@
import { ContractCreationModification, ContractModification, PartyModification } from '@vality/swag-claim-management'; import {
ContractCreationModification,
ContractModification,
PartyModification,
} from '@vality/swag-claim-management';
import { createBaseContractModification } from './create-base-contract-modification'; import { createBaseContractModification } from './create-base-contract-modification';
export function createContractCreationModification( export function createContractCreationModification(
id: string, id: string,
params: Omit<ContractCreationModification, 'contractModificationType'> params: Omit<ContractCreationModification, 'contractModificationType'>,
): PartyModification { ): PartyModification {
return { return {
...createBaseContractModification({ ...createBaseContractModification({
@ -18,7 +22,10 @@ export function createContractCreationModification(
}; };
} }
export function createTestContractCreationModification(id: string, contractorID: string): PartyModification { export function createTestContractCreationModification(
id: string,
contractorID: string,
): PartyModification {
return createContractCreationModification(id, { return createContractCreationModification(id, {
contractorID, contractorID,
}); });

View File

@ -6,12 +6,16 @@ import {
import { createBaseContractModification } from './create-base-contract-modification'; import { createBaseContractModification } from './create-base-contract-modification';
export const createContractLegalAgreementBindingModification = (id: string, legalAgreement: LegalAgreement) => export const createContractLegalAgreementBindingModification = (
id: string,
legalAgreement: LegalAgreement,
) =>
createBaseContractModification({ createBaseContractModification({
id, id,
modification: { modification: {
contractModificationType: contractModificationType:
ContractModification.ContractModificationTypeEnum.ContractLegalAgreementBindingModification, ContractModification.ContractModificationTypeEnum
.ContractLegalAgreementBindingModification,
legalAgreement, legalAgreement,
} as ContractLegalAgreementBindingModification, } as ContractLegalAgreementBindingModification,
}); });

View File

@ -1,18 +1,23 @@
import { ContractModification, ContractPayoutToolModification, PartyModification } from '@vality/swag-claim-management'; import {
ContractModification,
ContractPayoutToolModification,
PartyModification,
} from '@vality/swag-claim-management';
import { createBaseContractModification } from './create-base-contract-modification'; import { createBaseContractModification } from './create-base-contract-modification';
export function createContractPayoutToolCreationModification( export function createContractPayoutToolCreationModification(
id: string, id: string,
payoutToolID: string, payoutToolID: string,
params: Omit<ContractPayoutToolModification, 'payoutToolModificationType'> params: Omit<ContractPayoutToolModification, 'payoutToolModificationType'>,
): PartyModification { ): PartyModification {
return { return {
...createBaseContractModification({ ...createBaseContractModification({
id, id,
modification: { modification: {
contractModificationType: contractModificationType:
ContractModification.ContractModificationTypeEnum.ContractPayoutToolModificationUnit, ContractModification.ContractModificationTypeEnum
.ContractPayoutToolModificationUnit,
payoutToolID, payoutToolID,
modification: { modification: {
payoutToolModificationType: payoutToolModificationType:

View File

@ -1,18 +1,23 @@
import { ContractModification, ContractPayoutToolModification, PartyModification } from '@vality/swag-claim-management'; import {
ContractModification,
ContractPayoutToolModification,
PartyModification,
} from '@vality/swag-claim-management';
import { createBaseContractModification } from './create-base-contract-modification'; import { createBaseContractModification } from './create-base-contract-modification';
export function createContractPayoutToolInfoModification( export function createContractPayoutToolInfoModification(
id: string, id: string,
payoutToolID: string, payoutToolID: string,
params: Omit<ContractPayoutToolModification, 'payoutToolModificationType'> params: Omit<ContractPayoutToolModification, 'payoutToolModificationType'>,
): PartyModification { ): PartyModification {
return { return {
...createBaseContractModification({ ...createBaseContractModification({
id, id,
modification: { modification: {
contractModificationType: contractModificationType:
ContractModification.ContractModificationTypeEnum.ContractPayoutToolModificationUnit, ContractModification.ContractModificationTypeEnum
.ContractPayoutToolModificationUnit,
payoutToolID, payoutToolID,
modification: { modification: {
payoutToolModificationType: payoutToolModificationType:

View File

@ -25,7 +25,7 @@ export function createInternationalContractPayoutToolModification(
{ accountHolder?: CorrespondentAccount['accountHolder'] } { accountHolder?: CorrespondentAccount['accountHolder'] }
>; >;
} }
> >,
): PartyModification { ): PartyModification {
return createContractPayoutToolCreationModification(id, payoutToolID, { return createContractPayoutToolCreationModification(id, payoutToolID, {
currency: { currency: {

View File

@ -1,4 +1,8 @@
import { PartyModification, PayoutToolInfo, RussianBankAccount } from '@vality/swag-claim-management'; import {
PartyModification,
PayoutToolInfo,
RussianBankAccount,
} from '@vality/swag-claim-management';
import { createContractPayoutToolCreationModification } from './create-contract-payout-tool-creation-modification'; import { createContractPayoutToolCreationModification } from './create-contract-payout-tool-creation-modification';
@ -6,7 +10,7 @@ export function createRussianContractPayoutToolCreationModification(
id: string, id: string,
payoutToolID: string, payoutToolID: string,
params: Omit<RussianBankAccount, 'payoutToolType'>, params: Omit<RussianBankAccount, 'payoutToolType'>,
currency?: string currency?: string,
): PartyModification { ): PartyModification {
return createContractPayoutToolCreationModification(id, payoutToolID, { return createContractPayoutToolCreationModification(id, payoutToolID, {
currency: { currency: {

View File

@ -1,11 +1,15 @@
import { PartyModification, PayoutToolInfo, RussianBankAccount } from '@vality/swag-claim-management'; import {
PartyModification,
PayoutToolInfo,
RussianBankAccount,
} from '@vality/swag-claim-management';
import { createContractPayoutToolInfoModification } from './create-contract-payout-tool-info-modification'; import { createContractPayoutToolInfoModification } from './create-contract-payout-tool-info-modification';
export function createRussianContractPayoutToolInfoModification( export function createRussianContractPayoutToolInfoModification(
id: string, id: string,
payoutToolID: string, payoutToolID: string,
params: Omit<RussianBankAccount, 'payoutToolType'> params: Omit<RussianBankAccount, 'payoutToolType'>,
): PartyModification { ): PartyModification {
return createContractPayoutToolInfoModification(id, payoutToolID, { return createContractPayoutToolInfoModification(id, payoutToolID, {
payoutToolInfo: { payoutToolInfo: {

View File

@ -1,12 +1,16 @@
import { ContractorModification, PartyModification, PartyModificationType } from '@vality/swag-claim-management'; import {
ContractorModification,
PartyModification,
PartyModificationType,
} from '@vality/swag-claim-management';
import { PARTY_MODIFICATION } from '../consts'; import { PARTY_MODIFICATION } from '../consts';
import PartyModificationTypeEnum = PartyModificationType.PartyModificationTypeEnum; import PartyModificationTypeEnum = PartyModificationType.PartyModificationTypeEnum;
export function createBaseContractorModification<M extends Omit<ContractorModification, 'contractorModificationType'>>( export function createBaseContractorModification<
modification: M M extends Omit<ContractorModification, 'contractorModificationType'>,
): PartyModification { >(modification: M): PartyModification {
return { return {
...PARTY_MODIFICATION, ...PARTY_MODIFICATION,
partyModificationType: { partyModificationType: {

View File

@ -7,12 +7,16 @@ import {
import { createBaseContractorModification } from './create-base-contractor-modification'; import { createBaseContractorModification } from './create-base-contractor-modification';
export function createContractorLegalEntityModification(id: string, entity: LegalEntityType): PartyModification { export function createContractorLegalEntityModification(
id: string,
entity: LegalEntityType,
): PartyModification {
return { return {
...createBaseContractorModification({ ...createBaseContractorModification({
id, id,
modification: { modification: {
contractorModificationType: ContractorModification.ContractorModificationTypeEnum.Contractor, contractorModificationType:
ContractorModification.ContractorModificationTypeEnum.Contractor,
contractorType: { contractorType: {
contractorType: ContractorType.ContractorTypeEnum.LegalEntity, contractorType: ContractorType.ContractorTypeEnum.LegalEntity,
legalEntityType: { legalEntityType: {

View File

@ -4,7 +4,7 @@ import { createContractorLegalEntityModification } from './create-contractor-leg
export function createInternationalLegalEntityModification( export function createInternationalLegalEntityModification(
id: string, id: string,
params: Omit<InternationalLegalEntity, 'legalEntityType'> params: Omit<InternationalLegalEntity, 'legalEntityType'>,
): PartyModification { ): PartyModification {
return createContractorLegalEntityModification(id, { return createContractorLegalEntityModification(id, {
legalEntityType: 'InternationalLegalEntity', legalEntityType: 'InternationalLegalEntity',

View File

@ -1,7 +1,7 @@
import { PayoutToolInfo, RussianBankAccount } from '@vality/swag-claim-management'; import { PayoutToolInfo, RussianBankAccount } from '@vality/swag-claim-management';
export function createRussianBankAccountModification( export function createRussianBankAccountModification(
params: Omit<RussianBankAccount, 'payoutToolType'> params: Omit<RussianBankAccount, 'payoutToolType'>,
): RussianBankAccount { ): RussianBankAccount {
return { return {
payoutToolType: PayoutToolInfo.PayoutToolTypeEnum.RussianBankAccount, payoutToolType: PayoutToolInfo.PayoutToolTypeEnum.RussianBankAccount,

View File

@ -1,10 +1,14 @@
import { LegalEntityType, PartyModification, RussianLegalEntity } from '@vality/swag-claim-management'; import {
LegalEntityType,
PartyModification,
RussianLegalEntity,
} from '@vality/swag-claim-management';
import { createContractorLegalEntityModification } from './create-contractor-legal-entity-modification'; import { createContractorLegalEntityModification } from './create-contractor-legal-entity-modification';
export function createRussianLegalEntityModification( export function createRussianLegalEntityModification(
id: string, id: string,
params: Omit<RussianLegalEntity, 'legalEntityType'> params: Omit<RussianLegalEntity, 'legalEntityType'>,
): PartyModification { ): PartyModification {
return createContractorLegalEntityModification(id, { return createContractorLegalEntityModification(id, {
legalEntityType: LegalEntityType.LegalEntityTypeEnum.RussianLegalEntity, legalEntityType: LegalEntityType.LegalEntityTypeEnum.RussianLegalEntity,

View File

@ -1,11 +1,15 @@
import { PartyModification, PartyModificationType, ShopModificationUnit } from '@vality/swag-claim-management'; import {
PartyModification,
PartyModificationType,
ShopModificationUnit,
} from '@vality/swag-claim-management';
import { PARTY_MODIFICATION } from '../consts'; import { PARTY_MODIFICATION } from '../consts';
import PartyModificationTypeEnum = PartyModificationType.PartyModificationTypeEnum; import PartyModificationTypeEnum = PartyModificationType.PartyModificationTypeEnum;
export function createBaseShopModification( export function createBaseShopModification(
modification: Omit<ShopModificationUnit, 'partyModificationType'> modification: Omit<ShopModificationUnit, 'partyModificationType'>,
): PartyModification { ): PartyModification {
return { return {
...PARTY_MODIFICATION, ...PARTY_MODIFICATION,

View File

@ -4,7 +4,7 @@ import { createBaseShopModification } from './create-base-shop-modification';
export function createShopCreationModification( export function createShopCreationModification(
id: string, id: string,
params: Omit<ShopCreationModification, 'shopModificationType'> params: Omit<ShopCreationModification, 'shopModificationType'>,
): PartyModification { ): PartyModification {
return { return {
...createBaseShopModification({ ...createBaseShopModification({

View File

@ -42,7 +42,10 @@ const createTestLegalAgreement = (): LegalAgreement => ({
legalAgreementID: '000000/00', legalAgreementID: '000000/00',
}); });
const TEST_SHOP_CREATION: Omit<ShopCreationModification, 'shopModificationType' | 'contractID' | 'payoutToolID'> = { const TEST_SHOP_CREATION: Omit<
ShopCreationModification,
'shopModificationType' | 'contractID' | 'payoutToolID'
> = {
category: { category: {
categoryID: 1, categoryID: 1,
}, },
@ -67,6 +70,10 @@ export const createTestShopModifications = ({
createRussianLegalEntityModification(contractorID, TEST_RUSSIAN_LEGAL_ENTITY), createRussianLegalEntityModification(contractorID, TEST_RUSSIAN_LEGAL_ENTITY),
createContractCreationModification(contractID, { contractorID }), createContractCreationModification(contractID, { contractorID }),
createContractLegalAgreementBindingModification(contractID, createTestLegalAgreement()), createContractLegalAgreementBindingModification(contractID, createTestLegalAgreement()),
createRussianContractPayoutToolCreationModification(contractID, payoutToolID, TEST_RUSSIAN_BANK_ACCOUNT), createRussianContractPayoutToolCreationModification(
contractID,
payoutToolID,
TEST_RUSSIAN_BANK_ACCOUNT,
),
createShopCreationModification(shopID, { ...TEST_SHOP_CREATION, contractID, payoutToolID }), createShopCreationModification(shopID, { ...TEST_SHOP_CREATION, contractID, payoutToolID }),
]; ];

View File

@ -3,7 +3,7 @@ import { CommentModificationUnit } from '@vality/swag-claim-management';
import { SpecificClaimModificationUnit } from './specific-claim-modification-unit'; import { SpecificClaimModificationUnit } from './specific-claim-modification-unit';
export const createCommentModificationUnit = ( export const createCommentModificationUnit = (
commentId: string commentId: string,
): SpecificClaimModificationUnit<CommentModificationUnit> => ({ ): SpecificClaimModificationUnit<CommentModificationUnit> => ({
modificationType: 'ClaimModification', modificationType: 'ClaimModification',
claimModificationType: { claimModificationType: {

View File

@ -3,7 +3,7 @@ import { DocumentModificationUnit } from '@vality/swag-claim-management';
import { SpecificClaimModificationUnit } from './specific-claim-modification-unit'; import { SpecificClaimModificationUnit } from './specific-claim-modification-unit';
export const createDocumentModificationUnit = ( export const createDocumentModificationUnit = (
documentId: string documentId: string,
): SpecificClaimModificationUnit<DocumentModificationUnit> => ({ ): SpecificClaimModificationUnit<DocumentModificationUnit> => ({
modificationType: 'ClaimModification', modificationType: 'ClaimModification',
claimModificationType: { claimModificationType: {

View File

@ -8,7 +8,7 @@ type FileModificationType = FileModification.FileModificationTypeEnum;
export const createFileModificationUnit = ( export const createFileModificationUnit = (
fileId: string, fileId: string,
fileModificationType: FileModificationType = FileModificationType.FileCreated fileModificationType: FileModificationType = FileModificationType.FileCreated,
): SpecificClaimModificationUnit<FileModificationUnit> => ({ ): SpecificClaimModificationUnit<FileModificationUnit> => ({
modificationType: 'ClaimModification', modificationType: 'ClaimModification',
claimModificationType: { claimModificationType: {

View File

@ -25,7 +25,7 @@ export const createTestShopClaimChangeset = (
testShopID: string, testShopID: string,
testContractID: string, testContractID: string,
testPayoutToolID: string, testPayoutToolID: string,
testContractorID: string testContractorID: string,
): Modification[] => { ): Modification[] => {
return [ return [
createInternationalLegalEntityModification(testContractorID, { createInternationalLegalEntityModification(testContractorID, {

View File

@ -3,5 +3,5 @@ import * as moment from 'moment';
export const sortUnitsByCreatedAtAsc = ( export const sortUnitsByCreatedAtAsc = (
{ createdAt: a }: ModificationUnit, { createdAt: a }: ModificationUnit,
{ createdAt: b }: ModificationUnit { createdAt: b }: ModificationUnit,
): number => moment(a).diff(moment(b)); ): number => moment(a).diff(moment(b));

View File

@ -1,7 +1,15 @@
import { ClaimModification, ClaimModificationType, Modification } from '@vality/swag-claim-management'; import {
ClaimModification,
ClaimModificationType,
Modification,
} from '@vality/swag-claim-management';
import { Overwrite } from 'utility-types'; import { Overwrite } from 'utility-types';
export type SpecificClaimModificationUnit<M extends ClaimModificationType = ClaimModificationType> = Overwrite< export type SpecificClaimModificationUnit<M extends ClaimModificationType = ClaimModificationType> =
ClaimModification, Overwrite<
{ modificationType: typeof Modification.ModificationTypeEnum.ClaimModification; claimModificationType: M } ClaimModification,
>; {
modificationType: typeof Modification.ModificationTypeEnum.ClaimModification;
claimModificationType: M;
}
>;

View File

@ -2,11 +2,14 @@ import { ModificationUnit, DocumentModificationUnit } from '@vality/swag-claim-m
import { isClaimModification, isDocumentModificationUnit } from './type-guards'; import { isClaimModification, isDocumentModificationUnit } from './type-guards';
export const takeDocumentModificationUnits = (changeset: ModificationUnit[]): DocumentModificationUnit[] => export const takeDocumentModificationUnits = (
changeset: ModificationUnit[],
): DocumentModificationUnit[] =>
changeset.reduce( changeset.reduce(
(acc, { modification }) => (acc, { modification }) =>
isClaimModification(modification) && isDocumentModificationUnit(modification.claimModificationType) isClaimModification(modification) &&
isDocumentModificationUnit(modification.claimModificationType)
? acc.concat(modification.claimModificationType) ? acc.concat(modification.claimModificationType)
: acc, : acc,
[] as DocumentModificationUnit[] [] as DocumentModificationUnit[],
); );

View File

@ -1,16 +1,27 @@
import { ModificationUnit, FileModification, FileModificationUnit } from '@vality/swag-claim-management'; import {
ModificationUnit,
FileModification,
FileModificationUnit,
} from '@vality/swag-claim-management';
import { sortUnitsByCreatedAtAsc } from './sort-units'; import { sortUnitsByCreatedAtAsc } from './sort-units';
import { isClaimModification, isFileModificationUnit } from './type-guards'; import { isClaimModification, isFileModificationUnit } from './type-guards';
export const takeFileModificationUnits = (changeset: ModificationUnit[]): FileModificationUnit[] => export const takeFileModificationUnits = (changeset: ModificationUnit[]): FileModificationUnit[] =>
changeset.sort(sortUnitsByCreatedAtAsc).reduce((acc, { modification }) => { changeset.sort(sortUnitsByCreatedAtAsc).reduce((acc, { modification }) => {
if (isClaimModification(modification) && isFileModificationUnit(modification.claimModificationType)) { if (
isClaimModification(modification) &&
isFileModificationUnit(modification.claimModificationType)
) {
const m = modification.claimModificationType; const m = modification.claimModificationType;
if (m.fileModification.fileModificationType === FileModification.FileModificationTypeEnum.FileCreated) { if (
m.fileModification.fileModificationType ===
FileModification.FileModificationTypeEnum.FileCreated
) {
return acc.concat(m); return acc.concat(m);
} else if ( } else if (
m.fileModification.fileModificationType === FileModification.FileModificationTypeEnum.FileDeleted m.fileModification.fileModificationType ===
FileModification.FileModificationTypeEnum.FileDeleted
) { ) {
return acc.filter(({ fileId }) => fileId !== m.fileId); return acc.filter(({ fileId }) => fileId !== m.fileId);
} }

View File

@ -14,17 +14,17 @@ import ClaimModificationTypeEnum = ClaimModificationType.ClaimModificationTypeEn
const createTypeGuard = createUnionTypeGuardCreator<ClaimModificationType>('claimModificationType'); const createTypeGuard = createUnionTypeGuardCreator<ClaimModificationType>('claimModificationType');
export const isFileModificationUnit = createTypeGuard<FileModificationUnit>( export const isFileModificationUnit = createTypeGuard<FileModificationUnit>(
ClaimModificationTypeEnum.FileModificationUnit ClaimModificationTypeEnum.FileModificationUnit,
); );
export const isCommentModificationUnit = createTypeGuard<CommentModificationUnit>( export const isCommentModificationUnit = createTypeGuard<CommentModificationUnit>(
ClaimModificationTypeEnum.CommentModificationUnit ClaimModificationTypeEnum.CommentModificationUnit,
); );
export const isStatusModificationUnit = createTypeGuard<StatusModificationUnit>( export const isStatusModificationUnit = createTypeGuard<StatusModificationUnit>(
ClaimModificationTypeEnum.StatusModificationUnit ClaimModificationTypeEnum.StatusModificationUnit,
); );
export const isDocumentModificationUnit = createTypeGuard<DocumentModificationUnit>( export const isDocumentModificationUnit = createTypeGuard<DocumentModificationUnit>(
ClaimModificationTypeEnum.DocumentModificationUnit ClaimModificationTypeEnum.DocumentModificationUnit,
); );
export const isExternalInfoModificationUnit = createTypeGuard<ExternalInfoModificationUnit>( export const isExternalInfoModificationUnit = createTypeGuard<ExternalInfoModificationUnit>(
ClaimModificationTypeEnum.ExternalInfoModificationUnit ClaimModificationTypeEnum.ExternalInfoModificationUnit,
); );

View File

@ -3,6 +3,8 @@ import { DocumentCreated, DocumentModification } from '@vality/swag-claim-manage
import { createUnionTypeGuardCreator } from '../../../utils'; import { createUnionTypeGuardCreator } from '../../../utils';
const TYPE = DocumentModification.DocumentModificationTypeEnum; const TYPE = DocumentModification.DocumentModificationTypeEnum;
const createTypeGuard = createUnionTypeGuardCreator<DocumentModification>('documentModificationType'); const createTypeGuard = createUnionTypeGuardCreator<DocumentModification>(
'documentModificationType',
);
export const isDocumentCreated = createTypeGuard<DocumentCreated>(TYPE.DocumentCreated); export const isDocumentCreated = createTypeGuard<DocumentCreated>(TYPE.DocumentCreated);

View File

@ -23,5 +23,8 @@ export class OrganizationsDictionaryService {
/* eslint-enable @typescript-eslint/naming-convention */ /* eslint-enable @typescript-eslint/naming-convention */
})); }));
constructor(private t: TranslocoService, private dictionaryService: DictionaryService) {} constructor(
private t: TranslocoService,
private dictionaryService: DictionaryService,
) {}
} }

View File

@ -1,4 +1,9 @@
import { Invitation, InvitationStatusName, Invitee, InviteeContact } from '@vality/swag-organizations'; import {
Invitation,
InvitationStatusName,
Invitee,
InviteeContact,
} from '@vality/swag-organizations';
import { MOCK_MEMBER_ROLE } from './mock-member-role'; import { MOCK_MEMBER_ROLE } from './mock-member-role';

View File

@ -13,7 +13,7 @@ import { createApi } from '../utils';
export class CategoriesService extends createApi(ApiCategoriesService) { export class CategoriesService extends createApi(ApiCategoriesService) {
categories$ = defer(() => this.reloadCategories$).pipe( categories$ = defer(() => this.reloadCategories$).pipe(
switchMap(() => this.getCategories()), switchMap(() => this.getCategories()),
shareReplayRefCount() shareReplayRefCount(),
); );
private reloadCategories$ = new BehaviorSubject<void>(undefined); private reloadCategories$ = new BehaviorSubject<void>(undefined);

View File

@ -18,10 +18,13 @@ export class CountriesService extends createApi(ApiCountriesService) {
this.errorService.error(error, false); this.errorService.error(error, false);
return of([]); return of([]);
}), }),
shareReplay(SHARE_REPLAY_CONF) shareReplay(SHARE_REPLAY_CONF),
); );
constructor(injector: Injector, private errorService: ErrorService) { constructor(
injector: Injector,
private errorService: ErrorService,
) {
super(injector); super(injector);
this.getCountries = () => { this.getCountries = () => {
return this.getCountries().pipe(map((countries) => sortBy(countries, 'id'))); return this.getCountries().pipe(map((countries) => sortBy(countries, 'id')));

View File

@ -9,11 +9,14 @@ import { createApi } from '../utils';
providedIn: 'root', providedIn: 'root',
}) })
export class InvoiceTemplatesService extends createApi(ApiInvoiceTemplatesService) { export class InvoiceTemplatesService extends createApi(ApiInvoiceTemplatesService) {
constructor(injector: Injector, private partyIdPatchMethodService: PartyIdPatchMethodService) { constructor(
injector: Injector,
private partyIdPatchMethodService: PartyIdPatchMethodService,
) {
super(injector); super(injector);
this.createInvoiceTemplate = this.partyIdPatchMethodService.patch( this.createInvoiceTemplate = this.partyIdPatchMethodService.patch(
this.createInvoiceTemplate, this.createInvoiceTemplate,
(params, partyId) => (params.invoiceTemplateCreateParams.partyID = partyId) (params, partyId) => (params.invoiceTemplateCreateParams.partyID = partyId),
); );
} }
} }

View File

@ -13,7 +13,7 @@ export class InvoicesService extends createApi(ApiInvoicesService) {
super(injector); super(injector);
this.createInvoice = partyIdPatchMethodService.patch( this.createInvoice = partyIdPatchMethodService.patch(
this.createInvoice, this.createInvoice,
(p, id) => (p.invoiceParams.partyID = id) (p, id) => (p.invoiceParams.partyID = id),
); );
} }
} }

View File

@ -13,7 +13,7 @@ import { createApi } from '../utils';
export class PaymentInstitutionsService extends createApi(ApiPaymentInstitutionsService) { export class PaymentInstitutionsService extends createApi(ApiPaymentInstitutionsService) {
paymentInstitutions$ = defer(() => this.reload$).pipe( paymentInstitutions$ = defer(() => this.reload$).pipe(
switchMap(() => this.getPaymentInstitutions()), switchMap(() => this.getPaymentInstitutions()),
shareReplayRefCount() shareReplayRefCount(),
); );
private reload$ = new BehaviorSubject<void>(undefined); private reload$ = new BehaviorSubject<void>(undefined);

View File

@ -12,53 +12,105 @@ import { DictionaryService } from '../utils';
export class PaymentsDictionaryService { export class PaymentsDictionaryService {
invoicesTopicEventType$ = this.dictionaryService.create<InvoicesTopic.EventTypesEnum>(() => ({ invoicesTopicEventType$ = this.dictionaryService.create<InvoicesTopic.EventTypesEnum>(() => ({
/* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/naming-convention */
InvoiceCreated: this.t.translate('payments.invoicesTopicEventType.InvoiceCreated', null, 'dictionary'), InvoiceCreated: this.t.translate(
InvoicePaid: this.t.translate('payments.invoicesTopicEventType.InvoicePaid', null, 'dictionary'), 'payments.invoicesTopicEventType.InvoiceCreated',
InvoiceCancelled: this.t.translate('payments.invoicesTopicEventType.InvoiceCancelled', null, 'dictionary'), null,
InvoiceFulfilled: this.t.translate('payments.invoicesTopicEventType.InvoiceFulfilled', null, 'dictionary'), 'dictionary',
PaymentStarted: this.t.translate('payments.invoicesTopicEventType.PaymentStarted', null, 'dictionary'), ),
PaymentProcessed: this.t.translate('payments.invoicesTopicEventType.PaymentProcessed', null, 'dictionary'), InvoicePaid: this.t.translate(
PaymentCaptured: this.t.translate('payments.invoicesTopicEventType.PaymentCaptured', null, 'dictionary'), 'payments.invoicesTopicEventType.InvoicePaid',
PaymentCancelled: this.t.translate('payments.invoicesTopicEventType.PaymentCancelled', null, 'dictionary'), null,
PaymentRefunded: this.t.translate('payments.invoicesTopicEventType.PaymentRefunded', null, 'dictionary'), 'dictionary',
PaymentFailed: this.t.translate('payments.invoicesTopicEventType.PaymentFailed', null, 'dictionary'), ),
InvoiceCancelled: this.t.translate(
'payments.invoicesTopicEventType.InvoiceCancelled',
null,
'dictionary',
),
InvoiceFulfilled: this.t.translate(
'payments.invoicesTopicEventType.InvoiceFulfilled',
null,
'dictionary',
),
PaymentStarted: this.t.translate(
'payments.invoicesTopicEventType.PaymentStarted',
null,
'dictionary',
),
PaymentProcessed: this.t.translate(
'payments.invoicesTopicEventType.PaymentProcessed',
null,
'dictionary',
),
PaymentCaptured: this.t.translate(
'payments.invoicesTopicEventType.PaymentCaptured',
null,
'dictionary',
),
PaymentCancelled: this.t.translate(
'payments.invoicesTopicEventType.PaymentCancelled',
null,
'dictionary',
),
PaymentRefunded: this.t.translate(
'payments.invoicesTopicEventType.PaymentRefunded',
null,
'dictionary',
),
PaymentFailed: this.t.translate(
'payments.invoicesTopicEventType.PaymentFailed',
null,
'dictionary',
),
PaymentRefundCreated: this.t.translate( PaymentRefundCreated: this.t.translate(
'payments.invoicesTopicEventType.PaymentRefundCreated', 'payments.invoicesTopicEventType.PaymentRefundCreated',
null, null,
'dictionary' 'dictionary',
), ),
PaymentRefundSucceeded: this.t.translate( PaymentRefundSucceeded: this.t.translate(
'payments.invoicesTopicEventType.PaymentRefundSucceeded', 'payments.invoicesTopicEventType.PaymentRefundSucceeded',
null, null,
'dictionary' 'dictionary',
), ),
PaymentRefundFailed: this.t.translate( PaymentRefundFailed: this.t.translate(
'payments.invoicesTopicEventType.PaymentRefundFailed', 'payments.invoicesTopicEventType.PaymentRefundFailed',
null, null,
'dictionary' 'dictionary',
), ),
/* eslint-enable @typescript-eslint/naming-convention */ /* eslint-enable @typescript-eslint/naming-convention */
})); }));
customersTopicEventType$ = this.dictionaryService.create<CustomersTopic.EventTypesEnum>(() => ({ customersTopicEventType$ = this.dictionaryService.create<CustomersTopic.EventTypesEnum>(() => ({
/* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/naming-convention */
CustomerCreated: this.t.translate('payments.customersTopicEventType.CustomerCreated', null, 'dictionary'), CustomerCreated: this.t.translate(
CustomerDeleted: this.t.translate('payments.customersTopicEventType.CustomerDeleted', null, 'dictionary'), 'payments.customersTopicEventType.CustomerCreated',
CustomerReady: this.t.translate('payments.customersTopicEventType.CustomerReady', null, 'dictionary'), null,
'dictionary',
),
CustomerDeleted: this.t.translate(
'payments.customersTopicEventType.CustomerDeleted',
null,
'dictionary',
),
CustomerReady: this.t.translate(
'payments.customersTopicEventType.CustomerReady',
null,
'dictionary',
),
CustomerBindingStarted: this.t.translate( CustomerBindingStarted: this.t.translate(
'payments.customersTopicEventType.CustomerBindingStarted', 'payments.customersTopicEventType.CustomerBindingStarted',
null, null,
'dictionary' 'dictionary',
), ),
CustomerBindingSucceeded: this.t.translate( CustomerBindingSucceeded: this.t.translate(
'payments.customersTopicEventType.CustomerBindingSucceeded', 'payments.customersTopicEventType.CustomerBindingSucceeded',
null, null,
'dictionary' 'dictionary',
), ),
CustomerBindingFailed: this.t.translate( CustomerBindingFailed: this.t.translate(
'payments.customersTopicEventType.CustomerBindingFailed', 'payments.customersTopicEventType.CustomerBindingFailed',
null, null,
'dictionary' 'dictionary',
), ),
/* eslint-enable @typescript-eslint/naming-convention */ /* eslint-enable @typescript-eslint/naming-convention */
})); }));
@ -72,5 +124,8 @@ export class PaymentsDictionaryService {
failed: this.t.translate('payments.paymentStatus.failed', null, 'dictionary'), failed: this.t.translate('payments.paymentStatus.failed', null, 'dictionary'),
})); }));
constructor(private t: TranslocoService, private dictionaryService: DictionaryService) {} constructor(
private t: TranslocoService,
private dictionaryService: DictionaryService,
) {}
} }

View File

@ -9,11 +9,14 @@ import { createApi } from '../utils';
providedIn: 'root', providedIn: 'root',
}) })
export class PayoutsService extends createApi(ApiPayoutsService, [PartyIdExtension]) { export class PayoutsService extends createApi(ApiPayoutsService, [PartyIdExtension]) {
constructor(injector: Injector, private partyIdPatchMethodService: PartyIdPatchMethodService) { constructor(
injector: Injector,
private partyIdPatchMethodService: PartyIdPatchMethodService,
) {
super(injector); super(injector);
this.createPayout = partyIdPatchMethodService.patch( this.createPayout = partyIdPatchMethodService.patch(
this.createPayout, this.createPayout,
(params, partyId) => (params.payoutParams.partyID = partyId) (params, partyId) => (params.payoutParams.partyID = partyId),
); );
} }
} }

View File

@ -1,3 +1,4 @@
import { Shop } from '@vality/swag-payments'; import { Shop } from '@vality/swag-payments';
export const findShopById = (s: Shop[], shopID: string): Shop | null => s.find(({ id }) => id === shopID); export const findShopById = (s: Shop[], shopID: string): Shop | null =>
s.find(({ id }) => id === shopID);

View File

@ -3,4 +3,5 @@ import { Shop } from '@vality/swag-payments';
import { findShopById } from './find-shop-by-id'; import { findShopById } from './find-shop-by-id';
import { getShopName } from './get-shop-name'; import { getShopName } from './get-shop-name';
export const getShopNameById = (s: Shop[], shopID: string): string | null => getShopName(findShopById(s, shopID)); export const getShopNameById = (s: Shop[], shopID: string): string | null =>
getShopName(findShopById(s, shopID));

View File

@ -13,7 +13,7 @@ export class WebhooksService extends createApi(ApiWebhooksService, [PartyIdExten
super(injector); super(injector);
this.createWebhook = partyIdPatchMethodService.patch( this.createWebhook = partyIdPatchMethodService.patch(
this.createWebhook, this.createWebhook,
(params, partyID) => (params.webhookParams.partyID = partyID) (params, partyID) => (params.webhookParams.partyID = partyID),
); );
} }
} }

View File

@ -1,11 +1,15 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { DaDataService as ApiDaDataService, DaDataRequest } from '@vality/swag-questionary-aggr-proxy'; import {
DaDataService as ApiDaDataService,
DaDataRequest,
} from '@vality/swag-questionary-aggr-proxy';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { pluck } from 'rxjs/operators'; import { pluck } from 'rxjs/operators';
import { ParamsByRequestType, ResponseByRequestType, SuggestionsByRequestType } from './utils';
import { createApi } from '../utils'; import { createApi } from '../utils';
import { ParamsByRequestType, ResponseByRequestType, SuggestionsByRequestType } from './utils';
type RequestType = DaDataRequest.DaDataRequestTypeEnum; type RequestType = DaDataRequest.DaDataRequestTypeEnum;
@Injectable({ @Injectable({
@ -14,10 +18,12 @@ type RequestType = DaDataRequest.DaDataRequestTypeEnum;
export class DaDataService extends createApi(ApiDaDataService) { export class DaDataService extends createApi(ApiDaDataService) {
suggest<T extends RequestType>( suggest<T extends RequestType>(
daDataRequestType: T, daDataRequestType: T,
params: ParamsByRequestType[T] params: ParamsByRequestType[T],
): Observable<SuggestionsByRequestType[T]> { ): Observable<SuggestionsByRequestType[T]> {
const requestParams = { request: { daDataRequestType, ...params } }; const requestParams = { request: { daDataRequestType, ...params } };
const request = this.requestDaData({ daDataParams: requestParams }) as Observable<ResponseByRequestType[T]>; const request = this.requestDaData({ daDataParams: requestParams }) as Observable<
ResponseByRequestType[T]
>;
return request.pipe(pluck('suggestions')) as Observable<SuggestionsByRequestType[T]>; return request.pipe(pluck('suggestions')) as Observable<SuggestionsByRequestType[T]>;
} }
} }

View File

@ -52,7 +52,7 @@ export type ResponsesByRequestType = Mapping<
export class KonturFocusService extends createApi(ApiKonturFocusService) { export class KonturFocusService extends createApi(ApiKonturFocusService) {
request<T extends RequestType>( request<T extends RequestType>(
konturFocusRequestType: T, konturFocusRequestType: T,
requestParams: Partial<Omit<ParamsByRequestType[T], 'konturFocusRequestType'>> requestParams: Partial<Omit<ParamsByRequestType[T], 'konturFocusRequestType'>>,
): Observable<ResponsesByRequestType[T]['responses']> { ): Observable<ResponsesByRequestType[T]['responses']> {
return this.requestKonturFocus({ return this.requestKonturFocus({
konturFocusParams: { request: { konturFocusRequestType, ...requestParams } }, konturFocusParams: { request: { konturFocusRequestType, ...requestParams } },

View File

@ -1,5 +1,7 @@
import { ReqContractor, ReqIndividualEntity } from '@vality/swag-questionary-aggr-proxy'; import { ReqContractor, ReqIndividualEntity } from '@vality/swag-questionary-aggr-proxy';
export function isReqIndividualEntity(contractor: ReqContractor): contractor is ReqIndividualEntity { export function isReqIndividualEntity(
contractor: ReqContractor,
): contractor is ReqIndividualEntity {
return contractor.reqContractorType === 'ReqIndividualEntity'; return contractor.reqContractorType === 'ReqIndividualEntity';
} }

View File

@ -20,10 +20,14 @@ type DeepOnlyMutable<T> = T extends object
type ApiArgs = [Injector]; type ApiArgs = [Injector];
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
type MethodParams<P extends Record<PropertyKey, any>, K extends PropertyKey> = RequiredKeys<Omit<P, K>> extends never type MethodParams<P extends Record<PropertyKey, any>, K extends PropertyKey> = RequiredKeys<
Omit<P, K>
> extends never
? void | Overwrite<P, { [N in K]?: P[N] }> ? void | Overwrite<P, { [N in K]?: P[N] }>
: Overwrite<P, { [N in K]?: P[N] }>; : Overwrite<P, { [N in K]?: P[N] }>;
type Method<M, P extends PropertyKey> = M extends (...args: unknown[]) => Observable<HttpResponse<infer R>> type Method<M, P extends PropertyKey> = M extends (
...args: unknown[]
) => Observable<HttpResponse<infer R>>
? (params: DeepOnlyMutable<MethodParams<Parameters<M>[0], P>>) => Observable<R> ? (params: DeepOnlyMutable<MethodParams<Parameters<M>[0], P>>) => Observable<R>
: never; : never;
@ -33,12 +37,14 @@ type Method<M, P extends PropertyKey> = M extends (...args: unknown[]) => Observ
export function createApi< export function createApi<
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
T extends Record<PropertyKey, any> & { defaultHeaders: HttpHeaders }, T extends Record<PropertyKey, any> & { defaultHeaders: HttpHeaders },
E extends (new (...args: unknown[]) => ApiExtension)[] = [] E extends (new (...args: unknown[]) => ApiExtension)[] = [],
>(apiClass: new (...args: unknown[]) => T, extensions: E = [] as E) { >(apiClass: new (...args: unknown[]) => T, extensions: E = [] as E) {
@Injectable() @Injectable()
class Api { class Api {
private api = this.injector.get<T>(apiClass); private api = this.injector.get<T>(apiClass);
private extensions = [XrequestIdExtension, ...extensions].map((e) => this.injector.get<ApiExtension>(e)); private extensions = [XrequestIdExtension, ...extensions].map((e) =>
this.injector.get<ApiExtension>(e),
);
constructor(private injector: Injector) { constructor(private injector: Injector) {
if (this.api.defaultHeaders !== DEFAULT_HEADERS) { if (this.api.defaultHeaders !== DEFAULT_HEADERS) {
@ -47,17 +53,23 @@ export function createApi<
const methodNames = getMethods(apiClass, this.api); const methodNames = getMethods(apiClass, this.api);
Object.assign( Object.assign(
this, this,
Object.fromEntries(methodNames.map((name) => [name, (params) => this.call(name, params)])) Object.fromEntries(
methodNames.map((name) => [name, (params) => this.call(name, params)]),
),
); );
} }
private call(name: keyof T, params: Record<PropertyKey, unknown>) { private call(name: keyof T, params: Record<PropertyKey, unknown>) {
return this.createExtendedParams().pipe(switchMap((p) => this.api[name](Object.assign({}, params, ...p)))); return this.createExtendedParams().pipe(
switchMap((p) => this.api[name](Object.assign({}, params, ...p))),
);
} }
private createExtendedParams() { private createExtendedParams() {
return combineLatest( return combineLatest(
this.extensions.map((extension) => extension.selector()).map((p) => (isObservable(p) ? p : of(p))) this.extensions
.map((extension) => extension.selector())
.map((p) => (isObservable(p) ? p : of(p))),
); );
} }
} }
@ -65,8 +77,12 @@ export function createApi<
return Api as unknown as new (...args: ApiArgs) => { return Api as unknown as new (...args: ApiArgs) => {
[N in keyof T]: Method< [N in keyof T]: Method<
T[N], T[N],
| keyof UnionToIntersection<ObservableValue<ReturnType<InstanceType<E[number]>['selector']>>> | keyof UnionToIntersection<
| keyof UnionToIntersection<ObservableValue<ReturnType<XrequestIdExtension['selector']>>> ObservableValue<ReturnType<InstanceType<E[number]>['selector']>>
>
| keyof UnionToIntersection<
ObservableValue<ReturnType<XrequestIdExtension['selector']>>
>
>; >;
}; };
} }

View File

@ -2,5 +2,5 @@ import { Overwrite } from 'utility-types';
export type ApiMethodParams< export type ApiMethodParams<
M extends (params: object) => unknown, M extends (params: object) => unknown,
P extends keyof Parameters<M>[0] = never P extends keyof Parameters<M>[0] = never,
> = Overwrite<Parameters<M>[0], { [N in P]?: Parameters<M>[0][N] }>; > = Overwrite<Parameters<M>[0], { [N in P]?: Parameters<M>[0][N] }>;

View File

@ -1,5 +1,5 @@
export function getMethods(klass: new (...args: unknown[]) => unknown, instance: unknown) { export function getMethods(klass: new (...args: unknown[]) => unknown, instance: unknown) {
return Object.getOwnPropertyNames(klass.prototype).filter( return Object.getOwnPropertyNames(klass.prototype).filter(
(name) => typeof instance[name] === 'function' && name !== 'constructor' (name) => typeof instance[name] === 'function' && name !== 'constructor',
); );
} }

View File

@ -13,10 +13,12 @@ export class DictionaryService {
constructor(private readonly transloco: TranslocoService) {} constructor(private readonly transloco: TranslocoService) {}
create<T extends PropertyKey>(getTranslations: () => Record<T, string>): Observable<Record<T, string>> { create<T extends PropertyKey>(
getTranslations: () => Record<T, string>,
): Observable<Record<T, string>> {
return this.init$.pipe( return this.init$.pipe(
map(() => getTranslations()), map(() => getTranslations()),
shareReplayRefCount() shareReplayRefCount(),
); );
} }
} }

View File

@ -14,7 +14,7 @@ export class PartyIdExtension implements ApiExtension {
selector() { selector() {
return this.contextOrganizationService.organization$.pipe( return this.contextOrganizationService.organization$.pipe(
first(), first(),
map(({ party }) => ({ partyID: party, partyId: party })) map(({ party }) => ({ partyID: party, partyId: party })),
); );
} }
} }

View File

@ -11,7 +11,7 @@ import { PartyIdExtension } from './party-id-extension';
export class PartyIdPatchMethodService extends PartyIdExtension { export class PartyIdPatchMethodService extends PartyIdExtension {
patch<P extends object, R, E extends DeepPartial<P> | void>( patch<P extends object, R, E extends DeepPartial<P> | void>(
method: (params: P) => Observable<R>, method: (params: P) => Observable<R>,
patch: (params: P, partyId: string) => unknown patch: (params: P, partyId: string) => unknown,
): (params: E) => Observable<R> { ): (params: E) => Observable<R> {
return (params) => return (params) =>
this.selector().pipe( this.selector().pipe(
@ -19,7 +19,7 @@ export class PartyIdPatchMethodService extends PartyIdExtension {
const newParams = cloneDeep(params); const newParams = cloneDeep(params);
patch(newParams as unknown as P, partyID); patch(newParams as unknown as P, partyID);
return method(newParams as unknown as P); return method(newParams as unknown as P);
}) }),
); );
} }
} }

View File

@ -15,7 +15,7 @@ export class IdentitiesService extends createApi(ApiIdentitiesService) {
startWith<void>(undefined), startWith<void>(undefined),
switchMap(() => this.listIdentities()), switchMap(() => this.listIdentities()),
map((r) => r.result as Identity[]), map((r) => r.result as Identity[]),
shareReplayRefCount() shareReplayRefCount(),
); );
private reloadIdentities$ = new Subject<void>(); private reloadIdentities$ = new Subject<void>();

View File

@ -1,6 +1,13 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { TranslocoService } from '@ngneat/transloco'; import { TranslocoService } from '@ngneat/transloco';
import { DepositRevert, WithdrawalsTopic, DestinationsTopic, Deposit, Withdrawal, Report } from '@vality/swag-wallet'; import {
DepositRevert,
WithdrawalsTopic,
DestinationsTopic,
Deposit,
Withdrawal,
Report,
} from '@vality/swag-wallet';
import { DictionaryService } from '../utils'; import { DictionaryService } from '../utils';
@ -8,37 +15,49 @@ import { DictionaryService } from '../utils';
providedIn: 'root', providedIn: 'root',
}) })
export class WalletDictionaryService { export class WalletDictionaryService {
withdrawalsTopicEventType$ = this.dictionaryService.create<WithdrawalsTopic.EventTypesEnum>(() => ({ withdrawalsTopicEventType$ = this.dictionaryService.create<WithdrawalsTopic.EventTypesEnum>(
/* eslint-disable @typescript-eslint/naming-convention */ () => ({
WithdrawalStarted: this.t.translate('wallet.withdrawalsTopicEventType.WithdrawalStarted', null, 'dictionary'), /* eslint-disable @typescript-eslint/naming-convention */
WithdrawalSucceeded: this.t.translate( WithdrawalStarted: this.t.translate(
'wallet.withdrawalsTopicEventType.WithdrawalSucceeded', 'wallet.withdrawalsTopicEventType.WithdrawalStarted',
null, null,
'dictionary' 'dictionary',
), ),
WithdrawalFailed: this.t.translate('wallet.withdrawalsTopicEventType.WithdrawalFailed', null, 'dictionary'), WithdrawalSucceeded: this.t.translate(
/* eslint-enable @typescript-eslint/naming-convention */ 'wallet.withdrawalsTopicEventType.WithdrawalSucceeded',
})); null,
'dictionary',
),
WithdrawalFailed: this.t.translate(
'wallet.withdrawalsTopicEventType.WithdrawalFailed',
null,
'dictionary',
),
/* eslint-enable @typescript-eslint/naming-convention */
}),
);
destinationsTopicEventType$ = this.dictionaryService.create<DestinationsTopic.EventTypesEnum>(() => ({ destinationsTopicEventType$ = this.dictionaryService.create<DestinationsTopic.EventTypesEnum>(
/* eslint-disable @typescript-eslint/naming-convention */ () => ({
DestinationCreated: this.t.translate( /* eslint-disable @typescript-eslint/naming-convention */
'wallet.destinationsTopicEventType.DestinationCreated', DestinationCreated: this.t.translate(
null, 'wallet.destinationsTopicEventType.DestinationCreated',
'dictionary' null,
), 'dictionary',
DestinationUnauthorized: this.t.translate( ),
'wallet.destinationsTopicEventType.DestinationUnauthorized', DestinationUnauthorized: this.t.translate(
null, 'wallet.destinationsTopicEventType.DestinationUnauthorized',
'dictionary' null,
), 'dictionary',
DestinationAuthorized: this.t.translate( ),
'wallet.destinationsTopicEventType.DestinationAuthorized', DestinationAuthorized: this.t.translate(
null, 'wallet.destinationsTopicEventType.DestinationAuthorized',
'dictionary' null,
), 'dictionary',
/* eslint-enable @typescript-eslint/naming-convention */ ),
})); /* eslint-enable @typescript-eslint/naming-convention */
}),
);
depositRevertStatus$ = this.dictionaryService.create<DepositRevert.StatusEnum>(() => ({ depositRevertStatus$ = this.dictionaryService.create<DepositRevert.StatusEnum>(() => ({
/* eslint-disable @typescript-eslint/naming-convention */ /* eslint-disable @typescript-eslint/naming-convention */
@ -72,5 +91,8 @@ export class WalletDictionaryService {
/* eslint-enable @typescript-eslint/naming-convention */ /* eslint-enable @typescript-eslint/naming-convention */
})); }));
constructor(private t: TranslocoService, private dictionaryService: DictionaryService) {} constructor(
private t: TranslocoService,
private dictionaryService: DictionaryService,
) {}
} }

View File

@ -15,13 +15,13 @@ export class WalletsService extends createApi(ApiWalletsService, [PartyIdExtensi
wallets$ = this.listWallets({ limit: 1000 }).pipe( wallets$ = this.listWallets({ limit: 1000 }).pipe(
catchError(() => of({ result: [] })), catchError(() => of({ result: [] })),
pluck('result'), pluck('result'),
shareReplay(SHARE_REPLAY_CONF) shareReplay(SHARE_REPLAY_CONF),
); );
hasWallets$ = this.listWallets({ limit: 1 }).pipe( hasWallets$ = this.listWallets({ limit: 1 }).pipe(
catchError(() => of({ result: [] })), catchError(() => of({ result: [] })),
pluck('result', 'length'), pluck('result', 'length'),
map((l) => l > 0), map((l) => l > 0),
shareReplay(SHARE_REPLAY_CONF) shareReplay(SHARE_REPLAY_CONF),
); );
} }

View File

@ -1,7 +1,7 @@
<dsh-home> <dsh-home>
<dsh-sections *ngIf="bootstrapped$ | async; else spinner"></dsh-sections> <dsh-sections *ngIf="bootstrapped$ | async; else spinner"></dsh-sections>
<ng-template #spinner> <ng-template #spinner>
<div fxLayout="row" fxFlexAlign="center"> <div fxFlexAlign="center" fxLayout="row">
<dsh-spinner style="margin: auto"></dsh-spinner> <dsh-spinner style="margin: auto"></dsh-spinner>
</div> </div>
</ng-template> </ng-template>

View File

@ -1,5 +1,5 @@
import { Component, OnInit } from '@angular/core'; import { Component, OnInit } from '@angular/core';
import * as Sentry from '@sentry/angular'; import * as Sentry from '@sentry/angular-ivy';
import { first } from 'rxjs/operators'; import { first } from 'rxjs/operators';
import { BootstrapService } from './bootstrap.service'; import { BootstrapService } from './bootstrap.service';
@ -15,7 +15,7 @@ export class AppComponent implements OnInit {
constructor( constructor(
private bootstrapService: BootstrapService, private bootstrapService: BootstrapService,
private contextOrganizationService: ContextOrganizationService private contextOrganizationService: ContextOrganizationService,
) {} ) {}
ngOnInit(): void { ngOnInit(): void {

View File

@ -2,7 +2,12 @@ import { CommonModule } from '@angular/common';
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http'; import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { APP_INITIALIZER, ErrorHandler, LOCALE_ID, NgModule } from '@angular/core'; import { APP_INITIALIZER, ErrorHandler, LOCALE_ID, NgModule } from '@angular/core';
import { FlexLayoutModule } from '@angular/flex-layout'; import { FlexLayoutModule } from '@angular/flex-layout';
import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE, MAT_RIPPLE_GLOBAL_OPTIONS } from '@angular/material/core'; import {
DateAdapter,
MAT_DATE_FORMATS,
MAT_DATE_LOCALE,
MAT_RIPPLE_GLOBAL_OPTIONS,
} from '@angular/material/core';
import { MatDialogModule } from '@angular/material/dialog'; import { MatDialogModule } from '@angular/material/dialog';
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field'; import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
import { import {
@ -13,8 +18,13 @@ import {
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { TRANSLOCO_CONFIG, TRANSLOCO_LOADER, TranslocoModule, translocoConfig } from '@ngneat/transloco'; import {
import * as Sentry from '@sentry/angular'; TRANSLOCO_CONFIG,
TRANSLOCO_LOADER,
TranslocoModule,
translocoConfig,
} from '@ngneat/transloco';
import * as Sentry from '@sentry/angular-ivy';
import { AnapiModule } from '@dsh/app/api/anapi'; import { AnapiModule } from '@dsh/app/api/anapi';
import { ClaimManagementModule } from '@dsh/app/api/claim-management'; import { ClaimManagementModule } from '@dsh/app/api/claim-management';
@ -27,6 +37,8 @@ import { QUERY_PARAMS_SERIALIZERS } from '@dsh/app/shared/services/query-params/
import { createDateRangeWithPresetSerializer } from '@dsh/components/date-range-filter'; import { createDateRangeWithPresetSerializer } from '@dsh/components/date-range-filter';
import { SpinnerModule } from '@dsh/components/indicators'; import { SpinnerModule } from '@dsh/components/indicators';
import { ENV, environment } from '../environments';
import { ApiKeysModule } from './api/api-keys'; import { ApiKeysModule } from './api/api-keys';
import { OrganizationsModule } from './api/organizations'; import { OrganizationsModule } from './api/organizations';
import { AppComponent } from './app.component'; import { AppComponent } from './app.component';
@ -41,7 +53,6 @@ import { SentryErrorHandler } from './sentry-error-handler.service';
import { SentryHttpInterceptor } from './sentry-http-interceptor'; import { SentryHttpInterceptor } from './sentry-http-interceptor';
import { ThemeManager } from './theme-manager'; import { ThemeManager } from './theme-manager';
import { TranslocoHttpLoaderService } from './transloco-http-loader.service'; import { TranslocoHttpLoaderService } from './transloco-http-loader.service';
import { ENV, environment } from '../environments';
@NgModule({ @NgModule({
declarations: [AppComponent], declarations: [AppComponent],
@ -74,7 +85,14 @@ import { ENV, environment } from '../environments';
{ {
provide: APP_INITIALIZER, provide: APP_INITIALIZER,
useFactory: initializer, useFactory: initializer,
deps: [ConfigService, KeycloakService, LanguageService, ThemeManager, IconsService, Sentry.TraceService], deps: [
ConfigService,
KeycloakService,
LanguageService,
ThemeManager,
IconsService,
Sentry.TraceService,
],
multi: true, multi: true,
}, },
{ {
@ -89,7 +107,11 @@ import { ENV, environment } from '../environments';
}, },
{ provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: false } }, { provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: false } },
{ provide: MAT_DATE_FORMATS, useValue: MAT_MOMENT_DATE_FORMATS }, { provide: MAT_DATE_FORMATS, useValue: MAT_MOMENT_DATE_FORMATS },
{ provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE, MAT_MOMENT_DATE_ADAPTER_OPTIONS] }, {
provide: DateAdapter,
useClass: MomentDateAdapter,
deps: [MAT_DATE_LOCALE, MAT_MOMENT_DATE_ADAPTER_OPTIONS],
},
{ provide: MAT_RIPPLE_GLOBAL_OPTIONS, useValue: { disabled: true } }, { provide: MAT_RIPPLE_GLOBAL_OPTIONS, useValue: { disabled: true } },
{ provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: { appearance: 'outline' } }, { provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, useValue: { appearance: 'outline' } },
{ {

View File

@ -14,14 +14,14 @@ export class AppAuthGuardService extends KeycloakAuthGuard {
protected router: Router, protected router: Router,
protected keycloakAngular: KeycloakService, protected keycloakAngular: KeycloakService,
private errorService: ErrorService, private errorService: ErrorService,
private roleAccessService: RoleAccessService private roleAccessService: RoleAccessService,
) { ) {
super(router, keycloakAngular); super(router, keycloakAngular);
} }
async isAccessAllowed(route: ActivatedRouteSnapshot): Promise<boolean | UrlTree> { async isAccessAllowed(route: ActivatedRouteSnapshot): Promise<boolean | UrlTree> {
const isAccessAllowed = await firstValueFrom( const isAccessAllowed = await firstValueFrom(
this.roleAccessService.isAccessAllowed(route.data.roles as RoleAccessName[]) this.roleAccessService.isAccessAllowed(route.data.roles as RoleAccessName[]),
); );
if (!isAccessAllowed) { if (!isAccessAllowed) {
this.errorService.error('Access is denied', false); this.errorService.error('Access is denied', false);

View File

@ -11,7 +11,10 @@ import { RoleAccessName } from './types/role-access-name';
export class IsAccessAllowedPipe implements PipeTransform, OnDestroy { export class IsAccessAllowedPipe implements PipeTransform, OnDestroy {
private asyncPipe: AsyncPipe; private asyncPipe: AsyncPipe;
constructor(private roleAccessService: RoleAccessService, ref: ChangeDetectorRef) { constructor(
private roleAccessService: RoleAccessService,
ref: ChangeDetectorRef,
) {
this.asyncPipe = new AsyncPipe(ref); this.asyncPipe = new AsyncPipe(ref);
} }
@ -21,13 +24,15 @@ export class IsAccessAllowedPipe implements PipeTransform, OnDestroy {
transform( transform(
roleAccessNames: RoleAccessName[] | keyof typeof RoleAccessName, roleAccessNames: RoleAccessName[] | keyof typeof RoleAccessName,
type: 'every' | 'some' = 'every' type: 'every' | 'some' = 'every',
): boolean { ): boolean {
return this.asyncPipe.transform( return this.asyncPipe.transform(
this.roleAccessService.isAccessAllowed( this.roleAccessService.isAccessAllowed(
Array.isArray(roleAccessNames) ? roleAccessNames : [RoleAccessName[roleAccessNames]], Array.isArray(roleAccessNames)
type ? roleAccessNames
) : [RoleAccessName[roleAccessNames]],
type,
),
); );
} }
} }

View File

@ -13,15 +13,30 @@ export const ROLE_ACCESS_GROUPS: RoleAccessGroup[] = [
}, },
{ {
name: RoleAccessName.ViewInvoices, name: RoleAccessName.ViewInvoices,
availableRoles: [RoleId.Administrator, RoleId.Manager, RoleId.Accountant, RoleId.Integrator], availableRoles: [
RoleId.Administrator,
RoleId.Manager,
RoleId.Accountant,
RoleId.Integrator,
],
}, },
{ {
name: RoleAccessName.ViewPayments, name: RoleAccessName.ViewPayments,
availableRoles: [RoleId.Administrator, RoleId.Manager, RoleId.Accountant, RoleId.Integrator], availableRoles: [
RoleId.Administrator,
RoleId.Manager,
RoleId.Accountant,
RoleId.Integrator,
],
}, },
{ {
name: RoleAccessName.ViewRefunds, name: RoleAccessName.ViewRefunds,
availableRoles: [RoleId.Administrator, RoleId.Manager, RoleId.Accountant, RoleId.Integrator], availableRoles: [
RoleId.Administrator,
RoleId.Manager,
RoleId.Accountant,
RoleId.Integrator,
],
}, },
{ {
name: RoleAccessName.ViewPayouts, name: RoleAccessName.ViewPayouts,

View File

@ -9,7 +9,10 @@ import { RoleAccess } from './types/role-access';
import { RoleAccessName } from './types/role-access-name'; import { RoleAccessName } from './types/role-access-name';
const ROLE_ACCESSES_OBJECT = Object.fromEntries( const ROLE_ACCESSES_OBJECT = Object.fromEntries(
ROLE_ACCESS_GROUPS.flatMap((r) => [r, ...(r.children || [])] as RoleAccess[]).map((r) => [r.name, r.availableRoles]) ROLE_ACCESS_GROUPS.flatMap((r) => [r, ...(r.children || [])] as RoleAccess[]).map((r) => [
r.name,
r.availableRoles,
]),
); );
@Injectable({ @Injectable({
@ -18,15 +21,19 @@ const ROLE_ACCESSES_OBJECT = Object.fromEntries(
export class RoleAccessService { export class RoleAccessService {
constructor(private contextOrganizationService: ContextOrganizationService) {} constructor(private contextOrganizationService: ContextOrganizationService) {}
isAccessAllowed(roleAccessNames: RoleAccessName[], type: 'every' | 'some' = 'every'): Observable<boolean> { isAccessAllowed(
roleAccessNames: RoleAccessName[],
type: 'every' | 'some' = 'every',
): Observable<boolean> {
if (!roleAccessNames.length) return of(true); if (!roleAccessNames.length) return of(true);
return this.contextOrganizationService.member$.pipe( return this.contextOrganizationService.member$.pipe(
map((member) => { map((member) => {
const memberRoles = member.roles.map((r) => r.roleId); const memberRoles = member.roles.map((r) => r.roleId);
return roleAccessNames[type]((access) => return roleAccessNames[type](
ROLE_ACCESSES_OBJECT[access]?.some((role) => memberRoles.includes(role)) (access) =>
ROLE_ACCESSES_OBJECT[access]?.some((role) => memberRoles.includes(role)),
); );
}) }),
); );
} }
} }

View File

@ -8,6 +8,7 @@ export interface RoleAccess {
availableRoles: RoleId[]; availableRoles: RoleId[];
} }
export interface RoleAccessGroup extends Overwrite<RoleAccess, Partial<Pick<RoleAccess, 'availableRoles'>>> { export interface RoleAccessGroup
extends Overwrite<RoleAccess, Partial<Pick<RoleAccess, 'availableRoles'>>> {
children?: RoleAccess[]; children?: RoleAccess[];
} }

View File

@ -9,18 +9,20 @@ import { ShopsDataService, ErrorService, CommonError } from '@dsh/app/shared';
export class BootstrapService { export class BootstrapService {
bootstrapped$: Observable<boolean> = this.shopsDataService.shops$.pipe( bootstrapped$: Observable<boolean> = this.shopsDataService.shops$.pipe(
catchError((err) => catchError((err) =>
this.transloco.selectTranslate<string>('app.errors.bootstrapAppFailed', null, 'components').pipe( this.transloco
tap((msg) => this.errorService.error(new CommonError(msg))), .selectTranslate<string>('app.errors.bootstrapAppFailed', null, 'components')
switchMap(() => throwError(err)) .pipe(
) tap((msg) => this.errorService.error(new CommonError(msg))),
switchMap(() => throwError(err)),
),
), ),
map(() => true) map(() => true),
); );
constructor( constructor(
private shopsDataService: ShopsDataService, private shopsDataService: ShopsDataService,
private transloco: TranslocoService, private transloco: TranslocoService,
private errorService: ErrorService private errorService: ErrorService,
) {} ) {}
} }

View File

@ -7,10 +7,10 @@ import { catchError, distinctUntilChanged, map, startWith } from 'rxjs/operators
export const progress = ( export const progress = (
start$: Observable<unknown>, start$: Observable<unknown>,
end$: Observable<unknown>, end$: Observable<unknown>,
startValue = false startValue = false,
): Observable<boolean> => ): Observable<boolean> =>
merge(start$.pipe(map(() => true)), end$.pipe(map(() => false))).pipe( merge(start$.pipe(map(() => true)), end$.pipe(map(() => false))).pipe(
catchError(() => of(false)), catchError(() => of(false)),
startWith(startValue), startWith(startValue),
distinctUntilChanged() distinctUntilChanged(),
); );

View File

@ -34,10 +34,11 @@ export const replaceError = <T, E>(source: Observable<T>): Observable<T | BasicE
export const filterError = <E, T>(source: Observable<T | BasicError<E>>): Observable<E> => export const filterError = <E, T>(source: Observable<T | BasicError<E>>): Observable<E> =>
source.pipe( source.pipe(
filter<BasicError<E>>((value) => value instanceof BasicError), filter<BasicError<E>>((value) => value instanceof BasicError),
pluck('error') pluck('error'),
); );
/** /**
* @deprecated use toError() * @deprecated use toError()
*/ */
export const filterPayload = <T>(source: Observable<T | BasicError>): Observable<T> => source.pipe(filter(isPayload)); export const filterPayload = <T>(source: Observable<T | BasicError>): Observable<T> =>
source.pipe(filter(isPayload));

View File

@ -8,7 +8,7 @@ import { share } from 'rxjs/operators';
export const SHARE_REPLAY_CONF: ShareReplayConfig = { bufferSize: 1, refCount: true }; export const SHARE_REPLAY_CONF: ShareReplayConfig = { bufferSize: 1, refCount: true };
export function shareReplayRefCount<T>( export function shareReplayRefCount<T>(
params: Pick<ShareReplayConfig, 'bufferSize'> & { resetOnRefCountZeroTimer?: number } = {} params: Pick<ShareReplayConfig, 'bufferSize'> & { resetOnRefCountZeroTimer?: number } = {},
): MonoTypeOperatorFunction<T> { ): MonoTypeOperatorFunction<T> {
const state = new ReplaySubject<T>(1); const state = new ReplaySubject<T>(1);
return share({ return share({

View File

@ -5,7 +5,8 @@ import { shareReplay } from 'rxjs/operators';
export function shareReplayUntilDestroyed<T>( export function shareReplayUntilDestroyed<T>(
instance: unknown, instance: unknown,
{ bufferSize = 1, ...rest }: Omit<ShareReplayConfig, 'refCount'> = {} { bufferSize = 1, ...rest }: Omit<ShareReplayConfig, 'refCount'> = {},
): MonoTypeOperatorFunction<T> { ): MonoTypeOperatorFunction<T> {
return (src$) => src$.pipe(untilDestroyed(instance), shareReplay({ ...rest, bufferSize, refCount: false })); return (src$) =>
src$.pipe(untilDestroyed(instance), shareReplay({ ...rest, bufferSize, refCount: false }));
} }

View File

@ -3,4 +3,5 @@ import { map } from 'rxjs/operators';
import { ResultWithToken } from './result-with-token'; import { ResultWithToken } from './result-with-token';
export const mapResult = <T>(s: Observable<ResultWithToken<T>>): Observable<T[]> => s.pipe(map((r) => r.result)); export const mapResult = <T>(s: Observable<ResultWithToken<T>>): Observable<T[]> =>
s.pipe(map((r) => r.result));

View File

@ -3,7 +3,15 @@ import { switchMap } from 'rxjs/operators';
import { ResultWithToken } from './result-with-token'; import { ResultWithToken } from './result-with-token';
export const noContinuationToken = <T>(s: Observable<ResultWithToken<T>>): Observable<ResultWithToken<T>> => export const noContinuationToken = <T>(
s: Observable<ResultWithToken<T>>,
): Observable<ResultWithToken<T>> =>
s.pipe( s.pipe(
switchMap((r) => iif(() => !!r.continuationToken, throwError('Continuation token is not supported'), of(r))) switchMap((r) =>
iif(
() => !!r.continuationToken,
throwError('Continuation token is not supported'),
of(r),
),
),
); );

View File

@ -7,5 +7,5 @@ import { catchError, filter } from 'rxjs/operators';
export const takeError = <T>(source: Observable<T>) => export const takeError = <T>(source: Observable<T>) =>
source.pipe( source.pipe(
filter((_) => false), filter((_) => false),
catchError((err) => of(err)) catchError((err) => of(err)),
); );

View File

@ -1,16 +1,20 @@
<mat-form-field class="field"> <mat-form-field class="field">
<mat-label>{{ label }}</mat-label> <mat-label>{{ label }}</mat-label>
<input matInput [required]="required" [formControl]="control" [matAutocomplete]="auto" /> <input [formControl]="control" [matAutocomplete]="auto" [required]="required" matInput />
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="optionSelectedHandler($event)"> <mat-autocomplete #auto="matAutocomplete" (optionSelected)="optionSelectedHandler($event)">
<ng-container *ngIf="!(isOptionsLoading$ | async)"> <ng-container *ngIf="!(isOptionsLoading$ | async)">
<mat-option *ngFor="let option of options$ | async" [value]="option.label" class="option"> <mat-option
*ngFor="let option of options$ | async"
[value]="option.label"
class="option"
>
<div <div
[innerHTML]="option.label | highlight: control.value"
class="dsh-dadata-autocomplete-option-header" class="dsh-dadata-autocomplete-option-header"
[innerHTML]="option.label | highlight : control.value"
></div> ></div>
<div <div
[innerHTML]="option.description | highlight: control.value"
class="dsh-dadata-autocomplete-option-description" class="dsh-dadata-autocomplete-option-description"
[innerHTML]="option.description | highlight : control.value"
></div> ></div>
</mat-option> </mat-option>
</ng-container> </ng-container>

View File

@ -49,7 +49,10 @@ const REQUEST_TYPE_BY_TYPE: RequestTypeByType = {
templateUrl: 'dadata.component.html', templateUrl: 'dadata.component.html',
providers: createControlProviders(() => DaDataAutocompleteComponent), providers: createControlProviders(() => DaDataAutocompleteComponent),
}) })
export class DaDataAutocompleteComponent<T extends Type = Type, R extends DaDataRequestType = RequestTypeByType[T]> export class DaDataAutocompleteComponent<
T extends Type = Type,
R extends DaDataRequestType = RequestTypeByType[T],
>
extends FormControlSuperclass<string> extends FormControlSuperclass<string>
implements OnInit implements OnInit
{ {
@ -66,15 +69,16 @@ export class DaDataAutocompleteComponent<T extends Type = Type, R extends DaData
filter<string>(Boolean), filter<string>(Boolean),
debounce(() => interval(300)), debounce(() => interval(300)),
switchMap((v) => this.loadSuggestions(v)), switchMap((v) => this.loadSuggestions(v)),
shareReplayUntilDestroyed(this) shareReplayUntilDestroyed(this),
); );
options$: Observable<Option<ContentByRequestType[R]>[]> = this.suggestions$.pipe( options$: Observable<Option<ContentByRequestType[R]>[]> = this.suggestions$.pipe(
map((suggestions) => suggestions.map((s) => this.getOption(s))), map((suggestions) => suggestions.map((s) => this.getOption(s))),
shareReplayUntilDestroyed(this) shareReplayUntilDestroyed(this),
);
isOptionsLoading$: Observable<boolean> = progress(this.control.valueChanges, this.suggestions$).pipe(
shareReplayUntilDestroyed(this)
); );
isOptionsLoading$: Observable<boolean> = progress(
this.control.valueChanges,
this.suggestions$,
).pipe(shareReplayUntilDestroyed(this));
constructor(private daDataService: DaDataService) { constructor(private daDataService: DaDataService) {
super(); super();
@ -82,8 +86,12 @@ export class DaDataAutocompleteComponent<T extends Type = Type, R extends DaData
ngOnInit(): void { ngOnInit(): void {
this.isOptionsLoading$.pipe(untilDestroyed(this)).subscribe(); this.isOptionsLoading$.pipe(untilDestroyed(this)).subscribe();
this.suggestions$.pipe(filter(isEmpty), untilDestroyed(this)).subscribe(() => this.suggestionNotFound.emit()); this.suggestions$
this.suggestions$.pipe(takeError, untilDestroyed(this)).subscribe((error) => this.errorOccurred.next(error)); .pipe(filter(isEmpty), untilDestroyed(this))
.subscribe(() => this.suggestionNotFound.emit());
this.suggestions$
.pipe(takeError, untilDestroyed(this))
.subscribe((error) => this.errorOccurred.next(error));
} }
optionSelectedHandler(e: MatAutocompleteSelectedEvent): void { optionSelectedHandler(e: MatAutocompleteSelectedEvent): void {
@ -102,7 +110,7 @@ export class DaDataAutocompleteComponent<T extends Type = Type, R extends DaData
const params: ParamsByRequestType[R] = { query } as ParamsByRequestType[R]; const params: ParamsByRequestType[R] = { query } as ParamsByRequestType[R];
return this.daDataService.suggest( return this.daDataService.suggest(
REQUEST_TYPE_BY_TYPE[this.type], REQUEST_TYPE_BY_TYPE[this.type],
this.withSpecificParams(params) this.withSpecificParams(params),
) as unknown as Observable<ContentByRequestType[R][]>; ) as unknown as Observable<ContentByRequestType[R][]>;
} }

View File

@ -20,7 +20,10 @@ export class HighlightSearchPipe implements PipeTransform {
return value; return value;
} }
const replacedValue = value.replace(re, '<mark class="dsh-dadata-autocomplete-mark">' + match[0] + '</mark>'); const replacedValue = value.replace(
re,
'<mark class="dsh-dadata-autocomplete-mark">' + match[0] + '</mark>',
);
return this.sanitizer.bypassSecurityTrustHtml(replacedValue); return this.sanitizer.bypassSecurityTrustHtml(replacedValue);
} }
} }

View File

@ -3,6 +3,6 @@
[expanded]="(userDropdown.state$ | async) === 'open'" [expanded]="(userDropdown.state$ | async) === 'open'"
></dsh-user-dropdown> ></dsh-user-dropdown>
<dsh-dropdown width="287px" #userDropdown="dshDropdown" [hasArrow]="false" position="left"> <dsh-dropdown #userDropdown="dshDropdown" [hasArrow]="false" position="left" width="287px">
<ng-template><dsh-user (selected)="userDropdown.close()"></dsh-user></ng-template> <ng-template><dsh-user (selected)="userDropdown.close()"></dsh-user></ng-template>
</dsh-dropdown> </dsh-dropdown>

View File

@ -1,4 +1,10 @@
import { ChangeDetectionStrategy, Component, HostBinding, Input, ViewEncapsulation } from '@angular/core'; import {
ChangeDetectionStrategy,
Component,
HostBinding,
Input,
ViewEncapsulation,
} from '@angular/core';
import { coerceBoolean } from 'coerce-property'; import { coerceBoolean } from 'coerce-property';
@Component({ @Component({

View File

@ -1,16 +1,20 @@
<div <div
*transloco="let t; scope: 'components'; read: 'components.actionbar.organizations'"
fxLayout="column" fxLayout="column"
fxLayoutGap="16px" fxLayoutGap="16px"
*transloco="let t; scope: 'components'; read: 'components.actionbar.organizations'"
> >
<dsh-menu-item header routerLink="/organization-section/organizations" (click)="selected.emit()"> <dsh-menu-item
header
routerLink="/organization-section/organizations"
(click)="selected.emit()"
>
{{ t('title') }} {{ t('title') }}
</dsh-menu-item> </dsh-menu-item>
<dsh-menu-item <dsh-menu-item
*ngFor="let org of orgs$ | async" *ngFor="let org of orgs$ | async"
[fragment]="org.id"
class="dsh-user-link" class="dsh-user-link"
routerLink="/organization-section/organizations" routerLink="/organization-section/organizations"
[fragment]="org.id"
(click)="selected.emit()" (click)="selected.emit()"
> >
{{ org.name }} {{ org.name }}

View File

@ -4,9 +4,19 @@
(cancel)="close()" (cancel)="close()"
> >
<div fxLayout="column" fxLayoutGap="8px"> <div fxLayout="column" fxLayoutGap="8px">
<dsh-limited-panel (showMore)="showMore()" [hasMore]="(isLoading$ | async) === false && (hasMore$ | async)"> <dsh-limited-panel
<mat-radio-group [(ngModel)]="selectedOrganization" fxLayout="column" fxLayoutGap="24px"> [hasMore]="(isLoading$ | async) === false && (hasMore$ | async)"
<mat-radio-button *ngFor="let organization of organizations$ | async" [value]="organization"> (showMore)="showMore()"
>
<mat-radio-group
[(ngModel)]="selectedOrganization"
fxLayout="column"
fxLayoutGap="24px"
>
<mat-radio-button
*ngFor="let organization of organizations$ | async"
[value]="organization"
>
{{ organization.name }} {{ organization.name }}
</mat-radio-button> </mat-radio-button>
</mat-radio-group> </mat-radio-group>
@ -15,10 +25,13 @@
</div> </div>
<ng-container dshBaseDialogActions> <ng-container dshBaseDialogActions>
<button <button
dsh-button [disabled]="
!selectedOrganization ||
selectedOrganization.id === (contextOrganization$ | async)?.id
"
color="accent" color="accent"
dsh-button
(click)="confirm()" (click)="confirm()"
[disabled]="!selectedOrganization || selectedOrganization.id === (contextOrganization$ | async)?.id"
> >
{{ t('confirm') }} {{ t('confirm') }}
</button> </button>

View File

@ -34,7 +34,7 @@ export class SelectActiveOrganizationDialogComponent implements OnInit {
>, >,
private fetchOrganizationsService: FetchOrganizationsService, private fetchOrganizationsService: FetchOrganizationsService,
private router: Router, private router: Router,
private contextOrganizationService: ContextOrganizationService private contextOrganizationService: ContextOrganizationService,
) {} ) {}
ngOnInit(): void { ngOnInit(): void {
@ -43,7 +43,7 @@ export class SelectActiveOrganizationDialogComponent implements OnInit {
.pipe( .pipe(
first(), first(),
map(([orgs, activeOrg]) => orgs.find((org) => org.id === activeOrg.id)), map(([orgs, activeOrg]) => orgs.find((org) => org.id === activeOrg.id)),
untilDestroyed(this) untilDestroyed(this),
) )
.subscribe((organization) => (this.selectedOrganization = organization)); .subscribe((organization) => (this.selectedOrganization = organization));
} }

View File

@ -1,7 +1,11 @@
<div class="dsh-user-dropdown" fxLayout="column" fxLayoutGap="4px"> <div class="dsh-user-dropdown" fxLayout="column" fxLayoutGap="4px">
<div fxLayout fxLayoutGap="8px" fxLayoutAlign=" center"> <div fxLayout fxLayoutAlign=" center" fxLayoutGap="8px">
<div class="dsh-body-2 username">{{ username }}</div> <div class="dsh-body-2 username">{{ username }}</div>
<dsh-bi icon="chevron-down" size="sm" [@rotate]="expanded ? 'expanded' : 'collapsed'"></dsh-bi> <dsh-bi
[@rotate]="expanded ? 'expanded' : 'collapsed'"
icon="chevron-down"
size="sm"
></dsh-bi>
</div> </div>
<div class="dsh-caption organization" *ngIf="orgName$ | async">{{ orgName$ | async }}</div> <div *ngIf="orgName$ | async" class="dsh-caption organization">{{ orgName$ | async }}</div>
</div> </div>

View File

@ -4,9 +4,10 @@ import { map } from 'rxjs/operators';
import { ContextOrganizationService } from '@dsh/app/shared/services'; import { ContextOrganizationService } from '@dsh/app/shared/services';
import { ROTATE } from './utils/rotate-animation';
import { KeycloakService } from '../../../../auth'; import { KeycloakService } from '../../../../auth';
import { ROTATE } from './utils/rotate-animation';
@Component({ @Component({
selector: 'dsh-user-dropdown', selector: 'dsh-user-dropdown',
templateUrl: 'user-dropdown.component.html', templateUrl: 'user-dropdown.component.html',
@ -22,6 +23,6 @@ export class UserDropdownComponent {
constructor( constructor(
private contextOrganizationService: ContextOrganizationService, private contextOrganizationService: ContextOrganizationService,
private keycloakService: KeycloakService private keycloakService: KeycloakService,
) {} ) {}
} }

View File

@ -2,5 +2,8 @@ import { trigger, state, style, transition, animate } from '@angular/animations'
export const ROTATE = trigger('rotate', [ export const ROTATE = trigger('rotate', [
state('expanded', style({ transform: 'rotate(180deg)' })), state('expanded', style({ transform: 'rotate(180deg)' })),
transition('expanded <=> collapsed, void => collapsed', animate('225ms cubic-bezier(0.4,0.0,0.2,1)')), transition(
'expanded <=> collapsed, void => collapsed',
animate('225ms cubic-bezier(0.4,0.0,0.2,1)'),
),
]); ]);

View File

@ -4,15 +4,21 @@
fxLayoutGap="24px" fxLayoutGap="24px"
> >
<ng-container> <ng-container>
<dsh-menu-item class="dsh-body-2" *ngIf="activeOrg$ | async as activeOrg" (click)="toActiveOrg(activeOrg.id)">{{ <dsh-menu-item
activeOrg.name *ngIf="activeOrg$ | async as activeOrg"
}}</dsh-menu-item> class="dsh-body-2"
(click)="toActiveOrg(activeOrg.id)"
>{{ activeOrg.name }}</dsh-menu-item
>
<dsh-menu-item (click)="selectActiveOrg()">{{ t('selectActiveOrg') }}</dsh-menu-item> <dsh-menu-item (click)="selectActiveOrg()">{{ t('selectActiveOrg') }}</dsh-menu-item>
<dsh-menu-item (click)="openOrgList()">{{ t('orgList') }}</dsh-menu-item> <dsh-menu-item (click)="openOrgList()">{{ t('orgList') }}</dsh-menu-item>
</ng-container> </ng-container>
<mat-divider></mat-divider> <mat-divider></mat-divider>
<span class="dsh-body-2">{{ username }}</span> <span class="dsh-body-2">{{ username }}</span>
<dsh-menu-item *ngFor="let linkConfig of userLinksConfig$ | async" (click)="openBlank(linkConfig.href)"> <dsh-menu-item
*ngFor="let linkConfig of userLinksConfig$ | async"
(click)="openBlank(linkConfig.href)"
>
{{ linkConfig.title }} {{ linkConfig.title }}
</dsh-menu-item> </dsh-menu-item>
<dsh-menu-item (click)="logout()">{{ t('logout') }}</dsh-menu-item> <dsh-menu-item (click)="logout()">{{ t('logout') }}</dsh-menu-item>

View File

@ -38,7 +38,7 @@ export class UserComponent {
title: this.transloco.translate('actionbar.user.twoFactorAuth', {}, 'components'), title: this.transloco.translate('actionbar.user.twoFactorAuth', {}, 'components'),
href: `${this.keycloakAccountEndpoint}/totp`, href: `${this.keycloakAccountEndpoint}/totp`,
}, },
]) ]),
); );
constructor( constructor(
@ -48,7 +48,7 @@ export class UserComponent {
private router: Router, private router: Router,
private dialog: MatDialog, private dialog: MatDialog,
private transloco: TranslocoService, private transloco: TranslocoService,
@Inject(DIALOG_CONFIG) private dialogConfig: DialogConfig @Inject(DIALOG_CONFIG) private dialogConfig: DialogConfig,
) {} ) {}
openBlank(href: string): void { openBlank(href: string): void {
@ -62,12 +62,20 @@ export class UserComponent {
selectActiveOrg(): void { selectActiveOrg(): void {
this.selected.emit(); this.selected.emit();
this.dialog this.dialog
.open<SelectActiveOrganizationDialogComponent, void, BaseDialogResponseStatus | Organization>( .open<
SelectActiveOrganizationDialogComponent, SelectActiveOrganizationDialogComponent,
this.dialogConfig.medium void,
) BaseDialogResponseStatus | Organization
>(SelectActiveOrganizationDialogComponent, this.dialogConfig.medium)
.afterClosed() .afterClosed()
.pipe(filter((res) => !Object.values(BaseDialogResponseStatus).includes(res as BaseDialogResponseStatus))) .pipe(
filter(
(res) =>
!Object.values(BaseDialogResponseStatus).includes(
res as BaseDialogResponseStatus,
),
),
)
.subscribe((org: Organization) => { .subscribe((org: Organization) => {
this.contextOrganizationService.switchOrganization(org.id); this.contextOrganizationService.switchOrganization(org.id);
}); });
@ -79,7 +87,9 @@ export class UserComponent {
} }
toActiveOrg(activeOrg: string): void { toActiveOrg(activeOrg: string): void {
void this.router.navigate(['organization-section', 'organizations'], { fragment: activeOrg }); void this.router.navigate(['organization-section', 'organizations'], {
fragment: activeOrg,
});
this.selected.emit(); this.selected.emit();
} }
} }

View File

@ -20,7 +20,7 @@ export class HomeComponent implements OnInit {
private router: Router, private router: Router,
// need to create class when home component was init // need to create class when home component was init
private themeManager: ThemeManager, private themeManager: ThemeManager,
private breakpointObserver: BreakpointObserver private breakpointObserver: BreakpointObserver,
) {} ) {}
ngOnInit(): void { ngOnInit(): void {
@ -28,7 +28,7 @@ export class HomeComponent implements OnInit {
filter((event) => event instanceof NavigationEnd), filter((event) => event instanceof NavigationEnd),
map(() => true), map(() => true),
take(1), take(1),
untilDestroyed(this) untilDestroyed(this),
); );
this.isXSmallSmall$ = this.breakpointObserver this.isXSmallSmall$ = this.breakpointObserver
.observe([Breakpoints.XSmall, Breakpoints.Small]) .observe([Breakpoints.XSmall, Breakpoints.Small])

View File

@ -2,9 +2,10 @@ import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { FlexLayoutModule } from '@angular/flex-layout'; import { FlexLayoutModule } from '@angular/flex-layout';
import { LaptopGridComponent } from './laptop-grid.component';
import { ToolbarModule } from '../toolbar'; import { ToolbarModule } from '../toolbar';
import { LaptopGridComponent } from './laptop-grid.component';
@NgModule({ @NgModule({
imports: [CommonModule, ToolbarModule, FlexLayoutModule], imports: [CommonModule, ToolbarModule, FlexLayoutModule],
declarations: [LaptopGridComponent], declarations: [LaptopGridComponent],

View File

@ -1,16 +1,31 @@
<mat-drawer-container class="dsh-mobile-grid"> <mat-drawer-container class="dsh-mobile-grid">
<mat-drawer class="dsh-mobile-grid-drawer" mode="over" [autoFocus]="false"> <mat-drawer [autoFocus]="false" class="dsh-mobile-grid-drawer" mode="over">
<div class="dsh-mobile-grid-drawer-wrapper" fxLayout="column"> <div class="dsh-mobile-grid-drawer-wrapper" fxLayout="column">
<div class="dsh-mobile-grid-drawer-actions" fxLayout="row" fxLayoutAlign="end center"> <div class="dsh-mobile-grid-drawer-actions" fxLayout="row" fxLayoutAlign="end center">
<dsh-bi class="dsh-mobile-grid-toggle-button" (click)="closeSideNav()" icon="x" size="lg"></dsh-bi> <dsh-bi
class="dsh-mobile-grid-toggle-button"
icon="x"
size="lg"
(click)="closeSideNav()"
></dsh-bi>
</div> </div>
<dsh-mobile-menu fxFlex (menuItemSelected)="closeSideNav()"></dsh-mobile-menu> <dsh-mobile-menu fxFlex (menuItemSelected)="closeSideNav()"></dsh-mobile-menu>
</div> </div>
</mat-drawer> </mat-drawer>
<mat-drawer-content> <mat-drawer-content>
<div class="dsh-mobile-grid-content" fxLayout="column" fxLayoutGap="24px"> <div class="dsh-mobile-grid-content" fxLayout="column" fxLayoutGap="24px">
<div class="dsh-mobile-grid-content-actions" fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="24px"> <div
<dsh-bi class="dsh-mobile-grid-toggle-button" (click)="openSideNav()" icon="list" size="lg"></dsh-bi> class="dsh-mobile-grid-content-actions"
fxLayout="row"
fxLayoutAlign="start center"
fxLayoutGap="24px"
>
<dsh-bi
class="dsh-mobile-grid-toggle-button"
icon="list"
size="lg"
(click)="openSideNav()"
></dsh-bi>
<dsh-brand></dsh-brand> <dsh-brand></dsh-brand>
</div> </div>
<ng-content></ng-content> <ng-content></ng-content>

View File

@ -5,12 +5,20 @@ import { MatSidenavModule } from '@angular/material/sidenav';
import { BootstrapIconModule } from '@dsh/components/indicators'; import { BootstrapIconModule } from '@dsh/components/indicators';
import { MobileGridComponent } from './mobile-grid.component';
import { MobileMenuModule } from './mobile-menu';
import { BrandModule } from '../brand'; import { BrandModule } from '../brand';
import { MobileGridComponent } from './mobile-grid.component';
import { MobileMenuModule } from './mobile-menu';
@NgModule({ @NgModule({
imports: [CommonModule, MatSidenavModule, BrandModule, FlexLayoutModule, MobileMenuModule, BootstrapIconModule], imports: [
CommonModule,
MatSidenavModule,
BrandModule,
FlexLayoutModule,
MobileMenuModule,
BootstrapIconModule,
],
declarations: [MobileGridComponent], declarations: [MobileGridComponent],
exports: [MobileGridComponent], exports: [MobileGridComponent],
}) })

View File

@ -1,3 +1,3 @@
<div class="dsh-mobile-menu-nav-item" [ngClass]="{ 'dsh-mobile-nav-item-active': active }"> <div [ngClass]="{ 'dsh-mobile-nav-item-active': active }" class="dsh-mobile-menu-nav-item">
<ng-content></ng-content> <ng-content></ng-content>
</div> </div>

View File

@ -1,12 +1,12 @@
<div class="dsh-mobile-menu" fxLayout="column"> <div class="dsh-mobile-menu" fxLayout="column">
<div class="dsh-enu-nav-items" fxFlex fxLayout="column" fxLayoutGap="16px"> <div class="dsh-enu-nav-items" fxFlex fxLayout="column" fxLayoutGap="16px">
<dsh-mobile-menu-nav-item <dsh-mobile-menu-nav-item
*ngFor="let link of sectionLinks$ | async"
[routerLink]="link.path"
routerLinkActive
[routerLinkActiveOptions]="{ exact: link?.exact }"
#rla="routerLinkActive" #rla="routerLinkActive"
*ngFor="let link of sectionLinks$ | async"
[active]="rla.isActive" [active]="rla.isActive"
[routerLink]="link.path"
[routerLinkActiveOptions]="{ exact: link?.exact }"
routerLinkActive
(click)="menuItemSelected.emit()" (click)="menuItemSelected.emit()"
>{{ link.label }}</dsh-mobile-menu-nav-item >{{ link.label }}</dsh-mobile-menu-nav-item
> >

View File

@ -1,15 +1,15 @@
<div class="dsh-toolbar" fxLayout fxLayoutGap="24px" fxLayoutAlign="center center"> <div class="dsh-toolbar" fxLayout fxLayoutAlign="center center" fxLayoutGap="24px">
<dsh-brand fxFlex fxLayoutAlign="start"></dsh-brand> <dsh-brand fxFlex fxLayoutAlign="start"></dsh-brand>
<div fxFlex fxLayoutAlign="center"> <div fxFlex fxLayoutAlign="center">
<nav class="dsh-top-tab-nav-bar" mat-tab-nav-bar [tabPanel]="tabPanel"> <nav [tabPanel]="tabPanel" class="dsh-top-tab-nav-bar" mat-tab-nav-bar>
<a <a
*ngFor="let link of sectionLinks$ | async"
mat-tab-link
[routerLink]="link.path"
routerLinkActive
[routerLinkActiveOptions]="{ exact: link?.exact }"
#rla="routerLinkActive" #rla="routerLinkActive"
*ngFor="let link of sectionLinks$ | async"
[active]="rla.isActive" [active]="rla.isActive"
[routerLink]="link.path"
[routerLinkActiveOptions]="{ exact: link?.exact }"
mat-tab-link
routerLinkActive
> >
{{ link.label }} {{ link.label }}
</a> </a>

View File

@ -6,10 +6,11 @@ import { RouterModule } from '@angular/router';
import { SectionsLinksModule } from '@dsh/app/shared/services/sections-links'; import { SectionsLinksModule } from '@dsh/app/shared/services/sections-links';
import { ToolbarComponent } from './toolbar.component';
import { ActionbarModule } from '../actionbar'; import { ActionbarModule } from '../actionbar';
import { BrandModule } from '../brand'; import { BrandModule } from '../brand';
import { ToolbarComponent } from './toolbar.component';
@NgModule({ @NgModule({
imports: [ imports: [
CommonModule, CommonModule,

View File

@ -32,8 +32,9 @@ export class HumanizeDurationService {
} }
get shortEnglishHumanizer(): humanizeDuration.HumanizerOptions { get shortEnglishHumanizer(): humanizeDuration.HumanizerOptions {
const getLocalizedUnitFn = (unit: keyof ReturnType<HumanizeDurationService['getUnitLabels']>) => () => const getLocalizedUnitFn =
this.getUnitLabels()[unit]; (unit: keyof ReturnType<HumanizeDurationService['getUnitLabels']>) => () =>
this.getUnitLabels()[unit];
return { return {
language: 'short', language: 'short',
languages: { languages: {
@ -51,7 +52,10 @@ export class HumanizeDurationService {
}; };
} }
constructor(private languageService: LanguageService, private transloco: TranslocoService) {} constructor(
private languageService: LanguageService,
private transloco: TranslocoService,
) {}
getDiffMs(value: Value): number { getDiffMs(value: Value): number {
return Math.abs(this.isDiff(value) ? value : moment().diff(moment(value))); return Math.abs(this.isDiff(value) ? value : moment().diff(moment(value)));
@ -63,7 +67,11 @@ export class HumanizeDurationService {
if (isNaN(diffMs)) { if (isNaN(diffMs)) {
return null; return null;
} else if (diffMs < HumanizeDurationService.LESS_THAN_FEW_SECONDS) { } else if (diffMs < HumanizeDurationService.LESS_THAN_FEW_SECONDS) {
return this.transloco.selectTranslate('humanizeDuration.justNow', null, 'core-components'); return this.transloco.selectTranslate(
'humanizeDuration.justNow',
null,
'core-components',
);
} else if (config.isShort) { } else if (config.isShort) {
duration = this.duration(diffMs, { ...config, ...this.shortEnglishHumanizer }); duration = this.duration(diffMs, { ...config, ...this.shortEnglishHumanizer });
} else if (config.largest === 1) { } else if (config.largest === 1) {
@ -72,8 +80,12 @@ export class HumanizeDurationService {
duration = duration === 'минута' ? 'минуту' : duration; duration = duration === 'минута' ? 'минуту' : duration;
return of( return of(
config.hasAgoEnding config.hasAgoEnding
? `${duration} ${this.transloco.translate('humanizeDuration.ago', null, 'core-components')}` ? `${duration} ${this.transloco.translate(
: duration 'humanizeDuration.ago',
null,
'core-components',
)}`
: duration,
); );
} }
@ -97,14 +109,46 @@ export class HumanizeDurationService {
private getUnitLabels() { private getUnitLabels() {
return { return {
day: this.transloco.translate('humanizeDuration.shortUnit.day', null, 'core-components'), day: this.transloco.translate(
hour: this.transloco.translate('humanizeDuration.shortUnit.hour', null, 'core-components'), 'humanizeDuration.shortUnit.day',
millisecond: this.transloco.translate('humanizeDuration.shortUnit.millisecond', null, 'core-components'), null,
minute: this.transloco.translate('humanizeDuration.shortUnit.minute', null, 'core-components'), 'core-components',
month: this.transloco.translate('humanizeDuration.shortUnit.month', null, 'core-components'), ),
second: this.transloco.translate('humanizeDuration.shortUnit.second', null, 'core-components'), hour: this.transloco.translate(
week: this.transloco.translate('humanizeDuration.shortUnit.week', null, 'core-components'), 'humanizeDuration.shortUnit.hour',
year: this.transloco.translate('humanizeDuration.shortUnit.year', null, 'core-components'), null,
'core-components',
),
millisecond: this.transloco.translate(
'humanizeDuration.shortUnit.millisecond',
null,
'core-components',
),
minute: this.transloco.translate(
'humanizeDuration.shortUnit.minute',
null,
'core-components',
),
month: this.transloco.translate(
'humanizeDuration.shortUnit.month',
null,
'core-components',
),
second: this.transloco.translate(
'humanizeDuration.shortUnit.second',
null,
'core-components',
),
week: this.transloco.translate(
'humanizeDuration.shortUnit.week',
null,
'core-components',
),
year: this.transloco.translate(
'humanizeDuration.shortUnit.year',
null,
'core-components',
),
}; };
} }
} }

Some files were not shown because too many files have changed in this diff Show More