diff --git a/src/app/app-provider.module.ts b/src/app/app-provider.module.ts new file mode 100644 index 0000000..d4db7d8 --- /dev/null +++ b/src/app/app-provider.module.ts @@ -0,0 +1,37 @@ +import { NgModule, APP_INITIALIZER } from '@angular/core'; +import { HTTP_INTERCEPTORS } from '@angular/common/http'; +import { UserModule } from './pages/users/user/user.module'; + +import { AppService } from './service/app.service'; + + +export function initApp(appService: AppService) { + return () => appService.initApp(); +} +@NgModule({ + imports: [ + UserModule.forRoot(), + ], + exports: [], + providers: [ + AppService, + // ...GUARDS, + // CookieService, + // ClipboardService, + { + provide: APP_INITIALIZER, + useFactory: initApp, + deps: [AppService], + multi: true + }, + // { provide: HTTP_INTERCEPTORS, useClass: AuthHttpInterceptor, multi: true }, + { provide: 'virtualScroller.scrollThrottlingTime', useValue: 0 }, + { provide: 'virtualScroller.scrollDebounceTime', useValue: 0 }, + { provide: 'virtualScroller.scrollAnimationTime', useValue: 750 }, + { provide: 'virtualScroller.scrollbarWidth', useValue: undefined }, + { provide: 'virtualScroller.scrollbarHeight', useValue: undefined }, + { provide: 'virtualScroller.checkResizeInterval', useValue: 1000 }, + { provide: 'virtualScroller.resizeBypassRefreshThreshold', useValue: 5 } + ] +}) +export class AppProviderModule { } diff --git a/src/app/app-store.module.ts b/src/app/app-store.module.ts new file mode 100644 index 0000000..0692e74 --- /dev/null +++ b/src/app/app-store.module.ts @@ -0,0 +1,49 @@ +import { NgModule } from '@angular/core'; +import { StoreModule } from '@ngrx/store'; +import { StoreDevtoolsModule } from '@ngrx/store-devtools'; +import { + StoreRouterConnectingModule, +} from '@ngrx/router-store'; +import { EffectsModule } from '@ngrx/effects'; + +import { environment } from '../environments/environment'; +import { REDUCERS, META_REDUCERS, EFFECTS } from './store'; + +@NgModule({ + exports: [ + StoreModule, + ], + imports: [ + StoreModule.forRoot(REDUCERS, { metaReducers: META_REDUCERS }), + /** + * @ngrx/router-store keeps router state up-to-date in the store. + */ + StoreRouterConnectingModule.forRoot({ + /* + They stateKey defines the name of the state used by the router-store reducer. + This matches the key defined in the map of reducers + */ + stateKey: 'router', + }), + /** + * Store devtools instrument the store retaining past versions of state + * and recalculating new states. This enables powerful time-travel + * debugging. + * + * To use the debugger, install the Redux Devtools extension for either + * Chrome or Firefox + * + * See: https://github.com/zalmoxisus/redux-devtools-extension + */ + StoreDevtoolsModule.instrument({ + name: 'WebApp DevTools', + maxAge: 50, + logOnly: environment.production, + }), + EffectsModule.forRoot(EFFECTS), + ], + providers: [ + ], + +}) +export class AppStoreModule { } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 7f9885e..ec928d2 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -17,6 +17,8 @@ import { import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; +import { AppStoreModule } from './app-store.module'; +import { AppProviderModule } from './app-provider.module'; import { appFuseConfig } from './app.fuse'; import { LayoutModule } from './layout/layout.module'; @@ -43,10 +45,12 @@ import { from } from 'rxjs'; FuseThemeOptionsModule, HttpClientModule, - AppRoutingModule, - // App modules - LayoutModule + AppRoutingModule, + AppStoreModule, + AppProviderModule, + LayoutModule, + ], declarations: [AppComponent], providers: [], diff --git a/src/app/pages/common/util/service/abstract-rest.service.ts b/src/app/pages/common/util/service/abstract-rest.service.ts new file mode 100644 index 0000000..baf568c --- /dev/null +++ b/src/app/pages/common/util/service/abstract-rest.service.ts @@ -0,0 +1,48 @@ +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Observable, throwError } from 'rxjs'; +import { AbstractService, httpOptions } from './abstract.service'; +import { Base } from '../../../../../shared/common/model/base.model'; + +export abstract class AbstractRestService extends AbstractService { + public constructor(httpClient: HttpClient, apiEntryPoint: string) { + super(httpClient, apiEntryPoint); + } + + public getAll(): Observable { + return this.httpClient.get(this.apiEntryPoint); + } + + public get(id: string | number): Observable { + return this.httpClient.get(this.apiEntryPoint + `/${id}`, httpOptions); + } + + public save(model: T): Observable { + return model.id ? this.update(model) : this.add(model); + } + + public add(model: T): Observable { + return this.httpClient.put( + this.apiEntryPoint, + JSON.stringify(model), + httpOptions + ); + } + + public update(model: T): Observable { + if (!model.id) { + throwError('id of model is not valid'); + } + return this.httpClient.post( + `${this.apiEntryPoint}`, + JSON.stringify(model), + httpOptions + ); + } + + public delete(id: string | number): Observable { + return this.httpClient.delete( + `${this.apiEntryPoint}/${id}`, + httpOptions + ); + } +} diff --git a/src/app/pages/common/util/service/abstract.service.ts b/src/app/pages/common/util/service/abstract.service.ts new file mode 100644 index 0000000..b77d8ff --- /dev/null +++ b/src/app/pages/common/util/service/abstract.service.ts @@ -0,0 +1,18 @@ +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Base } from '../../../../../shared/common/model/base.model'; + +export const httpOptions = { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) +}; + +export abstract class AbstractService { + + public constructor( + protected httpClient: HttpClient, + protected apiEntryPoint: string, + ) { + + } +} diff --git a/src/app/pages/users/user/component/index.ts b/src/app/pages/users/user/component/index.ts index 9d31611..de372d8 100644 --- a/src/app/pages/users/user/component/index.ts +++ b/src/app/pages/users/user/component/index.ts @@ -1,5 +1,5 @@ -import { UserDetailComponent } from './user-detail.component'; -import { UserListComponent } from './user-list.component'; +import { UserDetailComponent } from './user-detail/user-detail.component'; +import { UserListComponent } from './user-list/user-list.component'; import { UserConnectComponent } from './user-connect/user-connect.component'; import { UserRegistComponent } from './user-regist/user-regist.component'; import { UserFeesComponent } from './user-fees/user-fees.component'; diff --git a/src/app/pages/users/user/component/user-detail.component.html b/src/app/pages/users/user/component/user-detail/user-detail.component.html similarity index 100% rename from src/app/pages/users/user/component/user-detail.component.html rename to src/app/pages/users/user/component/user-detail/user-detail.component.html diff --git a/src/app/pages/users/user/component/user-detail.component.scss b/src/app/pages/users/user/component/user-detail/user-detail.component.scss similarity index 100% rename from src/app/pages/users/user/component/user-detail.component.scss rename to src/app/pages/users/user/component/user-detail/user-detail.component.scss diff --git a/src/app/pages/users/user/component/user-detail.component.ts b/src/app/pages/users/user/component/user-detail/user-detail.component.ts similarity index 100% rename from src/app/pages/users/user/component/user-detail.component.ts rename to src/app/pages/users/user/component/user-detail/user-detail.component.ts diff --git a/src/app/pages/users/user/component/user-list.component.html b/src/app/pages/users/user/component/user-list/user-list.component.html similarity index 100% rename from src/app/pages/users/user/component/user-list.component.html rename to src/app/pages/users/user/component/user-list/user-list.component.html diff --git a/src/app/pages/users/user/component/user-list.component.scss b/src/app/pages/users/user/component/user-list/user-list.component.scss similarity index 100% rename from src/app/pages/users/user/component/user-list.component.scss rename to src/app/pages/users/user/component/user-list/user-list.component.scss diff --git a/src/app/pages/users/user/component/user-list.component.ts b/src/app/pages/users/user/component/user-list/user-list.component.ts similarity index 79% rename from src/app/pages/users/user/component/user-list.component.ts rename to src/app/pages/users/user/component/user-list/user-list.component.ts index 3ae933a..e1a758a 100644 --- a/src/app/pages/users/user/component/user-list.component.ts +++ b/src/app/pages/users/user/component/user-list/user-list.component.ts @@ -9,7 +9,7 @@ import { import { MatPaginator } from '@angular/material/paginator'; import { MatSort } from '@angular/material/sort'; import { DataSource } from '@angular/cdk/collections'; -import { BehaviorSubject, fromEvent, merge, Observable, Subject } from 'rxjs'; +import { BehaviorSubject, fromEvent, merge, Observable, Subject, from } from 'rxjs'; import { debounceTime, distinctUntilChanged, map } from 'rxjs/operators'; import { fuseAnimations } from 'src/@fuse/animations'; @@ -17,6 +17,9 @@ import { FuseUtils } from 'src/@fuse/utils'; import { takeUntil } from 'rxjs/internal/operators'; +import { User } from '../../../../../../shared/user/model/user.model'; +import { UserService } from '../../service/user.service'; + @Component({ selector: 'app-user-user-list', templateUrl: './user-list.component.html', @@ -61,7 +64,7 @@ export class UserListComponent implements OnInit, OnDestroy { * Constructor */ constructor( - + private userService: UserService ) { // Set the private defaults @@ -76,7 +79,7 @@ export class UserListComponent implements OnInit, OnDestroy { * On init */ ngOnInit(): void { - + this.fetchUserList(); } /** @@ -87,4 +90,15 @@ export class UserListComponent implements OnInit, OnDestroy { this._unsubscribeAll.next(); this._unsubscribeAll.complete(); } + + fetchUserList() { + this.userService.getAllUsers().pipe( + map((userList: User[]) => { + + if (userList && 0 < userList.length) { + console.log(userList); + } + }) + ).subscribe(); + } } diff --git a/src/app/pages/users/user/service/index.ts b/src/app/pages/users/user/service/index.ts new file mode 100644 index 0000000..63de552 --- /dev/null +++ b/src/app/pages/users/user/service/index.ts @@ -0,0 +1,5 @@ +import { UserService } from './user.service'; + +export const SERVICES = [ + UserService +]; diff --git a/src/app/pages/users/user/service/user.service.ts b/src/app/pages/users/user/service/user.service.ts new file mode 100644 index 0000000..390c092 --- /dev/null +++ b/src/app/pages/users/user/service/user.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { Observable } from 'rxjs'; +import { environment } from '../../../../../environments/environment'; +import { User } from '../../../../../shared/user/model/user.model'; +import { AbstractRestService } from '../../../common/util/service/abstract-rest.service'; + +@Injectable() +export class UserService extends AbstractRestService { + + public constructor(httpClient: HttpClient) { + super(httpClient, environment.apiEntryPoint + '/users'); + } + + public getAllUsers(): Observable { + return this.httpClient.get(`${this.apiEntryPoint}`); + } +} diff --git a/src/app/pages/users/user/store/index.ts b/src/app/pages/users/user/store/index.ts new file mode 100644 index 0000000..fc2faaa --- /dev/null +++ b/src/app/pages/users/user/store/index.ts @@ -0,0 +1,16 @@ +import { + createSelector, + createFeatureSelector, +} from '@ngrx/store'; + +// tslint:disable-next-line:no-empty-interface +export interface State { +} + +export const REDUCERS = { +}; + +export const EFFECTS = [ +]; + +export const selectState = createFeatureSelector('user'); diff --git a/src/app/pages/users/user/user-routing.module.ts b/src/app/pages/users/user/user-routing.module.ts index 4392c73..6980e0d 100644 --- a/src/app/pages/users/user/user-routing.module.ts +++ b/src/app/pages/users/user/user-routing.module.ts @@ -1,8 +1,8 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; -import { UserDetailComponent } from './component/user-detail.component'; -import { UserListComponent } from './component/user-list.component'; +import { UserDetailComponent } from './component/user-detail/user-detail.component'; +import { UserListComponent } from './component/user-list/user-list.component'; import { UserConnectComponent } from './component/user-connect/user-connect.component'; import { UserRegistComponent } from './component/user-regist/user-regist.component'; import { UserFeesComponent } from './component/user-fees/user-fees.component'; diff --git a/src/app/pages/users/user/user-store.module.ts b/src/app/pages/users/user/user-store.module.ts new file mode 100644 index 0000000..fa5446d --- /dev/null +++ b/src/app/pages/users/user/user-store.module.ts @@ -0,0 +1,25 @@ +import { NgModule, ModuleWithProviders } from '@angular/core'; +import { StoreModule } from '@ngrx/store'; +import { EffectsModule } from '@ngrx/effects'; + +import { + REDUCERS, + EFFECTS, +} from './store'; + +@NgModule({ + imports: [ + StoreModule.forFeature('user', REDUCERS), + EffectsModule.forFeature(EFFECTS), + ], +}) +export class UserStoreModule { +} + +@NgModule({ + imports: [ + UserStoreModule, + ], + exports: [] +}) +export class UserRootModule { } diff --git a/src/app/pages/users/user/user.module.ts b/src/app/pages/users/user/user.module.ts index 18eaef6..471f691 100644 --- a/src/app/pages/users/user/user.module.ts +++ b/src/app/pages/users/user/user.module.ts @@ -1,4 +1,4 @@ -import { NgModule } from '@angular/core'; +import { NgModule, ModuleWithProviders } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatChipsModule } from '@angular/material/chips'; @@ -26,6 +26,9 @@ import { MatStepperModule } from '@angular/material/stepper'; import { adapterFactory } from 'angular-calendar/date-adapters/date-fns'; +import { UserStoreModule } from './user-store.module'; +import { SERVICES } from './service'; + @NgModule({ imports: [ MatButtonModule, @@ -59,4 +62,19 @@ import { adapterFactory } from 'angular-calendar/date-adapters/date-fns'; declarations: [...COMPONENTS], }) -export class UserModule { } +export class UserModule { + public static forRoot(): ModuleWithProviders { + return { + ngModule: UserRootModule, + providers: [...SERVICES] + }; + } +} + +@NgModule({ + imports: [ + UserStoreModule, + ], + exports: [] +}) +export class UserRootModule { } diff --git a/src/app/service/app.service.ts b/src/app/service/app.service.ts new file mode 100644 index 0000000..946e57f --- /dev/null +++ b/src/app/service/app.service.ts @@ -0,0 +1,26 @@ +import { Injectable } from '@angular/core'; +import { Store, select } from '@ngrx/store'; +import { MatDialog } from '@angular/material'; +import { EventManager } from '@angular/platform-browser'; +import { CookieService } from 'ngx-cookie-service'; +import { TranslateService } from '@ngx-translate/core'; + +@Injectable() +export class AppService { + constructor( + private store: Store, + private eventManager: EventManager, + private cookieService: CookieService, + private tanslateService: TranslateService, + // private matDialog: MatDialog, + // private accountsService: AccountsService, + ) { } + + initApp(): Promise { + // return new Promise((resolve, reject) => { + // const browserLang = this.tanslateService.getBrowserCultureLang(); + + // }); + return null; + } +} diff --git a/src/app/store/index.ts b/src/app/store/index.ts new file mode 100644 index 0000000..405f32c --- /dev/null +++ b/src/app/store/index.ts @@ -0,0 +1,66 @@ +import { Type } from '@angular/core'; +import { + ActionReducer, + ActionReducerMap, + MetaReducer, + createSelector, +} from '@ngrx/store'; + +import * as fromRouter from '@ngrx/router-store'; + +import { environment } from '../../environments/environment'; + +// import * as AppEventsStore from './events'; +// import * as AppLayoutStore from './layout'; +// import * as AppLoginStore from './login'; +// import * as AppNicknameStore from './nickname'; +import * as AppRouterStore from './router'; + +export const EFFECTS: Type[] = [ + // AppLoginStore.Effects, + // AppEventsStore.Effects, + // AppNicknameStore.Effects, + AppRouterStore.Effects, +]; + +export const REDUCERS: ActionReducerMap = { + router: fromRouter.routerReducer, + // layout: AppLayoutStore.reducer, + // events: AppEventsStore.reducer, +}; + +// console.log all actions +export function logger(reducer: ActionReducer): ActionReducer { + return function (state: State, action: any): State { + const result = reducer(state, action); + console.groupCollapsed(action.type); + console.log('prev state', state); + console.log('action', action); + console.log('next state', result); + console.groupEnd(); + + return result; + }; +} + +export const META_REDUCERS: MetaReducer[] = !environment.production + ? [logger] + : []; + +export interface State { + router: fromRouter.RouterReducerState; + // layout: AppLayoutStore.State; + // events: AppEventsStore.State; +} + +export const AppRouterSelector = AppRouterStore.getSelectors( + (state: State) => state.router, +); + +// export const AppLayoutSelector = AppLayoutStore.getSelectors( +// (state: State) => state.layout, +// ); + +// export const AppEventsSelector = AppEventsStore.getSelectors( +// (state: State) => state.events, +// ); diff --git a/src/app/store/router/app-router.effect.ts b/src/app/store/router/app-router.effect.ts new file mode 100644 index 0000000..183eacf --- /dev/null +++ b/src/app/store/router/app-router.effect.ts @@ -0,0 +1,55 @@ +import { Injectable } from '@angular/core'; +// import { MatSnackBar, MatDialog } from '@angular/material'; +import { Location } from '@angular/common'; +import { Router } from '@angular/router'; + +import { Effect, Actions, ofType } from '@ngrx/effects'; +import { map, tap } from 'rxjs/operators'; + +@Injectable() +export class Effects { + constructor( + private actions$: Actions, + private router: Router, + private location: Location, + // private matSnackBar: MatSnackBar, + // private matDialog: MatDialog, + ) { } + + // @Effect({ dispatch: false }) + // userProfileGotoProfile$ = this.actions$.pipe( + // ofType(UserProfileStore.ActionType.GotoProfile), + // map((action: UserProfileStore.GotoProfile) => action.payload), + // tap((payload: { uid: string }) => { + // this.matDialog.closeAll(); + // this.router.navigateByUrl(`/article/${payload.uid}`); + // }), + // ); + + // @Effect({ dispatch: false }) + // userProfileGotoProfileEdit$ = this.actions$.pipe( + // ofType(UserProfileStore.ActionType.GotoProfileEdit), + // tap(() => { + // this.router.navigateByUrl(`/user/edit`); + // }), + // ); + + // @Effect({ dispatch: false }) + // userProfileGotoSettings$ = this.actions$.pipe( + // ofType(UserProfileStore.ActionType.GotoSettings), + // tap(() => { + // this.router.navigateByUrl(`/user/settings`); + // }), + // ); + + // @Effect({ dispatch: false }) + // articleRouterGotoSave$ = this.actions$.pipe( + // ofType(ArticleRouterStore.ActionType.GotoSave), + // map((action: ArticleRouterStore.GotoSave) => action.payload), + // tap((payload: { aid: string }) => { + // this.matDialog.closeAll(); + // this.router.navigateByUrl(`/article/write/${payload.aid}`); + // }), + // ); + +} diff --git a/src/app/store/router/app-router.state.ts b/src/app/store/router/app-router.state.ts new file mode 100644 index 0000000..8c30f98 --- /dev/null +++ b/src/app/store/router/app-router.state.ts @@ -0,0 +1,10 @@ +import { Selector, createSelector } from '@ngrx/store'; +import * as fromRouter from '@ngrx/router-store'; + +export type State = fromRouter.RouterReducerState; + +export function getSelectors(selector: Selector) { + return { + selectState: createSelector(selector, (state: State) => state.state), + }; +} diff --git a/src/app/store/router/index.ts b/src/app/store/router/index.ts new file mode 100644 index 0000000..d976c4e --- /dev/null +++ b/src/app/store/router/index.ts @@ -0,0 +1,2 @@ +export * from './app-router.effect'; +export * from './app-router.state'; diff --git a/src/environments/environment.hmr.ts b/src/environments/environment.hmr.ts index b129af6..0bcf859 100644 --- a/src/environments/environment.hmr.ts +++ b/src/environments/environment.hmr.ts @@ -1,4 +1,5 @@ export const environment = { production: false, - hmr : true + hmr: true, + apiEntryPoint: 'http://localhost:8088/api', }; diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts index bcbc881..b420753 100644 --- a/src/environments/environment.prod.ts +++ b/src/environments/environment.prod.ts @@ -1,4 +1,5 @@ export const environment = { production: true, - hmr : false + hmr: false, + apiEntryPoint: 'http://localhost:8088/api', }; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index afc7db5..ecd11a4 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -4,7 +4,8 @@ export const environment = { production: false, - hmr : false + hmr: false, + apiEntryPoint: 'http://localhost:8088/api', }; /* diff --git a/src/shared/common/model/base.model.ts b/src/shared/common/model/base.model.ts new file mode 100644 index 0000000..a01889b --- /dev/null +++ b/src/shared/common/model/base.model.ts @@ -0,0 +1,7 @@ + +export interface Base { + id?: string; + + createDate?: Date; + updateDate?: Date; +} diff --git a/src/shared/common/model/page-client.model.ts b/src/shared/common/model/page-client.model.ts new file mode 100644 index 0000000..aea77d6 --- /dev/null +++ b/src/shared/common/model/page-client.model.ts @@ -0,0 +1,10 @@ +export interface PageClient { + // content: Client[]; + totalPages: number; + totalElements: number; + last: boolean; + size: number; + first: boolean; + sort: string; + numberOfElements: number; +} diff --git a/src/shared/user/model/user.model.ts b/src/shared/user/model/user.model.ts new file mode 100644 index 0000000..b62ac77 --- /dev/null +++ b/src/shared/user/model/user.model.ts @@ -0,0 +1,17 @@ +import { Base } from '../../common/model/base.model'; + +export interface User extends Base { + username?: string; + nickname?: string; + email?: string; + block?: boolean; + isAdmin?: boolean; + sendEmail?: boolean; + activation?: string; + lastResetTime?: Date; + resetCount?: number; + otpKey?: string; + otp?: string; + requireReset?: boolean; + +}