https://codesandbox.io/s/login-authentication-usecontext-66t9t?file=/src/index.js
Here how we can pass token in headers for any other pages in codesandbox link. In my code i have action file like this. im getting my response in localstorage.how can i pass my accesstoken here as headers in this page.
import axios from 'axios';
export const upiAction = {
upi,
};
function upi(user) {
return (dispatch) => {
var data = {
upiId: user.upiId,
accountNumber: user.accountNumber,
};
axios
.post('http://localhost:9091/upiidcreation', data
)
.then((res) => {
console.log("res", (res));
const { data } = res;
alert(JSON.stringify(data.responseDesc));
// window.location.pathname = "./homes";
if (data.responseCode === "00") {
window.location.pathname = "./home"
}
})
.catch(err => {
dispatch(setUserUpiError(err, true));
alert("Please Check With details");
});
};
}
export function setUserUpi(showError) {
return {
type: 'SET_UPI_SUCCESS',
showError: showError,
};
}
export function setUserUpiError(error, showError) {
return {
type: 'SET_UPI_ERROR',
error: error,
showError: showError,
};
}
Related
Before supabase V2 I got my data and stored in with redux like this:
supabase V2 broke unfortunately some functionality with redux-next-wrapper
export const getServerSideProps = wrapper.getServerSideProps(
(store) => async ({ req }) => {
const { user } = await supabase.auth.api.getUserByCookie(req);
if (user === null) {
return {
redirect: {
permanent: false,
destination: "/auth",
},
props: {},
};
}
if (user) {
async function getData() {
let { data, error, status } = await supabase
.from("table")
.select(`id`)
.eq("id", user.id);
store.dispatch(writeUserData(data));
return data;
}
return {
props: {
data: await getData(),
},
};
}
}
);
Any ideas how I can achieve the same functionality with withPageAuth()?
export const getServerSideProps = withPageAuth({
redirectTo: '/foo',
async getServerSideProps (ctx, supabase) {
// Access the user object
const {
data: { user }
} = await supabase.auth.getUser()
return { props: { id: user?.id } }
}
})
This would be similar to what you already have except that the redirect is handled by the withPageAuth already.
export const getServerSideProps = withPageAuth({
redirectTo: '/auth',
async getServerSideProps (ctx, supabase) {
// Access the user object
const {
data: { user }
} = await supabase.auth.getUser()
let { data, error, status } = await supabase
.from("table")
.select(`id`)
.eq("id", user.id);
store.dispatch(writeUserData(data));
return { props: { data } }
}
})
I have this HOC line of code from withUser.tsx. When a user is authenticated, the authenticated pages will then be wrapped by it so that the specified user-role will be the one to only have access to pages intended.
import axios, { AxiosError } from "axios";
import { API } from "../config";
import { getCookie } from "../helpers/auth";
const withUser = (Page: any) => {
const WithAuthUser = (props: any): JSX.Element => <Page {...props} />;
WithAuthUser.getInitialProps = async (context: any): Promise<any> => {
const token = getCookie("token", context.req);
let user = null;
let userLinks = [];
if (token) {
try {
const response = await axios.get(`${API}/user`, {
headers: {
authorization: `Bearer ${token}`,
contentType: "application/json",
},
});
console.log("Response in withUser: ", response);
user = response.data.user;
userLinks = response.data.links;
} catch (err: unknown) {
const error = err as AxiosError;
if (error.response?.status === 401) {
user = null;
}
}
}
if (user === null) {
// redirect
context.res.writeHead(302, {
Location: "/",
});
context.res.end();
} else {
return {
...(Page.getInitialProps ? await Page.getInitialProps(context) : {}),
user,
token,
userLinks,
};
}
};
return WithAuthUser;
};
export default withUser;
Now, the above code is not my final writing of TypeScript, I could be wrong but this is how I converted it from JS, please feel free to give me a refactored TSX codes here, here is the JS version:
import axios from "axios";
import { API } from "../config";
import { getCookie } from "../helpers/auth";
const withUser = (Page) => {
const WithAuthUser = (props) => <Page {...props} />;
WithAuthUser.getInitialProps = async (context) => {
const token = getCookie("token", context.req);
let user = null;
let userLinks = [];
if (token) {
try {
const response = await axios.get(`${API}/user`, {
headers: {
authorization: `Bearer ${token}`,
contentType: "application/json",
},
});
console.log("Response in withUser: ", response);
user = response.data.user;
userLinks = response.data.links;
} catch (error) {
if (error.response.status === 401) {
user = null;
}
}
}
if (user === null) {
// redirect
context.res.writeHead(302, {
Location: "/",
});
context.res.end();
} else {
return {
...(Page.getInitialProps ? await Page.getInitialProps(context) : {}),
user,
token,
userLinks,
};
}
};
return WithAuthUser;
};
export default withUser;
But now, when using it when an Authenticated /user page, I could not get any data from the user. It will give me an undefined and for example, user.first_name will not be shown:
import withUser from "../withUser";
const User = ({ user }: any): JSX.Element => (
<div className="flex min-h-screen flex-col items-center justify-center">
{user.first_name}
</div>
);
export default withUser(User);
Any correct ways of implementing this would be very much appreciated. Thanks!
Whether you are in Reactjs or Nextjs, I think there needs to have a correct type definitions of your HOC component in the first place.
First you need to define your HOC component as a React.ComponentType:
const withUser = (ChildComp: React.ComponentType<any | string>) => { /* code follows */ }
you also need to define an interface for the expected values for these"
const token = getCookie("token", context.req);
let user = null;
let userLinks = [];
and when you wrap your child component, say user.tsx, do it like this:
type UserType = {
first_name: string
}
const User: React.SFC<ContainerProps> = ({ user}: UserType)=> (
<h1>{user.first_name ?? "User not found"}</h1>
);
export default withUser(User);
You can read more about here: Create a TypeScript HOC in React
Okay, sorry this was just a bug and I figure out that I did not have any userLinks from the REST API that I was passing in. So I can already consider this question as resolved as I have already fixed it.
Here is the code of my fix:
import axios, { AxiosError } from "axios";
import { API } from "../config";
import { getCookie } from "../helpers/auth";
const withUser = (Page: any) => {
const WithAuthUser = (props: any): JSX.Element => <Page {...props} />;
WithAuthUser.getInitialProps = async (context: any): Promise<any> => {
const token = getCookie("token", context.req);
console.log("token: ", token);
let user = null;
if (token) {
try {
const response = await axios.get(`${API}/user`, {
headers: {
authorization: `Bearer ${token}`,
contentType: "application/json",
},
});
console.log("response: ", response);
user = response.data;
} catch (err: unknown) {
const error = err as AxiosError;
if (error.response?.status === 401) {
user = null;
}
}
}
if (user === null) {
// redirect
context.res.writeHead(302, {
Location: "/",
});
context.res.end();
} else {
return {
...(Page.getInitialProps ? await Page.getInitialProps(context) : {}),
user,
token,
};
}
}
return WithAuthUser;
}
export default withUser;
Here i have my upi action folder ,here how can i add my jwt token from login page api to this page. what is the procedure for displaying token genereated from login page to be used in other pages in react.
import axios from 'axios';
export const upiAction = {
upi,
};
function upi(user) {
return (dispatch) => {
var data = {
upiId: user.upiId,
accountNumber: user.accountNumber,
};
axios
.post('http://localhost:9091/upiidcreation', data)
.then((res) => {
console.log("res", (res));
alert(JSON.stringify(res.data.responseDesc));
// window.location.pathname = "./homes";
})
.catch(err => {
dispatch(setUserUpiError(err, true));
alert("Please Check With details");
});
};
}
export function setUserUpi(showError) {
return {
type: 'SET_UPI_SUCCESS',
showError: showError,
};
}
export function setUserUpiError(error, showError) {
return {
type: 'SET_UPI_ERROR',
error: error,
showError: showError,
};
}
You can import your redux store in any file and then use the getState() function to get the current redux state.
Example:
import store from './store'
console.log('Current state: ', store.getState())
// {tokens: [...], otherState: {...}}
https://redux.js.org/tutorials/fundamentals/part-4-store#redux-store
I have the following code:
//agent.js
import axios from 'axios';
axios.defaults.baseURL = 'https://localhost:5001/api';
const requests = {
createUser: (payload) => {
axios.post('/users/create', payload);
},
getUsers: () => {
axios.get('/users').then((r) => {
console.log(r.data); //outputs the json response
return r.data;
});
}
};
const agent = {
requests
};
export default agent;
//reactComponent.js
import agent from './agent';
function Userlist() {
const users = agent.requests.getUsers();
console.log(users); //outputs undefined
}
What am I doing wrong as I get an undefined when making the request from my reactComponent.js.
Because you are not returning anything in your getUsers function.
getUsers: () => {
axios.get('/users').then((r) => {
console.log(r.data); //outputs the json response
return r.data;
});
}
Remove the function bracket and it should work,
getUsers: () =>
axios.get('/users').then((r) => {
console.log(r.data); //outputs the json response
return r.data;
});
Code under test
// imports
const router = express.Router()
// This is what needs to be mocked
const client = new AwesomeGraphQLClient({
endpoint: process.env.GRAPHCMS_URL || '',
fetch,
fetchOptions: {
headers: {
authorization: `Bearer ${process.env.GRAPHCMS_TOKEN}`
}
}
})
interface LoginRequest {
email: string
password: string
}
router.post(
'/login',
async (req: Request<{}, {}, LoginRequest>, res: Response) => {
try {
const JWT_SECRET = getEnvironment('JWT_SECRET')
const { email, password } = req.body
if (!email || !password) {
res.status(400).json({
message: 'auth.provide.credentials',
full: 'You should provide an email and password'
})
return
}
if (!JWT_SECRET) {
res.status(500).json({
message: 'auth.secret.not.found',
full: 'Secret not found'
})
// TODO error logging
return
}
const { appUsers } = await client.request<
GetUserByEmailResponse,
GetUserByEmailVariables
>(getUserByEmailQuery, {
email
})
if (appUsers.length === 0) {
res.status(404).json({
message: 'auth.wrong.credentials',
full: 'You provided wrong credentials'
})
return
}
const user = appUsers[0]
const result: boolean = await bcrypt.compare(password, user.password)
if (result) {
var token = jwt.sign({ id: user.id, email: user.email }, JWT_SECRET)
res.status(200).json({
token
})
return
}
res.status(200).json({
message: 'auth.wrong.credentials',
full: 'You provided wrong credentials in the end'
})
} catch (e) {
console.log('E', e)
const error: ErrorObject = handleError(e)
res.status(error.code).json(error)
}
}
)
Tests for code above
import request from 'supertest'
import app from '../../../app'
import { mocked } from 'ts-jest/utils'
import { compare } from 'bcrypt'
import { AwesomeGraphQLClient } from 'awesome-graphql-client'
const mockRequestFn = jest.fn().mockReturnValue({
appUsers: [
{
id: 'tests'
}
]
})
jest.mock('awesome-graphql-client', () => ({
AwesomeGraphQLClient: jest.fn().mockImplementation(() => ({
request: mockRequestFn
}))
}))
I am trying to mock a method on a non default exported class from Awesome GraphQL. I also want to spy on this method, so I created a separate jest.fn() with a return value. The problem is that request is not a function: TypeError: client.request is not a function.
How can I mock and spy on the method of a mocked non default exported class?
SOLUTION
Managed to find a workaround. Make the method a function that returns the called mockRequest. This way you can spy on AwesomeGraphQLClient.request with mockRequest.toHaveBeenCalledTimes(x).
let mockRequest = jest.fn().mockReturnValue({
appUsers: [
{
id: 'tests'
}
]
})
jest.mock('awesome-graphql-client', () => {
return {
AwesomeGraphQLClient: jest.fn().mockImplementation(() => {
return {
request: () => mockRequest()
}
})
}
})