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 type { AppDispatch, RootState } from '../store'
|
||||
import { createAsyncThunk } from '@reduxjs/toolkit'
|
||||
import type { NetworkApi } from '../network'
|
||||
|
||||
export const useAppDispatch = useDispatch.withTypes<AppDispatch>()
|
||||
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 './auth-slice'
|
||||
export * from './user-slice'
|
||||
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 './error'
|
||||
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