Last active
January 20, 2021 08:36
-
-
Save yuki-yano/fcc2520d6e02fb923ced7189188bce3d to your computer and use it in GitHub Desktop.
typescript-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 { Reducer, Dispatch } from "redux" | |
| import Cookies from "js-cookie" | |
| export type UserState = { | |
| accessToken: string | |
| loggingIn: boolean | |
| error: string | |
| } | |
| const initialState: UserState = { | |
| accessToken: "", | |
| loggingIn: false, | |
| error: "" | |
| } | |
| type Action = SigninStartedAction | ReturnType<typeof signinDone | typeof signinFailed> | |
| export type SigninStartedAction = { | |
| type: typeof SIGNIN_STARTED | |
| payload: SigninStartedPayload | |
| } | |
| export type SigninStartedPayload = { | |
| code: string | |
| state: string | |
| } | |
| export type SigninDonePayload = { | |
| accessToken: string | |
| } | |
| export type SigninFailedPayload = { | |
| error: string | |
| } | |
| const SIGNIN_STARTED = "SIGNIN_STARTED" | |
| const SIGNIN_DONE = "SIGNIN_DONE" | |
| const SIGNIN_FAILED = "SIGNIN_FAILED" | |
| export const signinStarted = (payload: SigninStartedPayload) => async (dispatch: Dispatch) => { | |
| if (Cookies.get("SigninState") !== payload.state) { | |
| return dispatch(actions.signinFailed({ error: "Error invalid state" })) | |
| } | |
| const res = await axios.post("//localhost:3000/auth/slack", { code: payload.code }) | |
| if (res.status === 200) { | |
| return dispatch(actions.signinDone({ accessToken: res.data.access_token })) | |
| } else { | |
| return dispatch(actions.signinFailed({ error: `Error ${res.status}: ${res.statusText}` })) | |
| } | |
| } | |
| const signinDone = (payload: SigninDonePayload) => ({ | |
| type: SIGNIN_DONE as typeof SIGNIN_DONE, | |
| payload | |
| }) | |
| const signinFailed = (payload: SigninFailedPayload) => ({ | |
| type: SIGNIN_FAILED as typeof SIGNIN_FAILED, | |
| payload | |
| }) | |
| export const actions = { signinStarted, signinDone, signinFailed } | |
| export const userReducer: Reducer<UserState, Action> = (state = initialState, action) => { | |
| switch (action.type) { | |
| case SIGNIN_STARTED: { | |
| return { | |
| ...state, | |
| loggingIn: true | |
| } | |
| } | |
| case SIGNIN_DONE: { | |
| return { | |
| ...state, | |
| accessToken: action.payload.accessToken, | |
| loggingIn: false | |
| } | |
| } | |
| default: { | |
| const _: never = action | |
| return state | |
| } | |
| } | |
| } | |
| import React from "react" | |
| import { Action } from "redux" | |
| import { ThunkDispatch } from "redux-thunk" | |
| import { connect } from "react-redux" | |
| import { signinStarted, SigninStartedPayload, UserState } 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>) => ({ | |
| onSignin(payload: SigninStartedPayload) { | |
| dispatch(signinStarted(payload)) | |
| } | |
| }) | |
| export default connect( | |
| mapStateToProps, | |
| mapDispatchToProps | |
| )(CallBack) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment