diff --git a/client/.eslintrc.cjs b/client/.eslintrc.cjs new file mode 100644 index 000000000..d6c953795 --- /dev/null +++ b/client/.eslintrc.cjs @@ -0,0 +1,18 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react-hooks/recommended', + ], + ignorePatterns: ['dist', '.eslintrc.cjs'], + parser: '@typescript-eslint/parser', + plugins: ['react-refresh'], + rules: { + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, +} diff --git a/client/.gitignore b/client/.gitignore new file mode 100644 index 000000000..a547bf36d --- /dev/null +++ b/client/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/client/README.md b/client/README.md new file mode 100644 index 000000000..0d6babedd --- /dev/null +++ b/client/README.md @@ -0,0 +1,30 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: + +- Configure the top-level `parserOptions` property like this: + +```js +export default { + // other rules... + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: ['./tsconfig.json', './tsconfig.node.json'], + tsconfigRootDir: __dirname, + }, +} +``` + +- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` +- Optionally add `plugin:@typescript-eslint/stylistic-type-checked` +- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list diff --git a/client/index.html b/client/index.html new file mode 100644 index 000000000..e4b78eae1 --- /dev/null +++ b/client/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + TS + + +
+ + + diff --git a/client/package.json b/client/package.json new file mode 100644 index 000000000..638e54493 --- /dev/null +++ b/client/package.json @@ -0,0 +1,38 @@ +{ + "name": "client", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview" + }, + "dependencies": { + "@fortawesome/fontawesome-free": "^6.5.2", + "@fortawesome/fontawesome-svg-core": "^6.5.2", + "@fortawesome/free-solid-svg-icons": "^6.5.2", + "@fortawesome/react-fontawesome": "^0.2.0", + "@reduxjs/toolkit": "^2.2.5", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-redux": "^9.1.2", + "react-router-dom": "^6.23.1" + }, + "devDependencies": { + "@types/react": "^18.2.66", + "@types/react-dom": "^18.2.22", + "@typescript-eslint/eslint-plugin": "^7.2.0", + "@typescript-eslint/parser": "^7.2.0", + "@vitejs/plugin-react": "^4.2.1", + "autoprefixer": "^10.4.19", + "eslint": "^8.57.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.6", + "postcss": "^8.4.38", + "tailwindcss": "^3.4.3", + "typescript": "^5.2.2", + "vite": "^5.2.0" + } +} diff --git a/client/postcss.config.js b/client/postcss.config.js new file mode 100644 index 000000000..2e7af2b7f --- /dev/null +++ b/client/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/client/src/Pages/Dashboard/index.tsx b/client/src/Pages/Dashboard/index.tsx new file mode 100644 index 000000000..099415cc0 --- /dev/null +++ b/client/src/Pages/Dashboard/index.tsx @@ -0,0 +1,43 @@ +import { useSelector, useDispatch } from 'react-redux'; +import { logout } from '../../userSlice.tsx'; +import { RootState } from '../../store'; +import ArgentBank, { ArgentBankProps } from '../../components/ArgentBank'; + + +const Dashboard = () => { + const user = useSelector((state: RootState) => state.user); + const dispatch = useDispatch(); + + const handleSignOut = () => { + dispatch(logout()); + window.location.href = '/'; + }; + + const argentBank: ArgentBankProps[] = [{ + title: 'Argent Bank Checking (x8349)', + money: '$2,082.79', + balance: 'Available Balance' + }, { + title: 'Argent Bank Savings (x6712)', + money: '$10,928.42', + balance: 'Available Balance' + }, { + title: 'Argent Bank Credit Card (x8349)', + money: '$184.30', + balance: 'Current Balance' + }] + + return ( +
+
+

Welcome back
{user.name} !

+ +
+ {argentBank.map((bank, index) => ( + + ))} +
+ ); +} + +export default Dashboard; diff --git a/client/src/Pages/Home/index.tsx b/client/src/Pages/Home/index.tsx new file mode 100644 index 000000000..395cea33c --- /dev/null +++ b/client/src/Pages/Home/index.tsx @@ -0,0 +1,14 @@ +import Hero from '../../components/Home/Hero'; +import Features from '../../components/Home/Features'; +import { Fragment } from 'react/jsx-runtime'; + +const Home = () => { + return ( + + + + + ); +} + +export default Home; diff --git a/client/src/Pages/SignIn/index.tsx b/client/src/Pages/SignIn/index.tsx new file mode 100644 index 000000000..5fc918e6b --- /dev/null +++ b/client/src/Pages/SignIn/index.tsx @@ -0,0 +1,41 @@ +import { FormEvent } from 'react'; +import { useDispatch } from 'react-redux'; +import { login } from '../../userSlice.tsx'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faCircleUser } from '@fortawesome/free-solid-svg-icons'; + +const SignIn = () => { + const dispatch = useDispatch(); + + const handleSignIn = (event: FormEvent) => { + event.preventDefault(); + dispatch(login('Tony Jarvis')); + window.location.href = '/dashboard'; + }; + + return ( +
+
+ +

Sign In

+
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
+ ); +} + +export default SignIn; \ No newline at end of file diff --git a/client/src/assets/images/argentBankLogo.png b/client/src/assets/images/argentBankLogo.png new file mode 100644 index 000000000..89ce0f0b6 Binary files /dev/null and b/client/src/assets/images/argentBankLogo.png differ diff --git a/client/src/assets/images/bank-tree.jpeg b/client/src/assets/images/bank-tree.jpeg new file mode 100644 index 000000000..42619f4e8 Binary files /dev/null and b/client/src/assets/images/bank-tree.jpeg differ diff --git a/client/src/assets/images/icon-chat.png b/client/src/assets/images/icon-chat.png new file mode 100644 index 000000000..13e80a37c Binary files /dev/null and b/client/src/assets/images/icon-chat.png differ diff --git a/client/src/assets/images/icon-money.png b/client/src/assets/images/icon-money.png new file mode 100644 index 000000000..16eef314e Binary files /dev/null and b/client/src/assets/images/icon-money.png differ diff --git a/client/src/assets/images/icon-security.png b/client/src/assets/images/icon-security.png new file mode 100644 index 000000000..5a0e69b8a Binary files /dev/null and b/client/src/assets/images/icon-security.png differ diff --git a/client/src/components/ArgentBank/index.tsx b/client/src/components/ArgentBank/index.tsx new file mode 100644 index 000000000..e785d979b --- /dev/null +++ b/client/src/components/ArgentBank/index.tsx @@ -0,0 +1,22 @@ +export type ArgentBankProps = { + title: string, + money: string, + balance: string +} + +const ArgentBank = ({title, money, balance}: ArgentBankProps) => { + return ( +
+
+

{title}

+

{money}

+

{balance}

+
+
+ +
+
+ ) +} + +export default ArgentBank \ No newline at end of file diff --git a/client/src/components/Footer/index.tsx b/client/src/components/Footer/index.tsx new file mode 100644 index 000000000..8f23226d1 --- /dev/null +++ b/client/src/components/Footer/index.tsx @@ -0,0 +1,9 @@ +const Footer = () => { + return ( + + ); +} + +export default Footer; diff --git a/client/src/components/Home/FeatureText/index.tsx b/client/src/components/Home/FeatureText/index.tsx new file mode 100644 index 000000000..65a46e37d --- /dev/null +++ b/client/src/components/Home/FeatureText/index.tsx @@ -0,0 +1,20 @@ +export type FeatureTextProps = { + img: { + src: string, + alt: string + }, + title: string, + text: string +} + +const FeatureText = ({img, title, text}: FeatureTextProps) => { + return ( +
+ {img.alt} +

{title}

+

{text}

+
+ ) +} + +export default FeatureText \ No newline at end of file diff --git a/client/src/components/Home/Features/index.tsx b/client/src/components/Home/Features/index.tsx new file mode 100644 index 000000000..5cd4a2f90 --- /dev/null +++ b/client/src/components/Home/Features/index.tsx @@ -0,0 +1,37 @@ +import FeatureText, { FeatureTextProps } from "../FeatureText"; + +const Features = () => { + const texts: FeatureTextProps[] = [{ + img: { + src: 'icon-chat.png', + alt: 'Chat Icon', + }, + title: 'You are our #1 priority', + text: 'Need to talk to a representative? You can get in touch through our 24/7 chat or through a phone call in less than 5 minutes.' + }, { + img: { + src: 'icon-money.png', + alt: 'Money Icon', + }, + title: 'More savings means higher rates', + text: 'The more you save with us, the higher your interest rate will be!' + }, { + img: { + src: 'icon-security.png', + alt: 'Security Icon', + }, + title: 'Security you can trust', + text: 'We use top of the line encryption to make sure your data and money is always safe.' + },] + + return ( +
+

Features

+ {texts.map((text, index) => ( + + ))} +
+ ); +} + +export default Features; diff --git a/client/src/components/Home/Hero/index.tsx b/client/src/components/Home/Hero/index.tsx new file mode 100644 index 000000000..33a2ab4ae --- /dev/null +++ b/client/src/components/Home/Hero/index.tsx @@ -0,0 +1,15 @@ +const Hero = () => { + return ( +
+
+

Promoted Content

+

No fees.

+

No minimum deposit.

+

High interest rates.

+

Open a savings account with Argent Bank today!

+
+
+ ); +} + +export default Hero; diff --git a/client/src/components/NavBar/index.tsx b/client/src/components/NavBar/index.tsx new file mode 100644 index 000000000..29eb3e6e1 --- /dev/null +++ b/client/src/components/NavBar/index.tsx @@ -0,0 +1,29 @@ +import { Link, Location, useLocation } from 'react-router-dom'; + +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faCircleUser, faRightFromBracket } from '@fortawesome/free-solid-svg-icons'; + + +const NavBar = () => { + const loc: Location = useLocation(); + return ( + + ); +} + +export default NavBar; diff --git a/client/src/main.tsx b/client/src/main.tsx new file mode 100644 index 000000000..0c67ce74b --- /dev/null +++ b/client/src/main.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +import ReactDOM from 'react-dom/client' +import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; + +import { Provider } from 'react-redux'; +import { store } from './store'; + +import Home from './pages/Home'; +import SignIn from './pages/SignIn'; +import Dashboard from './pages/Dashboard'; +import NavBar from './components/NavBar'; +import Footer from './components/Footer'; + +import './styles/index.css' +import { library } from '@fortawesome/fontawesome-svg-core'; +import { fas } from '@fortawesome/free-solid-svg-icons'; + +library.add(fas); + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + + + + } /> + } /> + } /> + +