Last active
January 2, 2019 07:41
-
-
Save yuki-yano/28a109f6dff332d40b420d10ab741060 to your computer and use it in GitHub Desktop.
typescript-fsa-redux-thunk-sample
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import axios from "axios" | |
| import { Dispatch } from "redux" | |
| import actionCreatorFactory from "typescript-fsa" | |
| import { reducerWithInitialState } from "typescript-fsa-reducers" | |
| import { asyncFactory } from "typescript-fsa-redux-thunk" | |
| import Cookies from "js-cookie" | |
| export type UserState = { | |
| accessToken: string | |
| loggingIn: boolean | |
| error?: Error | |
| } | |
| const initialState: UserState = { | |
| accessToken: "", | |
| loggingIn: false | |
| } | |
| export type SigninStartedPayload = { | |
| code: string | |
| state: string | |
| } | |
| export type SigninDonePayload = { | |
| accessToken: string | |
| } | |
| const actionCreator = actionCreatorFactory("thunk") | |
| const asyncActionCreator = asyncFactory<UserState>(actionCreator) | |
| export const signin = asyncActionCreator<SigninStartedPayload, SigninDonePayload, Error>( | |
| "SIGNIN", | |
| async (payload: SigninStartedPayload, _dispatch: Dispatch) => { | |
| if (Cookies.get("SigninState") !== payload.state) { | |
| throw new Error("Error invalid state") | |
| } | |
| const res = await axios.post("//localhost:3000/auth/slack", { code: payload.code }) | |
| if (res.status === 200) { | |
| return res.data | |
| } else { | |
| throw new Error(`Error ${res.status}: ${res.statusText}`) | |
| } | |
| } | |
| ) | |
| export const userReducer = reducerWithInitialState(initialState) | |
| .case(signin.async.started, state => ({ | |
| ...state, | |
| loggingIn: true | |
| })) | |
| .case(signin.async.done, (state, payload) => ({ | |
| ...state, | |
| // @ts-ignore | |
| accessToken: payload.result.access_token, | |
| loggingIn: false | |
| })) | |
| .case(signin.async.failed, (state, { error }) => ({ | |
| ...state, | |
| loggingIn: false, | |
| error | |
| })) | |
| import React from "react" | |
| import { Action } from "redux" | |
| import { connect } from "react-redux" | |
| import { ThunkDispatch } from "redux-thunk" | |
| import { signin, UserState, SigninStartedPayload } from "../modules/User" | |
| import { AppState } from "../store" | |
| type Props = ReturnType<typeof mapStateToProps> & ReturnType<typeof mapDispatchToProps> | |
| const CallBack: React.FC<Props> = (props: Props) => { | |
| const url = new URL(document.URL) | |
| const state = url.searchParams.get("state") || "" | |
| const code = url.searchParams.get("code") || "" | |
| return ( | |
| <div> | |
| <div>Login Processing</div> | |
| <a onClick={() => props.onSignin({ code, state })}>hoge</a> | |
| </div> | |
| ) | |
| } | |
| const mapStateToProps = (state: AppState) => ({ | |
| ...state.user | |
| }) | |
| const mapDispatchToProps = (dispatch: ThunkDispatch<UserState, void, Action>) => ({ | |
| async onSignin(payload: SigninStartedPayload) { | |
| try { | |
| await dispatch(signin.action(payload)) | |
| } catch (error) {} | |
| } | |
| }) | |
| export default connect( | |
| mapStateToProps, | |
| mapDispatchToProps | |
| )(CallBack) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment