slice
parent
f4fd3916b8
commit
f297b4986c
@ -0,0 +1,115 @@
|
|||||||
|
import { createSlice } from '@reduxjs/toolkit'
|
||||||
|
import type { PayloadAction } from '@reduxjs/toolkit'
|
||||||
|
import { createAppAsyncThunk } from './hooks'
|
||||||
|
import { networkApi, type ResponseData } from '../network'
|
||||||
|
|
||||||
|
interface AuthState {
|
||||||
|
accessToken: string
|
||||||
|
loading: boolean
|
||||||
|
error?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: AuthState = {
|
||||||
|
accessToken: '',
|
||||||
|
loading: false,
|
||||||
|
error: undefined,
|
||||||
|
}
|
||||||
|
|
||||||
|
const authSlice = createSlice({
|
||||||
|
name: 'auth',
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
setAccessToken(state, action: PayloadAction<AuthState>) {
|
||||||
|
state.accessToken = action.payload.accessToken
|
||||||
|
},
|
||||||
|
clearToken() {
|
||||||
|
return initialState
|
||||||
|
},
|
||||||
|
},
|
||||||
|
extraReducers: builder => {
|
||||||
|
builder
|
||||||
|
.addCase(fetchLogin.pending, state => {
|
||||||
|
state.loading = true
|
||||||
|
state.error = undefined
|
||||||
|
})
|
||||||
|
.addCase(fetchLogin.fulfilled, (state, action) => {
|
||||||
|
state.accessToken = String(action.payload.success?.[0]) || ''
|
||||||
|
state.loading = false
|
||||||
|
state.error = undefined
|
||||||
|
networkApi.token = state.accessToken
|
||||||
|
})
|
||||||
|
.addCase(fetchLogin.rejected, (state, action) => {
|
||||||
|
state.loading = false
|
||||||
|
if (action.payload) {
|
||||||
|
state.error = (action.payload as ResponseData).error
|
||||||
|
} else {
|
||||||
|
state.error = action.error.message
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.addCase(fetchLogout.pending, state => {
|
||||||
|
state.loading = true
|
||||||
|
state.error = undefined
|
||||||
|
})
|
||||||
|
.addCase(fetchLogout.fulfilled, state => {
|
||||||
|
state.accessToken = ''
|
||||||
|
state.loading = false
|
||||||
|
state.error = undefined
|
||||||
|
networkApi.token = ''
|
||||||
|
})
|
||||||
|
.addCase(fetchLogout.rejected, (state, action) => {
|
||||||
|
state.loading = false
|
||||||
|
if (action.payload) {
|
||||||
|
state.error = (action.payload as ResponseData).error
|
||||||
|
} else {
|
||||||
|
state.error = action.error.message
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
selectors: {
|
||||||
|
accessToken: (state: AuthState) => state.accessToken,
|
||||||
|
loading: (state: AuthState) => state.loading,
|
||||||
|
error: (state: AuthState) => state.error,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
type LoginProps = {
|
||||||
|
email: string
|
||||||
|
password: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const fetchLogin = createAppAsyncThunk<ResponseData, LoginProps>(
|
||||||
|
`${authSlice.name}/fetchLogin`,
|
||||||
|
async (props, { fulfillWithValue, rejectWithValue, extra: networkApi }) => {
|
||||||
|
try {
|
||||||
|
const data = await networkApi.request<ResponseData>('/login/', {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify(props),
|
||||||
|
})
|
||||||
|
return fulfillWithValue(data)
|
||||||
|
} catch (error) {
|
||||||
|
return rejectWithValue(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export const fetchLogout = createAppAsyncThunk<ResponseData>(
|
||||||
|
`${authSlice.name}/fetchLogout`,
|
||||||
|
async (_, { fulfillWithValue, rejectWithValue, extra: networkApi }) => {
|
||||||
|
try {
|
||||||
|
const data = await networkApi.request<ResponseData>('/logout/')
|
||||||
|
return fulfillWithValue(data)
|
||||||
|
} catch (error) {
|
||||||
|
return rejectWithValue(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
class Auth {
|
||||||
|
selector = { ...authSlice.selectors }
|
||||||
|
action = authSlice.actions
|
||||||
|
reducer = authSlice.reducer
|
||||||
|
name = authSlice.name
|
||||||
|
fetch = { login: fetchLogin, logout: fetchLogout }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const auth = new Auth()
|
||||||
@ -1,5 +1,14 @@
|
|||||||
import { useDispatch, useSelector } from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
import type { AppDispatch, RootState } from '../store'
|
import type { AppDispatch, RootState } from '../store'
|
||||||
|
import { createAsyncThunk } from '@reduxjs/toolkit'
|
||||||
|
import type { NetworkApi } from '../network'
|
||||||
|
|
||||||
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
|
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
|
||||||
export const useAppSelector = useSelector.withTypes<RootState>()
|
export const useAppSelector = useSelector.withTypes<RootState>()
|
||||||
|
|
||||||
|
export const createAppAsyncThunk = createAsyncThunk.withTypes<{
|
||||||
|
state: RootState
|
||||||
|
getState: () => RootState
|
||||||
|
dispatch: AppDispatch
|
||||||
|
extra: NetworkApi
|
||||||
|
}>()
|
||||||
|
|||||||
@ -1,2 +1,4 @@
|
|||||||
export * from './shop-slice'
|
export * from './shop-slice'
|
||||||
|
export * from './auth-slice'
|
||||||
|
export * from './user-slice'
|
||||||
export * from './hooks'
|
export * from './hooks'
|
||||||
|
|||||||
@ -0,0 +1,77 @@
|
|||||||
|
import { type PayloadAction, createSlice } from '@reduxjs/toolkit'
|
||||||
|
import { type UserType } from '../types'
|
||||||
|
import { createAppAsyncThunk } from './hooks'
|
||||||
|
import type { ResponseData } from '../network'
|
||||||
|
|
||||||
|
type UserState = {
|
||||||
|
user?: UserType
|
||||||
|
loading: boolean
|
||||||
|
error?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: UserState = {
|
||||||
|
user: undefined,
|
||||||
|
loading: false,
|
||||||
|
error: undefined,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const userSliceName = 'user'
|
||||||
|
|
||||||
|
const userSlice = createSlice({
|
||||||
|
name: userSliceName,
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
setUser: (state, action: PayloadAction<UserType>) => {
|
||||||
|
state.user = action.payload
|
||||||
|
},
|
||||||
|
clearUser() {
|
||||||
|
return initialState
|
||||||
|
},
|
||||||
|
},
|
||||||
|
extraReducers: builder => {
|
||||||
|
builder
|
||||||
|
.addCase(fetchUser.pending, state => {
|
||||||
|
state.loading = true
|
||||||
|
state.error = undefined
|
||||||
|
})
|
||||||
|
.addCase(fetchUser.fulfilled, (state, action) => {
|
||||||
|
state.user = action.payload.success?.[0] as UserType
|
||||||
|
state.loading = false
|
||||||
|
})
|
||||||
|
.addCase(fetchUser.rejected, (state, action) => {
|
||||||
|
state.loading = false
|
||||||
|
if (action.payload) {
|
||||||
|
state.error = (action.payload as ResponseData).error
|
||||||
|
} else {
|
||||||
|
state.error = action.error.message
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
selectors: {
|
||||||
|
user: (state: UserState) => state.user,
|
||||||
|
loading: (state: UserState) => state.loading,
|
||||||
|
error: (state: UserState) => state.error,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const fetchUser = createAppAsyncThunk<ResponseData>(
|
||||||
|
`${userSliceName}/fetchUser`,
|
||||||
|
async (_, { fulfillWithValue, rejectWithValue, extra: networkApi }) => {
|
||||||
|
try {
|
||||||
|
const data = await networkApi.request<ResponseData>('/user/')
|
||||||
|
return fulfillWithValue(data)
|
||||||
|
} catch (error) {
|
||||||
|
return rejectWithValue(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
class User {
|
||||||
|
selector = { ...userSlice.selectors }
|
||||||
|
action = userSlice.actions
|
||||||
|
reducer = userSlice.reducer
|
||||||
|
name = userSlice.name
|
||||||
|
fetch = { user: fetchUser }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const user = new User()
|
||||||
@ -1,3 +1,4 @@
|
|||||||
export * from './product'
|
export * from './product'
|
||||||
export * from './error'
|
export * from './error'
|
||||||
export * from './clean-component'
|
export * from './clean-component'
|
||||||
|
export * from './user'
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
export type UserType = {
|
||||||
|
id: number
|
||||||
|
nickname: string
|
||||||
|
email: string
|
||||||
|
token: string
|
||||||
|
token_expiry_date: Date
|
||||||
|
money: string
|
||||||
|
histories_id: number[]
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue