mirror of
https://github.com/valitydev/dashboard.git
synced 2024-11-06 02:25:23 +00:00
TD-372: Organization fixes; add BDT currency; update swag payments (#84)
This commit is contained in:
parent
418b418cad
commit
540d2706fb
3
.gitignore
vendored
3
.gitignore
vendored
@ -47,3 +47,6 @@ Thumbs.db
|
||||
|
||||
# Angular
|
||||
.angular
|
||||
|
||||
# Configs
|
||||
src/*Config.json
|
12
.run/Dev.run.xml
Normal file
12
.run/Dev.run.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Dev" type="js.build_tools.npm">
|
||||
<package-json value="$PROJECT_DIR$/package.json" />
|
||||
<command value="run" />
|
||||
<scripts>
|
||||
<script value="start" />
|
||||
</scripts>
|
||||
<node-interpreter value="project" />
|
||||
<envs />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
61
README.md
61
README.md
@ -6,31 +6,53 @@
|
||||
- [Angular Material](https://material.angular.io/)
|
||||
- [Prettier](https://prettier.io/)
|
||||
|
||||
## Initialization
|
||||
## Guides
|
||||
|
||||
### Install packages
|
||||
- [Using typography](https://material.angular.io/guide/typography)
|
||||
- [Theming your components](https://material.angular.io/guide/theming-your-components)
|
||||
|
||||
## Installation
|
||||
|
||||
1. Add environment and configurations:
|
||||
|
||||
- `src/appConfig.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"apiEndpoint": "https://api.xample.com",
|
||||
"urlShortenerEndpoint": "https://shrt.example.com",
|
||||
"checkoutEndpoint": "https://checkout.example.com",
|
||||
"docsEndpoints": {
|
||||
"payments": "https://example.com/docs"
|
||||
},
|
||||
"theme": {
|
||||
"name": "main"
|
||||
},
|
||||
"sentryDsn": "https://public@sentry.example.com/1",
|
||||
"keycloakEndpoint": "https://auth.example.com",
|
||||
"fileStorageEndpoint": "https://fs.example.com"
|
||||
}
|
||||
```
|
||||
|
||||
- `src/authConfig.json`:
|
||||
```json
|
||||
{
|
||||
"realm": "external",
|
||||
"auth-server-url": "https://auth.example.com/auth/",
|
||||
"ssl-required": "external",
|
||||
"resource": "koffing",
|
||||
"public-client": true
|
||||
}
|
||||
```
|
||||
|
||||
2. Install packages
|
||||
```sh
|
||||
npm ci
|
||||
```
|
||||
|
||||
## Development server
|
||||
|
||||
- API (Production API default)
|
||||
|
||||
- With mocks:
|
||||
|
||||
Change `./src/appConfig.json` API endpoints
|
||||
|
||||
1. Start
|
||||
|
||||
- Real Keycloak: `npm start`
|
||||
|
||||
- Stub Keycloak
|
||||
|
||||
1. Change `./src/authConfig.json` / `"auth-server-url"`:
|
||||
|
||||
1. `npm run stub`
|
||||
1. `npm start`
|
||||
|
||||
1. Navigate to `http://localhost:8000/`
|
||||
|
||||
@ -51,8 +73,3 @@ npm ci
|
||||
npm run build -- --prod --stats-json --extraWebpackConfig webpack.extra.js
|
||||
npx webpack-bundle-analyzer dist/stats.json
|
||||
```
|
||||
|
||||
## Guides
|
||||
|
||||
- [Using typography](https://material.angular.io/guide/typography)
|
||||
- [Theming your components](https://material.angular.io/guide/theming-your-components)
|
||||
|
14
package-lock.json
generated
14
package-lock.json
generated
@ -36,7 +36,7 @@
|
||||
"@vality/swag-dark-api": "0.1.1-a3f1678.0",
|
||||
"@vality/swag-messages": "1.0.1-03e1014.0",
|
||||
"@vality/swag-organizations": "1.0.1-cd6cc10.0",
|
||||
"@vality/swag-payments": "0.1.1-4550cf2.0",
|
||||
"@vality/swag-payments": "0.1.1-37e6f46.0",
|
||||
"@vality/swag-questionary-aggr-proxy": "0.1.1-1dc5add.0",
|
||||
"@vality/swag-url-shortener": "0.1.1-f780d07.0",
|
||||
"@vality/swag-wallet": "0.1.1-9a236df.0",
|
||||
@ -5040,9 +5040,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@vality/swag-payments": {
|
||||
"version": "0.1.1-4550cf2.0",
|
||||
"resolved": "https://registry.npmjs.org/@vality/swag-payments/-/swag-payments-0.1.1-4550cf2.0.tgz",
|
||||
"integrity": "sha512-UgWAkzaemcqMLJhSxwZGOeZ2v+UE7fonNTQDg/gh7FwS7kI7QWCIdIGyAEFXYEtnKRJDBWPbYXekmvLJP1kGmw==",
|
||||
"version": "0.1.1-37e6f46.0",
|
||||
"resolved": "https://registry.npmjs.org/@vality/swag-payments/-/swag-payments-0.1.1-37e6f46.0.tgz",
|
||||
"integrity": "sha512-mnINBuklAgRzkx/Q9RboScrdl2TZlXrHEywDZq4AaJFznoJLfR1yNrqjxh9g7SrNJfoTh+qbuJjxPgd+5oG7Tg==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
@ -21330,9 +21330,9 @@
|
||||
}
|
||||
},
|
||||
"@vality/swag-payments": {
|
||||
"version": "0.1.1-4550cf2.0",
|
||||
"resolved": "https://registry.npmjs.org/@vality/swag-payments/-/swag-payments-0.1.1-4550cf2.0.tgz",
|
||||
"integrity": "sha512-UgWAkzaemcqMLJhSxwZGOeZ2v+UE7fonNTQDg/gh7FwS7kI7QWCIdIGyAEFXYEtnKRJDBWPbYXekmvLJP1kGmw==",
|
||||
"version": "0.1.1-37e6f46.0",
|
||||
"resolved": "https://registry.npmjs.org/@vality/swag-payments/-/swag-payments-0.1.1-37e6f46.0.tgz",
|
||||
"integrity": "sha512-mnINBuklAgRzkx/Q9RboScrdl2TZlXrHEywDZq4AaJFznoJLfR1yNrqjxh9g7SrNJfoTh+qbuJjxPgd+5oG7Tg==",
|
||||
"requires": {
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
|
@ -54,7 +54,7 @@
|
||||
"@vality/swag-dark-api": "0.1.1-a3f1678.0",
|
||||
"@vality/swag-messages": "1.0.1-03e1014.0",
|
||||
"@vality/swag-organizations": "1.0.1-cd6cc10.0",
|
||||
"@vality/swag-payments": "0.1.1-4550cf2.0",
|
||||
"@vality/swag-payments": "0.1.1-37e6f46.0",
|
||||
"@vality/swag-questionary-aggr-proxy": "0.1.1-1dc5add.0",
|
||||
"@vality/swag-url-shortener": "0.1.1-f780d07.0",
|
||||
"@vality/swag-wallet": "0.1.1-9a236df.0",
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { TranslocoService } from '@ngneat/transloco';
|
||||
import { StatusOffsetCount, InvoiceStatus, Report, RefundStatus } from '@vality/swag-anapi-v2';
|
||||
import { InvoiceStatus, Report, RefundStatus, PaymentSearchResult } from '@vality/swag-anapi-v2';
|
||||
import { BankCardPaymentSystem } from '@vality/swag-anapi-v2/lib/model/bankCardPaymentSystem';
|
||||
import { BankCardTokenProvider } from '@vality/swag-anapi-v2/lib/model/bankCardTokenProvider';
|
||||
|
||||
@ -44,13 +44,14 @@ export class AnapiDictionaryService {
|
||||
other: this.t.translate('anapi.errorCode.other', null, 'dictionary'),
|
||||
}));
|
||||
|
||||
paymentStatus$ = this.dictionaryService.create<StatusOffsetCount.StatusEnum>(() => ({
|
||||
paymentStatus$ = this.dictionaryService.create<PaymentSearchResult.StatusEnum>(() => ({
|
||||
pending: this.t.translate('anapi.paymentStatus.pending', null, 'dictionary'),
|
||||
processed: this.t.translate('anapi.paymentStatus.processed', null, 'dictionary'),
|
||||
captured: this.t.translate('anapi.paymentStatus.captured', null, 'dictionary'),
|
||||
cancelled: this.t.translate('anapi.paymentStatus.cancelled', null, 'dictionary'),
|
||||
refunded: this.t.translate('anapi.paymentStatus.refunded', null, 'dictionary'),
|
||||
failed: this.t.translate('anapi.paymentStatus.failed', null, 'dictionary'),
|
||||
chargedback: this.t.translate('anapi.paymentStatus.chargedback', null, 'dictionary'),
|
||||
}));
|
||||
|
||||
invoiceStatus$ = this.dictionaryService.create<InvoiceStatus.StatusEnum>(() => ({
|
||||
|
@ -2,7 +2,7 @@ import { HttpResponse, HttpHeaders } from '@angular/common/http';
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { Observable, combineLatest, isObservable, of } from 'rxjs';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
import { RequiredKeys, UnionToIntersection, Overwrite } from 'utility-types';
|
||||
import { RequiredKeys, UnionToIntersection, Overwrite, ReadonlyKeys } from 'utility-types';
|
||||
|
||||
import { ApiExtension } from './utils/api-extension';
|
||||
import { getMethods } from './utils/get-methods';
|
||||
@ -11,13 +11,19 @@ import { XrequestIdExtension } from './utils/x-request-id-extension';
|
||||
|
||||
const DEFAULT_HEADERS = new HttpHeaders({ 'Content-Type': 'application/json; charset=utf-8' });
|
||||
|
||||
// Exclude readonly keys
|
||||
type DeepOnlyMutable<T> = T extends object
|
||||
? {
|
||||
[P in keyof T]: T[P] extends object ? Omit<T[P], ReadonlyKeys<T[P]>> : T[P];
|
||||
}
|
||||
: T;
|
||||
type ApiArgs = [Injector];
|
||||
|
||||
type MethodParams<P extends Record<PropertyKey, any>, K extends PropertyKey> = RequiredKeys<Omit<P, K>> extends never
|
||||
? void | 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>>
|
||||
? (params: MethodParams<Parameters<M>[0], P>) => Observable<R>
|
||||
? (params: DeepOnlyMutable<MethodParams<Parameters<M>[0], P>>) => Observable<R>
|
||||
: never;
|
||||
|
||||
/**
|
||||
|
@ -1,8 +1,6 @@
|
||||
import { getBaseClass } from '@dsh/utils';
|
||||
|
||||
import type AppConfigJson from '../../appConfig.json';
|
||||
|
||||
interface AppConfig {
|
||||
export interface Config {
|
||||
apiEndpoint: string;
|
||||
urlShortenerEndpoint: string;
|
||||
checkoutEndpoint: string;
|
||||
@ -16,6 +14,4 @@ interface AppConfig {
|
||||
keycloakEndpoint: string;
|
||||
fileStorageEndpoint: string;
|
||||
}
|
||||
|
||||
export type Config = typeof AppConfigJson extends AppConfig ? AppConfig : never;
|
||||
export const BASE_CONFIG = getBaseClass<Config>();
|
||||
|
23
src/app/sections/get-payment-status-color.ts
Normal file
23
src/app/sections/get-payment-status-color.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { PaymentSearchResult } from '@vality/swag-anapi-v2';
|
||||
|
||||
import { StatusColor as Color } from '../theme-manager';
|
||||
|
||||
export const getPaymentStatusColor = (status: PaymentSearchResult.StatusEnum): Color => {
|
||||
const statusEnum = PaymentSearchResult.StatusEnum;
|
||||
switch (status) {
|
||||
case statusEnum.Processed:
|
||||
return Color.Success;
|
||||
case statusEnum.Failed:
|
||||
return Color.Warn;
|
||||
case statusEnum.Refunded:
|
||||
return Color.Neutral;
|
||||
case statusEnum.Cancelled:
|
||||
return Color.Warn;
|
||||
case statusEnum.Captured:
|
||||
return Color.Success;
|
||||
case statusEnum.Pending:
|
||||
return Color.Pending;
|
||||
case statusEnum.Chargedback:
|
||||
return Color.Neutral;
|
||||
}
|
||||
};
|
@ -1,26 +0,0 @@
|
||||
import { PaymentStatus } from '@vality/swag-payments';
|
||||
|
||||
import { StatusColor as Color } from '../theme-manager';
|
||||
|
||||
export interface PaymentStatusInfo {
|
||||
color: Color;
|
||||
status: string;
|
||||
}
|
||||
|
||||
export const getPaymentStatusInfo = (status: PaymentStatus.StatusEnum): PaymentStatusInfo => {
|
||||
const statusEnum = PaymentStatus.StatusEnum;
|
||||
switch (status) {
|
||||
case statusEnum.Processed:
|
||||
return { color: Color.Success, status: 'processed' };
|
||||
case statusEnum.Failed:
|
||||
return { color: Color.Warn, status: 'failed' };
|
||||
case statusEnum.Refunded:
|
||||
return { color: Color.Neutral, status: 'refunded' };
|
||||
case statusEnum.Cancelled:
|
||||
return { color: Color.Warn, status: 'cancelled' };
|
||||
case statusEnum.Captured:
|
||||
return { color: Color.Success, status: 'captured' };
|
||||
case statusEnum.Pending:
|
||||
return { color: Color.Pending, status: 'pending' };
|
||||
}
|
||||
};
|
@ -17,7 +17,12 @@
|
||||
</div>
|
||||
</div>
|
||||
<ng-container dshBaseDialogActions>
|
||||
<button dsh-button color="accent" [disabled]="emailControl.invalid || !selectedRoles.length" (click)="create()">
|
||||
<button
|
||||
dsh-button
|
||||
color="accent"
|
||||
[disabled]="emailControl.invalid || !selectedRoles.length || (inProgress$ | async)"
|
||||
(click)="create()"
|
||||
>
|
||||
{{ t('send') }}
|
||||
</button>
|
||||
</ng-container>
|
||||
|
@ -16,6 +16,10 @@ const ORGANIZATION_SECTION_ROUTES: Routes = [
|
||||
path: 'organizations/:orgId',
|
||||
loadChildren: () => import('./organization-details').then((m) => m.OrganizationDetailsModule),
|
||||
},
|
||||
{
|
||||
path: 'accept-invitation',
|
||||
loadChildren: () => import('./accept-invitation').then((m) => m.AcceptInvitationModule),
|
||||
},
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'organizations',
|
||||
|
@ -2,10 +2,10 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { MatDialogRef } from '@angular/material/dialog';
|
||||
import { FormBuilder } from '@ngneat/reactive-forms';
|
||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||
import { Organization } from '@vality/swag-organizations';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { BehaviorSubject, switchMap } from 'rxjs';
|
||||
|
||||
import { OrgsService } from '@dsh/api/organizations';
|
||||
import { KeycloakTokenInfoService } from '@dsh/app/shared';
|
||||
import { BaseDialogResponseStatus } from '@dsh/app/shared/components/dialog/base-dialog';
|
||||
import { ErrorService } from '@dsh/app/shared/services/error';
|
||||
import { NotificationService } from '@dsh/app/shared/services/notification';
|
||||
@ -26,18 +26,24 @@ export class CreateOrganizationDialogComponent {
|
||||
private organizationsService: OrgsService,
|
||||
private notificationService: NotificationService,
|
||||
private errorService: ErrorService,
|
||||
private fb: FormBuilder
|
||||
private fb: FormBuilder,
|
||||
private keycloakTokenInfoService: KeycloakTokenInfoService
|
||||
) {}
|
||||
|
||||
@inProgressTo('inProgress$')
|
||||
create() {
|
||||
return this.organizationsService
|
||||
.createOrg({
|
||||
return this.keycloakTokenInfoService.partyID$
|
||||
.pipe(
|
||||
switchMap((owner) =>
|
||||
this.organizationsService.createOrg({
|
||||
organization: {
|
||||
name: this.form.value.name,
|
||||
} as Organization,
|
||||
owner,
|
||||
},
|
||||
})
|
||||
.pipe(untilDestroyed(this))
|
||||
),
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notificationService.success();
|
||||
|
@ -4,19 +4,10 @@ import { RouterModule, Routes } from '@angular/router';
|
||||
import { OrganizationsComponent } from './organizations.component';
|
||||
|
||||
export const ROUTES: Routes = [
|
||||
{
|
||||
path: '',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: OrganizationsComponent,
|
||||
},
|
||||
{
|
||||
path: 'accept-invitation',
|
||||
loadChildren: () => import('./accept-invitation').then((m) => m.AcceptInvitationModule),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
@ -1,7 +1,7 @@
|
||||
<ng-container>
|
||||
<ng-container *transloco="let t; scope: 'payment-section'; read: 'paymentSection.paymentDetails.statusDetailItem'">
|
||||
<dsh-details-item [title]="t('status')">
|
||||
<dsh-status [color]="paymentColor">{{ (paymentStatusDict$ | async)?.[paymentStatus] }}</dsh-status>
|
||||
<dsh-status [color]="paymentColor">{{ (paymentStatusDict$ | async)?.[status] }}</dsh-status>
|
||||
</dsh-details-item>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core';
|
||||
import { PaymentStatus } from '@vality/swag-payments';
|
||||
import { PaymentSearchResult } from '@vality/swag-anapi-v2';
|
||||
import isNil from 'lodash-es/isNil';
|
||||
import isObject from 'lodash-es/isObject';
|
||||
|
||||
import { PaymentsDictionaryService } from '@dsh/api/payments';
|
||||
import { AnapiDictionaryService } from '@dsh/api/anapi';
|
||||
import { ComponentChange, ComponentChanges } from '@dsh/type-utils';
|
||||
|
||||
import { StatusColor } from '../../../../../../../../../theme-manager';
|
||||
import { getPaymentStatusInfo } from '../../../../../../../../get-payment-status-info';
|
||||
import { getPaymentStatusColor } from '../../../../../../../../get-payment-status-color';
|
||||
|
||||
@Component({
|
||||
selector: 'dsh-payment-status',
|
||||
@ -15,13 +15,12 @@ import { getPaymentStatusInfo } from '../../../../../../../../get-payment-status
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PaymentStatusComponent implements OnChanges {
|
||||
@Input() status: PaymentStatus.StatusEnum;
|
||||
@Input() status: PaymentSearchResult.StatusEnum;
|
||||
|
||||
paymentColor: StatusColor;
|
||||
paymentStatus: string;
|
||||
paymentStatusDict$ = this.paymentsDictionaryService.paymentStatus$;
|
||||
paymentStatusDict$ = this.anapiDictionaryService.paymentStatus$;
|
||||
|
||||
constructor(private paymentsDictionaryService: PaymentsDictionaryService) {}
|
||||
constructor(private anapiDictionaryService: AnapiDictionaryService) {}
|
||||
|
||||
ngOnChanges(changes: ComponentChanges<PaymentStatusComponent>): void {
|
||||
if (isObject(changes.status)) {
|
||||
@ -33,8 +32,6 @@ export class PaymentStatusComponent implements OnChanges {
|
||||
if (isNil(paymentStatus)) {
|
||||
return;
|
||||
}
|
||||
const { status, color } = getPaymentStatusInfo(paymentStatus);
|
||||
this.paymentColor = color;
|
||||
this.paymentStatus = status;
|
||||
this.paymentColor = getPaymentStatusColor(paymentStatus);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ChangeDetectionStrategy, Component, Injector } from '@angular/core';
|
||||
import { provideValueAccessor } from '@s-libs/ng-core';
|
||||
import { Claim } from '@vality/swag-payments';
|
||||
import { Claim } from '@vality/swag-claim-management';
|
||||
|
||||
import { FilterSuperclass } from '@dsh/components/filter';
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ChangeDetectionStrategy, Component, Injector } from '@angular/core';
|
||||
import { provideValueAccessor, WrappedFormControlSuperclass } from '@s-libs/ng-core';
|
||||
import { Claim } from '@vality/swag-payments';
|
||||
import { Claim } from '@vality/swag-claim-management';
|
||||
|
||||
@Component({
|
||||
selector: 'dsh-claim-field',
|
||||
|
@ -14,7 +14,7 @@ export class CurrencyAutocompleteFieldComponent extends WrappedFormControlSuperc
|
||||
@Input() label: string;
|
||||
@Input() @coerceBoolean required = false;
|
||||
|
||||
options: Option<string>[] = ['RUB', 'USD', 'EUR', 'UAH', 'KZT', 'BYN', 'JPY', 'INR', 'AZN', 'BRL']
|
||||
options: Option<string>[] = ['RUB', 'USD', 'EUR', 'UAH', 'KZT', 'BYN', 'JPY', 'INR', 'AZN', 'BRL', 'BDT']
|
||||
.sort()
|
||||
.map((currency) => ({ label: currency, value: currency }));
|
||||
|
||||
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"apiEndpoint": "https://api.rbk.money",
|
||||
"urlShortenerEndpoint": "https://rbk.mn",
|
||||
"checkoutEndpoint": "https://checkout.rbk.money",
|
||||
"docsEndpoints": {
|
||||
"payments": "https://developer.rbk.money/api"
|
||||
},
|
||||
"theme": {
|
||||
"name": "main"
|
||||
},
|
||||
"sentryDsn": null,
|
||||
"keycloakEndpoint": "https://auth.rbk.money",
|
||||
"fileStorageEndpoint": "https://storage.rbk.money/files"
|
||||
}
|
@ -56,6 +56,7 @@
|
||||
"paymentStatus": {
|
||||
"cancelled": "Отменен",
|
||||
"captured": "Подтвержден",
|
||||
"chargedback": "Chargedback",
|
||||
"failed": "Неуспешен",
|
||||
"pending": "Запущен",
|
||||
"processed": "Обработан",
|
||||
|
@ -1,7 +0,0 @@
|
||||
{
|
||||
"realm": "external",
|
||||
"auth-server-url": "https://auth.rbk.money/auth/",
|
||||
"ssl-required": "external",
|
||||
"resource": "koffing",
|
||||
"public-client": true
|
||||
}
|
Loading…
Reference in New Issue
Block a user