Uncaught TypeError: Cannot read properties of undefined (reading 'type') with the redux-toolkit i'm facing this bug - redux-toolkit

I'm facing this error when I'm trying to a request my backend I'm using the redux toolkit for my project I read the documentation also but I can't understand why this is happening I'm a beginner in the redux toolkit so kindly assess me in this
here is my users like page
const signup = createAsyncThunk(
// you can there any thing its all your choice
'datauser/signup',
async (user, thunkAPI) => {
try {
const response = await userapi.signup(user)
console.log(response)
return response.data
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString()
return thunkAPI.rejectWithValue(message)
}
}
)
// initialize the state from there
const initialState = {
user: user?user:null,
isError: false,
isSuccess: false,
isLoading: false,
message: '',
}
export const registerslice = createSlice({
// name=.e.t.c is the type of the state
name: 'user',
initialState,
reducers: {
reset: (state) => {
state.isLoading = false
state.isSuccess = false
state.isError = false
state.message = ''
},
},
extraReducers: (builder) => {
builder
.addCase(signup.fulfilled, (state, action) => {
state.isLoading = false
state.isSuccess = true
state.user = action.payload
})
}
})
// Action creators are generated for each case reducer function
export const { reset } = registerslice.actions
export default registerslice.reducer
here is my apislice
const API = 'http://localhost:5000'
// register user
const signup= async(response,userData)=>{
const res=axios.post(`${API}/signup`,userData)
if (response.data) {
localStorage.setItem('user', JSON.stringify(response.data))
}
return res.data
}
this is my store
import userReducer from '../redux/userSlice'
export const store = configureStore({
reducer: {
auth: userReducer,
},
})

Related

NEXT JS AND MONGODB JWT integration

Looking for a backend dev that can simply help me implement MONGODB with nextJS and the current model I have now. I have bought https://www.devias.io admin dashboard, and just want to implement auth and database reading with it.
Just want the basic auth setup. It's already setup in the FILES just wanting to know how to configure it properly based on the devias guides
Has anyone done this before I can't find any documentation on it
It's setup with mock data at the moment
SRC/API/AUTH/index.js
import { createResourceId } from '../../utils/create-resource-id';
import { decode, JWT_EXPIRES_IN, JWT_SECRET, sign } from '../../utils/jwt';
import { wait } from '../../utils/wait';
import { users } from './data';
class AuthApi {
async signIn(request) {
const { email, password } = request;
await wait(500);
return new Promise((resolve, reject) => {
try {
// Find the user
const user = users.find((user) => user.email === email);
if (!user || (user.password !== password)) {
reject(new Error('Please check your email and password'));
return;
}
// Create the access token
const accessToken = sign({ userId: user.id }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });
resolve({ accessToken });
} catch (err) {
console.error('[Auth Api]: ', err);
reject(new Error('Internal server error'));
}
});
}
async signUp(request) {
const { email, name, password } = request;
await wait(1000);
return new Promise((resolve, reject) => {
try {
// Check if a user already exists
let user = users.find((user) => user.email === email);
if (user) {
reject(new Error('User already exists'));
return;
}
user = {
id: createResourceId(),
avatar: undefined,
email,
name,
password,
plan: 'Standard'
};
users.push(user);
const accessToken = sign({ userId: user.id }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });
resolve({ accessToken });
} catch (err) {
console.error('[Auth Api]: ', err);
reject(new Error('Internal server error'));
}
});
}
me(request) {
const { accessToken } = request;
return new Promise((resolve, reject) => {
try {
// Decode access token
const { userId } = decode(accessToken);
// Find the user
const user = users.find((user) => user.id === userId);
if (!user) {
reject(new Error('Invalid authorization token'));
return;
}
resolve({
id: user.id,
avatar: user.avatar,
email: user.email,
name: user.name,
plan: user.plan
});
} catch (err) {
console.error('[Auth Api]: ', err);
reject(new Error('Internal server error'));
}
});
}
}
export const authApi = new AuthApi();
then /SRC/API/AUTH/data.js
export const users = [
{
id: '5e86809283e28b96d2d38537',
avatar: '/assets/avatars/avatar-anika-visser.png',
email: 'demo#devias.io',
name: 'Anika Visser',
password: 'Password123!',
plan: 'Premium'
}
];
This is the documentation on it
JSON Web Token (JWT)
Most auth providers use this strategy under the hood to provide access tokens. Currently, the app doesn't cover the backend service, and this service is mocked (faked) using http client interceptors. The implementation is basic, but enough to give you a starting point.
How it was implemented
Since tokens are meant to be created on the backend server, they are built with encrypt, encode and decode utility methods because they are not meant to be used on the client. These utilities can be found in src/utils/jwt. These are for development purposes only, and you must remove (or avoid using) them.
How to use JWT Provider
The app is delivered with JWT Provider as default auth strategy. If you changed or removed it, and you want it back, simply follow these steps:
Step 1: Import the provider
Open src/pages/_app.js file, import the provider and wrap the App component with it.
// src/pages/_app.js
import { AuthConsumer, AuthProvider } from '../contexts/auth/jwt-context';
const App = (props) => {
const { Component, pageProps } = props;
return (
<AuthProvider>
<Component {...pageProps} />
</AuthProvider>
);
};
Step 2: Set the hook context
Open src/hooks/use-auth.js file and replace the current context the following line:
import { AuthContext } from '../contexts/auth/jwt-context';
How to use auth
Retrieve user profile
In the example below, you can find how it can be used in any component not just the App. Should you want to use it in any other component, you'll have to import the useAuth hook and use it as needed.
// src/pages/index.js
import { useAuth } from '../hooks/use-auth';
const Page = () => {
const { user } = useAuth();
return (
<div>
Email: {user.email}
</div>
);
};
Auth methods / actions
For simplicity and space limitations, the code below is used only to exemplify, actual code can be found in the components.
// src/pages/index.js
import { useAuth } from '../hooks/use-auth';
const Page = () => {
const { login } = useAuth();
const handleLogin = () => {
// Email/username and password
login('demo#devias.io', 'Password123!');
};
s
return (
<div>
<button onClick={handleLogin}>
Login
</button>
</div>
);
};
Implemented flows
Currently, the app only covers the main flows:
Register
Login
Logout
const mongoose = require('mongoose');
const jwt = require("jsonwebtoken");
// Connect to MongoDB
mongoose.connect('mongodb://localhost/yourdbname', {
useNewUrlParser: true,
useUnifiedTopology: true
});
const userSchema = new mongoose.Schema({
id: {
type: String,
required: true,
unique: true
},
email: {
type: String,
required: true
},
name: {
type: String,
required: true
},
password: {
type: String,
required: true
},
plan: {
type: String,
default:
'Standard'
},
avatar: {
type: String,
default:
null
},
});
const User = mongoose.model('User', userSchema);
const JWT_SECRET = process.env.JWT_SECRET;
const JWT_EXPIRES_IN = '7d';
class AuthApi {
async signIn(request) {
const {
email,
password
} = request;
const user = await User.findOne({
email
});
if (!user || (user.password !== password)) {
throw new Error('Please check your email and password');
}
const accessToken = jwt.sign({
userId: user.id
}, JWT_SECRET, {
expiresIn: JWT_EXPIRES_IN
});
return {
accessToken
};
}
async signUp(request) {
const {
email,
name,
password
} = request;
const existingUser = await User.findOne({
email
});
if (existingUser) {
throw new Error('User already exists');
}
const newUser = new User({
id: mongoose.Types.ObjectId(),
email,
name,
password,
plan: 'Standard',
avatar: null,
});
await newUser.save();
const accessToken = jwt.sign({
userId: newUser.id
}, JWT_SECRET, {
expiresIn: JWT_EXPIRES_IN
});
return {
accessToken
};
}
async me(request) {
const {
accessToken
} = request;
const decoded = jwt.verify(accessToken, JWT_SECRET);
const {
userId
} = decoded;
const user = await User.findById(userId);
if (!user) {
throw new Error('Invalid authorization token');
}
return {
id: user.id,
avatar: user.avatar,
email: user.email,
name: user.name,
plan: user.plan
};
}
}
export const authApi = new AuthApi();

React-query is not updating the state

I recently started to use react query, but I don't quite understand yet how the state works under the hood.
I have a query function that logs in the user:
async function signin(
model: AuthenticationControllerSignInRequest | null
): Promise<any> {
if (model) {
queryClient.invalidateQueries()
const response = await CalyxApi.authApi().authenticationControllerSignIn(
model
);
LocalStorage.set(LOCAL_STORAGE_KEY.AUTH, response.data.authToken);
return response.data.authToken
}
return loadFromStorage()
}
Inside I use loadFromStorage function that gets authToken from local storage.
async function loadFromStorage(): Promise<AuthTokenModel | undefined> {
const storedAuth = LocalStorage.get(LOCAL_STORAGE_KEY.AUTH);
if (storedAuth) {
if (new Date(storedAuth.validUntil) < new Date()) {
LocalStorage.remove(LOCAL_STORAGE_KEY.AUTH)
return undefined;
}
return storedAuth;
} else {
return undefined;
}
}
In my Login components I use the query hook passing in signin function and formik that refetches on submit:
...
const { data: auth, refetch, isLoading: authLoading } = useQuery(['auth', signinModel], () => authActions.signin(signinModel), { enabled: false });
const formik = useFormik({
validateOnChange: false,
validateOnBlur: false,
initialValues: {
email: '',
password: '',
},
validationSchema: loginFormSchema,
onSubmit: async (values) => {
await setSigninModel({
email: values.email,
password: values.password
})
await refetch()
}
});
...
This works just fine. I am able to authenticate the user which should prompt another function that fetches the user from DB:
const { data: auth } = useQuery(['auth'], () => authActions.signin(null))
const userId = auth?.userId;
console.log('useUserActions: ', userId)
async function fetchUser(): Promise<UserModel | undefined> {
if (!userId) {
errorSuccessActions.throwError('USER ID IS UNDEFINED');
return
}
const result = await CalyxApi.userApi().userControllerGetUser(userId)
if (result.data) {
const user = result.data.user
return user
}
errorSuccessActions.throwError('USER NOT FOUND IN DB');
return
}
function useFetchUser(reactQueryOptions?: {}) {
return useQuery<UserModel | undefined>(
["user", userId],
() => fetchUser(), {
...reactQueryOptions, refetchOnWindowFocus: false,
onError: (err) => errorSuccessActions.throwError(err),
onSuccess: (data) => {
queryClient.setQueryData(['user'], data);
},
initialData: () => {
const user: UserModel | undefined = queryClient.getQueryData('user')
if (user) {
return user
}
return undefined
}
})
}
This expects userId that I get from ´auth´ state. Problem is that I actually don't get it after signin function fires. I only get the state updated if I reload the page or i refocus on the tab.
I have a console.log that should log the userId but it always returns undefined. Only when I refocus on the window will it return the userId prompting to fetch the user.
I am not sure what am I missing to get the updated auth state and to get the userId right after I sign in.

react-admin authentication flow not working

Working on authentication react-admin using JWT token and storing in memory as closure variable.
Creating AuthToken from Django works fine, it's emitting the Token with user info as JSON.
Here is inMemoryJWT Manager
File: inMemoryJwt.js
// https://github.com/marmelab/ra-in-memory-jwt
const inMemoryJWTManager = () => {
let inMemoryJWT = null;
let isRefreshing = null;
// Token code goes here
const getToken = () => inMemoryJWT;
const setToken = (token) => {
inMemoryJWT = token;
return true;
};
const ereaseToken = () => {
inMemoryJWT = null;
return true;
}
return {
ereaseToken,
getToken,
setToken,
}
};
export default inMemoryJWTManager();
File: AuthProvider.js
oryJWTManager';
const authProvider = {
login: ({ username, password }) => {
const request = new Request('http://127.0.0.1:8000/api/token-auth/', {
method: 'POST',
body: JSON.stringify({ username, password }),
headers: new Headers({ 'Content-Type': 'application/json' }),
});
return fetch(request)
.then(response => {
console.log('Response status ' + response.status )
if (response.status < 200 || response.status >= 300) {
throw new Error(response.statusText);
}
console.log('response.json is ');
console.log(response.json());
return response.json();
})
.then(({ token }) => {
console.log(' about to set token in storage .......... ');
JwtManager.setToken(token);
const decodedToken = decodeJwt(token);
# Its not setting in localstorage
localStorage.setItem('token', token);
console.log('Token from lS : -------------',localStorage.getIdentity('token'));
localStorage.setItem('permissions', decodedToken.permissions);
})
.then(auth => {
localStorage.setItem('auth', JSON.stringify(auth));
})
.catch(response => {
console.log('Catch : ' );
console.log(response.json());
throw new Error('Network errorkkkkkkkkkkkkk')
});
},
logout: () => {
localStorage.setItem('not_authenticated', true);
localStorage.removeItem('auth');
localStorage.removeItem('role');
localStorage.removeItem('login');
localStorage.removeItem('user');
localStorage.removeItem('avatar');
inMemoryJWT.ereaseToken();
return Promise.resolve();
},
checkError: ({ status }) => {
if (status === 401 || status === 403) {
inMemoryJWT.ereaseToken();
return Promise.reject();
}
return Promise.resolve();
// return status === 401 || status === 403
// ? Promise.reject( { redirectTo: '/login' , logoutUser: false} )
// : Promise.resolve();
},
checkAuth: () => {
return inMemoryJWT.getToken() ? Promise.resolve() : Promise.reject({ redirectTo: '/no-access', message: 'login.required' });
// localStorage.getItem('auth')
// ? Promise.resolve()
// : Promise.reject({ redirectTo: '/no-access', message: 'login.required' }),
},
getPermissions: () => {
return inMemoryJWT.getToken() ? Promise.resolve() : Promise.reject();
// const role = localStorage.getItem('permissions');
// return role ? Promise.resolve(role) : Promise.reject();
},
getIdentity: () => {
try {
const { id, fullName, avatar } = JSON.parse(localStorage.getItem('auth'));
return Promise.resolve({ id, fullName, avatar });
} catch (error) {
return Promise.reject(error);
}
// return {
// id: localStorage.getItem('login'),
// fullName: localStorage.getItem('user'),
// avatar: localStorage.getItem('avatar'),
// };
},
}
export default authProvider;
App.js
const httpClient = (url, options = {}) => {
if (!options.headers) {
options.headers = new Headers({ Accept: 'application/json' });
}
const { token } = JSON.parse(localStorage.getItem('auth'));
options.headers.set('Authorization', `Bearer ${token}`);
return fetchUtils.fetchJson(url, options);
};
const dataProvider = drfProvider('http://127.0.0.1:8000/api/token-auth/', httpClient);
const App = () => (
<Admin title=""
loginPage={Login}
catchAll={NotFound}
logoutButton={PfsLogoutButton}
authProvider={authProvider}
dataProvider={dataProvider}
catchAll={NotFound}
dashboard={Dashboard} disableTelemetry>
The problem
The problem I am facing is to, It's not setting in-memory or local storage, also I get the message in the footer on the login button clicked. I am breaking my head with it for quite some time. Let me know if you need any other info.
Login required error for every page
HTTP Response goes here

Redux Toolkit state doesn't update even after adding extraReducers

I have a very limited understanding of the redux toolkit compared to its previous version. I am struggling to understand why isn't my state getting updated on the trigger of getUsers.
I have added the extraReducers as well.
import { createAsyncThunk, createSlice } from '#reduxjs/toolkit';
import { fetchSample } from './filterAPI';
export const getUsers = createAsyncThunk(
'primaryFilters/getUsers',
async (dispatch, getState) => {
console.log(getState, dispatch);
const response = await fetchSample();
return response;
}
);
const primaryFiltersSlice = createSlice({
name: 'primaryFilters',
initialState: {
dateFilter: {
dates: {
key: 'selection',
startDate: new Date(),
endDate: new Date(),
},
dummyData: null,
},
status: null,
},
extraReducers: (builder) => {
builder
.addCase(getUsers.pending, (state) => {
state.status = 'loading';
})
.addCase(getUsers.fulfilled, (state, action) => {
state.status = 'idle';
state.dummyData = action.payload;
})
.addCase(getUsers.rejected, (state, action) => {
state.status = 'failed';
});
},
});
export default primaryFiltersSlice.reducer;
Here's fetchSample function:
export const fetchSample = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
return response.json();
};
Additionally, I want to point out that my status is triggering from pending to idle and so on but my actual state isn't updating.
Here's the screenshot for the same:
I would also like to know how can we log the messages within those extraReducers.
For one, looking at your data structure, you probably want to update state.dateFilter.dummyData, not state.dummyData - at least assuming you want to match your initialState structure.
Also, createAsyncThunk does not take a callback dispatch, getState:
correct would be
export const getUsers = createAsyncThunk(
'primaryFilters/getUsers',
async (arg, {dispatch, getState}) => {
(but that does not make a difference here since you are using neither)
As for logging... just console.log? Or do you mean you are getting a Proxz object? In that case console.log(current(state))
For some reason, I am able to dispatch actions by keeping the status update at the bottom instead of the top. I would love to have a better explanation for the same, here's what exactly fixed my code:
import { createAsyncThunk, createSlice } from '#reduxjs/toolkit';
import { fetchSample } from './filterAPI';
export const getUsers = createAsyncThunk(
'primaryFilters/getUsers',
async (dispatch, getState) => {
console.log(getState, dispatch);
const response = await fetchSample();
return response;
}
);
// export const updateDates = () => {
// }
const primaryFiltersSlice = createSlice({
name: 'primaryFilters',
initialState: {
dateFilter: {
dates: {
key: 'selection',
startDate: new Date(),
endDate: new Date(),
},
dummyData: null,
},
status: null,
},
reducer: {
updateDate: (state, action) => {
console.log('Actions = ', action);
},
},
extraReducers: (builder) => {
builder
.addCase(getUsers.pending, (state) => {
state.status = 'loading';
})
.addCase(getUsers.fulfilled, (state, action) => {
state.dummyData = action.payload;
state.status = 'idle';
})
.addCase(getUsers.rejected, (state, action) => {
state.status = 'failed';
});
},
});
export default primaryFiltersSlice.reducer;

Best practice for using React hooks and Context API to update global state and fetch/provide data from multiple endpoints

I am new to React hooks/Context API. I have read the React hook/context docs, and I am still having trouble with the following:
My attempts to update global state by multiple consumer components
currently causes frequent overwriting of context state due to
rerendering (e.g., activity or details state is sometimes
null/undefined). This probably is why...
... I am getting 400 (bad request) and/or 500 (server) errors on random refreshes of the page (~30% of the time content loads as
expected, ~70% errors are thrown. I believe this is happening
because we have various context states that are being called
asynchronously).
I am not sure how to implement Axios Cancellation, given that our useEffect hooks are calling dispatch functions (e.g.,
getActivities()) in different files. The examples I've seen
involve fetching data within the component (rather than in context).
I am seeking assistance for #1 specifically. I would love guidance on how to accurately fetch data and store in context as global state, and then provide that context to child components, allowing them to consume/update context state without unnecessary rerendering.
Tried to only provide relevant code snippets below:
ActivityState.js -- should fetch activity data
...
const ActivityState = props => {
const initialState = {
activities: [],
isLoading: false,
isError: false
};
const HEADERS = {
'Content-Type': 'application/json',
'user_id': 1
}
const [state, dispatch] = useReducer(ActivityReducer, initialState);
const userContext = useContext(UserContext);
const getActivities = async () => {
const { loggedIn } = contactContext;
let didCancel = false; // attempts to start implementing axios cancellation
try {
const res = await axios.get(url);
dispatch({ type: GET_ACTIVITIES, payload: res.data.data.activities });
} catch (err) {
if (!didCancel) {
dispatch({ type: 'FETCH_FAILURE' });
}
}
}
const updateActivity = (path, data) => { //update context state
dispatch({ type: UPDATE_ACTIVITY, payload: { path: path, data: data } });
};
const saveActivity = () => { //send new activity data to the backend
const postData = {
actions: [{"293939": []}],
activities: state.activities
};
try {
const res = axios.post(url,{ data: postData }, { headers: HEADERS });
} catch (err) {
console.log(err);
}
}
return (
<ActivityContext.Provider
value={{
activities: state.activities,
data: state.data,
backup_data: state.backup_data,
getActivities,
updateActivity,
saveActivity,
}}
>
{props.children}
</ActivityContext.Provider>
);
};
export default ActivityState;
ActivityReducer.js -- switch statements to be dispatched by ActivityState.js
...
export default (state, action) => {
switch (action.type) {
case GET_ACTIVITIES:
return {
...state,
activities: action.payload,
isLoading: true
};
case FETCH_FAILURE:
return {
...state,
isLoading: false,
isError: true
};
case UPDATE_ACTIVITY:
const { payload: { path }, payload } = action;
const data = state;
if (!data.activities)
return { data };
const index = data.activities.findIndex(e => e.socium_tracking_number == path.id);
if(index === -1)
return { data };
_.set(data, `activities[${index}].${path.field}`, payload.data);
return {
data,
};
...
DetailsState.js -- dispatch functions to fetch details
const DetailsState = props => {
const initialState = {
details: null,
};
const [state, dispatch] = useReducer(DetailsReducer, initialState);
const getDetails = async () => {
try {
const res = await axios.get(url);
dispatch({ type: GET_DETAILS, payload: res.data.data[0].details});
}catch(err) {
console.log(err)
}
};
return (
<DetailsContext.Provider
value={{ details: state.details, getDetails }}
>
{ props.children }
</DetailsContext.Provider>
);
}
export default SchemaState;
DetailsReducer.js -- switch statement
export default (state, action) => {
switch (action.type) {
case GET_DETAILS:
return {
...state,
details: action.payload,
};
default:
return state;
}
};
ActivityTable.js -- component that consumes Activity Info
...
const ActivityTable = ({ activity }) => {
const activityContext = useContext(ActivityContext);
const { activities, filtered, getActivities } = activityContext;
const [order, setOrder] = React.useState('asc');
const [orderBy, setOrderBy] = React.useState(activities.wait_time);
// Get activity data on mount
useEffect(() => {
async function fetchData() {
await getActivities()
}
fetchData();
}, []);
...
CreateActivity.js -- component that consumes Activity and Details data
...
const CreateActivity = props => {
const activityContext = useContext(ActivityContext);
const { activities, filtered, getActivities, addActivity } = activityContext;
const detailsContext = useContext(DetailsContext);
const { details, getDetails } = detailsContext;
// Get activity and details data on mount
useEffect(() => {
async function fetchData() {
await getActivities();
await getSchema();
}
fetchData();
}, []);
...
I really tried to get smarter on these issues before approaching the SO community, so that my question(s) was more defined. But this is what I have. Happy to provide any info that I missed or clarify confusion. Thank you for your time