This commit is contained in:
kushiji 2020-11-08 20:28:46 +01:00
commit e609b58ac9
12 changed files with 249 additions and 37 deletions

View File

@ -2921,6 +2921,30 @@
"intersection-observer": "0.7.0"
}
},
"@ngrx/effects": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-10.0.1.tgz",
"integrity": "sha512-pw0hRQNlyBBRHH1NRWl3TF+RtEAS4XOSnoTHPtQ84Ib/bEribvexsdEq3k6yLWvR3tLTudb5J6SYwYawcM6omA==",
"requires": {
"tslib": "^2.0.0"
}
},
"@ngrx/store": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/@ngrx/store/-/store-10.0.1.tgz",
"integrity": "sha512-ZbPvhp/tRYnS3jZ28mDOX2LH3jfySXT0uv8ffIboM/o9QxBGHpAJyBct2zkpy4duYBc3i/sIbRn+CEpAjLXjHw==",
"requires": {
"tslib": "^2.0.0"
}
},
"@ngrx/store-devtools": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/@ngrx/store-devtools/-/store-devtools-10.0.1.tgz",
"integrity": "sha512-kwgF1yjjVn0FER+AG83OLCYSMuX4/E3L+DN4doSoZs4BNO9FdkYIIA4ul1nXT5d6SLiFFTmlufmbgc6HCF3pjQ==",
"requires": {
"tslib": "^2.0.0"
}
},
"@ngtools/webpack": {
"version": "10.0.0",
"resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-10.0.0.tgz",

View File

@ -19,6 +19,9 @@
"@angular/router": "~10.0.0",
"@nebular/eva-icons": "5.0.0",
"@nebular/theme": "^5.0.0",
"@ngrx/effects": "^10.0.1",
"@ngrx/store": "^10.0.1",
"@ngrx/store-devtools": "^10.0.1",
"@types/papaparse": "^5.0.3",
"d3": "^5.16.0",
"eva-icons": "^1.1.2",

View File

@ -6,7 +6,7 @@ import { Observable } from 'rxjs';
export class SendDataService {
constructor(private http: HttpClient) {}
postFile(file: File): Observable<File> {
postFile(file: File): Observable<any> {
const formData: FormData = new FormData();
const requestOptions = {
responseType: 'text' as 'json',

View File

@ -0,0 +1,18 @@
import { HttpErrorResponse } from '@angular/common/http';
import { createAction, props } from '@ngrx/store';
export const fetchFile = createAction(
'[FrontPage Component] Fetch File',
props<{ file: File }>()
);
export const sendFile = createAction('[FrontPage Component] Send File');
export const sendFileError = createAction(
'[FrontPage Component] Send Error',
props<{ error: HttpErrorResponse }>()
);
export const sendFileSuccess = createAction(
'[FrontPage Component] Send Success',
props<{ data: string }>()
);

View File

@ -18,6 +18,10 @@ import {
import { FrontPageModule } from './front-page/front-page.module';
import { SharedDataService } from './_services/shared-data.service';
import { SidebarItemsService } from './_services/sidebar-items.service';
import { StoreModule } from '@ngrx/store';
import { reducers, metaReducers } from './reducers';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { EffectsModule } from '@ngrx/effects';
@NgModule({
declarations: [AppComponent],
@ -32,6 +36,11 @@ import { SidebarItemsService } from './_services/sidebar-items.service';
NbEvaIconsModule,
FrontPageModule,
NbToastrModule.forRoot(),
StoreModule.forRoot(reducers, {
metaReducers,
}),
StoreDevtoolsModule.instrument({ maxAge: 25 }),
EffectsModule.forRoot([]),
],
bootstrap: [AppComponent],
providers: [SharedDataService, NbSidebarService, SidebarItemsService],

View File

@ -0,0 +1,71 @@
import { Injectable } from '@angular/core';
import { SendDataService } from '../_services/send-data.service';
import * as FrontPageActions from '../actions/front-page.actions';
import * as FrontPageSelectors from '../selectors/front-page.selectors';
import { Actions, ofType, createEffect } from '@ngrx/effects';
import { State as AppState } from '../reducers/index';
import { Store } from '@ngrx/store';
import {
exhaustMap,
withLatestFrom,
tap,
map,
catchError,
concatMap,
flatMap,
} from 'rxjs/operators';
import { of } from 'rxjs';
import { NbToastrService } from '@nebular/theme';
import { Router } from '@angular/router';
@Injectable()
export class FrontPageEffect {
constructor(
private sendDataService: SendDataService,
private actions$: Actions,
private store$: Store<AppState>,
private toastService: NbToastrService,
private router: Router
) {}
file$ = createEffect(() =>
this.actions$.pipe(
ofType(FrontPageActions.sendFile),
concatMap((action) =>
of(action).pipe(
withLatestFrom(this.store$.select(FrontPageSelectors.selectFile))
)
),
flatMap(([_, file]) =>
this.sendDataService.postFile(file).pipe(
map((result) => FrontPageActions.sendFileSuccess({ data: result })),
catchError((error) => of(FrontPageActions.sendFileError({ error })))
)
)
)
);
toast$ = createEffect(
() =>
this.actions$.pipe(
ofType(FrontPageActions.sendFileError),
tap(({ error }) => {
if (error.status === 406) {
this.toastService.danger('', 'Format pliku jest niepoprawny!', {
icon: 'alert-circle',
});
}
})
),
{ dispatch: false }
);
navigate$ = createEffect(
() =>
this.actions$.pipe(
ofType(FrontPageActions.sendFileSuccess),
tap(() => this.router.navigate(['/view']))
),
{ dispatch: false }
);
}

View File

@ -41,12 +41,12 @@
nbButton
status="success"
(click)="sendFile($event)"
[disabled]="!isFileFetched"
[disabled]="!(isFileFetched$ | async)"
>
Wyślij!
</button>
<p *ngIf="fileName">
<nb-icon icon="file-add-outline"></nb-icon> {{ fileName }}
<p *ngIf="fileName$ | async">
<nb-icon icon="file-add-outline"></nb-icon> {{ fileName$ | async }}
</p>
</div>
</section>

View File

@ -1,27 +1,26 @@
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { SendDataService } from '../_services/send-data.service';
import { SharedDataService } from '../_services/shared-data.service';
import { HttpErrorResponse } from '@angular/common/http';
import { NbToastrService } from '@nebular/theme';
import { Component, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { State } from '../reducers/index';
import { Observable } from 'rxjs';
import * as Selectors from '../selectors/front-page.selectors';
import { fetchFile, sendFile } from '../actions/front-page.actions';
@Component({
selector: 'app-front-page',
templateUrl: './front-page.component.html',
styleUrls: ['./front-page.component.scss'],
})
export class FrontPageComponent {
private file: File;
public fileName: string;
public isFileFetched: boolean;
export class FrontPageComponent implements OnInit {
file$: Observable<File>;
fileName$: Observable<string>;
isFileFetched$: Observable<boolean>;
constructor(
private sendDataService: SendDataService,
private sharedDataService: SharedDataService,
private router: Router,
private toastService: NbToastrService
) {
this.isFileFetched = false;
constructor(private store: Store<State>) {}
ngOnInit() {
this.file$ = this.store.select(Selectors.selectFile);
this.fileName$ = this.store.select(Selectors.selectFileName);
this.isFileFetched$ = this.store.select(Selectors.selectFetchStatus);
}
scrollTo(el: HTMLElement) {
@ -38,24 +37,10 @@ export class FrontPageComponent {
}
fetchFile(event: any): void {
this.file = event.target.files[0];
this.fileName = this.file.name;
this.isFileFetched = true;
this.store.dispatch(fetchFile({ file: event.target.files[0] }));
}
sendFile(event: any): void {
this.sendDataService.postFile(this.file).subscribe(
(res: any) => {
this.sharedDataService.setData(res);
this.router.navigate(['/view']);
},
(error: HttpErrorResponse) => {
if (error.status === 406) {
this.toastService.danger('', 'Format pliku jest niepoprawny!', {
icon: 'alert-circle',
});
}
}
);
this.store.dispatch({ type: '[FrontPage Component] Send File' });
}
}

View File

@ -9,6 +9,8 @@ import {
NbIconModule,
NbStepperModule,
} from '@nebular/theme';
import { EffectsModule } from '@ngrx/effects';
import { FrontPageEffect } from '../effects/front-page.effects';
@NgModule({
declarations: [FrontPageComponent],
@ -19,6 +21,7 @@ import {
NbCardModule,
NbIconModule,
NbStepperModule,
EffectsModule.forFeature([FrontPageEffect]),
],
providers: [SendDataService],
})

View File

@ -0,0 +1,46 @@
import { Action, createReducer, on } from '@ngrx/store';
import * as Actions from '../actions/front-page.actions';
export interface State {
file: File;
fileName: string;
isFileFetched: boolean;
}
export interface DataState {
data: any;
}
export const initialState: State = {
file: {} as File,
fileName: '',
isFileFetched: false,
};
export const initialDataState: DataState = {
data: '',
};
const _fileReducer = createReducer(
initialState,
on(Actions.fetchFile, (_, { file }) => ({
file: file,
fileName: file.name,
isFileFetched: true,
}))
);
const _dataReducer = createReducer(
initialDataState,
on(Actions.sendFileSuccess, (_, { data }) => {
return { data: data };
})
);
export function fileReducer(state: State | undefined, action: Action) {
return _fileReducer(state, action);
}
export function dataReducer(state: DataState | undefined, action: Action) {
return _dataReducer(state, action);
}

View File

@ -0,0 +1,31 @@
import { ActionReducer, ActionReducerMap, MetaReducer } from '@ngrx/store';
import { environment } from '../../environments/environment';
import {
fileReducer,
State as FileState,
DataState,
dataReducer,
} from './front-page.reducers';
export function debug(reducer: ActionReducer<any>): ActionReducer<any> {
return function (state, action) {
console.log('State: ', state);
console.log('Action: ', action);
return reducer(state, action);
};
}
export interface State {
fileState: FileState;
data: DataState;
}
export const reducers: ActionReducerMap<State> = {
fileState: fileReducer,
data: dataReducer,
};
export const metaReducers: MetaReducer<State>[] = !environment.production
? [debug]
: [];

View File

@ -0,0 +1,22 @@
import { createSelector, createFeatureSelector } from '@ngrx/store';
import { State as AppState } from '../reducers/index';
import { State as FileState } from '../reducers/front-page.reducers';
export const selectFeature = createFeatureSelector<AppState, FileState>(
'fileState'
);
export const selectFile = createSelector(
selectFeature,
(state: FileState) => state.file
);
export const selectFileName = createSelector(
selectFeature,
(state: FileState) => state.fileName
);
export const selectFetchStatus = createSelector(
selectFeature,
(state: FileState) => state.isFileFetched
);