The customer can now login to the actual TCPOS backend by making the API call and storing the token in localstorage
This commit is contained in:
parent
a1072bff05
commit
aa444c4e33
@ -24,6 +24,7 @@
|
|||||||
"@types/react": "^18.0.21",
|
"@types/react": "^18.0.21",
|
||||||
"@types/react-dom": "^18.0.6",
|
"@types/react-dom": "^18.0.6",
|
||||||
"@types/react-router-dom": "^5.3.3",
|
"@types/react-router-dom": "^5.3.3",
|
||||||
|
"axios": "^1.1.3",
|
||||||
"babel-loader": "^8.2.5",
|
"babel-loader": "^8.2.5",
|
||||||
"css-loader": "^6.7.1",
|
"css-loader": "^6.7.1",
|
||||||
"dayjs": "^1.11.6",
|
"dayjs": "^1.11.6",
|
||||||
|
9
src/api/axiosInstance.ts
Normal file
9
src/api/axiosInstance.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
export default axios.create({
|
||||||
|
baseURL: "http://localhost:5276",
|
||||||
|
timeout: 1000,
|
||||||
|
params : {
|
||||||
|
shopId: 10,
|
||||||
|
}
|
||||||
|
})
|
1
src/api/declarations.d.ts
vendored
Normal file
1
src/api/declarations.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
declare type ApiToken = string; // QUESTION: does this make sense, to have this declaration here since we use is in multiple files?
|
35
src/api/isTokenValid.ts
Normal file
35
src/api/isTokenValid.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import axiosInstance from "./axiosInstance";
|
||||||
|
|
||||||
|
|
||||||
|
const API_INVALID_SHOP_ID_CODE = 608;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the token of the user is valid.
|
||||||
|
*
|
||||||
|
* @param token the token of the logged in customer
|
||||||
|
* @returns whether the user's token is still valid for the backend (aka if he is still logged in)
|
||||||
|
*/
|
||||||
|
export default async function isTokenValid(token: ApiToken): Promise<boolean> {
|
||||||
|
// There is no official way to check if the token is still valid or not,
|
||||||
|
// so after asking Daniele Comes, he said to make a call to retrieveOrders
|
||||||
|
// with shopId of -1 so that the DB wouldn't be queried.
|
||||||
|
// If the answer is "Invalid field 'shopId'", then the token is valid.
|
||||||
|
// If it isn't, it will be picked up before checking the shopId and
|
||||||
|
// the answer will contain a certain variation of the message "Token is not valid"
|
||||||
|
|
||||||
|
// Daniele Comes said he asked the WOnD team to make an endpoint to ask if the token is valid.
|
||||||
|
|
||||||
|
let res = await axiosInstance.get("/retrieveOrders", {
|
||||||
|
params: {
|
||||||
|
token,
|
||||||
|
shopId: -1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (res.data.retrieveOrders.result != "ERROR")
|
||||||
|
throw new Error("The API somehow didn't answer ERROR when asking to retrieve orders from shop with id=-1... This is not normal!");
|
||||||
|
|
||||||
|
const errorCode: number = res.data.retrieveOrders.errorCode;
|
||||||
|
|
||||||
|
return (errorCode == API_INVALID_SHOP_ID_CODE);
|
||||||
|
}
|
36
src/api/login.ts
Normal file
36
src/api/login.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import axiosInstance from "./axiosInstance";
|
||||||
|
|
||||||
|
interface LoginResponse {
|
||||||
|
isLogged: boolean;
|
||||||
|
nextAction(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
class FailedLoginError extends Error{
|
||||||
|
code: number;
|
||||||
|
constructor (msg: string, code: number){
|
||||||
|
super(msg);
|
||||||
|
this.code = code;
|
||||||
|
Object.setPrototypeOf(this, FailedLoginError.prototype)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// type ApiToken = string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param user the name of user logging in (if it's a customer, then it's his email)
|
||||||
|
* @param password the password of the user
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default async function login(user: string, password: string): Promise<ApiToken>{
|
||||||
|
// const user = useContext(userContext);
|
||||||
|
const res = await axiosInstance.get("/login", { params: { user, password } });
|
||||||
|
if (res.data.login.result == "ERROR") {
|
||||||
|
const errCode: number = res.data.login.errorCode;
|
||||||
|
const errMsg: string = res.data.login.message;
|
||||||
|
throw new FailedLoginError(errMsg, errCode);
|
||||||
|
}
|
||||||
|
return res.data.login.customerProperties.token;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { FailedLoginError };
|
@ -7,6 +7,7 @@ import * as yup from "yup";
|
|||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import userContext from "@ts/userContext"
|
import userContext from "@ts/userContext"
|
||||||
import Typography from "@theme/modules/components/Typography";
|
import Typography from "@theme/modules/components/Typography";
|
||||||
|
import login , { FailedLoginError } from "@api/login";
|
||||||
|
|
||||||
type Inputs = {
|
type Inputs = {
|
||||||
email: string;
|
email: string;
|
||||||
@ -35,10 +36,6 @@ export default function Login() {
|
|||||||
resolver: yupResolver(schema),
|
resolver: yupResolver(schema),
|
||||||
});
|
});
|
||||||
|
|
||||||
function hash(s: string) {
|
|
||||||
return `hash of '${s}' to be definied`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { ref: emailRef, ...emailRegisterProps } = register("email");
|
const { ref: emailRef, ...emailRegisterProps } = register("email");
|
||||||
|
|
||||||
const emailProps = {
|
const emailProps = {
|
||||||
@ -65,12 +62,20 @@ export default function Login() {
|
|||||||
helperText: errors?.password?.message,
|
helperText: errors?.password?.message,
|
||||||
};
|
};
|
||||||
|
|
||||||
function onSubmit(data: Inputs) {
|
async function onSubmit(data: Inputs) {
|
||||||
console.warn("There will be an API call now with the following data");
|
console.warn("There will be an API call now with the following data");
|
||||||
data = { ...data, password: hash(data.password) };
|
|
||||||
user.setName(data.email);
|
|
||||||
console.table(data);
|
console.table(data);
|
||||||
setTimeout(() => navigate("/?logged"), 3000);
|
try {
|
||||||
|
const token: ApiToken = await login(data.email, data.password);
|
||||||
|
user.setToken(token);
|
||||||
|
window.localStorage.setItem("token", token); // this could be done with a hook (right?)
|
||||||
|
navigate("/");
|
||||||
|
}catch(err){
|
||||||
|
if (err instanceof FailedLoginError)
|
||||||
|
alert(`Failed to login user.\nError code: '${err.code}', error message: '${err.message}'`)
|
||||||
|
else
|
||||||
|
alert('Failed to make api call');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -116,7 +116,7 @@ export default function Transactions() {
|
|||||||
</Typography>
|
</Typography>
|
||||||
<Box className="box right">
|
<Box className="box right">
|
||||||
<Link variant="h6" className="link" href="/">
|
<Link variant="h6" className="link" href="/">
|
||||||
{user.name}
|
John Smith
|
||||||
</Link>
|
</Link>
|
||||||
<AccountCircleIcon className="icon" />
|
<AccountCircleIcon className="icon" />
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import isTokenValid from "@api/isTokenValid";
|
||||||
import ErrorPage from "@components/ErrorPage";
|
import ErrorPage from "@components/ErrorPage";
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { useNavigate, useSearchParams } from "react-router-dom";
|
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||||
@ -7,17 +8,17 @@ type AuthProps = {
|
|||||||
}
|
}
|
||||||
export default function AuthComponent({ children }: AuthProps) {
|
export default function AuthComponent({ children }: AuthProps) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const searchParams = useSearchParams()[0];
|
|
||||||
const isLogged = searchParams.has("logged");
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// navigate needs to be wrapped in a useEffect so that it gets executed after the component is mounted. Otherwise it doesn't redirect
|
// navigate needs to be wrapped in a useEffect so that it gets executed after the component is mounted. Otherwise it doesn't redirect
|
||||||
if (!isLogged)
|
(async () => {
|
||||||
navigate("/login", { replace: true });
|
const token: ApiToken = window.localStorage.getItem("token");
|
||||||
}, [isLogged])
|
const isLogged: boolean = token != null && await isTokenValid(token);
|
||||||
|
if (!isLogged)
|
||||||
|
navigate("/login", { replace: true });
|
||||||
|
})()
|
||||||
|
}, [])
|
||||||
|
|
||||||
if (isLogged)
|
// by default return the children, the effect will check if the user needs to be redirected
|
||||||
return <>{children}</>;
|
return <>{children}</>;
|
||||||
// else
|
|
||||||
// return <ErrorPage err={new Error("You are not logged in and you should have been redirected to the login page. Something went wrong.")}/>;
|
|
||||||
}
|
}
|
@ -41,8 +41,8 @@ const router = createBrowserRouter([
|
|||||||
|
|
||||||
|
|
||||||
const App = function () {
|
const App = function () {
|
||||||
const [name, setName] = useState("John Smith")
|
const [token, setToken] = useState<string>()
|
||||||
const userContextValue = { name, setName }
|
const userContextValue = { token, setToken }
|
||||||
return (
|
return (
|
||||||
<UserContext.Provider value={userContextValue}>
|
<UserContext.Provider value={userContextValue}>
|
||||||
<RouterProvider router={router} />
|
<RouterProvider router={router} />
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { createContext } from 'react'
|
import { createContext } from 'react'
|
||||||
|
|
||||||
export default createContext({
|
export default createContext({
|
||||||
name : "Unknown",
|
token : "Unknown",
|
||||||
setName: (name: string) => {}
|
setToken: (newToken: string) => {}
|
||||||
})
|
})
|
@ -14,6 +14,7 @@
|
|||||||
"@components/*": ["src/components/*"],
|
"@components/*": ["src/components/*"],
|
||||||
"@scss/*": ["src/scss/*"],
|
"@scss/*": ["src/scss/*"],
|
||||||
"@ts/*": ["src/ts/*"],
|
"@ts/*": ["src/ts/*"],
|
||||||
|
"@api/*": ["src/api/*"],
|
||||||
"@theme/*": ["themes/onepirate/*"],
|
"@theme/*": ["themes/onepirate/*"],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user