From 33d1d72d5e7f2e8e7f846bbf8651d7f128765c64 Mon Sep 17 00:00:00 2001 From: Paweł Bernaciak Date: Fri, 27 Oct 2023 16:09:31 +0200 Subject: New frontend project --- frontend/src/App.tsx | 130 ++++++++++++++++++++------------ frontend/src/components/ElementList.tsx | 46 +++++++++++ frontend/src/components/ElementView.tsx | 19 +++++ frontend/src/index.css | 3 + frontend/src/index.tsx | 21 ------ frontend/src/main.tsx | 13 ++++ frontend/src/reportWebVitals.tsx | 13 ---- frontend/src/setupTests.tsx | 5 -- frontend/src/types.ts | 26 +++++++ frontend/src/vite-env.d.ts | 1 + 10 files changed, 191 insertions(+), 86 deletions(-) create mode 100644 frontend/src/components/ElementList.tsx create mode 100644 frontend/src/components/ElementView.tsx create mode 100644 frontend/src/index.css delete mode 100644 frontend/src/index.tsx create mode 100644 frontend/src/main.tsx delete mode 100644 frontend/src/reportWebVitals.tsx delete mode 100644 frontend/src/setupTests.tsx create mode 100644 frontend/src/types.ts create mode 100644 frontend/src/vite-env.d.ts (limited to 'frontend/src') diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 996a794..7aae66c 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,58 +1,94 @@ -import React from 'react'; import { CredentialResponse, GoogleLogin } from '@react-oauth/google'; +import { FC, useEffect, useState } from 'react'; +import { LoginRequest, LoginResponse, User } from './types'; +import ElementList from './components/ElementList'; -interface LoginResponse { - id: number -} +const App: FC = () => { + const [user, setUser] = useState(undefined); -interface User { - id: Number, - elements: Element[], -} + useEffect(() => { + const userString = localStorage.getItem('user'); + if (userString == null) { + return; + } -interface Element { - id: Number, - userId: Number, - name: string, - state: ElementState, -} + setUser(JSON.parse(userString)); + }, []); -enum ElementState { - HasColor, - HasIcon, -} + const login = async (credentials: CredentialResponse) => { + if (credentials.credential == null) { + console.log('Error getting credentials from google'); + return; + } -function App() { - const responseMessage = async (googleResponse: CredentialResponse) => { - console.log(googleResponse); - const url: string = "/auth/login"; - const body = { - "googleToken": googleResponse.credential - }; - - const response = await fetch(url, { - method: "POST", - credentials: "include", - mode: "cors", - headers: { - "Content-Type": "application/json" - }, - body: JSON.stringify(body), - }); - if (!response.ok) { - console.log("Backend conection problem"); - return; - } - - const user = await response.json() as LoginResponse; - console.log(user); + // Authenticate with API and get user ID + const loginRequest: LoginRequest = { + googleToken: credentials.credential, }; + const loginResponse = await fetch('/api/auth/login', { + method: 'POST', + credentials: 'include', + mode: 'cors', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(loginRequest), + }); + if (!loginResponse.ok) { + console.log('Error connecting to API. Code: ', loginResponse.status); + return; + } + const userLoginResponse: LoginResponse = await loginResponse.json(); + + //Get info about user using ID + const userInfoResponse = await fetch(`/api/user/${userLoginResponse.id}`, { + credentials: 'include', + }); + if (!userInfoResponse.ok) { + console.log('Error connecting to API. Code: ', userInfoResponse.status); + return; + } + const userResponse: User = await userInfoResponse.json(); + + localStorage.setItem('user', JSON.stringify(userResponse)); + setUser(userResponse); + }; + + const logout = async (e: React.MouseEvent) => { + e.preventDefault(); + + const response = await fetch('api/auth/logout', { + method: 'POST', + credentials: 'include', + }); + if (response.status != 200) { + console.log('Error logging out. Code: ', response.status); + return; + } + + localStorage.removeItem('user'); + setUser(undefined); + }; - return ( -
- -
- ); + return ( +
+
+ {user ? ( + <> +

Hello {user.name}

+ + Logout + + + ) : ( + + )} +
+ +
+ ); } export default App; diff --git a/frontend/src/components/ElementList.tsx b/frontend/src/components/ElementList.tsx new file mode 100644 index 0000000..20b27dd --- /dev/null +++ b/frontend/src/components/ElementList.tsx @@ -0,0 +1,46 @@ +import { FC, useEffect, useState } from 'react'; +import {Element} from '../types'; +import ElementView from './ElementView'; + +const ElementList: FC = () => { + const [elements, setElements] = useState([]); + + useEffect(() => { + const initialElements: number[] = [1, 2, 3, 4]; + + const elementStateString = localStorage.getItem('elementState'); + if (elementStateString != null) { + setElements(JSON.parse(elementStateString)); + return; + } + + const fetchElements = async () => { + const elems: Element[] = []; + + for (const elemId of initialElements) { + const response = await fetch(`/api/element/${elemId}`); + const elem: Element = await response.json(); + elems.push(elem); + } + + localStorage.setItem('elementState', JSON.stringify(elems)); + setElements(elems); + }; + + fetchElements().catch(console.error); + }, []); + + useEffect(() => { + if (elements.length != 0) { + localStorage.setItem('elementState', JSON.stringify(elements)); + } + }, [elements]) + + return ( + <> + {elements.map(elem => )} + + ); +}; + +export default ElementList; diff --git a/frontend/src/components/ElementView.tsx b/frontend/src/components/ElementView.tsx new file mode 100644 index 0000000..4f9d489 --- /dev/null +++ b/frontend/src/components/ElementView.tsx @@ -0,0 +1,19 @@ +import { FC } from 'react'; +import { Element } from '../types'; + +interface ElementViewProps { + element: Element; +} + +const ElementView: FC = ({ element }) => { + return ( +
+
+ +

{element.name}

+
+
+ ); +}; + +export default ElementView; diff --git a/frontend/src/index.css b/frontend/src/index.css new file mode 100644 index 0000000..bd6213e --- /dev/null +++ b/frontend/src/index.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; \ No newline at end of file diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx deleted file mode 100644 index 162d1a1..0000000 --- a/frontend/src/index.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import App from './App'; -import reportWebVitals from './reportWebVitals'; -import { GoogleOAuthProvider } from '@react-oauth/google'; - -const rootElem: HTMLElement = document.getElementById('root')!; - -const root = ReactDOM.createRoot(rootElem); -root.render( - - - - - -); - -// If you want to start measuring performance in your app, pass a function -// to log results (for example: reportWebVitals(console.log)) -// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals -reportWebVitals(null); diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx new file mode 100644 index 0000000..4e3e75d --- /dev/null +++ b/frontend/src/main.tsx @@ -0,0 +1,13 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App.tsx' +import './index.css' +import {GoogleOAuthProvider} from '@react-oauth/google'; + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + + + , +) diff --git a/frontend/src/reportWebVitals.tsx b/frontend/src/reportWebVitals.tsx deleted file mode 100644 index f00fe6c..0000000 --- a/frontend/src/reportWebVitals.tsx +++ /dev/null @@ -1,13 +0,0 @@ -const reportWebVitals = (onPerfEntry: any) => { - if (onPerfEntry && onPerfEntry instanceof Function) { - import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { - getCLS(onPerfEntry); - getFID(onPerfEntry); - getFCP(onPerfEntry); - getLCP(onPerfEntry); - getTTFB(onPerfEntry); - }); - } -}; - -export default reportWebVitals; diff --git a/frontend/src/setupTests.tsx b/frontend/src/setupTests.tsx deleted file mode 100644 index 8f2609b..0000000 --- a/frontend/src/setupTests.tsx +++ /dev/null @@ -1,5 +0,0 @@ -// jest-dom adds custom jest matchers for asserting on DOM nodes. -// allows you to do things like: -// expect(element).toHaveTextContent(/react/i) -// learn more: https://github.com/testing-library/jest-dom -import '@testing-library/jest-dom'; diff --git a/frontend/src/types.ts b/frontend/src/types.ts new file mode 100644 index 0000000..ecdd808 --- /dev/null +++ b/frontend/src/types.ts @@ -0,0 +1,26 @@ +export interface LoginRequest { + googleToken: string; +} + +export interface LoginResponse { + id: number; +} + +export interface User { + id: number; + name: string; + elements: Element[]; +} + +export interface Element { + id: number; + userId: number; + name: string; + state: ElementState; + icon: string; +} + +export enum ElementState { + HasColor, + HasIcon, +} diff --git a/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts new file mode 100644 index 0000000..151aa68 --- /dev/null +++ b/frontend/src/vite-env.d.ts @@ -0,0 +1 @@ +/// \ No newline at end of file -- cgit v1.2.3