This commit is contained in:
crusader 2017-06-27 22:00:55 +09:00
parent 77b2c1ed7b
commit 9139cd82ae
51 changed files with 939 additions and 389 deletions

View File

@ -20,15 +20,18 @@
"stats": "set NODE_ENV=production && webpack --progress --config ./config/webpack/webpack.config.stats.js --profile --json > ./config/webpack/stats/stats.json"
},
"devDependencies": {
"@types/auth0-lock": "^10.16.0",
"@types/history": "^4.6.0",
"@types/jest": "^19.2.4",
"@types/material-ui": "^0.17.11",
"@types/prop-types": "^15.5.1",
"@types/react": "^15.0.24",
"@types/react-addons-test-utils": "^0.14.18",
"@types/react-dom": "^15.5.0",
"@types/react-redux": "4.4.40",
"@types/react-router": "^4.0.9",
"@types/react-router-dom": "^4.0.4",
"@types/react": "^15.0.32",
"@types/react-addons-test-utils": "^0.14.19",
"@types/react-dom": "^15.5.1",
"@types/react-redux": "^4.4.45",
"@types/react-router": "^4.0.12",
"@types/react-router-dom": "^4.0.5",
"@types/react-router-redux": "^5.0.3",
"@types/react-tap-event-plugin": "^0.0.30",
"@types/redux": "^3.6.0",
"@types/redux-actions": "^1.2.6",
@ -62,22 +65,24 @@
"webpack-visualizer-plugin": "^0.1.11"
},
"dependencies": {
"auth0-lock": "^10.18.0",
"history": "^4.6.3",
"immutable": "^3.8.1",
"material-ui": "^0.18.3",
"prop-types":"^15.5.10",
"react": "^15.5.4",
"react-dom": "15.5.4",
"prop-types": "^15.5.10",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-immutable-proptypes": "^2.1.0",
"react-redux": "^5.0.5",
"react-router": "^4.1.1",
"react-router-dom": "^4.1.1",
"react-router-redux": "next",
"react-tap-event-plugin": "^2.0.1",
"redux": "^3.6.0",
"redux": "^3.7.1",
"redux-actions": "^2.0.3",
"redux-saga": "^0.15.3",
"redux-saga": "^0.15.4",
"reselect": "^3.0.1"
},
"jest": {
"moduleFileExtensions": [
"ts",

View File

@ -0,0 +1,31 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Route } from 'react-router-dom';
import { RouteComponentProps, Switch } from 'react-router';
import Signin from 'member/signin/views/Signin';
export interface Props {
}
export interface State {
}
export default class App extends React.Component<Props, State> {
public constructor(props: Props, context: State) {
super(props, context);
}
public render(): JSX.Element {
return (
<div>
<Switch>
<Route exact path='/' component={Signin} />
</Switch>
</div>
);
}
}

View File

@ -0,0 +1,8 @@
interface IModule<IComponentType, IContainerType, IViewType, IReduxType> {
components: IComponentType;
containers: IContainerType;
views: IViewType;
redux: IReduxType;
}
export default IModule;

View File

@ -1,8 +1,8 @@
interface Action<Payload = {}> {
type: any;
import * as Redux from 'redux';
interface Action<Payload = {}> extends Redux.Action {
payload?: Payload;
error?: Error;
}
export default Action;

View File

@ -1,10 +1,8 @@
import Action from './Action';
interface IModule<State, Payload> {
Name: string;
ActionTypes: {[key: string]: any};
Actions: {[key: string]: any};
Reducer: (state: State, action: Action<Payload>) => State;
export interface IModule<State = {}, Payload = {}> {
state: State;
reducer: (state: State, action: Action<Payload>) => State;
}
export default IModule;

View File

@ -1,55 +0,0 @@
import { Iterable, Map, Record as ImmutableRecord } from 'immutable';
export interface Record<T extends Record<T>> extends Map<string, any> {
set: (prop: string, val: any) => T;
delete: (key: string) => T;
remove: (key: string) => T;
clear: () => T;
update: {
(updater: (value: T) => any): T;
(key: string, updater: (value: any) => any): T;
(key: string, notSetValue: any, updater: (value: any) => any): T;
};
merge: (obj: any) => T;
mergeWith: (
merger: (previous?: any, next?: any, key?: string) => any,
obj: any,
) => T;
mergeDeep: (obj: any) => T;
mergeDeepWith: (
merger: (previous?: any, next?: any, key?: string) => any,
obj: any,
) => T;
setIn: (keyPath: any[] | Iterable<any, any>, value: any) => T;
deleteIn: (keyPath: Array<any> | Iterable<any, any>) => T;
removeIn: (keyPath: Array<any> | Iterable<any, any>) => T;
updateIn: {
(keyPath: any[] | Iterable<any, any>, updater: (value: any) => any): T;
(
keyPath: any[] | Iterable<any, any>,
notSetValue: any,
updater: (value: any) => any,
): T
};
mergeIn: (keyPath: any[] | Iterable<any, any>, obj: any) => T;
mergeDeepIn: (keyPath: any[] | Iterable<any, any>, obj: any) => T;
withMutations: (mutator: (mutable: T) => any) => T;
asMutable: () => T;
asImmutable: () => T;
}
export function makeRecordType<O, R extends Record<R> & O>
(defaultVal: O, val: O = null, name?: string): R {
const RecordFactory = makeRecordFactory<O, R>(defaultVal, name);
return val ? RecordFactory(val) : RecordFactory();
}
export function makeRecordFactory<O, R extends Record<R> & O>
(obj: O, name?: string): (val?: O) => R {
const iRecord = ImmutableRecord(obj, name);
return (val: O = null) => {
return new iRecord(val) as R;
};
}

View File

@ -0,0 +1,9 @@
export function* getAppContainer(containerId: string): any {
const appContainer = yield new Promise(resolve => {
document.addEventListener('DOMContentLoaded', () => {
resolve(document.getElementById(containerId));
});
});
return appContainer;
}

View File

@ -0,0 +1,25 @@
import { colors, getMuiTheme, MuiTheme, spacing } from 'material-ui/styles';
import { fade } from 'material-ui/utils/colorManipulator';
const muiTheme:MuiTheme = getMuiTheme({
spacing: spacing,
fontFamily: 'Roboto, sans-serif',
palette: {
primary1Color: colors.cyan500,
primary2Color: colors.cyan700,
primary3Color: colors.grey400,
accent1Color: colors.pinkA200,
accent2Color: colors.grey100,
accent3Color: colors.grey500,
textColor: colors.darkBlack,
alternateTextColor: colors.white,
canvasColor: colors.white,
borderColor: colors.grey300,
disabledColor: fade(colors.darkBlack, 0.3),
pickerHeaderColor: colors.cyan500,
clockCircleColor: fade(colors.darkBlack, 0.07),
shadowColor: colors.fullBlack,
},
});
export default muiTheme;

View File

@ -0,0 +1,14 @@
import { Action, combineReducers } from 'redux';
import { routerReducer, RouterState } from 'react-router-redux';
import * as Member from 'member';
export interface State {
member: Member.State;
router: RouterState;
}
export const reducer = combineReducers<State>({
member: Member.reducer,
router: routerReducer,
});

View File

@ -0,0 +1,2 @@

View File

@ -0,0 +1,18 @@
import { applyMiddleware, compose, createStore, Store } from 'redux';
import { routerMiddleware } from 'react-router-redux';
import { SagaMiddleware } from 'redux-saga';
import { History } from 'history';
import { reducer, State } from './configureRedux';
export default function configureStore(history: History, sagaMiddleware: SagaMiddleware<any>): Store<State> {
const middlewares = [sagaMiddleware, routerMiddleware(history)];
const store = createStore<State>(
reducer,
applyMiddleware(...middlewares),
);
// sagaMiddleware.run(rootSaga);
return store;
}

View File

@ -1,32 +1,56 @@
import * as member from 'member/redux';
import { Action, createStore, combineReducers } from 'redux';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import createSagaMiddleware, { SagaMiddleware } from 'redux-saga';
import { createHashHistory } from 'history';
export interface StateRecord {
member: member.StateRecord;
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import * as injectTapEventPlugin from 'react-tap-event-plugin';
import * as system from 'commons/util/system';
import configureStore from 'config/configureStore';
import muiTheme from 'config/configureMuiTheme';
import App from 'app/views/container/component/App';
injectTapEventPlugin();
const sagaMiddleware: SagaMiddleware<any> = createSagaMiddleware();
const history = createHashHistory();
const store = configureStore(history, sagaMiddleware);
function* app(): any {
const appContainer = yield system.getAppContainer('react-placeholder');
ReactDOM.render(
<div style={{
width: '100vw',
height: '100vh',
backgroundColor: 'white',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}>
<h1>Loading...</h1>
</div>,
appContainer,
);
ReactDOM.render(
<Provider store={store}>
<ConnectedRouter history={history}>
<MuiThemeProvider muiTheme={muiTheme}>
<App/>
</MuiThemeProvider>
</ConnectedRouter>
</Provider>,
appContainer,
);
}
export interface IActionTypes {
member: member.IActionTypes;
}
export const ActionTypes: IActionTypes = {
member: member.ActionTypes,
};
export interface IActions {
member: member.IActions;
}
export const Actions: IActions = {
member: member.Actions,
};
export const Reducers = combineReducers<StateRecord>({
member: member.Reducers,
});
let store = createStore(Reducers);
console.log('');
sagaMiddleware.run(app);

View File

@ -1,7 +1,7 @@
import {MemberStatus} from './MemberStatus';
export interface Member {
interface Member {
id?: number;
email: string;
name: string;
@ -10,3 +10,5 @@ export interface Member {
createDate?: Date;
status?: MemberStatus;
}
export default Member;

18
src/ts/member/index.ts Normal file
View File

@ -0,0 +1,18 @@
import { Action, combineReducers } from 'redux';
import IModule from 'commons/redux/Module';
import * as signin from './signin';
import * as signout from './signout';
import * as signup from './signup';
export interface State {
signin: signin.State;
signout: signin.State;
signup: signin.State;
}
export const reducer = combineReducers<State>({
signin: signin.reducer,
signout: signout.reducer,
signup: signup.reducer,
});

View File

@ -1,44 +0,0 @@
import { Action, combineReducers } from 'redux';
import * as signin from './signin';
import * as signout from './signout';
import * as signup from './signup';
export const ModuleName = 'member';
export interface StateRecord {
signin: signin.StateRecord;
signout: signout.StateRecord;
signup: signup.StateRecord;
}
export interface IActionTypes {
signin: signin.IActionTypes;
signout: signout.IActionTypes;
signup: signup.IActionTypes;
}
export const ActionTypes: IActionTypes = {
signin: signin.ActionTypes,
signout: signout.ActionTypes,
signup: signup.ActionTypes,
};
export interface IActions {
signin: signin.IActions;
signout: signout.IActions;
signup: signup.IActions;
}
export const Actions: IActions = {
signin: signin.Actions,
signout: signout.Actions,
signup: signup.Actions,
};
export const Reducers = combineReducers<StateRecord>({
signin: signin.Reducers,
signout: signout.Reducers,
signup: signup.Reducers,
});

View File

@ -1,90 +0,0 @@
import Action from 'commons/redux/Action';
import { Record, makeRecordFactory } from 'commons/util/immutable/Record';
import { Member } from 'member/api/model/Member';
export const ModuleName = 'signin';
export type REQUEST = '@overflow/member/signin/REQUEST';
export type REQUEST_SUCCESS = '@overflow/member/signin/REQUEST_SUCCESS';
export type REQUEST_FAILURE = '@overflow/member/signin/REQUEST_FAILURE';
export interface SigninPayload {
signinId: string;
signinPw: string;
}
export interface MemberPayload extends Member {
}
export interface State {
isAuthenticated: boolean;
member?: Member;
error?: Error;
}
export interface StateRecord extends Record<StateRecord>, State {
}
const makeStateRecord = makeRecordFactory<State, StateRecord>({
isAuthenticated: undefined,
member: undefined,
error: undefined,
});
export interface IActionTypes {
REQUEST: REQUEST;
REQUEST_SUCCESS: REQUEST_SUCCESS;
REQUEST_FAILURE: REQUEST_FAILURE;
}
export const ActionTypes: IActionTypes = {
REQUEST: '@overflow/member/signin/REQUEST',
REQUEST_SUCCESS: '@overflow/member/signin/REQUEST_SUCCESS',
REQUEST_FAILURE: '@overflow/member/signin/REQUEST_FAILURE',
};
export interface IActions {
request: (signinId: string, signinPw: string) => Action<SigninPayload>;
requestSuccess: (member: Member) => Action<Member>;
requestFailure: (error: Error) => Action;
}
export const Actions: IActions = {
request(signinId: string, signinPw: string): Action<SigninPayload> {
return {
type: ActionTypes.REQUEST,
payload: {
signinId: signinId,
signinPw: signinPw,
},
};
},
requestSuccess(member: Member): Action<Member> {
return {
type: ActionTypes.REQUEST,
payload: member,
};
},
requestFailure(error: Error): Action {
return {
type: ActionTypes.REQUEST,
error: error,
};
},
};
export function Reducers(state: StateRecord = makeStateRecord(), action: Action<MemberPayload | Error>): StateRecord {
switch (action.type) {
case ActionTypes.REQUEST_SUCCESS:
{
return state.merge({isAuthenticated: true, member: action.payload});
}
case ActionTypes.REQUEST_FAILURE:
{
return state.merge({isAuthenticated: false, error: action.error});
}
default:
return state;
}
}

View File

@ -1,70 +0,0 @@
import Action from 'commons/redux/Action';
import { Record, makeRecordFactory } from 'commons/util/immutable/Record';
import { Member } from 'member/api/model/Member';
export type REQUEST = '@overflow/member/signout/REQUEST';
export type REQUEST_SUCCESS = '@overflow/member/signout/REQUEST_SUCCESS';
export type REQUEST_FAILURE = '@overflow/member/signout/REQUEST_FAILURE';
export const ModuleName = 'signout';
export interface State {
}
export interface StateRecord extends Record<StateRecord>, State {
}
const makeStateRecord = makeRecordFactory<State, StateRecord>({
});
export interface IActionTypes {
REQUEST: REQUEST;
REQUEST_SUCCESS: REQUEST_SUCCESS;
REQUEST_FAILURE: REQUEST_FAILURE;
}
export const ActionTypes: IActionTypes = {
REQUEST: '@overflow/member/signout/REQUEST',
REQUEST_SUCCESS: '@overflow/member/signout/REQUEST_SUCCESS',
REQUEST_FAILURE: '@overflow/member/signout/REQUEST_FAILURE',
};
export interface IActions {
request: () => Action;
requestSuccess: () => Action;
requestFailure: (error: Error) => Action;
}
export const Actions: IActions = {
request(): Action {
return {
type: ActionTypes.REQUEST,
};
},
requestSuccess(): Action {
return {
type: ActionTypes.REQUEST,
};
},
requestFailure(error: Error): Action {
return {
type: ActionTypes.REQUEST,
error: error,
};
},
};
export function Reducers(state: StateRecord = makeStateRecord(), action: Action): StateRecord {
switch (action.type) {
case ActionTypes.REQUEST_SUCCESS:
{
return state.merge({isAuthenticated: true, member: action.payload});
}
case ActionTypes.REQUEST_FAILURE:
{
return state.merge({isAuthenticated: false, error: action.error});
}
default:
return state;
}
}

View File

@ -1,81 +0,0 @@
import Action from 'commons/redux/Action';
import { Record, makeRecordFactory } from 'commons/util/immutable/Record';
import { Member } from 'member/api/model/Member';
export const ModuleName = 'signup';
export type REQUEST = '@overflow/member/signup/REQUEST';
export type REQUEST_SUCCESS = '@overflow/member/signup/REQUEST_SUCCESS';
export type REQUEST_FAILURE = '@overflow/member/signup/REQUEST_FAILURE';
export interface MemberPayload extends Member {
}
export interface State {
isRegistered: boolean;
member?: Member;
error?: Error;
}
export interface StateRecord extends Record<StateRecord>, State {
}
const makeStateRecord = makeRecordFactory<State, StateRecord>({
isRegistered: undefined,
member: undefined,
error: undefined,
});
export interface IActionTypes {
REQUEST: REQUEST;
REQUEST_SUCCESS: REQUEST_SUCCESS;
REQUEST_FAILURE: REQUEST_FAILURE;
}
export const ActionTypes: IActionTypes = {
REQUEST: '@overflow/member/signup/REQUEST',
REQUEST_SUCCESS: '@overflow/member/signup/REQUEST_SUCCESS',
REQUEST_FAILURE: '@overflow/member/signup/REQUEST_FAILURE',
};
export interface IActions {
request: (member: Member) => Action<MemberPayload>;
requestSuccess: (member: Member) => Action<Member>;
requestFailure: (error: Error) => Action;
}
export const Actions: IActions = {
request(member: Member): Action<MemberPayload> {
return {
type: ActionTypes.REQUEST,
payload: member,
};
},
requestSuccess(member: Member): Action<Member> {
return {
type: ActionTypes.REQUEST,
payload: member,
};
},
requestFailure(error: Error): Action {
return {
type: ActionTypes.REQUEST,
error: error,
};
},
};
export function Reducers(state: StateRecord = makeStateRecord(), action: Action<MemberPayload | Error>): StateRecord {
switch (action.type) {
case ActionTypes.REQUEST_SUCCESS:
{
return state.merge({isRegistered: true, member: action.payload});
}
case ActionTypes.REQUEST_FAILURE:
{
return state.merge({isRegistered: false, error: action.error});
}
default:
return state;
}
}

View File

@ -0,0 +1 @@
export * from './redux';

View File

@ -0,0 +1,41 @@
import Action from 'commons/redux/Action';
import Member from 'member/api/model/Member';
import actionTypes from './type';
import SigninPayload from '../payload/SigninPayload';
export interface Actions {
request: (signinId: string, signinPw: string) => Action<SigninPayload>;
requestSuccess: (member: Member) => Action<Member>;
requestFailure: (error: Error) => Action;
}
export const actions: Actions = {
request(signinId: string, signinPw: string): Action<SigninPayload> {
return {
type: actionTypes.REQUEST,
payload: {
signinId: signinId,
signinPw: signinPw,
},
};
},
requestSuccess(member: Member): Action<Member> {
return {
type: actionTypes.REQUEST,
payload: member,
};
},
requestFailure(error: Error): Action {
return {
type: actionTypes.REQUEST,
error: error,
};
},
};
export default actions;

View File

@ -0,0 +1,17 @@
export type REQUEST = '@overflow/member/signin/REQUEST';
export type REQUEST_SUCCESS = '@overflow/member/signin/REQUEST_SUCCESS';
export type REQUEST_FAILURE = '@overflow/member/signin/REQUEST_FAILURE';
export interface ActionTypes {
REQUEST: REQUEST;
REQUEST_SUCCESS: REQUEST_SUCCESS;
REQUEST_FAILURE: REQUEST_FAILURE;
}
export const actionTypes: ActionTypes = {
REQUEST: '@overflow/member/signin/REQUEST',
REQUEST_SUCCESS: '@overflow/member/signin/REQUEST_SUCCESS',
REQUEST_FAILURE: '@overflow/member/signin/REQUEST_FAILURE',
};
export default actionTypes;

View File

@ -0,0 +1,2 @@
export * from './state';
export * from './reducer';

View File

@ -0,0 +1,6 @@
interface SigninPayload {
signinId: string;
signinPw: string;
}
export default SigninPayload;

View File

@ -0,0 +1,24 @@
import Action from 'commons/redux/Action';
import IModule from 'commons/redux/Module';
import Member from 'member/api/model/Member';
import actionTypes from '../action/type';
import State, { defaultState } from '../state';
export function reducer(state: State = defaultState, action: Action<Member | Error>): State {
switch (action.type) {
case actionTypes.REQUEST_SUCCESS:
{
return state;
}
case actionTypes.REQUEST_FAILURE:
{
return state;
}
default:
return state;
}
}

View File

@ -0,0 +1,43 @@
import { takeLatest, SagaIterator } from 'redux-saga';
import { call, put } from 'redux-saga/effects';
import Action from 'commons/redux/Action';
import Member from 'member/api/model/Member';
import actions from '../action';
import actionTypes from '../action/type';
import SigninPayload from '../payload/SigninPayload';
export function* signin(action: Action<SigninPayload>): SagaIterator {
try {
const {signinId, signinPw} = action.payload;
// yield put({
// type: types.SENDING_REQUEST,
// payload: {sendingRequest: true},
// });
// const responseBody = yield call(api.login, signinId, signinPw);
// if (responseBody.token === undefined) {
// throw new Error(MESSAGES.UNABLE_TO_FIND_TOKEN_IN_LOGIN_RESPONSE);
// }
let member: Member = {
email: 'crusader@loafle.com',
name: 'crusader',
phone: '02-900-9000',
companyName: 'LOAFLE',
};
yield put(actions.requestSuccess(member));
} catch (e) {
yield put(actions.requestFailure(e));
} finally {
// yield put({
// type: types.SENDING_REQUEST,
// payload: {sendingRequest: false},
// });
}
}
export function* watchSignin(): any {
yield takeLatest(actionTypes.REQUEST, signin);
}

View File

@ -0,0 +1,15 @@
import Member from 'member/api/model/Member';
export interface State {
isAuthenticated: boolean;
member?: Member;
error?: Error;
}
export const defaultState: State = {
isAuthenticated: undefined,
member: undefined,
error: undefined,
};
export default State;

View File

@ -0,0 +1,14 @@
import * as React from 'react';
import { RouteComponentProps } from 'react-router';
import SigninContainer from './containers/Signin';
class Signin extends React.Component<RouteComponentProps<object>, object> {
public render(): JSX.Element {
return (
<SigninContainer/>
);
}
}
export default Signin;

View File

@ -0,0 +1,30 @@
import { connect, Dispatch } from 'react-redux';
import {
Signin,
Props as SigninProps,
State as SigninState,
} from './components/Signin';
import signinActions from 'member/signin/redux/action';
export function mapStateToProps(state: any): SigninProps {
return {
};
}
export function mapDispatchToProps(dispatch: Dispatch<any>): SigninProps {
return {
onSignin: (signinId: string, signinPw: string) => {
dispatch(signinActions.request(signinId, signinPw));
},
onSignup: () => {
return;
},
onResetPassword: () => {
return;
},
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Signin);

View File

@ -0,0 +1,90 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
Dialog,
Divider,
FlatButton,
MenuItem,
Paper,
RaisedButton,
SelectField,
Slider,
TextField,
} from 'material-ui';
export interface Props {
onSignin?: (signinId: string, signinPw: string) => void;
onSignup?: () => void;
onResetPassword?: () => void;
}
export interface State {
signinId: string;
signinPw: string;
}
export class Signin extends React.Component<Props, State> {
public static defaultProps: Partial<Props> = {
onSignin: (signinId: string, signinPw: string): void => {
console.log('onSignin');
},
onSignup: (): void => {
console.log('onSignup');
},
onResetPassword: (): void => {
console.log('onResetPassword');
},
};
public constructor(props: Props, context: State) {
super(props, context);
this.state = {
signinId: '',
signinPw: '',
};
}
public render(): JSX.Element {
return (
<div>
<TextField
hintText='smith@gmail.com'
floatingLabelText='Email address*'
errorText=''
underlineShow={true}
value={this.state.signinId}
onChange={(e, newValue) => this.setState({ signinId: newValue })}
/>
<br />
<TextField
hintText='Password'
floatingLabelText='Password'
type='password'
value={this.state.signinPw}
onChange={(e, newValue) => this.setState({ signinPw: newValue })}
/>
<br />
<RaisedButton
label='Sign In'
primary={true}
onClick={(e) => this.props.onSignin(this.state.signinId, this.state.signinPw)}
/>
<RaisedButton
label='Sign Up'
primary={false}
onClick={this.props.onSignup}
/>
<RaisedButton
label='Reset Password'
primary={false}
onClick={this.props.onResetPassword}
/>
</div>
);
}
}

View File

@ -0,0 +1 @@
export * from './redux';

View File

@ -0,0 +1,33 @@
import Action from 'commons/redux/Action';
import actionTypes from './type';
import SignoutPayload from '../payload/SignoutPayload';
export interface Actions {
request: () => Action;
requestSuccess: () => Action;
requestFailure: (error: Error) => Action;
}
export const actions: Actions = {
request(): Action {
return {
type: actionTypes.REQUEST,
};
},
requestSuccess(): Action {
return {
type: actionTypes.REQUEST,
};
},
requestFailure(error: Error): Action {
return {
type: actionTypes.REQUEST,
error: error,
};
},
};
export default actions;

View File

@ -0,0 +1,17 @@
export type REQUEST = '@overflow/member/signout/REQUEST';
export type REQUEST_SUCCESS = '@overflow/member/signout/REQUEST_SUCCESS';
export type REQUEST_FAILURE = '@overflow/member/signout/REQUEST_FAILURE';
export interface ActionTypes {
REQUEST: REQUEST;
REQUEST_SUCCESS: REQUEST_SUCCESS;
REQUEST_FAILURE: REQUEST_FAILURE;
}
export const actionTypes: ActionTypes = {
REQUEST: '@overflow/member/signout/REQUEST',
REQUEST_SUCCESS: '@overflow/member/signout/REQUEST_SUCCESS',
REQUEST_FAILURE: '@overflow/member/signout/REQUEST_FAILURE',
};
export default actionTypes;

View File

@ -0,0 +1,2 @@
export * from './state';
export * from './reducer';

View File

@ -0,0 +1,4 @@
interface SignoutPayload {
}
export default SignoutPayload;

View File

@ -0,0 +1,21 @@
import Action from 'commons/redux/Action';
import IModule from 'commons/redux/Module';
import actionTypes from '../action/type';
import State, { defaultState } from '../state';
export function reducer(state: State = defaultState, action: Action): State {
switch (action.type) {
case actionTypes.REQUEST_SUCCESS:
{
return state;
}
case actionTypes.REQUEST_FAILURE:
{
return state;
}
default:
return state;
}
}

View File

@ -0,0 +1,44 @@
// import Action from 'commons/redux/Action';
// import { SigninPayload } from 'member/signin/redux';
// import { takeLatest } from 'redux-saga';
// import { call, put } from 'redux-saga/effects';
// export function * signin(action: Action<SigninPayload>) {
// try {
// const {signinId, signinPw} = action.payload;
// yield put({
// type: types.SENDING_REQUEST,
// payload: {sendingRequest: true},
// });
// const responseBody = yield call(api.login, signinId, signinPw);
// if (responseBody.token === undefined) {
// throw new Error(MESSAGES.UNABLE_TO_FIND_TOKEN_IN_LOGIN_RESPONSE);
// }
// yield put({
// type: types.LOGIN__SUCCEEDED,
// payload: {
// idToken: responseBody.token,
// },
// });
// } catch (e) {
// yield put({
// type: types.LOGIN__FAILED,
// payload: {
// message: e.message,
// statusCode: e.statusCode,
// },
// });
// } finally {
// yield put({
// type: types.SENDING_REQUEST,
// payload: {sendingRequest: false},
// });
// }
// }
// export function * watchSignin() {
// yield * takeLatest(types.LOGIN__REQUESTED, signin);
// }

View File

@ -0,0 +1,15 @@
import Member from 'member/api/model/Member';
export interface State {
isAuthenticated: boolean;
member?: Member;
error?: Error;
}
export const defaultState: State = {
isAuthenticated: undefined,
member: undefined,
error: undefined,
};
export default State;

View File

View File

@ -0,0 +1,85 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
Dialog,
Divider,
FlatButton,
MenuItem,
Paper,
RaisedButton,
SelectField,
Slider,
TextField,
} from 'material-ui';
export interface Props {
onSignin?: (signinId: string, signinPw: string) => void;
onSignup?: () => void;
onResetPassword?: () => void;
}
export interface State {
signinId: string;
signinPw: string;
}
export class Signin extends React.Component<Props, State> {
public static defaultProps: Partial<Props> = {
onSignin: (signinId: string, signinPw: string): void => {
console.log('onSignin');
},
onSignup: (): void => {
console.log('onSignup');
},
onResetPassword: (): void => {
console.log('onResetPassword');
},
};
public constructor(props: Props, context: State) {
super(props, context);
}
public render(): JSX.Element {
return (
<div>
<TextField
hintText='smith@gmail.com'
floatingLabelText='Email address*'
errorText=''
underlineShow={true}
value={this.state.signinId}
onChange={(e, newValue) => this.setState({ signinId: newValue })}
/>
<br />
<TextField
hintText='Password'
floatingLabelText='Password'
type='password'
value={this.state.signinPw}
onChange={(e, newValue) => this.setState({ signinPw: newValue })}
/>
<br />
<RaisedButton
label='Sign In'
primary={true}
onClick={(e) => this.props.onSignin(this.state.signinId, this.state.signinPw)}
/>
<RaisedButton
label='Sign Up'
primary={false}
onClick={this.props.onSignup}
/>
<RaisedButton
label='Reset Password'
primary={false}
onClick={this.props.onResetPassword}
/>
</div>
);
}
}

View File

@ -0,0 +1 @@
export * from './redux';

View File

@ -0,0 +1,37 @@
import Action from 'commons/redux/Action';
import Member from 'member/api/model/Member';
import actionTypes from './type';
import SignupPayload from '../payload/SignupPayload';
export interface Actions {
request: (signupPayload: SignupPayload) => Action<SignupPayload>;
requestSuccess: (member: Member) => Action<Member>;
requestFailure: (error: Error) => Action;
}
export const actions: Actions = {
request(signupPayload: SignupPayload): Action<SignupPayload> {
return {
type: actionTypes.REQUEST,
payload: signupPayload,
};
},
requestSuccess(member: Member): Action<Member> {
return {
type: actionTypes.REQUEST,
payload: member,
};
},
requestFailure(error: Error): Action {
return {
type: actionTypes.REQUEST,
error: error,
};
},
};
export default actions;

View File

@ -0,0 +1,17 @@
export type REQUEST = '@overflow/member/signup/REQUEST';
export type REQUEST_SUCCESS = '@overflow/member/signup/REQUEST_SUCCESS';
export type REQUEST_FAILURE = '@overflow/member/signup/REQUEST_FAILURE';
export interface ActionTypes {
REQUEST: REQUEST;
REQUEST_SUCCESS: REQUEST_SUCCESS;
REQUEST_FAILURE: REQUEST_FAILURE;
}
export const actionTypes: ActionTypes = {
REQUEST: '@overflow/member/signup/REQUEST',
REQUEST_SUCCESS: '@overflow/member/signup/REQUEST_SUCCESS',
REQUEST_FAILURE: '@overflow/member/signup/REQUEST_FAILURE',
};
export default actionTypes;

View File

@ -0,0 +1,2 @@
export * from './state';
export * from './reducer';

View File

@ -0,0 +1,6 @@
import Member from 'member/api/model/Member';
interface SignupPayload extends Member {
}
export default SignupPayload;

View File

@ -0,0 +1,24 @@
import Action from 'commons/redux/Action';
import IModule from 'commons/redux/Module';
import Member from 'member/api/model/Member';
import actionTypes from '../action/type';
import State, { defaultState } from '../state';
export function reducer(state: State = defaultState, action: Action<Member | Error>): State {
switch (action.type) {
case actionTypes.REQUEST_SUCCESS:
{
return state;
}
case actionTypes.REQUEST_FAILURE:
{
return state;
}
default:
return state;
}
}

View File

@ -0,0 +1,44 @@
// import Action from 'commons/redux/Action';
// import { SigninPayload } from 'member/signin/redux';
// import { takeLatest } from 'redux-saga';
// import { call, put } from 'redux-saga/effects';
// export function * signin(action: Action<SigninPayload>) {
// try {
// const {signinId, signinPw} = action.payload;
// yield put({
// type: types.SENDING_REQUEST,
// payload: {sendingRequest: true},
// });
// const responseBody = yield call(api.login, signinId, signinPw);
// if (responseBody.token === undefined) {
// throw new Error(MESSAGES.UNABLE_TO_FIND_TOKEN_IN_LOGIN_RESPONSE);
// }
// yield put({
// type: types.LOGIN__SUCCEEDED,
// payload: {
// idToken: responseBody.token,
// },
// });
// } catch (e) {
// yield put({
// type: types.LOGIN__FAILED,
// payload: {
// message: e.message,
// statusCode: e.statusCode,
// },
// });
// } finally {
// yield put({
// type: types.SENDING_REQUEST,
// payload: {sendingRequest: false},
// });
// }
// }
// export function * watchSignin() {
// yield * takeLatest(types.LOGIN__REQUESTED, signin);
// }

View File

@ -0,0 +1,15 @@
import Member from 'member/api/model/Member';
export interface State {
isRegistered: boolean;
member?: Member;
error?: Error;
}
export const defaultState: State = {
isRegistered: undefined,
member: undefined,
error: undefined,
};
export default State;

View File

View File

@ -0,0 +1,85 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {
Dialog,
Divider,
FlatButton,
MenuItem,
Paper,
RaisedButton,
SelectField,
Slider,
TextField,
} from 'material-ui';
export interface Props {
onSignin?: (signinId: string, signinPw: string) => void;
onSignup?: () => void;
onResetPassword?: () => void;
}
export interface State {
signinId: string;
signinPw: string;
}
export class Signin extends React.Component<Props, State> {
public static defaultProps: Partial<Props> = {
onSignin: (signinId: string, signinPw: string): void => {
console.log('onSignin');
},
onSignup: (): void => {
console.log('onSignup');
},
onResetPassword: (): void => {
console.log('onResetPassword');
},
};
public constructor(props: Props, context: State) {
super(props, context);
}
public render(): JSX.Element {
return (
<div>
<TextField
hintText='smith@gmail.com'
floatingLabelText='Email address*'
errorText=''
underlineShow={true}
value={this.state.signinId}
onChange={(e, newValue) => this.setState({ signinId: newValue })}
/>
<br />
<TextField
hintText='Password'
floatingLabelText='Password'
type='password'
value={this.state.signinPw}
onChange={(e, newValue) => this.setState({ signinPw: newValue })}
/>
<br />
<RaisedButton
label='Sign In'
primary={true}
onClick={(e) => this.props.onSignin(this.state.signinId, this.state.signinPw)}
/>
<RaisedButton
label='Sign Up'
primary={false}
onClick={this.props.onSignup}
/>
<RaisedButton
label='Reset Password'
primary={false}
onClick={this.props.onResetPassword}
/>
</div>
);
}
}