From 42bad6aeab661c11aef4ab02574bd700f01aad3e Mon Sep 17 00:00:00 2001 From: "Cross, Liam (UG - Comp Sci & Elec Eng)" <lc01383@surrey.ac.uk> Date: Tue, 2 Apr 2024 14:21:09 +0000 Subject: [PATCH] Register now calls backend --- GatewayAPI/Program.cs | 14 ++++ client/package-lock.json | 91 +++++++++++++++++++++ client/package.json | 1 + client/src/components/Login/Login.tsx | 2 +- client/src/components/Register/Register.tsx | 30 +++++-- client/src/contexts/AuthContext.ts | 8 +- client/src/helpers/Api.ts | 5 ++ client/src/helpers/UserType.ts | 3 + client/src/providers/AuthProvider.tsx | 28 ++++--- client/src/services/Register/Register.ts | 14 ++++ client/vite.config.ts | 4 +- 11 files changed, 176 insertions(+), 24 deletions(-) create mode 100644 client/src/helpers/Api.ts create mode 100644 client/src/helpers/UserType.ts create mode 100644 client/src/services/Register/Register.ts diff --git a/GatewayAPI/Program.cs b/GatewayAPI/Program.cs index 8f7722b..c8b364e 100644 --- a/GatewayAPI/Program.cs +++ b/GatewayAPI/Program.cs @@ -9,6 +9,17 @@ builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); +// Add CORS service +builder.Services.AddCors(options => +{ + options.AddPolicy("AllowAirlineClient", builder => + { + builder.WithOrigins("http://localhost:4200") + .AllowAnyMethod() + .AllowAnyHeader(); + }); +}); + // Add Http Typed Clients for each Microservice builder.Services.AddHttpClients(builder.Configuration); @@ -21,6 +32,9 @@ if (app.Environment.IsDevelopment()) app.UseSwaggerUI(); } +// Enable CORS +app.UseCors("AllowAirlineClient"); + //app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); diff --git a/client/package-lock.json b/client/package-lock.json index 831fa4a..2b93a1b 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -8,6 +8,7 @@ "name": "client", "version": "0.0.0", "dependencies": { + "axios": "^1.6.8", "react": "^18.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.51.1", @@ -1562,6 +1563,21 @@ "node": ">=8" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1724,6 +1740,17 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1779,6 +1806,14 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -2262,6 +2297,38 @@ "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2646,6 +2713,25 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", @@ -2865,6 +2951,11 @@ "node": ">= 0.8.0" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", diff --git a/client/package.json b/client/package.json index 14ef04f..f33bceb 100644 --- a/client/package.json +++ b/client/package.json @@ -10,6 +10,7 @@ "preview": "vite preview --host" }, "dependencies": { + "axios": "^1.6.8", "react": "^18.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.51.1", diff --git a/client/src/components/Login/Login.tsx b/client/src/components/Login/Login.tsx index ab0c224..350f62d 100644 --- a/client/src/components/Login/Login.tsx +++ b/client/src/components/Login/Login.tsx @@ -18,7 +18,7 @@ export function Login() { const onSubmit = (formValue: ILogin) => { setError('TODO: remove me once actual errors are implemented'); console.log('ready to make login api call', formValue); - giveAuth('testToken'); + giveAuth(); navigate('/'); }; diff --git a/client/src/components/Register/Register.tsx b/client/src/components/Register/Register.tsx index 933ab0c..d3db23c 100644 --- a/client/src/components/Register/Register.tsx +++ b/client/src/components/Register/Register.tsx @@ -1,8 +1,12 @@ -import { useForm } from 'react-hook-form'; import { useState } from 'react'; +import { useNavigate } from 'react-router-dom'; +import { useForm } from 'react-hook-form'; +import { AxiosError } from 'axios'; +import { registerUser } from '../../services/Register/Register'; +import { useAuth } from '../../hooks/useAuth'; import './Register.scss'; -interface IRegister { +export interface IRegisterForm { name: string; email: string; password: string; @@ -11,10 +15,12 @@ interface IRegister { } export function Register() { + const { giveAuth, updateUser } = useAuth(); + const navigate = useNavigate(); const [error, setError] = useState(''); - const { register, handleSubmit } = useForm<IRegister>({mode: 'onChange'}); + const { register, handleSubmit } = useForm<IRegisterForm>({mode: 'onChange'}); - const onSubmit = (formValue: IRegister) => { + const onSubmit = async (formValue: IRegisterForm) => { if (formValue.password.length < 7) { setError('password length must be greater than 6 characters'); return; @@ -25,8 +31,16 @@ export function Register() { return; } - setError(''); - console.log('ready to make register api call'); + setError(''); + + try { + const result = await registerUser(formValue); + giveAuth(); + updateUser(result.data); + navigate('/customer-dashboard'); + } catch (error) { + setError(((error as AxiosError).response?.data ?? 'unexpected error') as string); + } }; return ( @@ -57,8 +71,8 @@ export function Register() { <div className='form-group'> <label>Customer Type</label> <select {...register('customerType', { required: true })}> - <option value="Customer">Customer</option> - <option value="Airline">Airline</option> + <option value="customer">Customer</option> + <option value="airline">Airline</option> </select> </div> diff --git a/client/src/contexts/AuthContext.ts b/client/src/contexts/AuthContext.ts index 16e7a00..9190203 100644 --- a/client/src/contexts/AuthContext.ts +++ b/client/src/contexts/AuthContext.ts @@ -1,13 +1,17 @@ import { createContext } from 'react'; +import { IUser } from '../providers/AuthProvider'; interface IAuthContext { isAuth: boolean; - giveAuth: (token: string) => void; + giveAuth: () => void; removeAuth: () => void; + user?: IUser; + updateUser: (newUser: IUser) => void; } export const AuthContext = createContext<IAuthContext>({ isAuth: false, giveAuth: () => console.error('no give auth function'), - removeAuth: () => console.error('no remove auth function') + removeAuth: () => console.error('no remove auth function'), + updateUser: () => console.error('no update user function') }); diff --git a/client/src/helpers/Api.ts b/client/src/helpers/Api.ts new file mode 100644 index 0000000..f313797 --- /dev/null +++ b/client/src/helpers/Api.ts @@ -0,0 +1,5 @@ +import axios from 'axios'; + +export default axios.create({ + baseURL: 'http://localhost:5267/api/' +}); diff --git a/client/src/helpers/UserType.ts b/client/src/helpers/UserType.ts new file mode 100644 index 0000000..46ca75a --- /dev/null +++ b/client/src/helpers/UserType.ts @@ -0,0 +1,3 @@ +export function userStringToType(user: string) { + return user.toLowerCase() === 'customer' ? 0 : 1; +} diff --git a/client/src/providers/AuthProvider.tsx b/client/src/providers/AuthProvider.tsx index ee85b03..668859c 100644 --- a/client/src/providers/AuthProvider.tsx +++ b/client/src/providers/AuthProvider.tsx @@ -2,28 +2,34 @@ import { ReactNode, useEffect, useState } from 'react'; import { AuthContext } from '../contexts/AuthContext'; import Spinner from '../components/Spinner/Spinner'; +export interface IUser { + id: number; + email: string; + username: string; + type: number; +} + function AuthProvider({ children }: { children: ReactNode }) { const [loading, setLoading] = useState(true); - const [token, setToken] = useState(localStorage.getItem('token') ?? ''); + const [auth, setAuth] = useState(false); + const [user, setUser] = useState<IUser>(); useEffect(() => { - if (token) { - // validate token - } - setTimeout(() => setLoading(false), 500); // Fake api timer }, []); - const giveAuth = (token: string) => { - setToken(token); - localStorage.setItem('token', token); + const giveAuth = () => { + setAuth(true); }; const removeAuth = () => { - setToken(''); - localStorage.removeItem('token'); + setAuth(false); }; + const updateUser = (newUser: IUser) => { + setUser(newUser); + } + if (loading) { return ( <div className='full'> @@ -33,7 +39,7 @@ function AuthProvider({ children }: { children: ReactNode }) { } return ( - <AuthContext.Provider value={{ isAuth: !!token, giveAuth, removeAuth }}> + <AuthContext.Provider value={{ isAuth: auth, giveAuth, removeAuth, user, updateUser }}> {!loading && children} </AuthContext.Provider> ); diff --git a/client/src/services/Register/Register.ts b/client/src/services/Register/Register.ts new file mode 100644 index 0000000..1b7fd7f --- /dev/null +++ b/client/src/services/Register/Register.ts @@ -0,0 +1,14 @@ +import { AxiosResponse } from 'axios'; +import Api from '../../helpers/Api'; +import { IRegisterForm } from '../../components/Register/Register'; +import { userStringToType } from '../../helpers/UserType'; +import { IUser } from '../../providers/AuthProvider'; + +export async function registerUser(form: IRegisterForm): Promise<AxiosResponse<IUser>> { + return Api.post('User/register', { + Email: form.email, + Username: form.name, + Password: form.password, + UserType: userStringToType(form.customerType) + }); +} diff --git a/client/vite.config.ts b/client/vite.config.ts index f4777b8..df18a65 100644 --- a/client/vite.config.ts +++ b/client/vite.config.ts @@ -5,11 +5,11 @@ import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], preview: { - port: 8080, + port: 4200, strictPort: true }, server: { - port: 8080, + port: 4200, strictPort: true } }) -- GitLab