From b470f59ce296a137071922612afa682ef19486fa Mon Sep 17 00:00:00 2001 From: Alejandra <90076947+alejsdev@users.noreply.github.com> Date: Thu, 15 Feb 2024 17:17:26 -0500 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Migrate=20to=20RouterProvider=20and?= =?UTF-8?q?=20other=20refactors=20(#598)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- src/new-frontend/src/App.css | 42 ------------ src/new-frontend/src/App.tsx | 61 ----------------- .../src/assets/images/fastapi-logo.png | Bin 17680 -> 0 bytes .../src/assets/images/fastapi-logo.svg | 51 ++++++++++++++ .../src/assets/images/favicon.png | Bin 412 -> 5043 bytes .../src/components/ActionsMenu.tsx | 6 +- src/new-frontend/src/components/Navbar.tsx | 30 +++++---- src/new-frontend/src/components/Sidebar.tsx | 25 ++++--- .../src/components/SidebarItems.tsx | 47 +++++++------ src/new-frontend/src/components/UserInfo.tsx | 29 -------- src/new-frontend/src/components/UserMenu.tsx | 45 +++++++++++++ src/new-frontend/src/main.tsx | 38 +++++++++-- .../CreateItem.tsx => modals/AddItem.tsx} | 28 ++++---- .../CreateUser.tsx => modals/AddUser.tsx} | 25 +++---- .../src/{pages => }/modals/DeleteAlert.tsx | 35 +++++++--- .../src/{pages => }/modals/EditItem.tsx | 4 +- .../src/{pages => }/modals/EditUser.tsx | 10 +-- .../src/pages/{main => }/Admin.tsx | 19 +++--- src/new-frontend/src/pages/Dashboard.tsx | 22 ++++++ src/new-frontend/src/pages/ErrorPage.tsx | 26 ++++++++ .../src/pages/{main => }/Items.tsx | 17 +++-- src/new-frontend/src/pages/Layout.tsx | 15 ----- .../src/pages/{auth => }/Login.tsx | 10 +-- src/new-frontend/src/pages/NotFound.tsx | 18 ----- .../src/pages/RecoverPassword.tsx | 63 ++++++++++++++++++ src/new-frontend/src/pages/Root.tsx | 42 ++++++++++++ .../{main/Profile.tsx => UserSettings.tsx} | 6 +- src/new-frontend/src/pages/main/Dashboard.tsx | 24 ------- .../src/{pages => }/panels/Appearance.tsx | 2 +- .../src/{pages => }/panels/ChangePassword.tsx | 2 +- .../src/{pages => }/panels/DeleteAccount.tsx | 2 +- .../{pages => }/panels/UserInformation.tsx | 4 +- src/new-frontend/src/theme.tsx | 37 ++++++++++ 33 files changed, 472 insertions(+), 313 deletions(-) delete mode 100644 src/new-frontend/src/App.css delete mode 100644 src/new-frontend/src/App.tsx delete mode 100644 src/new-frontend/src/assets/images/fastapi-logo.png create mode 100644 src/new-frontend/src/assets/images/fastapi-logo.svg delete mode 100644 src/new-frontend/src/components/UserInfo.tsx create mode 100644 src/new-frontend/src/components/UserMenu.tsx rename src/new-frontend/src/{pages/modals/CreateItem.tsx => modals/AddItem.tsx} (80%) rename src/new-frontend/src/{pages/modals/CreateUser.tsx => modals/AddUser.tsx} (81%) rename src/new-frontend/src/{pages => }/modals/DeleteAlert.tsx (60%) rename src/new-frontend/src/{pages => }/modals/EditItem.tsx (89%) rename src/new-frontend/src/{pages => }/modals/EditUser.tsx (85%) rename src/new-frontend/src/pages/{main => }/Admin.tsx (89%) create mode 100644 src/new-frontend/src/pages/Dashboard.tsx create mode 100644 src/new-frontend/src/pages/ErrorPage.tsx rename src/new-frontend/src/pages/{main => }/Items.tsx (88%) delete mode 100644 src/new-frontend/src/pages/Layout.tsx rename src/new-frontend/src/pages/{auth => }/Login.tsx (89%) delete mode 100644 src/new-frontend/src/pages/NotFound.tsx create mode 100644 src/new-frontend/src/pages/RecoverPassword.tsx create mode 100644 src/new-frontend/src/pages/Root.tsx rename src/new-frontend/src/pages/{main/Profile.tsx => UserSettings.tsx} (92%) delete mode 100644 src/new-frontend/src/pages/main/Dashboard.tsx rename src/new-frontend/src/{pages => }/panels/Appearance.tsx (89%) rename src/new-frontend/src/{pages => }/panels/ChangePassword.tsx (90%) rename src/new-frontend/src/{pages => }/panels/DeleteAccount.tsx (82%) rename src/new-frontend/src/{pages => }/panels/UserInformation.tsx (88%) create mode 100644 src/new-frontend/src/theme.tsx diff --git a/src/new-frontend/src/App.css b/src/new-frontend/src/App.css deleted file mode 100644 index b9d355df2..000000000 --- a/src/new-frontend/src/App.css +++ /dev/null @@ -1,42 +0,0 @@ -#root { - max-width: 1280px; - margin: 0 auto; - padding: 2rem; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: filter 300ms; -} -.logo:hover { - filter: drop-shadow(0 0 2em #646cffaa); -} -.logo.react:hover { - filter: drop-shadow(0 0 2em #61dafbaa); -} - -@keyframes logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -@media (prefers-reduced-motion: no-preference) { - a:nth-of-type(2) .logo { - animation: logo-spin infinite 20s linear; - } -} - -.card { - padding: 2em; -} - -.read-the-docs { - color: #888; -} diff --git a/src/new-frontend/src/App.tsx b/src/new-frontend/src/App.tsx deleted file mode 100644 index e9d621683..000000000 --- a/src/new-frontend/src/App.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { Route, BrowserRouter as Router, Routes } from 'react-router-dom'; - -import { ChakraProvider, extendTheme } from '@chakra-ui/react'; - -import Layout from './pages/Layout'; -import NotFound from './pages/NotFound'; -import Login from './pages/auth/Login'; -import RecoverPassword from './pages/auth/RecoverPassword'; -import Admin from './pages/main/Admin'; -import Dashboard from './pages/main/Dashboard'; -import Items from './pages/main/Items'; -import Profile from './pages/main/Profile'; - -// Theme -const theme = extendTheme({ - colors: { - ui: { - main: "#009688", - secondary: "#EDF2F7", - success: '#48BB78', - danger: '#E53E3E', - } - }, - components: { - Tabs: { - variants: { - enclosed: { - tab: { - _selected: { - color: 'ui.main', - }, - }, - }, - }, - }, - }, -}); - -function App() { - return ( - <> - - - - } /> - } /> - }> - } /> - } /> - } /> - } /> - - } /> - - - - - ) -} - -export default App diff --git a/src/new-frontend/src/assets/images/fastapi-logo.png b/src/new-frontend/src/assets/images/fastapi-logo.png deleted file mode 100644 index 57d9eec137c0458dd83539835397fdd299e650ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17680 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 XuqwmUh9A!VCZQy!E?XsS^7a1$wHKYW diff --git a/src/new-frontend/src/assets/images/fastapi-logo.svg b/src/new-frontend/src/assets/images/fastapi-logo.svg new file mode 100644 index 000000000..d3dad4bec --- /dev/null +++ b/src/new-frontend/src/assets/images/fastapi-logo.svg @@ -0,0 +1,51 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + diff --git a/src/new-frontend/src/assets/images/favicon.png b/src/new-frontend/src/assets/images/favicon.png index b3dcdd3090e52a3d94affb00a40df2fe8a56d4ba..e5b7c3ada7d093d237711560e03f6a841a4a41b2 100644 GIT binary patch literal 5043 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 = ({ type }) => { - const createUserModal = useDisclosure(); - const createItemModal = useDisclosure(); + const addUserModal = useDisclosure(); + const addItemModal = useDisclosure(); return ( <> - - - - - + + + ); }; diff --git a/src/new-frontend/src/components/Sidebar.tsx b/src/new-frontend/src/components/Sidebar.tsx index d483a8c8e..0d281520a 100644 --- a/src/new-frontend/src/components/Sidebar.tsx +++ b/src/new-frontend/src/components/Sidebar.tsx @@ -1,15 +1,16 @@ import React from 'react'; -import { Box, Drawer, DrawerBody, DrawerCloseButton, DrawerContent, DrawerOverlay, Flex, IconButton, Image, useDisclosure } from '@chakra-ui/react'; +import { Box, Drawer, DrawerBody, DrawerCloseButton, DrawerContent, DrawerOverlay, Flex, IconButton, Image, useDisclosure, Text } from '@chakra-ui/react'; import { FiMenu } from 'react-icons/fi'; -import Logo from "../assets/images/fastapi-logo.png"; +import Logo from "../assets/images/fastapi-logo.svg"; import SidebarItems from './SidebarItems'; -import UserInfo from './UserInfo'; +import { useUserStore } from '../store/user-store'; const Sidebar: React.FC = () => { const { isOpen, onOpen, onClose } = useDisclosure(); + const { user } = useUserStore(); return ( <> @@ -20,12 +21,15 @@ const Sidebar: React.FC = () => { - + - Logo + Logo - + { + user?.email && + Logged in as: {user.email} + } @@ -33,12 +37,15 @@ const Sidebar: React.FC = () => { {/* Desktop */} - + - Logo + Logo - + { + user?.email && + Logged in as: {user.email} + } diff --git a/src/new-frontend/src/components/SidebarItems.tsx b/src/new-frontend/src/components/SidebarItems.tsx index e0f928136..2282aaa3f 100644 --- a/src/new-frontend/src/components/SidebarItems.tsx +++ b/src/new-frontend/src/components/SidebarItems.tsx @@ -1,16 +1,14 @@ import React from 'react'; -import { Flex, Icon, Text } from '@chakra-ui/react'; -import { FiBriefcase, FiHome, FiLogOut, FiSettings, FiUsers } from 'react-icons/fi'; -import { Link, useNavigate } from 'react-router-dom'; - +import { Box, Flex, Icon, Text } from '@chakra-ui/react'; +import { FiBriefcase, FiHome, FiSettings, FiUsers } from 'react-icons/fi'; +import { Link, useLocation } from 'react-router-dom'; const items = [ { icon: FiHome, title: 'Dashboard', path: "/" }, { icon: FiBriefcase, title: 'Items', path: "/items" }, { icon: FiUsers, title: 'Admin', path: "/admin" }, { icon: FiSettings, title: 'User Settings', path: "/settings" }, - { icon: FiLogOut, title: 'Log out' } ]; interface SidebarItemsProps { @@ -18,32 +16,33 @@ interface SidebarItemsProps { } const SidebarItems: React.FC = ({ onClose }) => { - const navigate = useNavigate(); - - const handleLogout = async () => { - localStorage.removeItem("access_token"); - navigate("/login"); - // TODO: reset all Zustand states - }; + const location = useLocation(); const listItems = items.map((item) => ( - - - - - {item.title} - - - + + + {item.title} )); return ( <> - {listItems} + + {listItems} + + ); }; diff --git a/src/new-frontend/src/components/UserInfo.tsx b/src/new-frontend/src/components/UserInfo.tsx deleted file mode 100644 index ddea6d002..000000000 --- a/src/new-frontend/src/components/UserInfo.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; - -import { Avatar, Flex, Skeleton, Text } from '@chakra-ui/react'; -import { FaUserAstronaut } from 'react-icons/fa'; - -import { useUserStore } from '../store/user-store'; - - -const UserInfo: React.FC = () => { - const { user } = useUserStore(); - - - return ( - <> - {user ? ( - - } size='sm' alignSelf="center" /> - {/* TODO: Conditional tooltip based on email length */} - {user.email} - - ) : - - } - - ); - -} - -export default UserInfo; \ No newline at end of file diff --git a/src/new-frontend/src/components/UserMenu.tsx b/src/new-frontend/src/components/UserMenu.tsx new file mode 100644 index 000000000..224af6012 --- /dev/null +++ b/src/new-frontend/src/components/UserMenu.tsx @@ -0,0 +1,45 @@ +import React from 'react'; + +import { IconButton } from '@chakra-ui/button'; +import { Box } from '@chakra-ui/layout'; +import { Menu, MenuButton, MenuItem, MenuList } from '@chakra-ui/menu'; +import { FaUserAstronaut } from 'react-icons/fa'; +import { FiLogOut, FiUser } from 'react-icons/fi'; +import { useNavigate } from 'react-router'; +import { Link } from 'react-router-dom'; + +const UserMenu: React.FC = () => { + const navigate = useNavigate(); + + const handleLogout = async () => { + localStorage.removeItem("access_token"); + navigate("/login"); + // TODO: reset all Zustand states + }; + + return ( + <> + + + } + bg="ui.main" + isRound + /> + + } as={Link} to="settings"> + My profile + + } onClick={handleLogout} color="ui.danger"> + Log out + + + + + + ); +}; + +export default UserMenu; diff --git a/src/new-frontend/src/main.tsx b/src/new-frontend/src/main.tsx index f9ebbd94f..146cbb549 100644 --- a/src/new-frontend/src/main.tsx +++ b/src/new-frontend/src/main.tsx @@ -1,20 +1,50 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; -import { ChakraProvider } from '@chakra-ui/react'; +import { ChakraProvider } from '@chakra-ui/provider'; +import { createStandaloneToast } from '@chakra-ui/toast'; +import { RouterProvider, createBrowserRouter } from 'react-router-dom'; -import App from './App'; import { OpenAPI } from './client'; +import Admin from './pages/Admin'; +import Dashboard from './pages/Dashboard'; +import ErrorPage from './pages/ErrorPage'; +import Items from './pages/Items'; +import Login from './pages/Login'; +import RecoverPassword from './pages/RecoverPassword'; +import Root from './pages/Root'; +import Profile from './pages/UserSettings'; +import theme from './theme'; + OpenAPI.BASE = import.meta.env.VITE_API_URL; OpenAPI.TOKEN = async () => { return localStorage.getItem('access_token') || ''; } +const router = createBrowserRouter([ + { + path: '/', + element: , + errorElement: , + children: [ + { path: '/', element: }, + { path: 'items', element: }, + { path: 'admin', element: }, + { path: 'settings', element: }, + ], + }, + { path: 'login', element: , errorElement: , }, + { path: 'recover-password', element: , errorElement: , }, +]); + +const { ToastContainer } = createStandaloneToast(); + ReactDOM.createRoot(document.getElementById('root')!).render( - - + + + , ) diff --git a/src/new-frontend/src/pages/modals/CreateItem.tsx b/src/new-frontend/src/modals/AddItem.tsx similarity index 80% rename from src/new-frontend/src/pages/modals/CreateItem.tsx rename to src/new-frontend/src/modals/AddItem.tsx index d3574353a..c7967019c 100644 --- a/src/new-frontend/src/pages/modals/CreateItem.tsx +++ b/src/new-frontend/src/modals/AddItem.tsx @@ -3,41 +3,41 @@ import React, { useState } from 'react'; import { Button, FormControl, FormLabel, Input, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay, useToast } from '@chakra-ui/react'; import { SubmitHandler, useForm } from 'react-hook-form'; -import { ItemCreate } from '../../client'; -import { useItemsStore } from '../../store/items-store'; +import { ItemCreate } from '../client'; +import { useItemsStore } from '../store/items-store'; -interface CreateItemProps { +interface AddItemProps { isOpen: boolean; onClose: () => void; } -const CreateItem: React.FC = ({ isOpen, onClose }) => { +const AddItem: React.FC = ({ isOpen, onClose }) => { const toast = useToast(); const [isLoading, setIsLoading] = useState(false); - const { register, handleSubmit } = useForm(); + const { register, handleSubmit, reset } = useForm(); const { addItem } = useItemsStore(); const onSubmit: SubmitHandler = async (data) => { + setIsLoading(true); try { - setIsLoading(true); await addItem(data); - setIsLoading(false); - toast({ title: 'Success!', description: 'Item created successfully.', status: 'success', isClosable: true, }); + reset(); onClose(); } catch (err) { - setIsLoading(false); toast({ title: 'Something went wrong.', description: 'Failed to create item. Please try again.', status: 'error', isClosable: true, }); + } finally { + setIsLoading(false); } }; @@ -51,7 +51,7 @@ const CreateItem: React.FC = ({ isOpen, onClose }) => { > - Create Item + Add Item @@ -59,7 +59,7 @@ const CreateItem: React.FC = ({ isOpen, onClose }) => { @@ -67,13 +67,13 @@ const CreateItem: React.FC = ({ isOpen, onClose }) => { - diff --git a/src/new-frontend/src/pages/main/Admin.tsx b/src/new-frontend/src/pages/Admin.tsx similarity index 89% rename from src/new-frontend/src/pages/main/Admin.tsx rename to src/new-frontend/src/pages/Admin.tsx index 70fd5eb88..17b410fab 100644 --- a/src/new-frontend/src/pages/main/Admin.tsx +++ b/src/new-frontend/src/pages/Admin.tsx @@ -2,9 +2,9 @@ import React, { useEffect, useState } from 'react'; import { Box, Container, Flex, Heading, Spinner, Table, TableContainer, Tbody, Td, Th, Thead, Tr, useToast } from '@chakra-ui/react'; -import ActionsMenu from '../../components/ActionsMenu'; -import Navbar from '../../components/Navbar'; -import { useUsersStore } from '../../store/users-store'; +import ActionsMenu from '../components/ActionsMenu'; +import Navbar from '../components/Navbar'; +import { useUsersStore } from '../store/users-store'; const Admin: React.FC = () => { const toast = useToast(); @@ -13,21 +13,23 @@ const Admin: React.FC = () => { useEffect(() => { const fetchUsers = async () => { + setIsLoading(true); try { - setIsLoading(true); await getUsers(); - setIsLoading(false); } catch (err) { - setIsLoading(false); toast({ title: 'Something went wrong.', description: 'Failed to fetch users. Please try again.', status: 'error', isClosable: true, }); + } finally { + setIsLoading(false); } } - fetchUsers(); + if (users.length === 0) { + fetchUsers(); + } }, []) return ( @@ -35,7 +37,7 @@ const Admin: React.FC = () => { {isLoading ? ( // TODO: Add skeleton - + ) : ( users && @@ -52,6 +54,7 @@ const Admin: React.FC = () => { Email Role Status + Actions diff --git a/src/new-frontend/src/pages/Dashboard.tsx b/src/new-frontend/src/pages/Dashboard.tsx new file mode 100644 index 000000000..e0a5e07a5 --- /dev/null +++ b/src/new-frontend/src/pages/Dashboard.tsx @@ -0,0 +1,22 @@ +import React from 'react'; + +import { Box, Text } from '@chakra-ui/react'; + +import { useUserStore } from '../store/user-store'; + + +const Dashboard: React.FC = () => { + const { user } = useUserStore(); + + return ( + <> + + Hi, {user?.full_name || user?.email} 👋🏼 + Welcome back, nice to see you again! + + + + ) +} + +export default Dashboard; \ No newline at end of file diff --git a/src/new-frontend/src/pages/ErrorPage.tsx b/src/new-frontend/src/pages/ErrorPage.tsx new file mode 100644 index 000000000..f8bd796ec --- /dev/null +++ b/src/new-frontend/src/pages/ErrorPage.tsx @@ -0,0 +1,26 @@ +import { Button, Container, Text } from "@chakra-ui/react"; + +import { Link, useRouteError } from "react-router-dom"; + +const ErrorPage: React.FC = () => { + const error = useRouteError(); + console.log(error); + + return ( + <> + + Oops! + Houston, we have a problem. + An unexpected error has occurred. + {error.statusText || error.message} + + + + ); +} + +export default ErrorPage; + + diff --git a/src/new-frontend/src/pages/main/Items.tsx b/src/new-frontend/src/pages/Items.tsx similarity index 88% rename from src/new-frontend/src/pages/main/Items.tsx rename to src/new-frontend/src/pages/Items.tsx index 7e2a2fb31..bcf1c04dd 100644 --- a/src/new-frontend/src/pages/main/Items.tsx +++ b/src/new-frontend/src/pages/Items.tsx @@ -2,9 +2,9 @@ import React, { useEffect, useState } from 'react'; import { Container, Flex, Heading, Spinner, Table, TableContainer, Tbody, Td, Th, Thead, Tr, useToast } from '@chakra-ui/react'; -import ActionsMenu from '../../components/ActionsMenu'; -import Navbar from '../../components/Navbar'; -import { useItemsStore } from '../../store/items-store'; +import ActionsMenu from '../components/ActionsMenu'; +import Navbar from '../components/Navbar'; +import { useItemsStore } from '../store/items-store'; const Items: React.FC = () => { @@ -14,21 +14,23 @@ const Items: React.FC = () => { useEffect(() => { const fetchItems = async () => { + setIsLoading(true); try { - setIsLoading(true); await getItems(); - setIsLoading(false); } catch (err) { - setIsLoading(false); toast({ title: 'Something went wrong.', description: 'Failed to fetch items. Please try again.', status: 'error', isClosable: true, }); + } finally { + setIsLoading(false); } } - fetchItems(); + if (items.length === 0) { + fetchItems(); + } }, []) @@ -53,6 +55,7 @@ const Items: React.FC = () => { ID Title Description + Actions diff --git a/src/new-frontend/src/pages/Layout.tsx b/src/new-frontend/src/pages/Layout.tsx deleted file mode 100644 index bbf1087ce..000000000 --- a/src/new-frontend/src/pages/Layout.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { Outlet } from 'react-router-dom'; -import Sidebar from '../components/Sidebar'; - -import { Flex } from '@chakra-ui/react'; - -const Layout = () => { - return ( - - - - - ); -}; - -export default Layout; diff --git a/src/new-frontend/src/pages/auth/Login.tsx b/src/new-frontend/src/pages/Login.tsx similarity index 89% rename from src/new-frontend/src/pages/auth/Login.tsx rename to src/new-frontend/src/pages/Login.tsx index 53e01ed22..b9e89803e 100644 --- a/src/new-frontend/src/pages/auth/Login.tsx +++ b/src/new-frontend/src/pages/Login.tsx @@ -5,12 +5,12 @@ import { Button, Center, Container, FormControl, Icon, Image, Input, InputGroup, import { SubmitHandler, useForm } from "react-hook-form"; import { Link as ReactRouterLink, useNavigate } from "react-router-dom"; -import Logo from "../../assets/images/fastapi-logo.png"; -import { LoginService } from "../../client"; -import { Body_login_login_access_token as AccessToken } from "../../client/models/Body_login_login_access_token"; +import Logo from "../assets/images/fastapi-logo.svg"; +import { LoginService } from "../client"; +import { Body_login_login_access_token as AccessToken } from "../client/models/Body_login_login_access_token"; const Login: React.FC = () => { -const [show, setShow] = useBoolean(); + const [show, setShow] = useBoolean(); const navigate = useNavigate(); const { register, handleSubmit } = useForm(); const onSubmit: SubmitHandler = async (data) => { @@ -62,7 +62,7 @@ const [show, setShow] = useBoolean(); - diff --git a/src/new-frontend/src/pages/NotFound.tsx b/src/new-frontend/src/pages/NotFound.tsx deleted file mode 100644 index b6f5dee4e..000000000 --- a/src/new-frontend/src/pages/NotFound.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { Button, Container, Text } from "@chakra-ui/react"; - -import { Link } from "react-router-dom"; - -const NotFound = () => ( - <> - - 404 - Houston, we have a problem. - It looks like the page you're looking for doesn't exist. - - - -); - -export default NotFound; diff --git a/src/new-frontend/src/pages/RecoverPassword.tsx b/src/new-frontend/src/pages/RecoverPassword.tsx new file mode 100644 index 000000000..4de1aba19 --- /dev/null +++ b/src/new-frontend/src/pages/RecoverPassword.tsx @@ -0,0 +1,63 @@ +import React from "react"; + +import { Button, Container, FormControl, Heading, Input, Text, useToast } from "@chakra-ui/react"; +import { SubmitHandler, useForm } from "react-hook-form"; + +import { LoginService } from "../client"; + +interface FormData { + email: string; +} + +const RecoverPassword: React.FC = () => { + const { register, handleSubmit } = useForm(); + const toast = useToast(); + + const onSubmit: SubmitHandler = async (data) => { + const response = await LoginService.recoverPassword({ + email: data.email, + }); + console.log(response); + + toast({ + title: "Email sent.", + description: "We sent an email with a link to get back into your account.", + status: "success", + isClosable: true, + }); + }; + + return ( + + + Password Recovery + + + + A password recovery email will be sent to the registered account. + + + + + + ); +}; + +export default RecoverPassword; diff --git a/src/new-frontend/src/pages/Root.tsx b/src/new-frontend/src/pages/Root.tsx new file mode 100644 index 000000000..3ebcd9ddc --- /dev/null +++ b/src/new-frontend/src/pages/Root.tsx @@ -0,0 +1,42 @@ +import { useEffect } from 'react'; + +import { Outlet } from 'react-router-dom'; +import Sidebar from '../components/Sidebar'; + +import { Flex, useToast } from '@chakra-ui/react'; +import { useUserStore } from '../store/user-store'; +import UserMenu from '../components/UserMenu'; + +const Root: React.FC = () => { + const toast = useToast(); + const { getUser } = useUserStore(); + + useEffect(() => { + const fetchUser = async () => { + const token = localStorage.getItem('access_token'); + if (token) { + try { + await getUser(); + } catch (err) { + toast({ + title: 'Something went wrong.', + description: 'Failed to fetch user. Please try again.', + status: 'error', + isClosable: true, + }); + } + } + } + fetchUser(); + }, []); + + return ( + + + + + + ); +}; + +export default Root; \ No newline at end of file diff --git a/src/new-frontend/src/pages/main/Profile.tsx b/src/new-frontend/src/pages/UserSettings.tsx similarity index 92% rename from src/new-frontend/src/pages/main/Profile.tsx rename to src/new-frontend/src/pages/UserSettings.tsx index 4ef140f86..a8156a459 100644 --- a/src/new-frontend/src/pages/main/Profile.tsx +++ b/src/new-frontend/src/pages/UserSettings.tsx @@ -9,7 +9,7 @@ import UserInformation from '../panels/UserInformation'; -const Profile: React.FC = () => { +const UserSettings: React.FC = () => { return ( <> @@ -19,7 +19,7 @@ const Profile: React.FC = () => { - Profile + My profile Password Appearance Danger zone @@ -45,5 +45,5 @@ const Profile: React.FC = () => { ); }; -export default Profile; +export default UserSettings; diff --git a/src/new-frontend/src/pages/main/Dashboard.tsx b/src/new-frontend/src/pages/main/Dashboard.tsx deleted file mode 100644 index 3c616a703..000000000 --- a/src/new-frontend/src/pages/main/Dashboard.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; - -import { Box, Text } from '@chakra-ui/react'; - -import { useUserStore } from '../../store/user-store'; - - -const Dashboard: React.FC = () => { - const { user } = useUserStore(); - - return ( - <> - {user ? ( - - Hi, {user.full_name || user.email} 👋🏼 - Welcome back, nice to see you again! - - ) : null} - - - ) -} - -export default Dashboard; \ No newline at end of file diff --git a/src/new-frontend/src/pages/panels/Appearance.tsx b/src/new-frontend/src/panels/Appearance.tsx similarity index 89% rename from src/new-frontend/src/pages/panels/Appearance.tsx rename to src/new-frontend/src/panels/Appearance.tsx index af16abf6b..71caee624 100644 --- a/src/new-frontend/src/pages/panels/Appearance.tsx +++ b/src/new-frontend/src/panels/Appearance.tsx @@ -24,7 +24,7 @@ const Appearance: React.FC = () => { - + ); diff --git a/src/new-frontend/src/pages/panels/ChangePassword.tsx b/src/new-frontend/src/panels/ChangePassword.tsx similarity index 90% rename from src/new-frontend/src/pages/panels/ChangePassword.tsx rename to src/new-frontend/src/panels/ChangePassword.tsx index f7437bf54..1f1f056a2 100644 --- a/src/new-frontend/src/pages/panels/ChangePassword.tsx +++ b/src/new-frontend/src/panels/ChangePassword.tsx @@ -23,7 +23,7 @@ const ChangePassword: React.FC = () => { Confirm new password - diff --git a/src/new-frontend/src/pages/panels/DeleteAccount.tsx b/src/new-frontend/src/panels/DeleteAccount.tsx similarity index 82% rename from src/new-frontend/src/pages/panels/DeleteAccount.tsx rename to src/new-frontend/src/panels/DeleteAccount.tsx index 1616b1d98..793605ccf 100644 --- a/src/new-frontend/src/pages/panels/DeleteAccount.tsx +++ b/src/new-frontend/src/panels/DeleteAccount.tsx @@ -13,7 +13,7 @@ const DeleteAccount: React.FC = () => { Are you sure you want to delete your account? This action cannot be undone. - diff --git a/src/new-frontend/src/pages/panels/UserInformation.tsx b/src/new-frontend/src/panels/UserInformation.tsx similarity index 88% rename from src/new-frontend/src/pages/panels/UserInformation.tsx rename to src/new-frontend/src/panels/UserInformation.tsx index f7673ed00..13f6ba24f 100644 --- a/src/new-frontend/src/pages/panels/UserInformation.tsx +++ b/src/new-frontend/src/panels/UserInformation.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { Button, Container, FormControl, FormLabel, Heading, Input, Text } from '@chakra-ui/react'; -import { useUserStore } from '../../store/user-store'; +import { useUserStore } from '../store/user-store'; const UserInformation: React.FC = () => { const [editMode, setEditMode] = useState(false); @@ -39,7 +39,7 @@ const UserInformation: React.FC = () => { } - diff --git a/src/new-frontend/src/theme.tsx b/src/new-frontend/src/theme.tsx new file mode 100644 index 000000000..cc62ba12e --- /dev/null +++ b/src/new-frontend/src/theme.tsx @@ -0,0 +1,37 @@ +import { extendTheme } from "@chakra-ui/react" + +const theme = extendTheme({ + colors: { + ui: { + main: "#009688", + secondary: "#EDF2F7", + success: '#48BB78', + danger: '#E53E3E', + focus: 'red', + } + }, + components: { + Tabs: { + variants: { + enclosed: { + tab: { + _selected: { + color: 'ui.main', + }, + }, + }, + }, + }, + Input: { + baseStyle: { + field: { + _focus: { + borderColor: 'ui.focus', + }, + }, + }, + }, + }, +}); + +export default theme; \ No newline at end of file