mirror of
https://github.com/valitydev/dashboard.git
synced 2024-11-06 02:25:23 +00:00
Remove claim details module (#105)
This commit is contained in:
parent
fdb6d848d9
commit
53893ef0ef
@ -29,8 +29,7 @@
|
||||
"name": "main"
|
||||
},
|
||||
"sentryDsn": "https://public@sentry.example.com/1",
|
||||
"keycloakEndpoint": "https://auth.example.com",
|
||||
"fileStorageEndpoint": "https://fs.example.com"
|
||||
"keycloakEndpoint": "https://auth.example.com"
|
||||
}
|
||||
```
|
||||
|
||||
|
21
package-lock.json
generated
21
package-lock.json
generated
@ -34,7 +34,6 @@
|
||||
"@vality/swag-anapi-v2": "2.0.1-0405be2.0",
|
||||
"@vality/swag-claim-management": "0.1.1-bfc2e6c.0",
|
||||
"@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-d71aebc.0",
|
||||
"@vality/swag-questionary-aggr-proxy": "0.1.1-1dc5add.0",
|
||||
@ -5015,18 +5014,6 @@
|
||||
"@angular/core": "^13.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vality/swag-messages": {
|
||||
"version": "1.0.1-03e1014.0",
|
||||
"resolved": "https://registry.npmjs.org/@vality/swag-messages/-/swag-messages-1.0.1-03e1014.0.tgz",
|
||||
"integrity": "sha512-iaKra/x2etzbD1kwjvmoKqXqX1yTd4RblMwhhKyUDFzSxWwija/jcsPpFqOznwWD5z95EncPsLXGvjsMwxr7Fg==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^13.0.0",
|
||||
"@angular/core": "^13.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vality/swag-organizations": {
|
||||
"version": "1.0.1-cd6cc10.0",
|
||||
"resolved": "https://registry.npmjs.org/@vality/swag-organizations/-/swag-organizations-1.0.1-cd6cc10.0.tgz",
|
||||
@ -21318,14 +21305,6 @@
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"@vality/swag-messages": {
|
||||
"version": "1.0.1-03e1014.0",
|
||||
"resolved": "https://registry.npmjs.org/@vality/swag-messages/-/swag-messages-1.0.1-03e1014.0.tgz",
|
||||
"integrity": "sha512-iaKra/x2etzbD1kwjvmoKqXqX1yTd4RblMwhhKyUDFzSxWwija/jcsPpFqOznwWD5z95EncPsLXGvjsMwxr7Fg==",
|
||||
"requires": {
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"@vality/swag-organizations": {
|
||||
"version": "1.0.1-cd6cc10.0",
|
||||
"resolved": "https://registry.npmjs.org/@vality/swag-organizations/-/swag-organizations-1.0.1-cd6cc10.0.tgz",
|
||||
|
@ -13,7 +13,7 @@
|
||||
"i18n:extract": "transloco-keys-manager extract",
|
||||
"i18n:check": "transloco-keys-manager find --emit-error-on-extra-keys",
|
||||
"coverage": "npx http-server -c-1 -o -p 9875 ./coverage",
|
||||
"lint-cmd": "eslint \"src/**/*.{ts,js,html}\" --max-warnings 1137",
|
||||
"lint-cmd": "eslint \"src/**/*.{ts,js,html}\" --max-warnings 1067",
|
||||
"lint": "npm run lint-cmd",
|
||||
"lint-fix": "npm run lint-cmd -- --fix",
|
||||
"lint-errors": "npm run lint-cmd -- --quiet",
|
||||
@ -52,7 +52,6 @@
|
||||
"@vality/swag-anapi-v2": "2.0.1-0405be2.0",
|
||||
"@vality/swag-claim-management": "0.1.1-bfc2e6c.0",
|
||||
"@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-d71aebc.0",
|
||||
"@vality/swag-questionary-aggr-proxy": "0.1.1-1dc5add.0",
|
||||
|
@ -1,9 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ConversationsService as ApiConversationsService } from '@vality/swag-messages';
|
||||
|
||||
import { createApi } from '../utils';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ConversationsService extends createApi(ApiConversationsService) {}
|
@ -1,3 +0,0 @@
|
||||
export * from './messages.module';
|
||||
export * from './conversations.service';
|
||||
export * from './utils';
|
@ -1,16 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Configuration } from '@vality/swag-messages';
|
||||
|
||||
import { ConfigService } from '../../config';
|
||||
|
||||
@NgModule({
|
||||
providers: [
|
||||
{
|
||||
provide: Configuration,
|
||||
deps: [ConfigService],
|
||||
useFactory: (configService: ConfigService) =>
|
||||
new Configuration({ basePath: `${configService.apiEndpoint}/dark-api/v1` }),
|
||||
},
|
||||
],
|
||||
})
|
||||
export class MessagesModule {}
|
@ -1,6 +0,0 @@
|
||||
import { ConversationParam } from '@vality/swag-messages';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
export const createSingleMessageConversationParams = (conversationId: string, text: string): ConversationParam[] => [
|
||||
{ conversationId, messages: [{ messageId: uuid(), text }] },
|
||||
];
|
@ -1 +0,0 @@
|
||||
export * from './create-single-message-conversation-params';
|
@ -19,7 +19,6 @@ import * as Sentry from '@sentry/angular';
|
||||
import { AnapiModule } from '@dsh/api/anapi';
|
||||
import { ClaimManagementModule } from '@dsh/api/claim-management';
|
||||
import { DarkApiModule } from '@dsh/api/dark-api';
|
||||
import { MessagesModule } from '@dsh/api/messages';
|
||||
import { PaymentsModule } from '@dsh/api/payments';
|
||||
import { QuestionaryAggrProxyModule } from '@dsh/api/questionary-aggr-proxy';
|
||||
import { UrlShortenerModule } from '@dsh/api/url-shortener';
|
||||
@ -62,7 +61,6 @@ import { TranslocoHttpLoaderService } from './transloco-http-loader.service';
|
||||
ClaimManagementModule,
|
||||
AnapiModule,
|
||||
PaymentsModule,
|
||||
MessagesModule,
|
||||
OrganizationsModule,
|
||||
UrlShortenerModule,
|
||||
QuestionaryAggrProxyModule,
|
||||
|
@ -12,6 +12,5 @@ export interface Config {
|
||||
};
|
||||
sentryDsn?: string;
|
||||
keycloakEndpoint: string;
|
||||
fileStorageEndpoint: string;
|
||||
}
|
||||
export const BASE_CONFIG = getBaseClass<Config>();
|
||||
|
@ -28,7 +28,7 @@ export const initializer =
|
||||
},
|
||||
loadUserProfileAtStartUp: true,
|
||||
enableBearerInterceptor: true,
|
||||
bearerExcludedUrls: ['/assets', configService.fileStorageEndpoint],
|
||||
bearerExcludedUrls: ['/assets'],
|
||||
bearerPrefix: 'Bearer',
|
||||
}),
|
||||
])
|
||||
|
@ -1,9 +0,0 @@
|
||||
<dsh-panel>
|
||||
<dsh-panel-header>
|
||||
{{ comment$ | async }}
|
||||
<div *transloco="let c; scope: 'components'; read: 'components.shared'">
|
||||
<div *ngIf="isLoading$ | async">{{ c('loading') }}</div>
|
||||
<div *ngIf="error$ | async">{{ c('httpError') }}</div>
|
||||
</div>
|
||||
</dsh-panel-header>
|
||||
</dsh-panel>
|
@ -1,25 +0,0 @@
|
||||
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { CommentModificationUnit } from '@vality/swag-claim-management';
|
||||
|
||||
import { CommentContainerService } from './comment-container.service';
|
||||
|
||||
@Component({
|
||||
selector: 'dsh-comment-container',
|
||||
templateUrl: 'comment-container.component.html',
|
||||
providers: [CommentContainerService],
|
||||
})
|
||||
export class CommentContainerComponent implements OnChanges {
|
||||
@Input() unit: CommentModificationUnit;
|
||||
|
||||
comment$ = this.commentContainerService.comment$;
|
||||
isLoading$ = this.commentContainerService.isLoading$;
|
||||
error$ = this.commentContainerService.error$;
|
||||
|
||||
constructor(private commentContainerService: CommentContainerService) {}
|
||||
|
||||
ngOnChanges({ unit }: SimpleChanges) {
|
||||
if (unit.firstChange || unit.currentValue.commentId !== unit.previousValue.commentId) {
|
||||
this.commentContainerService.receiveConversation(unit.currentValue.commentId);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
import { TranslocoModule } from '@ngneat/transloco';
|
||||
|
||||
import { MessagesModule } from '@dsh/api/messages';
|
||||
import { LayoutModule } from '@dsh/components/layout';
|
||||
|
||||
import { CommentContainerComponent } from './comment-container.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, LayoutModule, FlexLayoutModule, TranslocoModule, MessagesModule],
|
||||
declarations: [CommentContainerComponent],
|
||||
exports: [CommentContainerComponent],
|
||||
})
|
||||
export class CommentContainerModule {}
|
@ -1,35 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Subject } from 'rxjs';
|
||||
import { map, pluck, shareReplay, switchMap } from 'rxjs/operators';
|
||||
|
||||
import { ConversationsService } from '@dsh/api/messages';
|
||||
import { takeError } from '@dsh/operators';
|
||||
|
||||
@Injectable()
|
||||
export class CommentContainerService {
|
||||
private receiveConversation$: Subject<string> = new Subject();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
comment$ = this.receiveConversation$.pipe(
|
||||
switchMap((conversationId) => this.conversationsService.getConversations({ conversationId: [conversationId] })),
|
||||
map(({ conversations }) =>
|
||||
conversations.reduce((acc, { messages }) => (messages.length > 0 ? messages[0] : acc), { text: '' })
|
||||
),
|
||||
pluck('text'),
|
||||
shareReplay(1)
|
||||
);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
isLoading$ = this.comment$.pipe(shareReplay(1));
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
error$ = this.comment$.pipe(takeError, shareReplay(1));
|
||||
|
||||
constructor(private conversationsService: ConversationsService) {
|
||||
this.comment$.subscribe();
|
||||
}
|
||||
|
||||
receiveConversation(commentId: string) {
|
||||
this.receiveConversation$.next(commentId);
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
export * from './comment-container.module';
|
@ -1,13 +0,0 @@
|
||||
<dsh-panel *transloco="let c; scope: 'components'; read: 'components.shared'" color="accent">
|
||||
<dsh-panel-header>
|
||||
<div *ngIf="isLoading$ | async">{{ c('loading') }}</div>
|
||||
<div *ngIf="error$ | async">{{ c('httpError') }}</div>
|
||||
<div *ngIf="fileInfo$ | async as fileInfo" fxLayout="row" fxLayoutAlign="space-between" fxLayoutGap="20px">
|
||||
<div>{{ fileInfo.fileName }}</div>
|
||||
<div fxLayout="row" fxLayoutGap="8px" fxLayoutAlign=" center">
|
||||
<dsh-bi *ngIf="deletion" class="icon" icon="x" size="lg" (click)="deleteByCondition()"></dsh-bi>
|
||||
<dsh-panel-header-icon class="icon" icon="save" (click)="download()"></dsh-panel-header-icon>
|
||||
</div>
|
||||
</div>
|
||||
</dsh-panel-header>
|
||||
</dsh-panel>
|
@ -1,3 +0,0 @@
|
||||
.icon {
|
||||
cursor: pointer;
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { FileModificationUnit } from '@vality/swag-claim-management';
|
||||
import { filter } from 'rxjs/operators';
|
||||
|
||||
import { ConfirmActionDialogComponent } from '@dsh/components/popups';
|
||||
|
||||
import { coerceBoolean } from '../../../../../utils';
|
||||
import { FileContainerService } from './file-container.service';
|
||||
|
||||
@Component({
|
||||
selector: 'dsh-file-container',
|
||||
templateUrl: 'file-container.component.html',
|
||||
styleUrls: ['file-container.component.scss'],
|
||||
providers: [FileContainerService],
|
||||
})
|
||||
export class FileContainerComponent implements OnChanges {
|
||||
@Input() unit: FileModificationUnit;
|
||||
@Input() @coerceBoolean deletion = false;
|
||||
@Output() delete = new EventEmitter<FileModificationUnit>();
|
||||
|
||||
fileInfo$ = this.fileContainerService.fileInfo$;
|
||||
isLoading$ = this.fileContainerService.isLoading$;
|
||||
error$ = this.fileContainerService.error$;
|
||||
|
||||
constructor(private fileContainerService: FileContainerService, private dialog: MatDialog) {}
|
||||
|
||||
ngOnChanges({ unit }: SimpleChanges) {
|
||||
if (unit.firstChange || unit.currentValue.fileId !== unit.previousValue.fileId) {
|
||||
this.fileContainerService.getFileInfo(unit.currentValue.fileId);
|
||||
}
|
||||
}
|
||||
|
||||
download() {
|
||||
this.fileContainerService.downloadFile(this.unit.fileId);
|
||||
}
|
||||
|
||||
deleteByCondition() {
|
||||
this.dialog
|
||||
.open(ConfirmActionDialogComponent)
|
||||
.afterClosed()
|
||||
.pipe(filter((r) => r === 'confirm'))
|
||||
.subscribe(() => {
|
||||
this.delete.emit(this.unit);
|
||||
});
|
||||
}
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { TranslocoModule } from '@ngneat/transloco';
|
||||
|
||||
import { BootstrapIconModule } from '@dsh/components/indicators';
|
||||
import { LayoutModule } from '@dsh/components/layout';
|
||||
import { ConfirmActionDialogModule } from '@dsh/components/popups';
|
||||
|
||||
import { FileContainerComponent } from './file-container.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
FlexLayoutModule,
|
||||
LayoutModule,
|
||||
TranslocoModule,
|
||||
ConfirmActionDialogModule,
|
||||
MatDialogModule,
|
||||
BootstrapIconModule,
|
||||
],
|
||||
declarations: [FileContainerComponent],
|
||||
exports: [FileContainerComponent],
|
||||
})
|
||||
export class FileContainerModule {}
|
@ -1,46 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { TranslocoService } from '@ngneat/transloco';
|
||||
import { FileData } from '@vality/swag-dark-api';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { shareReplay, switchMap } from 'rxjs/operators';
|
||||
|
||||
import { FilesService } from '@dsh/api/dark-api';
|
||||
import { takeError } from '@dsh/operators';
|
||||
import { download } from '@dsh/utils';
|
||||
|
||||
@Injectable()
|
||||
export class FileContainerService {
|
||||
private getFileInfo$ = new Subject<string>();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
fileInfo$: Observable<FileData> = this.getFileInfo$.pipe(
|
||||
switchMap((fileID) => this.filesService.getDecodedFileInfo({ fileID })),
|
||||
shareReplay(1)
|
||||
);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
isLoading$ = this.fileInfo$.pipe(shareReplay(1));
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
error$ = this.fileInfo$.pipe(takeError, shareReplay(1));
|
||||
|
||||
constructor(
|
||||
private filesService: FilesService,
|
||||
private snackBar: MatSnackBar,
|
||||
private transloco: TranslocoService
|
||||
) {
|
||||
this.fileInfo$.subscribe();
|
||||
}
|
||||
|
||||
getFileInfo(fileID: string) {
|
||||
this.getFileInfo$.next(fileID);
|
||||
}
|
||||
|
||||
downloadFile(fileID: string) {
|
||||
this.filesService.downloadFile({ fileID }).subscribe(
|
||||
({ url }) => download(url),
|
||||
() => this.snackBar.open(this.transloco.translate('shared.commonError', null, 'components'), 'OK')
|
||||
);
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
export * from './file-container.module';
|
@ -1,2 +0,0 @@
|
||||
export * from './comment-container';
|
||||
export * from './file-container';
|
@ -15,10 +15,6 @@ const CLAIM_SECTION_ROUTES: Routes = [
|
||||
path: 'claims',
|
||||
loadChildren: () => import('./claims/claims.module').then((m) => m.ClaimsModule),
|
||||
},
|
||||
{
|
||||
path: 'claims/:claimId',
|
||||
loadChildren: () => import('./claim/claim.module').then((m) => m.ClaimModule),
|
||||
},
|
||||
{ path: '', redirectTo: 'claims', pathMatch: 'full' },
|
||||
],
|
||||
},
|
||||
|
@ -1,17 +0,0 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { ClaimComponent } from './claim.component';
|
||||
|
||||
const CLAIM_ROUTES: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: ClaimComponent,
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(CLAIM_ROUTES)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class ClaimRoutingModule {}
|
@ -1,58 +0,0 @@
|
||||
<div
|
||||
*transloco="let t; scope: 'claim-section'; read: 'claimSection.claim'"
|
||||
class="container"
|
||||
fxLayout="column"
|
||||
fxLayoutGap="32px"
|
||||
>
|
||||
<div fxLayout="column" fxLayoutGap="8px">
|
||||
<h1 class="dsh-display-1">
|
||||
{{ t('headline') }} <span dshTextColor="secondary">#{{ claimID$ | async }}</span>
|
||||
</h1>
|
||||
<ol dsh-breadcrumb>
|
||||
<li dsh-breadcrumb-item>
|
||||
<a dshTextColor="secondary" [routerLink]="['/claim-section/claims']">{{ t('breadcrumbs.claims') }}</a>
|
||||
</li>
|
||||
<li dsh-breadcrumb-item>{{ t('breadcrumbs.claimDetails') }}</li>
|
||||
</ol>
|
||||
</div>
|
||||
<ng-container *ngIf="!(error$ | async)">
|
||||
<ng-container *ngIf="isLoading$ | async | debounce; else content">
|
||||
<div fxLayout fxLayoutAlign="center center">
|
||||
<dsh-spinner></dsh-spinner>
|
||||
</div>
|
||||
</ng-container>
|
||||
<ng-template #content>
|
||||
<dsh-card>
|
||||
<dsh-status class="claim-status" [color]="claimStatus$ | async | claimStatusColor" mark="false">
|
||||
{{ (claimStatusDict$ | async)?.[claimStatus$ | async] }}
|
||||
</dsh-status>
|
||||
<div fxLayout="column" fxLayoutGap="24px">
|
||||
<dsh-conversation></dsh-conversation>
|
||||
<div fxLayout="row" fxLayoutAlign="space-between">
|
||||
<div>
|
||||
<button
|
||||
*ngIf="revokeAvailable$ | async"
|
||||
dsh-text-button
|
||||
color="warn"
|
||||
(click)="revokeClaim()"
|
||||
>
|
||||
{{ t('revokeClaim') }}
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
*ngIf="reviewAvailable$ | async"
|
||||
[disabled]="reviewInProgress$ | async"
|
||||
dsh-button
|
||||
color="accent"
|
||||
(click)="reviewClaim()"
|
||||
>
|
||||
{{ t('reviewClaim') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</dsh-card>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</div>
|
@ -1,13 +0,0 @@
|
||||
$dsh-claim-details-padding: 80px 0 0 0;
|
||||
$dsh-claim-details-max-width: 936px;
|
||||
|
||||
.container {
|
||||
padding: $dsh-claim-details-padding;
|
||||
max-width: $dsh-claim-details-max-width;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.claim-status {
|
||||
position: absolute;
|
||||
right: 24px;
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||
import { pluck } from 'rxjs/operators';
|
||||
|
||||
import { ClaimManagementDictionaryService } from '@dsh/api/claim-management';
|
||||
|
||||
import { ReceiveClaimService } from './receive-claim.service';
|
||||
import { ReviewClaimService } from './review-claim.service';
|
||||
import { RevokeClaimService } from './revoke-claim.service';
|
||||
import { RouteParamClaimService } from './route-param-claim.service';
|
||||
import { UpdateClaimService } from './update-claim';
|
||||
|
||||
@Component({
|
||||
templateUrl: 'claim.component.html',
|
||||
styleUrls: ['claim.component.scss'],
|
||||
providers: [
|
||||
RouteParamClaimService,
|
||||
ReceiveClaimService,
|
||||
RevokeClaimService,
|
||||
UpdateClaimService,
|
||||
ReviewClaimService,
|
||||
],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ClaimComponent implements OnInit {
|
||||
claimID$ = this.receiveClaimService.claim$.pipe(pluck('id'));
|
||||
claimStatus$ = this.receiveClaimService.claim$.pipe(pluck('status'));
|
||||
isLoading$ = this.receiveClaimService.isLoading$;
|
||||
error$ = this.receiveClaimService.error$;
|
||||
revokeAvailable$ = this.revokeClaimService.revokeAvailable$;
|
||||
reviewAvailable$ = this.reviewClaimService.reviewAvailable$;
|
||||
reviewInProgress$ = this.reviewClaimService.inProgress$;
|
||||
claimStatusDict$ = this.claimManagementDictionaryService.claimStatus$;
|
||||
|
||||
constructor(
|
||||
private receiveClaimService: ReceiveClaimService,
|
||||
private revokeClaimService: RevokeClaimService,
|
||||
private reviewClaimService: ReviewClaimService,
|
||||
private claimManagementDictionaryService: ClaimManagementDictionaryService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.receiveClaimService.receiveClaim();
|
||||
}
|
||||
|
||||
revokeClaim() {
|
||||
this.revokeClaimService.revokeClaim();
|
||||
}
|
||||
|
||||
reviewClaim() {
|
||||
this.reviewClaimService.reviewClaim();
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { TranslocoModule } from '@ngneat/transloco';
|
||||
|
||||
import { BaseDialogModule } from '@dsh/app/shared/components/dialog/base-dialog';
|
||||
import { ApiModelTypesModule } from '@dsh/app/shared/pipes/api-model-types';
|
||||
import { ButtonModule } from '@dsh/components/buttons';
|
||||
import { IndicatorsModule } from '@dsh/components/indicators';
|
||||
import { LayoutModule } from '@dsh/components/layout';
|
||||
import { BreadcrumbModule } from '@dsh/components/navigation';
|
||||
import { ConfirmActionDialogModule } from '@dsh/components/popups';
|
||||
import { DebounceModule } from '@dsh/pipes/debounce/debounce.module';
|
||||
|
||||
import { ClaimRoutingModule } from './claim-routing.module';
|
||||
import { ClaimComponent } from './claim.component';
|
||||
import { ConversationModule } from './conversation';
|
||||
import { RevokeClaimDialogComponent } from './revoke-claim-dialog';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
LayoutModule,
|
||||
ButtonModule,
|
||||
FlexLayoutModule,
|
||||
ClaimRoutingModule,
|
||||
ConversationModule,
|
||||
TranslocoModule,
|
||||
IndicatorsModule,
|
||||
ReactiveFormsModule,
|
||||
MatInputModule,
|
||||
ConfirmActionDialogModule,
|
||||
BaseDialogModule,
|
||||
MatSelectModule,
|
||||
BreadcrumbModule,
|
||||
ApiModelTypesModule,
|
||||
DebounceModule,
|
||||
],
|
||||
declarations: [ClaimComponent, RevokeClaimDialogComponent],
|
||||
})
|
||||
export class ClaimModule {}
|
@ -1,20 +0,0 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
import { StatusColor } from '../../../../theme-manager';
|
||||
import { TimelineAction } from './to-timeline-info';
|
||||
|
||||
@Pipe({
|
||||
name: 'actionColor',
|
||||
})
|
||||
export class ActionColorPipe implements PipeTransform {
|
||||
transform(action: TimelineAction): StatusColor | null {
|
||||
switch (action) {
|
||||
case TimelineAction.StatusAccepted:
|
||||
return StatusColor.Success;
|
||||
case TimelineAction.StatusDenied:
|
||||
case TimelineAction.StatusRevoked:
|
||||
return StatusColor.Warn;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
import { TimelineAction } from './to-timeline-info';
|
||||
|
||||
@Pipe({
|
||||
name: 'actionIcon',
|
||||
})
|
||||
export class ActionIconPipe implements PipeTransform {
|
||||
transform(action: TimelineAction): string {
|
||||
return (
|
||||
{
|
||||
[TimelineAction.StatusPending]: 'plus',
|
||||
[TimelineAction.StatusReview]: 'check',
|
||||
[TimelineAction.StatusRevoked]: 'x',
|
||||
[TimelineAction.StatusDenied]: 'x',
|
||||
[TimelineAction.StatusAccepted]: 'check-all',
|
||||
[TimelineAction.FilesAdded]: 'plus',
|
||||
[TimelineAction.CommentAdded]: 'plus',
|
||||
[TimelineAction.ChangesAdded]: 'plus',
|
||||
} as const
|
||||
)[action];
|
||||
}
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
<div *transloco="let t; scope: 'claim-section'; read: 'claimSection.conversation'" fxLayout="column" fxLayoutGap="20px">
|
||||
<dsh-timeline>
|
||||
<dsh-timeline-item>
|
||||
<dsh-timeline-item-title>
|
||||
<span>{{ t('timeline.claimCreated') }} </span>
|
||||
<span>{{ claimCreatedAt$ | async | humanizedDuration: { largest: 1 } }} {{ t('ago') }}</span>
|
||||
</dsh-timeline-item-title>
|
||||
<dsh-timeline-item-badge>
|
||||
<dsh-bi icon="pencil" size="sm"></dsh-bi>
|
||||
</dsh-timeline-item-badge>
|
||||
</dsh-timeline-item>
|
||||
<dsh-timeline-item *ngFor="let item of timelineInfo$ | async; trackBy: simpleTrackBy">
|
||||
<dsh-timeline-item-title>
|
||||
<div fxFlex fxLayout="row" fxLayoutAlign="space-between end">
|
||||
<div>
|
||||
<span class="dsh-body-2">{{ userTypeLabels[item.userInfo.userType] | async }} </span>
|
||||
<span class="mat-body-2">{{ timelineActionLabels[item.action] | async }} </span>
|
||||
<span>{{ item.createdAt | humanizedDuration: { largest: 1 } }} {{ t('ago') }}</span>
|
||||
</div>
|
||||
<dsh-bi
|
||||
*ngIf="item.action === 'changesAdded'"
|
||||
class="title-action-icon"
|
||||
svgIcon="three-dots"
|
||||
[matMenuTriggerFor]="menu"
|
||||
></dsh-bi>
|
||||
</div>
|
||||
<mat-menu #menu="matMenu" xPosition="before">
|
||||
<button mat-menu-item (click)="expandAll = !expandAll">{{ t('action.toggleDetails') }}</button>
|
||||
</mat-menu>
|
||||
</dsh-timeline-item-title>
|
||||
<dsh-timeline-item-badge [color]="item.action | actionColor">
|
||||
<dsh-bi [icon]="item.action | actionIcon"></dsh-bi>
|
||||
</dsh-timeline-item-badge>
|
||||
<dsh-timeline-item-content *ngIf="item.modifications.length !== 0">
|
||||
<div *ngFor="let modification of item.modifications; trackBy: simpleTrackBy">
|
||||
<dsh-comment-container
|
||||
*ngIf="isCommentModificationUnit(modification)"
|
||||
[unit]="modification.claimModificationType"
|
||||
></dsh-comment-container>
|
||||
<dsh-file-container
|
||||
*ngIf="isFileModificationUnit(modification)"
|
||||
[unit]="modification.claimModificationType"
|
||||
deletion
|
||||
(delete)="deleteFile(modification)"
|
||||
></dsh-file-container>
|
||||
</div>
|
||||
</dsh-timeline-item-content>
|
||||
</dsh-timeline-item>
|
||||
</dsh-timeline>
|
||||
<dsh-send-comment (conversationSaved)="commentSaved($event)"></dsh-send-comment>
|
||||
</div>
|
@ -1,3 +0,0 @@
|
||||
.title-action-icon {
|
||||
cursor: pointer;
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { TranslocoService } from '@ngneat/transloco';
|
||||
import { FileModificationUnit, Modification, UserInfo } from '@vality/swag-claim-management';
|
||||
import { Conversation } from '@vality/swag-messages';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import {
|
||||
isClaimModification,
|
||||
isCommentModificationUnit,
|
||||
isFileModificationUnit,
|
||||
SpecificClaimModificationUnit,
|
||||
} from '@dsh/api/claim-management';
|
||||
|
||||
import { ConversationService } from './conversation.service';
|
||||
|
||||
import UserTypeEnum = UserInfo.UserTypeEnum;
|
||||
|
||||
@Component({
|
||||
selector: 'dsh-conversation',
|
||||
templateUrl: 'conversation.component.html',
|
||||
styleUrls: ['conversation.component.scss'],
|
||||
providers: [ConversationService],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ConversationComponent {
|
||||
timelineInfo$ = this.conversationService.timelineInfo$;
|
||||
claimCreatedAt$ = this.conversationService.claimCreatedAt$;
|
||||
timelineActionLabels = this.getTimelineActionLabels();
|
||||
userTypeLabels = this.getUserTypeLabels();
|
||||
|
||||
expandAll = false;
|
||||
|
||||
constructor(private conversationService: ConversationService, private transloco: TranslocoService) {}
|
||||
|
||||
isCommentModificationUnit(m: Modification): boolean {
|
||||
return isClaimModification(m) && isCommentModificationUnit(m.claimModificationType);
|
||||
}
|
||||
|
||||
isFileModificationUnit(m: Modification): boolean {
|
||||
return isClaimModification(m) && isFileModificationUnit(m.claimModificationType);
|
||||
}
|
||||
|
||||
commentSaved(id: Conversation['conversationId']) {
|
||||
this.conversationService.commentSaved(id);
|
||||
}
|
||||
|
||||
simpleTrackBy(index: number): number {
|
||||
return index;
|
||||
}
|
||||
|
||||
deleteFile(m: SpecificClaimModificationUnit<FileModificationUnit>) {
|
||||
this.conversationService.deleteFile(m.claimModificationType.fileId);
|
||||
}
|
||||
|
||||
private getTimelineActionLabels() {
|
||||
return {
|
||||
changesAdded: this.transloco.selectTranslate(
|
||||
'conversation.timelineActions.changesAdded',
|
||||
null,
|
||||
'claim-section'
|
||||
),
|
||||
commentAdded: this.transloco.selectTranslate(
|
||||
'conversation.timelineActions.commentAdded',
|
||||
null,
|
||||
'claim-section'
|
||||
),
|
||||
filesAdded: this.transloco.selectTranslate(
|
||||
'conversation.timelineActions.filesAdded',
|
||||
null,
|
||||
'claim-section'
|
||||
),
|
||||
statusAccepted: this.transloco.selectTranslate(
|
||||
'conversation.timelineActions.statusAccepted',
|
||||
null,
|
||||
'claim-section'
|
||||
),
|
||||
statusDenied: this.transloco.selectTranslate(
|
||||
'conversation.timelineActions.statusDenied',
|
||||
null,
|
||||
'claim-section'
|
||||
),
|
||||
statusPending: this.transloco.selectTranslate(
|
||||
'conversation.timelineActions.statusPending',
|
||||
null,
|
||||
'claim-section'
|
||||
),
|
||||
statusReview: this.transloco.selectTranslate(
|
||||
'conversation.timelineActions.statusReview',
|
||||
null,
|
||||
'claim-section'
|
||||
),
|
||||
statusRevoked: this.transloco.selectTranslate(
|
||||
'conversation.timelineActions.statusRevoked',
|
||||
null,
|
||||
'claim-section'
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
private getUserTypeLabels(): Record<UserTypeEnum, Observable<string>> {
|
||||
return {
|
||||
internal_user: this.transloco.selectTranslate(
|
||||
'conversation.userTypes.internal_user',
|
||||
null,
|
||||
'claim-section'
|
||||
),
|
||||
external_user: this.transloco.selectTranslate(
|
||||
'conversation.userTypes.external_user',
|
||||
null,
|
||||
'claim-section'
|
||||
),
|
||||
};
|
||||
}
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { TranslocoModule } from '@ngneat/transloco';
|
||||
import { ngfModule } from 'angular-file';
|
||||
|
||||
import { MessagesModule } from '@dsh/api/messages';
|
||||
import { ButtonModule } from '@dsh/components/buttons';
|
||||
import { BootstrapIconModule } from '@dsh/components/indicators';
|
||||
import { LayoutModule } from '@dsh/components/layout';
|
||||
import { ConfirmActionDialogModule } from '@dsh/components/popups';
|
||||
|
||||
import { HumanizeDurationModule } from '../../../../humanize-duration';
|
||||
import { CommentContainerModule, FileContainerModule } from '../../claim-modification-containers';
|
||||
import { ActionColorPipe } from './action-color.pipe';
|
||||
import { ActionIconPipe } from './action-icon.pipe';
|
||||
import { ConversationComponent } from './conversation.component';
|
||||
import { SendCommentComponent } from './send-comment';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
LayoutModule,
|
||||
ButtonModule,
|
||||
FlexLayoutModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
BootstrapIconModule,
|
||||
CommonModule,
|
||||
HumanizeDurationModule,
|
||||
TranslocoModule,
|
||||
CommentContainerModule,
|
||||
FileContainerModule,
|
||||
ReactiveFormsModule,
|
||||
MessagesModule,
|
||||
MatMenuModule,
|
||||
ConfirmActionDialogModule,
|
||||
ngfModule,
|
||||
],
|
||||
declarations: [ConversationComponent, ActionColorPipe, ActionIconPipe, SendCommentComponent],
|
||||
exports: [ConversationComponent],
|
||||
})
|
||||
export class ConversationModule {}
|
@ -1,24 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { FileModification } from '@vality/swag-claim-management';
|
||||
import { Conversation } from '@vality/swag-messages';
|
||||
import { map, pluck, shareReplay } from 'rxjs/operators';
|
||||
|
||||
import { ReceiveClaimService } from '../receive-claim.service';
|
||||
import { UpdateClaimService } from '../update-claim';
|
||||
import { toTimelineInfo } from './to-timeline-info';
|
||||
|
||||
@Injectable()
|
||||
export class ConversationService {
|
||||
timelineInfo$ = this.receiveClaimService.claim$.pipe(pluck('changeset'), map(toTimelineInfo), shareReplay(1));
|
||||
claimCreatedAt$ = this.receiveClaimService.claim$.pipe(pluck('createdAt'), shareReplay(1));
|
||||
|
||||
constructor(private receiveClaimService: ReceiveClaimService, private updateClaimService: UpdateClaimService) {}
|
||||
|
||||
commentSaved(id: Conversation['conversationId']) {
|
||||
this.updateClaimService.updateByConversation(id);
|
||||
}
|
||||
|
||||
deleteFile(id: string) {
|
||||
this.updateClaimService.updateByFiles([id], FileModification.FileModificationTypeEnum.FileDeleted);
|
||||
}
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
export * from './conversation.component';
|
||||
export * from './conversation.module';
|
@ -1 +0,0 @@
|
||||
export * from './send-comment.component';
|
@ -1,38 +0,0 @@
|
||||
<div *transloco="let t; scope: 'claim-section'; read: 'claimSection.conversation'">
|
||||
<form [formGroup]="form" fxLayout="row" fxLayoutGap="10px">
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>{{ t('sendComment') }}</mat-label>
|
||||
<input formControlName="comment" matInput type="text" autocomplete="off" />
|
||||
</mat-form-field>
|
||||
<div class="action">
|
||||
<button
|
||||
dsh-icon-button
|
||||
color="accent"
|
||||
(click)="sendComment(form.value.comment)"
|
||||
[disabled]="(inProgress$ | async) || !form.valid"
|
||||
>
|
||||
<dsh-bi icon="send"></dsh-bi>
|
||||
</button>
|
||||
</div>
|
||||
<div class="action">
|
||||
<button
|
||||
dsh-icon-button
|
||||
[disabled]="inProgress$ | async"
|
||||
ngfSelect
|
||||
(filesChange)="startUploading($event)"
|
||||
[files]="[]"
|
||||
>
|
||||
<dsh-bi icon="paperclip"></dsh-bi>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div *ngIf="errorCode$ | async">
|
||||
<div
|
||||
*transloco="let errors; scope: 'claim-section'; read: 'claimSection.sendComment.errors'"
|
||||
class="mat-caption"
|
||||
>
|
||||
<!-- t(saveConversationsFailed) -->
|
||||
{{ errors(errorCode$ | async) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,5 +0,0 @@
|
||||
$dsh-action-padding: 10px 0 0 0;
|
||||
|
||||
.action {
|
||||
padding: $dsh-action-padding;
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Output } from '@angular/core';
|
||||
import { UntypedFormGroup } from '@angular/forms';
|
||||
import { Conversation } from '@vality/swag-messages';
|
||||
import { combineLatest } from 'rxjs';
|
||||
import { map, shareReplay } from 'rxjs/operators';
|
||||
|
||||
import { SendCommentService } from './send-comment.service';
|
||||
import { UploadFilesService } from './upload-files.service';
|
||||
|
||||
@Component({
|
||||
selector: 'dsh-send-comment',
|
||||
templateUrl: 'send-comment.component.html',
|
||||
styleUrls: ['send-comment.component.scss'],
|
||||
providers: [SendCommentService, UploadFilesService],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class SendCommentComponent {
|
||||
@Output() conversationSaved: EventEmitter<Conversation['conversationId']> = new EventEmitter();
|
||||
|
||||
form: UntypedFormGroup = this.sendCommentService.form;
|
||||
errorCode$ = this.sendCommentService.errorCode$;
|
||||
inProgress$ = combineLatest([this.sendCommentService.inProgress$, this.fileUploaderService.isUploading$]).pipe(
|
||||
map((v) => v.includes(true)),
|
||||
shareReplay(1)
|
||||
);
|
||||
|
||||
constructor(private sendCommentService: SendCommentService, private fileUploaderService: UploadFilesService) {
|
||||
this.sendCommentService.conversationSaved$.subscribe((id) => this.conversationSaved.next(id));
|
||||
}
|
||||
|
||||
sendComment(comment: string) {
|
||||
this.sendCommentService.sendComment(comment);
|
||||
}
|
||||
|
||||
startUploading(files: File[]) {
|
||||
this.fileUploaderService.uploadFiles(files);
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { Conversation } from '@vality/swag-messages';
|
||||
import { BehaviorSubject, forkJoin, merge, Observable, of, Subject, EMPTY } from 'rxjs';
|
||||
import { catchError, filter, pluck, switchMap, tap } from 'rxjs/operators';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { createSingleMessageConversationParams, ConversationsService } from '@dsh/api/messages';
|
||||
import { progress } from '@dsh/operators';
|
||||
|
||||
import { UiError } from '../../../../ui-error';
|
||||
|
||||
@Injectable()
|
||||
export class SendCommentService {
|
||||
private conversationId$: BehaviorSubject<Conversation['conversationId'] | null> = new BehaviorSubject(null);
|
||||
private error$: BehaviorSubject<UiError> = new BehaviorSubject({ hasError: false });
|
||||
private sendComment$: Subject<string> = new Subject();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
form: UntypedFormGroup;
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
conversationSaved$: Observable<Conversation['conversationId']> = this.conversationId$.pipe(filter((id) => !!id));
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
errorCode$: Observable<string> = this.error$.pipe(pluck('code'));
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
inProgress$: Observable<boolean> = progress(this.sendComment$, merge(this.conversationId$, this.error$));
|
||||
|
||||
constructor(private fb: UntypedFormBuilder, private conversationsService: ConversationsService) {
|
||||
this.form = this.fb.group({
|
||||
comment: ['', [Validators.maxLength(1000)]],
|
||||
});
|
||||
this.sendComment$
|
||||
.pipe(
|
||||
tap(() => this.error$.next({ hasError: false })),
|
||||
switchMap((text) => {
|
||||
const conversationId = uuid();
|
||||
const conversationParam = createSingleMessageConversationParams(conversationId, text);
|
||||
return forkJoin([
|
||||
of(conversationId),
|
||||
this.conversationsService.saveConversations({ conversationParam }).pipe(
|
||||
catchError((ex) => {
|
||||
console.error(ex);
|
||||
const error = { hasError: true, code: 'saveConversationsFailed' };
|
||||
this.error$.next(error);
|
||||
return EMPTY;
|
||||
})
|
||||
),
|
||||
]);
|
||||
})
|
||||
)
|
||||
.subscribe(([conversationId]) => {
|
||||
this.conversationId$.next(conversationId);
|
||||
this.form.reset();
|
||||
});
|
||||
}
|
||||
|
||||
sendComment(comment: string) {
|
||||
if (comment.length === 0) {
|
||||
return;
|
||||
}
|
||||
this.sendComment$.next(comment);
|
||||
}
|
||||
}
|
@ -1,55 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { TranslocoService } from '@ngneat/transloco';
|
||||
import { combineLatest, merge, Observable, Subject } from 'rxjs';
|
||||
import { map, share, shareReplay, switchMap } from 'rxjs/operators';
|
||||
|
||||
import { FilesService } from '@dsh/api/dark-api';
|
||||
import { progress, filterError, filterPayload, replaceError } from '@dsh/operators';
|
||||
|
||||
import { UpdateClaimService } from '../../update-claim';
|
||||
|
||||
@Injectable()
|
||||
export class UploadFilesService {
|
||||
private uploadFiles$ = new Subject<File[]>();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
uploadedFiles$: Observable<string[]>;
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
errors$: Observable<any>;
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
isUploading$: Observable<boolean>;
|
||||
|
||||
constructor(
|
||||
private filesService: FilesService,
|
||||
private snackBar: MatSnackBar,
|
||||
private transloco: TranslocoService,
|
||||
private updateClaimService: UpdateClaimService
|
||||
) {
|
||||
const uploadFilesWithError$ = this.uploadFiles$.pipe(
|
||||
switchMap((files) => this.filesService.uploadFiles(files).pipe(replaceError)),
|
||||
share()
|
||||
);
|
||||
this.uploadedFiles$ = uploadFilesWithError$.pipe(filterPayload, shareReplay(1));
|
||||
this.errors$ = uploadFilesWithError$.pipe(filterError, shareReplay(1));
|
||||
const isUploading$ = progress(this.uploadFiles$, merge(this.uploadedFiles$, this.errors$));
|
||||
this.isUploading$ = combineLatest([isUploading$, this.updateClaimService.inProgress$]).pipe(
|
||||
map((v) => v.includes(true)),
|
||||
shareReplay(1)
|
||||
);
|
||||
|
||||
this.errors$.subscribe(() =>
|
||||
this.snackBar.open(this.transloco.translate('shared.commonError', null, 'components'), 'OK')
|
||||
);
|
||||
this.uploadedFiles$.subscribe(() =>
|
||||
this.snackBar.open(this.transloco.translate('conversation.filesUploaded', null, 'claim-section'), 'OK', {
|
||||
duration: 5000,
|
||||
})
|
||||
);
|
||||
this.uploadedFiles$.subscribe((fileIds) => this.updateClaimService.updateByFiles(fileIds));
|
||||
}
|
||||
|
||||
uploadFiles(files: File[]) {
|
||||
this.uploadFiles$.next(files);
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
import {
|
||||
ClaimModificationType,
|
||||
FileModification,
|
||||
FileModificationUnit,
|
||||
StatusModificationUnit,
|
||||
} from '@vality/swag-claim-management';
|
||||
|
||||
import {
|
||||
isCommentModificationUnit,
|
||||
isDocumentModificationUnit,
|
||||
isFileModificationUnit,
|
||||
isStatusModificationUnit,
|
||||
} from '@dsh/api/claim-management';
|
||||
|
||||
import { TimelineAction } from './model';
|
||||
|
||||
function getStatusModificationTimelineAction(unit: StatusModificationUnit): TimelineAction | null {
|
||||
const status = StatusModificationUnit.StatusEnum;
|
||||
switch (unit.status) {
|
||||
case status.Accepted:
|
||||
return TimelineAction.StatusAccepted;
|
||||
case status.Denied:
|
||||
return TimelineAction.StatusDenied;
|
||||
case status.Pending:
|
||||
return TimelineAction.StatusPending;
|
||||
case status.Review:
|
||||
return TimelineAction.StatusReview;
|
||||
case status.Revoked:
|
||||
return TimelineAction.StatusRevoked;
|
||||
case status.PendingAcceptance:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function getFileModificationTimelineAction(unit: FileModificationUnit): TimelineAction {
|
||||
const type = FileModification.FileModificationTypeEnum;
|
||||
switch (unit.fileModification.fileModificationType) {
|
||||
case type.FileCreated:
|
||||
return TimelineAction.FilesAdded;
|
||||
case type.FileDeleted:
|
||||
return TimelineAction.FilesDeleted;
|
||||
}
|
||||
}
|
||||
|
||||
export function getClaimModificationTimelineAction(m: ClaimModificationType): TimelineAction | null {
|
||||
if (isFileModificationUnit(m)) {
|
||||
return getFileModificationTimelineAction(m);
|
||||
} else if (isStatusModificationUnit(m)) {
|
||||
return getStatusModificationTimelineAction(m);
|
||||
} else if (isDocumentModificationUnit(m)) {
|
||||
return TimelineAction.ChangesAdded;
|
||||
} else if (isCommentModificationUnit(m)) {
|
||||
return TimelineAction.CommentAdded;
|
||||
}
|
||||
throw new Error(`Unknown claimModificationType: ${m.claimModificationType}`);
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
export * from './to-timeline-info';
|
||||
export * from './model';
|
@ -1,2 +0,0 @@
|
||||
export * from './timeline-item-info';
|
||||
export * from './timeline-action';
|
@ -1,11 +0,0 @@
|
||||
export enum TimelineAction {
|
||||
ChangesAdded = 'changesAdded',
|
||||
FilesAdded = 'filesAdded',
|
||||
FilesDeleted = 'filesDeleted',
|
||||
CommentAdded = 'commentAdded',
|
||||
StatusReview = 'statusReview',
|
||||
StatusPending = 'statusPending',
|
||||
StatusDenied = 'statusDenied',
|
||||
StatusRevoked = 'statusRevoked',
|
||||
StatusAccepted = 'statusAccepted',
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
import { Modification, UserInfo } from '@vality/swag-claim-management';
|
||||
|
||||
import { TimelineAction } from './timeline-action';
|
||||
|
||||
export interface TimelineItemInfo {
|
||||
action: TimelineAction;
|
||||
userInfo: UserInfo;
|
||||
createdAt: string;
|
||||
modifications: Modification[];
|
||||
}
|
@ -1,229 +0,0 @@
|
||||
import {
|
||||
ClaimModification,
|
||||
Modification,
|
||||
ModificationUnit,
|
||||
StatusModificationUnit,
|
||||
UserInfo,
|
||||
} from '@vality/swag-claim-management';
|
||||
|
||||
import { TimelineAction, TimelineItemInfo } from './model';
|
||||
import { toTimelineInfo } from './to-timeline-info';
|
||||
|
||||
const genUserInfo = (userType: UserInfo.UserTypeEnum): UserInfo => ({
|
||||
userId: '',
|
||||
email: '',
|
||||
username: '',
|
||||
userType,
|
||||
});
|
||||
|
||||
const genPartialModification = (
|
||||
modificationID: number,
|
||||
createdAt: string,
|
||||
modificationType: Modification.ModificationTypeEnum,
|
||||
userType: UserInfo.UserTypeEnum = 'external_user'
|
||||
) => ({
|
||||
modificationID,
|
||||
createdAt: createdAt as any,
|
||||
userInfo: genUserInfo(userType),
|
||||
modification: {
|
||||
modificationType,
|
||||
},
|
||||
});
|
||||
|
||||
const genStatusModificationUnit = (
|
||||
modificationID: number,
|
||||
createdAt: string,
|
||||
status: StatusModificationUnit.StatusEnum
|
||||
): ModificationUnit => {
|
||||
const m = genPartialModification(modificationID, createdAt, 'ClaimModification');
|
||||
return {
|
||||
...m,
|
||||
modification: {
|
||||
...m.modification,
|
||||
claimModificationType: {
|
||||
claimModificationType: 'StatusModificationUnit',
|
||||
status,
|
||||
statusModification: { statusModificationType: 'StatusChanged' },
|
||||
},
|
||||
} as ClaimModification,
|
||||
};
|
||||
};
|
||||
|
||||
const genCommentModificationUnit = (modificationID: number, createdAt: string, commentId: string): ModificationUnit => {
|
||||
const m = genPartialModification(modificationID, createdAt, 'ClaimModification');
|
||||
return {
|
||||
...m,
|
||||
modification: {
|
||||
...m.modification,
|
||||
claimModificationType: {
|
||||
claimModificationType: 'CommentModificationUnit',
|
||||
commentId,
|
||||
commentModification: { commentModificationType: 'CommentCreated' },
|
||||
},
|
||||
} as ClaimModification,
|
||||
};
|
||||
};
|
||||
|
||||
const genFileModificationUnit = (modificationID: number, createdAt: string, fileId: string): ModificationUnit => {
|
||||
const m = genPartialModification(modificationID, createdAt, 'ClaimModification');
|
||||
return {
|
||||
...m,
|
||||
modification: {
|
||||
...m.modification,
|
||||
claimModificationType: {
|
||||
claimModificationType: 'FileModificationUnit',
|
||||
fileId,
|
||||
fileModification: { fileModificationType: 'FileCreated' },
|
||||
},
|
||||
} as ClaimModification,
|
||||
};
|
||||
};
|
||||
|
||||
const genDocumentModificationUnit = (
|
||||
modificationID: number,
|
||||
createdAt: string,
|
||||
documentId: string
|
||||
): ModificationUnit => {
|
||||
const m = genPartialModification(modificationID, createdAt, 'ClaimModification');
|
||||
return {
|
||||
...m,
|
||||
modification: {
|
||||
...m.modification,
|
||||
claimModificationType: {
|
||||
claimModificationType: 'DocumentModificationUnit',
|
||||
documentId,
|
||||
documentModification: { documentModificationType: 'DocumentCreated' },
|
||||
},
|
||||
} as ClaimModification,
|
||||
};
|
||||
};
|
||||
|
||||
describe('toTimelineInfo', () => {
|
||||
it('DocumentModificationUnit should return changesAdded action', () => {
|
||||
const createdAt = '2019-11-21T18:30:00.000000Z';
|
||||
const units = [genDocumentModificationUnit(66, createdAt, '7dfbc2fe-7ac4-416a-9f96-documentId1')];
|
||||
const result = toTimelineInfo(units);
|
||||
const expected = [
|
||||
{
|
||||
action: TimelineAction.ChangesAdded,
|
||||
userInfo: units[0].userInfo,
|
||||
createdAt,
|
||||
modifications: [units[0].modification],
|
||||
} as TimelineItemInfo,
|
||||
];
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('FileModificationUnit should return filesAdded action', () => {
|
||||
const createdAt = '2019-11-21T18:40:00.000000Z';
|
||||
const units = [genFileModificationUnit(67, createdAt, '7dfbc2fe-7ac4-416a-9f96-fileId1')];
|
||||
const result = toTimelineInfo(units);
|
||||
const expected = [
|
||||
{
|
||||
action: TimelineAction.FilesAdded,
|
||||
userInfo: units[0].userInfo,
|
||||
createdAt,
|
||||
modifications: [units[0].modification],
|
||||
} as TimelineItemInfo,
|
||||
];
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('StatusModificationUnit with status review should return statusReview action', () => {
|
||||
const createdAt = '2019-11-21T18:43:00.000000Z';
|
||||
const units = [genStatusModificationUnit(69, createdAt, 'review')];
|
||||
const result = toTimelineInfo(units);
|
||||
const expected = [
|
||||
{
|
||||
action: TimelineAction.StatusReview,
|
||||
userInfo: units[0].userInfo,
|
||||
createdAt,
|
||||
modifications: [],
|
||||
} as TimelineItemInfo,
|
||||
];
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('StatusModificationUnit with status accepted should return statusAccepted action', () => {
|
||||
const createdAt = '2019-11-21T18:43:00.000000Z';
|
||||
const units = [genStatusModificationUnit(69, createdAt, 'accepted')];
|
||||
const result = toTimelineInfo(units);
|
||||
const expected = [
|
||||
{
|
||||
action: TimelineAction.StatusAccepted,
|
||||
userInfo: units[0].userInfo,
|
||||
createdAt,
|
||||
modifications: [],
|
||||
} as TimelineItemInfo,
|
||||
];
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('StatusModificationUnit with status denied should return statusDenied action', () => {
|
||||
const createdAt = '2019-11-21T18:43:00.000000Z';
|
||||
const units = [genStatusModificationUnit(69, createdAt, 'denied')];
|
||||
const result = toTimelineInfo(units);
|
||||
const expected = [
|
||||
{
|
||||
action: TimelineAction.StatusDenied,
|
||||
userInfo: units[0].userInfo,
|
||||
createdAt,
|
||||
modifications: [],
|
||||
} as TimelineItemInfo,
|
||||
];
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('StatusModificationUnit with status revoked should return statusRevoked action', () => {
|
||||
const createdAt = '2019-11-21T18:43:00.000000Z';
|
||||
const units = [genStatusModificationUnit(69, createdAt, 'revoked')];
|
||||
const result = toTimelineInfo(units);
|
||||
const expected = [
|
||||
{
|
||||
action: TimelineAction.StatusRevoked,
|
||||
userInfo: units[0].userInfo,
|
||||
createdAt,
|
||||
modifications: [],
|
||||
} as TimelineItemInfo,
|
||||
];
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('StatusModificationUnit with status pending should return statusPending action', () => {
|
||||
const createdAt = '2019-11-21T18:43:00.000000Z';
|
||||
const units = [genStatusModificationUnit(69, createdAt, 'pending')];
|
||||
const result = toTimelineInfo(units);
|
||||
const expected = [
|
||||
{
|
||||
action: TimelineAction.StatusPending,
|
||||
userInfo: units[0].userInfo,
|
||||
createdAt,
|
||||
modifications: [],
|
||||
} as TimelineItemInfo,
|
||||
];
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('StatusModificationUnit with status pendingAcceptance should ignore', () => {
|
||||
const createdAt = '2019-11-21T18:43:00.000000Z';
|
||||
const units = [genStatusModificationUnit(69, createdAt, 'pendingAcceptance')];
|
||||
const result = toTimelineInfo(units);
|
||||
const expected = [];
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
|
||||
it('CommentModificationUnit should return commentAdded action', () => {
|
||||
const createdAt = '2019-11-21T18:43:00.000000Z';
|
||||
const units = [genCommentModificationUnit(70, createdAt, '7dfbc2fe-7ac4-416a-9f96-commentId1')];
|
||||
const result = toTimelineInfo(units);
|
||||
const expected = [
|
||||
{
|
||||
action: TimelineAction.CommentAdded,
|
||||
userInfo: units[0].userInfo,
|
||||
createdAt,
|
||||
modifications: [units[0].modification],
|
||||
} as TimelineItemInfo,
|
||||
];
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
});
|
@ -1,70 +0,0 @@
|
||||
import { ClaimModification, FileModificationUnit, Modification, ModificationUnit } from '@vality/swag-claim-management';
|
||||
|
||||
import { isClaimModification, sortUnitsByCreatedAtAsc } from '@dsh/api/claim-management';
|
||||
|
||||
import { getClaimModificationTimelineAction } from './get-claim-modification-timeline-action';
|
||||
import { TimelineAction, TimelineItemInfo } from './model';
|
||||
|
||||
const getUnitTimelineAction = (modification: Modification): TimelineAction | null => {
|
||||
if (isClaimModification(modification)) {
|
||||
return getClaimModificationTimelineAction(modification.claimModificationType);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const deleteAddedFile = (acc: TimelineItemInfo[], deletedFileId: string): TimelineItemInfo[] => {
|
||||
const result = acc.slice();
|
||||
for (let i = 0, item = result[0]; i < result.length; i += 1, item = result[i]) {
|
||||
if (item.action !== TimelineAction.FilesAdded) {
|
||||
continue;
|
||||
}
|
||||
const fileModificationIdx = (item.modifications as ClaimModification[]).findIndex(
|
||||
({ claimModificationType }) => (claimModificationType as FileModificationUnit).fileId === deletedFileId
|
||||
);
|
||||
if (fileModificationIdx === -1) {
|
||||
continue;
|
||||
}
|
||||
if (item.modifications.length === 1) {
|
||||
result.splice(i, 1);
|
||||
} else {
|
||||
item.modifications.splice(fileModificationIdx, 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
console.error(`Deleted file "${deletedFileId}" not found`);
|
||||
return result;
|
||||
};
|
||||
|
||||
const getFileId = (modification: Modification): string =>
|
||||
((modification as ClaimModification).claimModificationType as FileModificationUnit).fileId;
|
||||
|
||||
const reduceToAcceptedTimelineItem = (
|
||||
acc: TimelineItemInfo[],
|
||||
{ createdAt, modification, userInfo }: ModificationUnit
|
||||
): TimelineItemInfo[] => {
|
||||
const action = getUnitTimelineAction(modification);
|
||||
if (!action) {
|
||||
return acc;
|
||||
}
|
||||
const modifications = [];
|
||||
switch (action) {
|
||||
case TimelineAction.FilesDeleted:
|
||||
return deleteAddedFile(acc, getFileId(modification));
|
||||
case TimelineAction.ChangesAdded:
|
||||
case TimelineAction.FilesAdded:
|
||||
case TimelineAction.CommentAdded:
|
||||
modifications.push(modification);
|
||||
}
|
||||
const timelineInfo = {
|
||||
action,
|
||||
userInfo,
|
||||
createdAt: createdAt as any,
|
||||
modifications,
|
||||
};
|
||||
return [...acc, timelineInfo];
|
||||
};
|
||||
|
||||
export const toTimelineInfo = (units: ModificationUnit[]): TimelineItemInfo[] =>
|
||||
Array.isArray(units) && units.length
|
||||
? units.slice().sort(sortUnitsByCreatedAtAsc).reduce(reduceToAcceptedTimelineItem, [])
|
||||
: [];
|
@ -1 +0,0 @@
|
||||
export * from './claim.module';
|
@ -1,48 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { TranslocoService } from '@ngneat/transloco';
|
||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||
import { Claim } from '@vality/swag-claim-management';
|
||||
import { BehaviorSubject, Subject, timer, defer } from 'rxjs';
|
||||
import { filter, shareReplay, switchMap } from 'rxjs/operators';
|
||||
|
||||
import { RouteParamClaimService } from './route-param-claim.service';
|
||||
|
||||
const POLLING_PERIOD = 5000;
|
||||
|
||||
@UntilDestroy()
|
||||
@Injectable()
|
||||
export class ReceiveClaimService {
|
||||
claim$ = defer(() => this.claimState$).pipe(filter(Boolean), shareReplay(1));
|
||||
error$ = defer(() => this.receiveClaimError$);
|
||||
isLoading$ = this.routeParamClaimService.isLoading$;
|
||||
|
||||
private claimState$ = new BehaviorSubject<Claim>(null);
|
||||
private receiveClaimError$ = new BehaviorSubject(false);
|
||||
private receiveClaim$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
private routeParamClaimService: RouteParamClaimService,
|
||||
private snackBar: MatSnackBar,
|
||||
private transloco: TranslocoService
|
||||
) {
|
||||
this.receiveClaim$
|
||||
.pipe(
|
||||
switchMap(() => timer(0, POLLING_PERIOD)),
|
||||
switchMap(() => this.routeParamClaimService.claim$),
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe(
|
||||
(claim) => this.claimState$.next(claim),
|
||||
(err) => {
|
||||
console.error(err);
|
||||
this.snackBar.open(this.transloco.translate('shared.commonError', null, 'components'), 'OK');
|
||||
this.receiveClaimError$.next(true);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
receiveClaim() {
|
||||
this.receiveClaim$.next();
|
||||
}
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { TranslocoService } from '@ngneat/transloco';
|
||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||
import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
|
||||
import { catchError, filter, map, shareReplay, switchMap, tap } from 'rxjs/operators';
|
||||
|
||||
import { ClaimsService } from '@dsh/api/claim-management';
|
||||
import { NotificationService } from '@dsh/app/shared';
|
||||
import { ConfirmActionDialogComponent } from '@dsh/components/popups';
|
||||
|
||||
import { UiError } from '../../ui-error';
|
||||
import { ReceiveClaimService } from './receive-claim.service';
|
||||
import { RouteParamClaimService } from './route-param-claim.service';
|
||||
|
||||
@UntilDestroy()
|
||||
@Injectable()
|
||||
export class ReviewClaimService {
|
||||
private reviewClaim$: Subject<void> = new Subject();
|
||||
private error$: BehaviorSubject<UiError> = new BehaviorSubject({ hasError: false });
|
||||
private progress$: BehaviorSubject<boolean> = new BehaviorSubject(false);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
reviewAvailable$: Observable<boolean> = this.receiveClaimService.claim$.pipe(
|
||||
map(({ status }) => status === 'pending'),
|
||||
shareReplay(1)
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
inProgress$: Observable<boolean> = this.progress$.asObservable();
|
||||
|
||||
constructor(
|
||||
private claimsApiService: ClaimsService,
|
||||
private routeParamClaimService: RouteParamClaimService,
|
||||
private receiveClaimService: ReceiveClaimService,
|
||||
private dialog: MatDialog,
|
||||
private transloco: TranslocoService,
|
||||
private notificationService: NotificationService
|
||||
) {
|
||||
this.reviewClaim$
|
||||
.pipe(
|
||||
tap(() => {
|
||||
this.error$.next({ hasError: false });
|
||||
this.progress$.next(true);
|
||||
}),
|
||||
switchMap(() =>
|
||||
this.dialog
|
||||
.open(ConfirmActionDialogComponent)
|
||||
.afterClosed()
|
||||
.pipe(
|
||||
tap((r) => {
|
||||
if (r === 'cancel') {
|
||||
this.progress$.next(false);
|
||||
}
|
||||
}),
|
||||
filter((r) => r === 'confirm')
|
||||
)
|
||||
),
|
||||
switchMap(() => this.routeParamClaimService.claim$),
|
||||
switchMap(({ id, revision }) =>
|
||||
this.claimsApiService
|
||||
.requestReviewClaimByIDWithRevisionCheck({ claimID: id, claimRevision: revision })
|
||||
.pipe(
|
||||
catchError((ex) => {
|
||||
this.progress$.next(false);
|
||||
console.error(ex);
|
||||
const error = { hasError: true, code: 'requestReviewClaimByIDFailed' };
|
||||
this.notificationService.error(
|
||||
this.transloco.translate(
|
||||
'claim.requestReviewClaimByIDFailed',
|
||||
null,
|
||||
'claim-section'
|
||||
)
|
||||
);
|
||||
this.error$.next(error);
|
||||
return of(error);
|
||||
})
|
||||
)
|
||||
),
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe(() => {
|
||||
this.receiveClaimService.receiveClaim();
|
||||
this.notificationService.success(this.transloco.translate('claim.reviewed', null, 'claim-section'));
|
||||
});
|
||||
}
|
||||
|
||||
reviewClaim() {
|
||||
this.reviewClaim$.next();
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
export * from './revoke-claim-dialog.component';
|
@ -1,33 +0,0 @@
|
||||
<ng-container *transloco="let t; scope: 'claim-section'; read: 'claimSection.revokeClaimDialog'">
|
||||
<dsh-base-dialog [title]="t('subheading')" (cancel)="cancel()">
|
||||
<form [formGroup]="form">
|
||||
<mat-form-field fxFlex>
|
||||
<mat-label>{{ t('reason') }}</mat-label>
|
||||
<mat-select formControlName="reason">
|
||||
<mat-option *ngFor="let reason of reasons" [value]="reason">
|
||||
{{ reason }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</form>
|
||||
<div *ngIf="errorCode$ | async">
|
||||
<div
|
||||
*transloco="let errors; scope: 'claim-section'; read: 'claimSection.revokeClaimDialog.errors'"
|
||||
class="mat-caption"
|
||||
>
|
||||
<!-- t(revokeClaimByIDFailed) -->
|
||||
{{ errors(errorCode$ | async) }}
|
||||
</div>
|
||||
</div>
|
||||
<div dshBaseDialogActions fxLayout="row" fxLayoutAlign="end">
|
||||
<button
|
||||
dsh-button
|
||||
color="warn"
|
||||
(click)="revoke(form.value.reason)"
|
||||
[disabled]="!form.valid || (inProgress$ | async)"
|
||||
>
|
||||
{{ t('revoke') }}
|
||||
</button>
|
||||
</div>
|
||||
</dsh-base-dialog>
|
||||
</ng-container>
|
@ -1,33 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { RevokeClaimDialogService } from './revoke-claim-dialog.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: 'revoke-claim-dialog.component.html',
|
||||
providers: [RevokeClaimDialogService],
|
||||
})
|
||||
export class RevokeClaimDialogComponent {
|
||||
form = this.revokeClaimDialogService.form;
|
||||
|
||||
// It's necessary to hardcode reasons (backend issue)
|
||||
reasons = [
|
||||
'Длительное ожидание подключения',
|
||||
'Не устраивает комиссия',
|
||||
'Большой пакет документов',
|
||||
'Не подходит продукт',
|
||||
'Нет сплитов',
|
||||
];
|
||||
|
||||
errorCode$ = this.revokeClaimDialogService.errorCode$;
|
||||
inProgress$ = this.revokeClaimDialogService.inProgress$;
|
||||
|
||||
constructor(private revokeClaimDialogService: RevokeClaimDialogService) {}
|
||||
|
||||
cancel(): void {
|
||||
this.revokeClaimDialogService.back();
|
||||
}
|
||||
|
||||
revoke(reason: string): void {
|
||||
this.revokeClaimDialogService.revoke(reason);
|
||||
}
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
import { Inject, Injectable } from '@angular/core';
|
||||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import get from 'lodash-es/get';
|
||||
import { BehaviorSubject, Observable, of, Subject } from 'rxjs';
|
||||
import { catchError, filter, pluck, switchMap, tap } from 'rxjs/operators';
|
||||
|
||||
import { ClaimsService } from '@dsh/api/claim-management';
|
||||
|
||||
import { progress } from '../../../../custom-operators';
|
||||
import { UiError } from '../../../ui-error';
|
||||
|
||||
@Injectable()
|
||||
export class RevokeClaimDialogService {
|
||||
private revoke$: Subject<string> = new Subject();
|
||||
private error$: BehaviorSubject<UiError> = new BehaviorSubject({ hasError: false });
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
errorCode$: Observable<string> = this.error$.pipe(pluck('code'));
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
inProgress$: Observable<boolean> = progress(this.revoke$, this.error$);
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
form: UntypedFormGroup;
|
||||
|
||||
constructor(
|
||||
private dialogRef: MatDialogRef<unknown, 'cancel' | 'revoked'>,
|
||||
private claimsApiService: ClaimsService,
|
||||
private fb: UntypedFormBuilder,
|
||||
@Inject(MAT_DIALOG_DATA) private data: { claimId: number; revision: number }
|
||||
) {
|
||||
this.form = this.fb.group({
|
||||
reason: ['', [Validators.required, Validators.maxLength(1000)]],
|
||||
});
|
||||
this.revoke$
|
||||
.pipe(
|
||||
tap(() => this.error$.next({ hasError: false })),
|
||||
switchMap((reason) =>
|
||||
this.claimsApiService
|
||||
.revokeClaimByID({ claimID: this.data.claimId, claimRevision: this.data.revision, reason })
|
||||
.pipe(
|
||||
catchError((ex) => {
|
||||
console.error(ex);
|
||||
const error = { hasError: true, code: 'revokeClaimByIDFailed' };
|
||||
this.error$.next(error);
|
||||
return of(error);
|
||||
})
|
||||
)
|
||||
),
|
||||
filter((res) => get(res, ['hasError']) !== true)
|
||||
)
|
||||
.subscribe(() => this.dialogRef.close('revoked'));
|
||||
}
|
||||
|
||||
back() {
|
||||
this.dialogRef.close('cancel');
|
||||
}
|
||||
|
||||
revoke(reason: string) {
|
||||
this.revoke$.next(reason);
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { TranslocoService } from '@ngneat/transloco';
|
||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||
import { Subject } from 'rxjs';
|
||||
import { filter, first, map, switchMap } from 'rxjs/operators';
|
||||
|
||||
import { ReceiveClaimService } from './receive-claim.service';
|
||||
import { RevokeClaimDialogComponent } from './revoke-claim-dialog';
|
||||
import { RouteParamClaimService } from './route-param-claim.service';
|
||||
|
||||
@UntilDestroy()
|
||||
@Injectable()
|
||||
export class RevokeClaimService {
|
||||
private revokeClaim$ = new Subject<void>();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
revokeAvailable$ = this.receiveClaimService.claim$.pipe(
|
||||
map(({ status }) => status !== 'revoked' && status !== 'denied' && status !== 'accepted')
|
||||
);
|
||||
|
||||
constructor(
|
||||
private routeParamClaimService: RouteParamClaimService,
|
||||
private receiveClaimService: ReceiveClaimService,
|
||||
private snackBar: MatSnackBar,
|
||||
private transloco: TranslocoService,
|
||||
private dialog: MatDialog
|
||||
) {
|
||||
this.revokeClaim$
|
||||
.pipe(
|
||||
switchMap(() => this.routeParamClaimService.claim$.pipe(first())),
|
||||
switchMap(({ id, revision }) => this.openRevokeClaimDialog(id, revision)),
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe(() => {
|
||||
this.receiveClaimService.receiveClaim();
|
||||
this.snackBar.open(this.transloco.translate('claim.revoked', null, 'claim-section'), 'OK', {
|
||||
duration: 2000,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
revokeClaim() {
|
||||
this.revokeClaim$.next();
|
||||
}
|
||||
|
||||
private openRevokeClaimDialog(claimId: number, revision: number) {
|
||||
return this.dialog
|
||||
.open(RevokeClaimDialogComponent, {
|
||||
width: '500px',
|
||||
data: { claimId, revision },
|
||||
})
|
||||
.afterClosed()
|
||||
.pipe(filter((r) => r === 'revoked'));
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { switchMap, pluck } from 'rxjs/operators';
|
||||
|
||||
import { ClaimsService } from '@dsh/api/claim-management';
|
||||
import { progressTo, inProgressFrom } from '@dsh/utils';
|
||||
|
||||
@Injectable()
|
||||
export class RouteParamClaimService {
|
||||
claim$ = this.route.params.pipe(
|
||||
pluck('claimId'),
|
||||
switchMap((claimID) => this.claimsService.getClaimByID({ claimID }).pipe(progressTo(this.progress$)))
|
||||
);
|
||||
isLoading$ = inProgressFrom(() => this.progress$, this.claim$);
|
||||
|
||||
private progress$ = new BehaviorSubject(0);
|
||||
|
||||
constructor(private route: ActivatedRoute, private claimsService: ClaimsService) {}
|
||||
}
|
@ -1 +0,0 @@
|
||||
export * from './update-claim.service';
|
@ -1,15 +0,0 @@
|
||||
import { FileModification } from '@vality/swag-claim-management';
|
||||
import { Conversation } from '@vality/swag-messages';
|
||||
|
||||
export interface UpdateParams {
|
||||
type: 'updateConversation' | 'updateFiles';
|
||||
}
|
||||
|
||||
export interface UpdateConversationParams extends UpdateParams {
|
||||
conversationId: Conversation['conversationId'];
|
||||
}
|
||||
|
||||
export interface UpdateFilesParams extends UpdateParams {
|
||||
fileIds: string[];
|
||||
fileModificationType: FileModification.FileModificationTypeEnum;
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import { Modification } from '@vality/swag-claim-management';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { createCommentModificationUnit, createFileModificationUnit } from '@dsh/api/claim-management';
|
||||
|
||||
import { UpdateParams } from './model';
|
||||
import { isUpdateConversation, isUpdateFiles } from './type-guards';
|
||||
|
||||
export const toChangeset = (s: Observable<UpdateParams>): Observable<Modification[]> =>
|
||||
s.pipe(
|
||||
map((params) => {
|
||||
if (isUpdateConversation(params)) {
|
||||
return [createCommentModificationUnit(params.conversationId)];
|
||||
}
|
||||
if (isUpdateFiles(params)) {
|
||||
return params.fileIds.map((id) => createFileModificationUnit(id, params.fileModificationType));
|
||||
}
|
||||
throw new Error('Unknown update claim params');
|
||||
})
|
||||
);
|
@ -1,5 +0,0 @@
|
||||
import { UpdateConversationParams, UpdateFilesParams, UpdateParams } from './model';
|
||||
|
||||
export const isUpdateConversation = (p: UpdateParams): p is UpdateConversationParams => p.type === 'updateConversation';
|
||||
|
||||
export const isUpdateFiles = (p: UpdateParams): p is UpdateFilesParams => p.type === 'updateFiles';
|
@ -1,74 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { TranslocoService } from '@ngneat/transloco';
|
||||
import { FileModification } from '@vality/swag-claim-management';
|
||||
import { Conversation } from '@vality/swag-messages';
|
||||
import { BehaviorSubject, combineLatest, Observable, of, Subject } from 'rxjs';
|
||||
import { catchError, share, switchMap, tap } from 'rxjs/operators';
|
||||
|
||||
import { ClaimsService } from '@dsh/api/claim-management';
|
||||
import { NotificationService } from '@dsh/app/shared';
|
||||
|
||||
import { progress } from '../../../../custom-operators';
|
||||
import { UiError } from '../../../ui-error';
|
||||
import { ReceiveClaimService } from '../receive-claim.service';
|
||||
import { RouteParamClaimService } from '../route-param-claim.service';
|
||||
import { UpdateConversationParams, UpdateFilesParams, UpdateParams } from './model';
|
||||
import { toChangeset } from './to-changeset';
|
||||
|
||||
@Injectable()
|
||||
export class UpdateClaimService {
|
||||
inProgress$: Observable<boolean>;
|
||||
|
||||
private updateBy$ = new Subject<UpdateParams>();
|
||||
private error$ = new BehaviorSubject<UiError>({ hasError: false });
|
||||
|
||||
constructor(
|
||||
private receiveClaimService: ReceiveClaimService,
|
||||
private routeParamClaimService: RouteParamClaimService,
|
||||
private claimApiService: ClaimsService,
|
||||
private notificationService: NotificationService,
|
||||
private transloco: TranslocoService
|
||||
) {
|
||||
const updated$ = this.updateBy$.pipe(
|
||||
tap(() => this.error$.next({ hasError: false })),
|
||||
toChangeset,
|
||||
switchMap((changeset) => combineLatest([of(changeset), this.routeParamClaimService.claim$])),
|
||||
switchMap(([changeset, { id, revision }]) =>
|
||||
this.claimApiService.updateClaimByID({ claimID: id, claimRevision: revision, changeset }).pipe(
|
||||
catchError((ex) => {
|
||||
console.error(ex);
|
||||
const error = { hasError: true, code: 'updateClaimByIDFailed' };
|
||||
this.notificationService.error(
|
||||
this.transloco.translate(`updateClaim.updateClaimByIDFailed`, null, 'claim-section')
|
||||
);
|
||||
this.error$.next(error);
|
||||
return of(error);
|
||||
})
|
||||
)
|
||||
),
|
||||
share()
|
||||
);
|
||||
|
||||
this.inProgress$ = progress(this.updateBy$, updated$);
|
||||
updated$.subscribe(() => this.receiveClaimService.receiveClaim());
|
||||
}
|
||||
|
||||
updateByConversation(conversationId: Conversation['conversationId']) {
|
||||
this.updateBy$.next({
|
||||
type: 'updateConversation',
|
||||
conversationId,
|
||||
} as UpdateConversationParams);
|
||||
}
|
||||
|
||||
updateByFiles(
|
||||
fileIds: string[],
|
||||
fileModificationType: FileModification.FileModificationTypeEnum = FileModification.FileModificationTypeEnum
|
||||
.FileCreated
|
||||
) {
|
||||
this.updateBy$.next({
|
||||
type: 'updateFiles',
|
||||
fileIds,
|
||||
fileModificationType,
|
||||
} as UpdateFilesParams);
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
<dsh-last-updated (update)="refreshList()" [lastUpdated]="lastUpdated"></dsh-last-updated>
|
||||
<dsh-claim-row-header></dsh-claim-row-header>
|
||||
<ng-container *ngFor="let claim of claimList">
|
||||
<dsh-claim-row [claim]="claim" (goToClaimDetails)="goToClaimDetails.emit($event)"></dsh-claim-row>
|
||||
<dsh-claim-row [claim]="claim"></dsh-claim-row>
|
||||
</ng-container>
|
||||
<dsh-show-more-panel *ngIf="hasMore" (showMore)="showMoreElements()" [isLoading]="isLoading"></dsh-show-more-panel>
|
||||
<div *ngIf="isEmptyList" class="mat-headline">
|
||||
|
@ -1,111 +0,0 @@
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { TranslocoTestingModule } from '@ngneat/transloco';
|
||||
import { Claim } from '@vality/swag-claim-management';
|
||||
|
||||
import { EmptySearchResultModule } from '@dsh/components/empty-search-result';
|
||||
import { SpinnerModule } from '@dsh/components/indicators';
|
||||
import { AccordionModule, CardModule } from '@dsh/components/layout';
|
||||
import { ShowMorePanelModule } from '@dsh/components/show-more-panel';
|
||||
|
||||
import { generateMockClaim } from '../tests/generate-mock-claim';
|
||||
import { ClaimsListComponent } from './claims-list.component';
|
||||
|
||||
@Component({
|
||||
selector: 'dsh-claim-row-header',
|
||||
template: '',
|
||||
})
|
||||
class MockRowHeaderComponent {}
|
||||
|
||||
@Component({
|
||||
selector: 'dsh-claim-row',
|
||||
template: '',
|
||||
})
|
||||
class MockRowComponent {
|
||||
@Input() claim: Claim;
|
||||
|
||||
@Output() goToClaimDetails: EventEmitter<number> = new EventEmitter();
|
||||
}
|
||||
|
||||
describe('ClaimsListComponent', () => {
|
||||
let component: ClaimsListComponent;
|
||||
let fixture: ComponentFixture<ClaimsListComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [
|
||||
FlexLayoutModule,
|
||||
SpinnerModule,
|
||||
EmptySearchResultModule,
|
||||
AccordionModule,
|
||||
CardModule,
|
||||
ShowMorePanelModule,
|
||||
NoopAnimationsModule,
|
||||
HttpClientTestingModule,
|
||||
TranslocoTestingModule.withLangs(
|
||||
{
|
||||
ru: {
|
||||
emptySearchResult: 'Данные за указанный период отсутствуют',
|
||||
},
|
||||
},
|
||||
{
|
||||
availableLangs: ['ru'],
|
||||
defaultLang: 'ru',
|
||||
}
|
||||
),
|
||||
],
|
||||
declarations: [ClaimsListComponent, MockRowHeaderComponent, MockRowComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ClaimsListComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('isEmptyList', () => {
|
||||
it('should be false if list was not provided', () => {
|
||||
expect(component.isEmptyList).toBe(false);
|
||||
});
|
||||
|
||||
it('should be true if list is empty', () => {
|
||||
component.claimList = [];
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.isEmptyList).toBe(true);
|
||||
});
|
||||
|
||||
it('should be false if list contains at least one element', () => {
|
||||
component.claimList = new Array(1).fill(generateMockClaim(1));
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.isEmptyList).toBe(false);
|
||||
|
||||
component.claimList = new Array(15).fill(generateMockClaim(1));
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.isEmptyList).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('showMoreElements', () => {
|
||||
it('should emit output event showMore', () => {
|
||||
const spyOnShowMore = spyOn(component.showMore, 'emit');
|
||||
|
||||
component.showMoreElements();
|
||||
|
||||
expect(spyOnShowMore).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
@ -16,7 +16,6 @@ export class ClaimsListComponent {
|
||||
|
||||
@Output() refresh = new EventEmitter<void>();
|
||||
@Output() showMore = new EventEmitter<void>();
|
||||
@Output() goToClaimDetails: EventEmitter<number> = new EventEmitter();
|
||||
|
||||
get isListExist(): boolean {
|
||||
return !isNil(this.claimList);
|
||||
|
@ -6,6 +6,7 @@
|
||||
>
|
||||
<dsh-row-header-label fxHide.lt-md fxFlex="15">#</dsh-row-header-label>
|
||||
<dsh-row-header-label fxHide.lt-md fxFlex="25"> {{ claims('panel.status') }} </dsh-row-header-label>
|
||||
<dsh-row-header-label fxFlex.gt-sm="30" fxFlex> {{ claims('panel.updatedAt') }} </dsh-row-header-label>
|
||||
<dsh-row-header-label fxFlex.gt-sm="30" fxFlex></dsh-row-header-label>
|
||||
<dsh-row-header-label fxFlex.gt-sm="30" fxFlex fxLayoutAlign="end center">
|
||||
{{ claims('panel.updatedAt') }}
|
||||
</dsh-row-header-label>
|
||||
</dsh-row>
|
||||
|
@ -1,46 +0,0 @@
|
||||
import { ChangeDetectionStrategy } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { TranslocoTestingModule } from '@ngneat/transloco';
|
||||
|
||||
import { RowModule } from '@dsh/components/layout';
|
||||
|
||||
import * as ru from '../../../../../../../assets/i18n/ru.json';
|
||||
import { ClaimRowHeaderComponent } from './claim-row-header.component';
|
||||
|
||||
const TRANSLATION_CONFIG = {
|
||||
ru,
|
||||
};
|
||||
|
||||
describe('ClaimRowHeaderComponent', () => {
|
||||
let fixture: ComponentFixture<ClaimRowHeaderComponent>;
|
||||
let component: ClaimRowHeaderComponent;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
RowModule,
|
||||
TranslocoTestingModule.withLangs(TRANSLATION_CONFIG, {
|
||||
availableLangs: ['ru'],
|
||||
defaultLang: 'ru',
|
||||
}),
|
||||
],
|
||||
declarations: [ClaimRowHeaderComponent],
|
||||
})
|
||||
.overrideComponent(ClaimRowHeaderComponent, {
|
||||
set: {
|
||||
changeDetection: ChangeDetectionStrategy.Default,
|
||||
},
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ClaimRowHeaderComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -14,15 +14,8 @@
|
||||
>{{ (claimStatusDict$ | async)?.[item.status] }}</dsh-status
|
||||
>
|
||||
</dsh-row-label>
|
||||
<dsh-row-label fxFlex.gt-sm="30" fxFlex>
|
||||
<dsh-row-label fxFlex.gt-sm="30" fxFlex fxLayoutAlign="end center">
|
||||
<span fxHide.lt-md>{{ item.updatedAt | date: 'dd MMMM yyyy, HH:mm' }}</span>
|
||||
<span fxHide.gt-sm>{{ item.updatedAt | date: 'dd.MM.yyyy, HH:mm' }}</span>
|
||||
</dsh-row-label>
|
||||
<dsh-row-label fxFlex.gt-sm="30" fxFlex fxLayout="row" fxLayoutAlign="end center"
|
||||
><dsh-navigation-link
|
||||
*transloco="let claims; scope: 'claim-section'; read: 'claimSection.claimRow'"
|
||||
[text]="claims('details')"
|
||||
(click)="goToClaimDetails.emit(claim.id)"
|
||||
></dsh-navigation-link
|
||||
></dsh-row-label>
|
||||
</ng-template>
|
||||
|
@ -1,77 +0,0 @@
|
||||
import { ChangeDetectionStrategy } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { TranslocoTestingModule } from '@ngneat/transloco';
|
||||
import * as moment from 'moment';
|
||||
|
||||
import { ClaimStatusColorPipe } from '@dsh/app/shared/pipes/api-model-types/claim-status-color.pipe';
|
||||
import { StatusModule } from '@dsh/components/indicators';
|
||||
import { RowModule } from '@dsh/components/layout';
|
||||
|
||||
import * as ru from '../../../../../../../assets/i18n/ru.json';
|
||||
import { generateMockClaim } from '../../../tests/generate-mock-claim';
|
||||
import { ClaimRowComponent } from './claim-row.component';
|
||||
|
||||
const TRANSLATION_CONFIG = {
|
||||
ru,
|
||||
};
|
||||
|
||||
describe('ClaimRowComponent', () => {
|
||||
let fixture: ComponentFixture<ClaimRowComponent>;
|
||||
let component: ClaimRowComponent;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
RowModule,
|
||||
TranslocoTestingModule.withLangs(TRANSLATION_CONFIG, {
|
||||
availableLangs: ['ru'],
|
||||
defaultLang: 'ru',
|
||||
}),
|
||||
StatusModule,
|
||||
],
|
||||
declarations: [ClaimRowComponent, ClaimStatusColorPipe],
|
||||
})
|
||||
.overrideComponent(ClaimRowComponent, {
|
||||
set: {
|
||||
changeDetection: ChangeDetectionStrategy.Default,
|
||||
},
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ClaimRowComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
describe('template', () => {
|
||||
it('should show loading value if claim was not provided', () => {
|
||||
const labels = fixture.debugElement.queryAll(By.css('dsh-row dsh-row-label'));
|
||||
|
||||
expect(labels.length).toBe(1);
|
||||
expect(labels[0].nativeElement.textContent.trim()).toBe('Loading ...');
|
||||
});
|
||||
|
||||
it('should show row component if claim was provided', () => {
|
||||
const claim = generateMockClaim();
|
||||
const { createdAt } = claim;
|
||||
component.claim = claim;
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
const labels = fixture.debugElement.queryAll(By.css('dsh-row dsh-row-label'));
|
||||
|
||||
expect(labels[0].nativeElement.textContent.trim()).toBe('1');
|
||||
expect(labels[1].nativeElement.textContent.trim()).toBe('В ожидании');
|
||||
expect(labels[2].nativeElement.children[0].textContent.trim()).toBe(
|
||||
moment(createdAt).format('DD MMMM YYYY, HH:mm')
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
@ -1,4 +1,4 @@
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
import { Claim } from '@vality/swag-claim-management';
|
||||
|
||||
import { ClaimManagementDictionaryService } from '@dsh/api/claim-management';
|
||||
@ -11,8 +11,6 @@ import { ClaimManagementDictionaryService } from '@dsh/api/claim-management';
|
||||
export class ClaimRowComponent {
|
||||
@Input() claim: Claim;
|
||||
|
||||
@Output() goToClaimDetails: EventEmitter<number> = new EventEmitter();
|
||||
|
||||
claimStatusDict$ = this.claimManagementDictionaryService.claimStatus$;
|
||||
|
||||
constructor(private claimManagementDictionaryService: ClaimManagementDictionaryService) {}
|
||||
|
@ -25,6 +25,5 @@
|
||||
[claimList]="claimsList$ | async"
|
||||
(refresh)="refresh()"
|
||||
(showMore)="fetchMore()"
|
||||
(goToClaimDetails)="goToClaimDetails($event)"
|
||||
></dsh-claims-list>
|
||||
</div>
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { QueryParamsService } from '@dsh/app/shared';
|
||||
import { ShopCreationService } from '@dsh/app/shared/components/shop-creation';
|
||||
@ -25,7 +24,6 @@ export class ClaimsComponent {
|
||||
|
||||
constructor(
|
||||
private fetchClaimsService: FetchClaimsService,
|
||||
private router: Router,
|
||||
private qp: QueryParamsService<Filters>,
|
||||
private shopCreationService: ShopCreationService
|
||||
) {}
|
||||
@ -43,10 +41,6 @@ export class ClaimsComponent {
|
||||
this.fetchClaimsService.refresh();
|
||||
}
|
||||
|
||||
goToClaimDetails(id: number): void {
|
||||
void this.router.navigate(['claim-section', 'claims', id]);
|
||||
}
|
||||
|
||||
createShop(): void {
|
||||
this.shopCreationService.createShop();
|
||||
}
|
||||
|
@ -1,19 +1,4 @@
|
||||
{
|
||||
"claim": {
|
||||
"breadcrumbs": {
|
||||
"claimDetails": "Claim details",
|
||||
"claims": "Claims"
|
||||
},
|
||||
"headline": "Claim details",
|
||||
"requestReviewClaimByIDFailed": "Failed to send the claim for review",
|
||||
"reviewClaim": "Send for review",
|
||||
"reviewed": "The claim has been successfully submitted for review",
|
||||
"revokeClaim": "Revoke",
|
||||
"revoked": "The claim has been successfully revoked"
|
||||
},
|
||||
"claimRow": {
|
||||
"details": "Claim details"
|
||||
},
|
||||
"claimRowHeader": {
|
||||
"panel": {
|
||||
"status": "Status",
|
||||
@ -26,46 +11,5 @@
|
||||
"claims": {
|
||||
"createClaim": "Create claim",
|
||||
"title": "Claims"
|
||||
},
|
||||
"conversation": {
|
||||
"action": {
|
||||
"toggleDetails": "Disclose / hide the details"
|
||||
},
|
||||
"ago": "ago",
|
||||
"filesUploaded": "The file has been successfully uploaded",
|
||||
"sendComment": "Add a comment",
|
||||
"timeline": {
|
||||
"claimCreated": "The claim has been created"
|
||||
},
|
||||
"timelineActions": {
|
||||
"changesAdded": "have added the following information",
|
||||
"commentAdded": "have added comments",
|
||||
"filesAdded": "have added documents",
|
||||
"statusAccepted": "approved the claim",
|
||||
"statusDenied": "denied the claim",
|
||||
"statusPending": "reviewed the claim",
|
||||
"statusReview": "have submitted a claim for review",
|
||||
"statusRevoked": "revoked the claim"
|
||||
},
|
||||
"userTypes": {
|
||||
"external_user": "You",
|
||||
"internal_user": "Manager"
|
||||
}
|
||||
},
|
||||
"revokeClaimDialog": {
|
||||
"errors": {
|
||||
"revokeClaimByIDFailed": "Failed to revoke the claim"
|
||||
},
|
||||
"reason": "Specify the reason",
|
||||
"revoke": "Revoke",
|
||||
"subheading": "Withdrawal of claim"
|
||||
},
|
||||
"sendComment": {
|
||||
"errors": {
|
||||
"saveConversationsFailed": "Failed to save comment"
|
||||
}
|
||||
},
|
||||
"updateClaim": {
|
||||
"updateClaimByIDFailed": "Failed to update the claim"
|
||||
}
|
||||
}
|
||||
|
@ -1,19 +1,4 @@
|
||||
{
|
||||
"claim": {
|
||||
"breadcrumbs": {
|
||||
"claimDetails": "Детали заявки",
|
||||
"claims": "Заявки"
|
||||
},
|
||||
"headline": "Детали заявки",
|
||||
"requestReviewClaimByIDFailed": "Не удалось отправить заявку на рассмотрение",
|
||||
"reviewClaim": "Отправить на рассмотрение",
|
||||
"reviewed": "Заявка успешно отправлена на рассмотрение",
|
||||
"revokeClaim": "Отозвать",
|
||||
"revoked": "Заявка успешно отозвана"
|
||||
},
|
||||
"claimRow": {
|
||||
"details": "Детали заявки"
|
||||
},
|
||||
"claimRowHeader": {
|
||||
"panel": {
|
||||
"status": "Статус",
|
||||
@ -26,46 +11,5 @@
|
||||
"claims": {
|
||||
"createClaim": "Создать заявку",
|
||||
"title": "Заявки"
|
||||
},
|
||||
"conversation": {
|
||||
"action": {
|
||||
"toggleDetails": "Раскрыть / скрыть детали"
|
||||
},
|
||||
"ago": "назад",
|
||||
"filesUploaded": "Файл успешно загружен",
|
||||
"sendComment": "Оставьте комментарий",
|
||||
"timeline": {
|
||||
"claimCreated": "Заявка создана"
|
||||
},
|
||||
"timelineActions": {
|
||||
"changesAdded": "добавлены следующие сведения",
|
||||
"commentAdded": "добавлены комментарии",
|
||||
"filesAdded": "добавлены документы",
|
||||
"statusAccepted": "одобрена заявка",
|
||||
"statusDenied": "отклонена заявка",
|
||||
"statusPending": "рассмотрена заявка",
|
||||
"statusReview": "заявка отправлена на рассмотрение",
|
||||
"statusRevoked": "отозвана заявка"
|
||||
},
|
||||
"userTypes": {
|
||||
"external_user": "Вами",
|
||||
"internal_user": "Менеджером"
|
||||
}
|
||||
},
|
||||
"revokeClaimDialog": {
|
||||
"errors": {
|
||||
"revokeClaimByIDFailed": "Не удалось отозвать заявку"
|
||||
},
|
||||
"reason": "Укажите причину",
|
||||
"revoke": "Отозвать",
|
||||
"subheading": "Отзыв заявки"
|
||||
},
|
||||
"sendComment": {
|
||||
"errors": {
|
||||
"saveConversationsFailed": "Не удалось сохранить комментарий"
|
||||
}
|
||||
},
|
||||
"updateClaim": {
|
||||
"updateClaimByIDFailed": "Не удалось обновить заявку"
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
export * from './layout.module';
|
||||
export * from './card';
|
||||
export * from './panel';
|
||||
export * from './timeline';
|
||||
export * from './dropdown';
|
||||
export * from './details-item';
|
||||
export * from './row';
|
||||
|
@ -11,13 +11,11 @@ import { LinkLabelModule } from './link-label';
|
||||
import { PanelModule } from './panel';
|
||||
import { RowModule } from './row';
|
||||
import { SectionHeaderModule } from './section-header';
|
||||
import { TimelineModule } from './timeline';
|
||||
|
||||
const EXPORTED_MODULES = [
|
||||
CardModule,
|
||||
DropdownModule,
|
||||
PanelModule,
|
||||
TimelineModule,
|
||||
DetailsItemModule,
|
||||
RowModule,
|
||||
AccordionModule,
|
||||
|
@ -1,30 +0,0 @@
|
||||
@use '@angular/material' as mat;
|
||||
@import './timeline-item/timeline-item-badge/timeline-item-badge-theme';
|
||||
|
||||
@mixin dsh-timeline-theme($theme) {
|
||||
$foreground: map-get($theme, foreground);
|
||||
$success-base: map-get($theme, success-base);
|
||||
$pending-base: map-get($theme, pending-base);
|
||||
$warn-base: map-get($theme, warn-base);
|
||||
$line-color: map-get($foreground, border);
|
||||
|
||||
.dsh-timeline {
|
||||
border-bottom-color: $line-color;
|
||||
|
||||
&::after {
|
||||
background-color: $line-color;
|
||||
}
|
||||
}
|
||||
|
||||
.dsh-timeline-item-badge {
|
||||
background-color: $line-color;
|
||||
}
|
||||
|
||||
@include dsh-timeline-item-badge-theme($theme);
|
||||
}
|
||||
|
||||
@mixin dsh-timeline-typography($config) {
|
||||
.dsh-timeline {
|
||||
@include mat.typography-level($config, body-1);
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
export * from './timeline.module';
|
@ -1 +0,0 @@
|
||||
export * from './timeline-item.component';
|
@ -1,24 +0,0 @@
|
||||
@import '../../../../../styles/utils/fill';
|
||||
|
||||
@mixin dsh-timeline-item-badge-theme($theme) {
|
||||
$success-base: map-get($theme, success-base);
|
||||
$pending-base: map-get($theme, pending-base);
|
||||
$warn-base: map-get($theme, warn-base);
|
||||
|
||||
.dsh-timeline-item-badge {
|
||||
&-success {
|
||||
background-color: $success-base;
|
||||
@include fill(map-get($background, card));
|
||||
}
|
||||
|
||||
&-pending {
|
||||
background-color: $pending-base;
|
||||
@include fill(map-get($background, card));
|
||||
}
|
||||
|
||||
&-warn {
|
||||
background-color: $warn-base;
|
||||
@include fill(map-get($background, card));
|
||||
}
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
export * from './timeline-item-badge.component';
|
@ -1,20 +0,0 @@
|
||||
@import '../../timeline.scss';
|
||||
|
||||
.dsh-timeline-item-badge {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
display: flex;
|
||||
height: $badge-size;
|
||||
width: $badge-size;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 50%;
|
||||
z-index: 10;
|
||||
|
||||
mat-icon {
|
||||
height: $badge-icon-size;
|
||||
width: $badge-icon-size;
|
||||
font-size: $badge-icon-size;
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component, HostBinding, Input, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
import { StatusColor } from '../../../../../app/theme-manager';
|
||||
|
||||
@Component({
|
||||
selector: 'dsh-timeline-item-badge',
|
||||
template: '<ng-content></ng-content>',
|
||||
styleUrls: ['timeline-item-badge.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class TimelineItemBadgeComponent {
|
||||
@Input() color: StatusColor;
|
||||
|
||||
@HostBinding('class.dsh-timeline-item-badge') rootClass = true;
|
||||
|
||||
@HostBinding('class.dsh-timeline-item-badge-success') get success() {
|
||||
return this.color === StatusColor.Success;
|
||||
}
|
||||
|
||||
@HostBinding('class.dsh-timeline-item-badge-warn') get warn() {
|
||||
return this.color === StatusColor.Warn;
|
||||
}
|
||||
|
||||
@HostBinding('class.dsh-timeline-item-badge-pending') get pending() {
|
||||
return this.color === StatusColor.Pending;
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
export * from './timeline-item-content.component';
|
@ -1,6 +0,0 @@
|
||||
@import '../../timeline.scss';
|
||||
|
||||
.dsh-timeline-item-content {
|
||||
display: block;
|
||||
padding-top: $content-padding;
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component, HostBinding, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'dsh-timeline-item-content, [dsh-timeline-item-content]',
|
||||
template: '<ng-content></ng-content>',
|
||||
styleUrls: ['timeline-item-content.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class TimelineItemContentComponent {
|
||||
@HostBinding('class.dsh-timeline-item-content') rootClass = true;
|
||||
}
|
@ -1 +0,0 @@
|
||||
export * from './timeline-item-title.component';
|
@ -1,7 +0,0 @@
|
||||
@import '../../timeline.scss';
|
||||
|
||||
.dsh-timeline-item-title {
|
||||
min-height: $badge-size;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component, HostBinding, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'dsh-timeline-item-title',
|
||||
template: '<ng-content></ng-content>',
|
||||
styleUrls: ['timeline-item-title.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class TimelineItemTitleComponent {
|
||||
@HostBinding('class.dsh-timeline-item-title') rootClass = true;
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
@import '../timeline.scss';
|
||||
|
||||
.dsh-timeline-item {
|
||||
display: block;
|
||||
padding-bottom: $content-padding;
|
||||
padding-left: $badge-size + $content-padding;
|
||||
position: relative;
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component, HostBinding, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'dsh-timeline-item',
|
||||
template: '<ng-content></ng-content>',
|
||||
styleUrls: ['timeline-item.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class TimelineItemComponent {
|
||||
@HostBinding('class.dsh-timeline-item') rootClass = true;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
@import './timeline.scss';
|
||||
|
||||
.dsh-timeline {
|
||||
position: relative;
|
||||
border-bottom: $line-width solid;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: $line-width;
|
||||
left: $badge-size * 0.5 - $line-width * 0.5;
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component, HostBinding, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'dsh-timeline',
|
||||
template: '<ng-content></ng-content>',
|
||||
styleUrls: ['timeline.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class TimelineComponent {
|
||||
@HostBinding('class.dsh-timeline') rootClass = true;
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
|
||||
import { TimelineItemComponent } from './timeline-item';
|
||||
import { TimelineItemBadgeComponent } from './timeline-item/timeline-item-badge';
|
||||
import { TimelineItemContentComponent } from './timeline-item/timeline-item-content';
|
||||
import { TimelineItemTitleComponent } from './timeline-item/timeline-item-title';
|
||||
import { TimelineComponent } from './timeline.component';
|
||||
|
||||
const EXPORTED_DECLARATIONS = [
|
||||
TimelineComponent,
|
||||
TimelineItemComponent,
|
||||
TimelineItemTitleComponent,
|
||||
TimelineItemBadgeComponent,
|
||||
TimelineItemContentComponent,
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [FlexLayoutModule, CommonModule],
|
||||
declarations: EXPORTED_DECLARATIONS,
|
||||
exports: EXPORTED_DECLARATIONS,
|
||||
})
|
||||
export class TimelineModule {}
|
@ -1,4 +0,0 @@
|
||||
$badge-size: 32px;
|
||||
$badge-icon-size: 16px;
|
||||
$line-width: 2px;
|
||||
$content-padding: 16px;
|
@ -1,77 +0,0 @@
|
||||
import { Component, Provider, Type } from '@angular/core';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
import { StatusColor } from '../../../app/theme-manager';
|
||||
import { TimelineItemBadgeComponent } from './timeline-item/timeline-item-badge';
|
||||
import { TimelineItemContentComponent } from './timeline-item/timeline-item-content';
|
||||
import { TimelineItemTitleComponent } from './timeline-item/timeline-item-title';
|
||||
import { TimelineModule } from './timeline.module';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
<dsh-timeline>
|
||||
<dsh-timeline-item>
|
||||
<dsh-timeline-item-badge [color]="color">Badge</dsh-timeline-item-badge>
|
||||
<dsh-timeline-item-title>Title</dsh-timeline-item-title>
|
||||
<dsh-timeline-item-content>Content</dsh-timeline-item-content>
|
||||
</dsh-timeline-item>
|
||||
</dsh-timeline>
|
||||
`,
|
||||
})
|
||||
class SampleTimelineComponent {
|
||||
color: StatusColor;
|
||||
}
|
||||
|
||||
describe('Timeline', () => {
|
||||
function createComponent<T>(
|
||||
component: Type<T>,
|
||||
providers: Provider[] = [],
|
||||
declarations: any[] = []
|
||||
): ComponentFixture<T> {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [TimelineModule, NoopAnimationsModule],
|
||||
declarations: [component, ...declarations],
|
||||
providers,
|
||||
}).compileComponents();
|
||||
const fixture = TestBed.createComponent<T>(component);
|
||||
fixture.detectChanges();
|
||||
return fixture;
|
||||
}
|
||||
|
||||
describe('TimelineItem', () => {
|
||||
it('should have badge', () => {
|
||||
const fixture = createComponent(SampleTimelineComponent);
|
||||
expect(
|
||||
fixture.debugElement.query(By.directive(TimelineItemBadgeComponent)).nativeElement.textContent.trim()
|
||||
).toBe('Badge');
|
||||
});
|
||||
|
||||
it('should have title', () => {
|
||||
const fixture = createComponent(SampleTimelineComponent);
|
||||
expect(
|
||||
fixture.debugElement.query(By.directive(TimelineItemTitleComponent)).nativeElement.textContent.trim()
|
||||
).toBe('Title');
|
||||
});
|
||||
|
||||
it('should have content', () => {
|
||||
const fixture = createComponent(SampleTimelineComponent);
|
||||
expect(
|
||||
fixture.debugElement.query(By.directive(TimelineItemContentComponent)).nativeElement.textContent.trim()
|
||||
).toBe('Content');
|
||||
});
|
||||
|
||||
it('should change class when setting color', () => {
|
||||
const getClassName = <T>(f: ComponentFixture<T>, type = TimelineItemBadgeComponent): string =>
|
||||
f.debugElement.query(By.directive(type)).nativeElement.className;
|
||||
const fixture = createComponent(SampleTimelineComponent);
|
||||
const sourceBadgeClass = getClassName(fixture);
|
||||
expect(sourceBadgeClass).toEqual('dsh-timeline-item-badge');
|
||||
fixture.componentInstance.color = StatusColor.Warn;
|
||||
fixture.detectChanges();
|
||||
const badgeClassAfterSetColor = getClassName(fixture);
|
||||
expect(badgeClassAfterSetColor).toEqual('dsh-timeline-item-badge dsh-timeline-item-badge-warn');
|
||||
});
|
||||
});
|
||||
});
|
@ -3,7 +3,6 @@
|
||||
@import '../../components/buttons/button-toggle/button-toggle-theme';
|
||||
@import '../../components/layout/card/card-theme';
|
||||
@import '../../components/layout/panel/panel-theme';
|
||||
@import '../../components/layout/timeline/timeline-theme';
|
||||
@import '../../components/layout/dropdown/dropdown-theme';
|
||||
@import '../../components/layout/details-item/details-item-theme';
|
||||
@import '../../components/layout/row/row-theme';
|
||||
@ -43,7 +42,6 @@
|
||||
@include dsh-button-theme($theme);
|
||||
@include dsh-button-toggle-theme($theme);
|
||||
@include dsh-status-theme($theme);
|
||||
@include dsh-timeline-theme($theme);
|
||||
@include dsh-dadata-autocomplete-theme($theme);
|
||||
@include dsh-details-item-theme($theme);
|
||||
@include dsh-file-uploader-theme($theme);
|
||||
|
@ -3,7 +3,6 @@
|
||||
@import '../../components/buttons/button/button-theme';
|
||||
@import '../../components/buttons/button-toggle/button-toggle-theme';
|
||||
@import '../../components/layout/card/card-theme';
|
||||
@import '../../components/layout/timeline/timeline-theme';
|
||||
@import '../../components/layout/panel/panel-theme';
|
||||
@import '../../components/layout/dropdown/dropdown-theme';
|
||||
@import '../../components/layout/row/row-theme';
|
||||
@ -33,7 +32,6 @@
|
||||
@include dsh-card-typography($config);
|
||||
@include dsh-button-toggle-typography($config);
|
||||
@include dsh-dropdown-typography($config);
|
||||
@include dsh-timeline-typography($config);
|
||||
@include dsh-dadata-autocomplete-typography($config);
|
||||
@include dsh-panel-typography($config);
|
||||
@include dsh-charts-typography($config);
|
||||
|
Loading…
Reference in New Issue
Block a user