This commit is contained in:
byung eun park 2019-08-17 21:45:20 +09:00
parent 0e94a19d27
commit cd76913035
18 changed files with 668 additions and 3 deletions

View File

@ -5,7 +5,11 @@ const routes: Routes = [
{
path: 'pages',
loadChildren: './pages/pages.module#PagesModule'
}
},
{
path: 'auth',
loadChildren: './pages/accounts/accounts.module#AccountsModule'
},
];
@NgModule({

View File

@ -82,11 +82,14 @@ $typography: mat-typography-config(
@import 'src/app/layout/components/chat-panel/chat-panel.theme';
@import 'src/app/layout/components/toolbar/toolbar.theme';
@import 'src/app/pages/accounts/component/authentication/authentication.theme';
// Define a mixin for easier access
@mixin components-theme($theme) {
// Layout components
@include chat-panel-theme($theme);
@include toolbar-theme($theme);
@include login-theme($theme);
}
// -----------------------------------------------------------------------------------------------------

View File

@ -0,0 +1,37 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
// import { AccountsLayoutComponent } from '../../layout/component/accounts/accounts.layout.component';
// import { AuthenticationPageComponent } from './component/authentication/authentication.page.component';
// import { WelcomePageComponent } from './component/welcome/welcome.page.component';
// import { AuthenticationCallbackPageComponent } from './component/authentication/authentication-callback.page.component';
import { AuthenticationComponent } from './component/authentication/authentication.component';
const routes: Routes = [
{
path: 'signin',
component: AuthenticationComponent,
// children: [
// {
// path: 'authentication',
// component: AuthenticationPageComponent
// },
// {
// path: 'authentication/callback',
// component: AuthenticationCallbackPageComponent
// },
// {
// path: 'welcome',
// component: WelcomePageComponent
// }
// ]
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class AccountsRoutingPageModule { }

View File

@ -0,0 +1,17 @@
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('accounts', REDUCERS),
EffectsModule.forFeature(EFFECTS),
],
})
export class AccountsStoreModule {
}

View File

@ -0,0 +1,62 @@
import { NgModule, ModuleWithProviders } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import { COMPONENTS } from './component';
import { AccountsService } from './service/accounts.service';
import { AccountsStoreModule } from './accounts-store.module';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { FuseSharedModule } from 'src/@fuse/shared.module';
import { AccountsRoutingPageModule } from './accounts-routing.page.module';
// import { SharedModule } from '../../../common/shared/shared.module';
@NgModule({
imports: [
CommonModule,
TranslateModule,
AccountsRoutingPageModule,
MatButtonModule,
MatCheckboxModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
FuseSharedModule
// SharedModule,
],
declarations: [
...COMPONENTS,
],
exports: [
...COMPONENTS,
],
})
export class AccountsModule {
public static forRoot(): ModuleWithProviders<AccountsRootModule> {
return {
ngModule: AccountsRootModule,
providers: [
AccountsService,
],
};
}
}
@NgModule({
imports: [
AccountsStoreModule,
],
exports: [
]
})
export class AccountsRootModule {
}

View File

@ -0,0 +1,75 @@
<div id="login" fxLayout="column">
<div id="login-form-wrapper" fxLayout="column" fxLayoutAlign="center center">
<div id="login-form" [@animate]="{value:'*',params:{duration:'300ms',y:'100px'}}">
<div class="logo">
<img src="assets/images/logos/fuse.svg">
</div>
<div class="title">LOGIN TO YOUR ACCOUNT</div>
<form name="loginForm" [formGroup]="loginForm" (submit)="onSignin()" novalidate>
<mat-form-field appearance="outline">
<mat-label>username</mat-label>
<input matInput formControlName="username">
<mat-icon matSuffix class="secondary-text">mail</mat-icon>
<mat-error *ngIf="loginForm.get('username').hasError('required')">
username is required
</mat-error>
<mat-error *ngIf="!loginForm.get('username').hasError('required') &&
loginForm.get('username').hasError('username')">
Please enter a valid username
</mat-error>
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Password</mat-label>
<input matInput type="password" formControlName="password">
<mat-icon matSuffix class="secondary-text">vpn_key</mat-icon>
<mat-error>
Password is required
</mat-error>
</mat-form-field>
<div class="remember-forgot-password" fxLayout="row" fxLayout.xs="column" fxLayoutAlign="space-between center">
<mat-checkbox class="remember-me" aria-label="Remember Me">
Remember Me
</mat-checkbox>
<a class="forgot-password" [routerLink]="'/pages/auth/forgot-password'">
Forgot Password?
</a>
</div>
<button mat-raised-button color="accent" class="submit-button" aria-label="LOG IN"
[disabled]="loginForm.invalid">
LOGIN
</button>
</form>
<!--
<div class="separator">
<span class="text">OR</span>
</div>
<button mat-raised-button class="google">
Log in with Google
</button>
<button mat-raised-button class="facebook">
Log in with Facebook
</button>
<div class="register" fxLayout="column" fxLayoutAlign="center center">
<span class="text">Don't have an account?</span>
<a class="link" [routerLink]="'/pages/auth/register'">Create an account</a>
</div> -->
</div>
</div>
</div>

View File

@ -0,0 +1,147 @@
@import "src/@fuse/scss/fuse.scss";
authentication {
#login {
width: 100%;
background: url('/assets/images/backgrounds/dark-material-bg.jpg') no-repeat;
background-size: cover;
#login-form-wrapper {
flex: 1 0 auto;
padding: 32px;
@include media-breakpoint('xs') {
padding: 16px;
}
#login-form {
width: 384px;
max-width: 384px;
padding: 32px;
text-align: center;
@include mat-elevation(16);
@include media-breakpoint('xs') {
padding: 24px;
width: 100%;
}
.logo {
width: 128px;
margin: 32px auto;
}
.title {
font-size: 20px;
margin: 16px 0 32px 0;
}
form {
width: 100%;
text-align: left;
mat-form-field {
width: 100%;
}
mat-checkbox {
margin: 0;
}
.remember-forgot-password {
font-size: 13px;
margin-top: 8px;
.remember-me {
margin-bottom: 16px
}
.forgot-password {
font-size: 13px;
font-weight: 600;
margin-bottom: 16px
}
}
.submit-button {
width: 220px;
margin: 16px auto;
display: block;
@include media-breakpoint('xs') {
width: 90%;
}
}
}
.register {
margin: 32px auto 24px auto;
font-weight: 600;
.text {
margin-right: 8px;
}
}
.separator {
font-size: 15px;
font-weight: 600;
margin: 24px auto;
position: relative;
overflow: hidden;
width: 100px;
.text {
display: inline-flex;
position: relative;
padding: 0 8px;
z-index: 9999;
&:before,
&:after {
content: '';
display: block;
width: 30px;
position: absolute;
top: 10px;
border-top: 1px solid;
}
&:before {
right: 100%;
}
&:after {
left: 100%;
}
}
}
button {
&.google,
&.facebook {
width: 192px;
text-transform: none;
color: #FFFFFF;
font-size: 13px;
}
@include media-breakpoint('xs') {
width: 80%;
}
&.google {
background-color: #D73D32;
margin-bottom: 8px;
}
&.facebook {
background-color: rgb(63, 92, 154);
}
}
}
}
}
}

View File

@ -0,0 +1,68 @@
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { FuseConfigService } from 'src/@fuse/services/config.service';
import { fuseAnimations } from 'src/@fuse/animations';
@Component({
selector: 'authentication',
templateUrl: './authentication.component.html',
styleUrls: ['./authentication.component.scss'],
encapsulation: ViewEncapsulation.None,
animations: fuseAnimations
})
export class AuthenticationComponent implements OnInit {
loginForm: FormGroup;
/**
* Constructor
*
* @param {FuseConfigService} _fuseConfigService
* @param {FormBuilder} _formBuilder
*/
constructor(
private _fuseConfigService: FuseConfigService,
private _formBuilder: FormBuilder
) {
// Configure the layout
this._fuseConfigService.config = {
layout: {
navbar: {
hidden: true
},
toolbar: {
hidden: true
},
footer: {
hidden: true
},
sidepanel: {
hidden: true
}
}
};
}
// -----------------------------------------------------------------------------------------------------
// @ Lifecycle hooks
// -----------------------------------------------------------------------------------------------------
/**
* On init
*/
ngOnInit(): void {
this.loginForm = this._formBuilder.group({
username: ['', [Validators.required]],
password: ['', Validators.required]
});
}
onSignin(): void {
let userName = this.loginForm.get('username').value;
let password = this.loginForm.get('password').value;
}
}

View File

@ -0,0 +1,35 @@
@mixin login-theme($theme) {
$background: map-get($theme, background);
$foreground: map-get($theme, foreground);
$is-dark: map-get($theme, is-dark);
authentication {
#login {
#login-form-wrapper {
#login-form {
@if ($is-dark) {
background: mat-color($fuse-navy, 600);
} @else {
background: map-get($background, card);
}
.separator {
color: map-get($foreground, divider);
.text {
&:before,
&:after {
border-top-color: map-get($foreground, divider);
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,5 @@
import { AuthenticationComponent } from './authentication/authentication.component';
export const COMPONENTS = [
AuthenticationComponent,
];

View File

@ -0,0 +1,68 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { CookieService } from 'ngx-cookie-service';
import { environment } from '../../../../environments/environment';
import { User } from '../../../../shared/user/model/user.model';
@Injectable()
export class AccountsService {
public constructor(
private httpClient: HttpClient,
private cookieService: CookieService,
) {
}
// public authenticate(oauthType: string, params?: Map<string, string>) {
// const query = this.getQueryParams(params);
// const externalUrl = new URL(`${environment.oauth[oauthType].authenticateURL}?${query}`);
// window.open(externalUrl.href, '_self');
// }
// public authenticateOneall(oauthType: string, params?: Map<string, string>) {
// const callbackUri = `${environment.oauth.oneall.callbackURL}?${this.getQueryParams(params)}`;
// let query = '';
// query += `service=social_login`;
// query += `&callback_uri=${callbackUri}`;
// const externalUrl = new URL(`${environment.oauth.oneall.authenticateURL}/${oauthType}/?${query}`);
// window.open(externalUrl.href, '_self');
// }
protected getQueryParams(params?: Map<string, string>): string {
let query = '';
if (!params || 0 === params.size) {
model
return query;
}
params.forEach((value, key) => {
if ('' !== query) {
query += '&';
}
query += `${key}=${value}`;
});
return query;
}
public login(username: string, password: string): Observable<User> {
const model = {
username,
password
};
return this.httpClient.post<User>(
`${this.apiEntryPoint}/auth/signin`,
model
);
}
}

View File

@ -0,0 +1,48 @@
import { Action } from '@ngrx/store';
import { User } from '../../../../../shared/user/model/user.model';
export enum ActionType {
LoginProcessing = '[account.auth] LoginProcessing',
LoginSuccess = '[account.auth] LoginSuccess',
LogoutSuccess = '[account.auth] LogoutSuccess',
ChangeUser = '[account.auth] ChangeUser',
LoginRequired = '[account.auth] LoginRequired',
}
export class LoginProcessing implements Action {
readonly type = ActionType.LoginProcessing;
constructor(public payload: { processing: boolean }) { }
}
export class LoginSuccess implements Action {
readonly type = ActionType.LoginSuccess;
constructor(public payload: { user: User, returnURL: string }) { }
}
export class ChangeUser implements Action {
readonly type = ActionType.ChangeUser;
constructor(public payload: { user: User }) { }
}
export class LogoutSuccess implements Action {
readonly type = ActionType.LogoutSuccess;
}
export class LoginRequired implements Action {
readonly type = ActionType.LoginRequired;
constructor() { }
}
export type Actions =
| LoginProcessing
| LoginSuccess
| ChangeUser
| LogoutSuccess
| LoginRequired
;

View File

@ -0,0 +1,43 @@
import { Actions, ActionType } from './auth.action';
import { State, initialState } from './auth.state';
export function reducer(state: State = initialState, action: Actions): State {
switch (action.type) {
case ActionType.LoginProcessing: {
return {
...state,
processing: action.payload.processing
};
}
case ActionType.LoginSuccess: {
return {
...state,
processing: false,
logined: true,
user: action.payload.user
};
}
case ActionType.ChangeUser: {
return {
...state,
user: action.payload.user
};
}
case ActionType.LogoutSuccess: {
return {
...state,
processing: false,
logined: false,
user: null
};
}
default: {
return state;
}
}
}

View File

@ -0,0 +1,22 @@
import { Selector, createSelector } from '@ngrx/store';
import { User } from '../../../../../shared/user/model/user.model';
export interface State {
processing: boolean;
logined: boolean;
user: User | null;
}
export const initialState: State = {
processing: false,
logined: false,
user: null,
};
export function getSelectors<S>(selector: Selector<any, State>) {
return {
selectProcessing: createSelector(selector, (state: State) => state.processing),
selectLogined: createSelector(selector, (state: State) => state.logined),
selectUser: createSelector(selector, (state: State) => state.user),
};
}

View File

@ -0,0 +1,3 @@
export * from './auth.action';
export * from './auth.reducer';
export * from './auth.state';

View File

@ -0,0 +1,24 @@
import {
createSelector,
createFeatureSelector,
} from '@ngrx/store';
import * as AuthStore from './auth';
export interface State {
auth: AuthStore.State;
}
export const REDUCERS = {
auth: AuthStore.reducer,
};
export const EFFECTS = [
];
export const selectState = createFeatureSelector<State>('accounts');
export const AuthSelector = AuthStore.getSelectors(createSelector(
selectState,
(state: State) => state.auth,
));

View File

@ -4,6 +4,7 @@ import { FuseSharedModule } from 'src/@fuse/shared.module';
import { PagesRoutingModule } from './pages-routing.module';
@NgModule({
imports: [FuseSharedModule, PagesRoutingModule]
imports: [FuseSharedModule, PagesRoutingModule],
declarations: []
})
export class PagesModule { }

View File

@ -48,6 +48,9 @@ export class UserListComponent implements OnInit, OnDestroy {
'recentConnectIp'
];
total: number;
userList: User[];
@ViewChild(MatPaginator, { static: true })
paginator: MatPaginator;