Skip to content

Instantly share code, notes, and snippets.

@yuki-yano
Last active January 2, 2019 07:41
Show Gist options
  • Select an option

  • Save yuki-yano/28a109f6dff332d40b420d10ab741060 to your computer and use it in GitHub Desktop.

Select an option

Save yuki-yano/28a109f6dff332d40b420d10ab741060 to your computer and use it in GitHub Desktop.
typescript-fsa-redux-thunk-sample
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