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-dom": "^18.0.6",
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"axios": "^1.1.3",
|
||||
"babel-loader": "^8.2.5",
|
||||
"css-loader": "^6.7.1",
|
||||
"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 userContext from "@ts/userContext"
|
||||
import Typography from "@theme/modules/components/Typography";
|
||||
import login , { FailedLoginError } from "@api/login";
|
||||
|
||||
type Inputs = {
|
||||
email: string;
|
||||
@ -35,10 +36,6 @@ export default function Login() {
|
||||
resolver: yupResolver(schema),
|
||||
});
|
||||
|
||||
function hash(s: string) {
|
||||
return `hash of '${s}' to be definied`;
|
||||
}
|
||||
|
||||
const { ref: emailRef, ...emailRegisterProps } = register("email");
|
||||
|
||||
const emailProps = {
|
||||
@ -65,12 +62,20 @@ export default function Login() {
|
||||
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");
|
||||
data = { ...data, password: hash(data.password) };
|
||||
user.setName(data.email);
|
||||
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 (
|
||||
|
@ -116,7 +116,7 @@ export default function Transactions() {
|
||||
</Typography>
|
||||
<Box className="box right">
|
||||
<Link variant="h6" className="link" href="/">
|
||||
{user.name}
|
||||
John Smith
|
||||
</Link>
|
||||
<AccountCircleIcon className="icon" />
|
||||
</Box>
|
||||
|
@ -1,3 +1,4 @@
|
||||
import isTokenValid from "@api/isTokenValid";
|
||||
import ErrorPage from "@components/ErrorPage";
|
||||
import React, { useEffect } from "react";
|
||||
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||
@ -7,17 +8,17 @@ type AuthProps = {
|
||||
}
|
||||
export default function AuthComponent({ children }: AuthProps) {
|
||||
const navigate = useNavigate();
|
||||
const searchParams = useSearchParams()[0];
|
||||
const isLogged = searchParams.has("logged");
|
||||
|
||||
useEffect(() => {
|
||||
// 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)
|
||||
navigate("/login", { replace: true });
|
||||
}, [isLogged])
|
||||
(async () => {
|
||||
const token: ApiToken = window.localStorage.getItem("token");
|
||||
const isLogged: boolean = token != null && await isTokenValid(token);
|
||||
if (!isLogged)
|
||||
navigate("/login", { replace: true });
|
||||
})()
|
||||
}, [])
|
||||
|
||||
if (isLogged)
|
||||
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.")}/>;
|
||||
// by default return the children, the effect will check if the user needs to be redirected
|
||||
return <>{children}</>;
|
||||
}
|
@ -41,8 +41,8 @@ const router = createBrowserRouter([
|
||||
|
||||
|
||||
const App = function () {
|
||||
const [name, setName] = useState("John Smith")
|
||||
const userContextValue = { name, setName }
|
||||
const [token, setToken] = useState<string>()
|
||||
const userContextValue = { token, setToken }
|
||||
return (
|
||||
<UserContext.Provider value={userContextValue}>
|
||||
<RouterProvider router={router} />
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { createContext } from 'react'
|
||||
|
||||
export default createContext({
|
||||
name : "Unknown",
|
||||
setName: (name: string) => {}
|
||||
token : "Unknown",
|
||||
setToken: (newToken: string) => {}
|
||||
})
|
@ -14,6 +14,7 @@
|
||||
"@components/*": ["src/components/*"],
|
||||
"@scss/*": ["src/scss/*"],
|
||||
"@ts/*": ["src/ts/*"],
|
||||
"@api/*": ["src/api/*"],
|
||||
"@theme/*": ["themes/onepirate/*"],
|
||||
}
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user