diff --git a/src/new-frontend/src/App.css b/src/new-frontend/src/App.css
deleted file mode 100644
index b9d355df2a..0000000000
--- 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 e9d621683b..0000000000
--- 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 (
- <>
-
-
-
- } />
- } />
- }>
- } />
- } />
- } />
- } />
-
- } />
-
- ChakraProvider>
-
- >
- )
-}
-
-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 57d9eec137..0000000000
Binary files a/src/new-frontend/src/assets/images/fastapi-logo.png and /dev/null differ
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 0000000000..d3dad4bec8
--- /dev/null
+++ b/src/new-frontend/src/assets/images/fastapi-logo.svg
@@ -0,0 +1,51 @@
+
+
diff --git a/src/new-frontend/src/assets/images/favicon.png b/src/new-frontend/src/assets/images/favicon.png
index b3dcdd3090..e5b7c3ada7 100644
Binary files a/src/new-frontend/src/assets/images/favicon.png and b/src/new-frontend/src/assets/images/favicon.png differ
diff --git a/src/new-frontend/src/components/ActionsMenu.tsx b/src/new-frontend/src/components/ActionsMenu.tsx
index 1d14c47b30..ea7d8bd25b 100644
--- a/src/new-frontend/src/components/ActionsMenu.tsx
+++ b/src/new-frontend/src/components/ActionsMenu.tsx
@@ -4,9 +4,9 @@ import { Button, Menu, MenuButton, MenuItem, MenuList, useDisclosure } from '@ch
import { BsThreeDotsVertical } from 'react-icons/bs';
import { FiTrash, FiEdit } from 'react-icons/fi';
-import Delete from '../pages/modals/DeleteAlert';
-import EditUser from '../pages/modals/EditUser';
-import EditItem from '../pages/modals/EditItem';
+import Delete from '../modals/DeleteAlert';
+import EditUser from '../modals/EditUser';
+import EditItem from '../modals/EditItem';
interface ActionsMenuProps {
type: string;
diff --git a/src/new-frontend/src/components/Navbar.tsx b/src/new-frontend/src/components/Navbar.tsx
index 1e347a9387..bc130f1f7d 100644
--- a/src/new-frontend/src/components/Navbar.tsx
+++ b/src/new-frontend/src/components/Navbar.tsx
@@ -1,28 +1,34 @@
import React from 'react';
-import { Button, Flex, Icon, useDisclosure } from '@chakra-ui/react';
-import { FaPlus } from "react-icons/fa";
+import { Button, Flex, Icon, Input, InputGroup, InputLeftElement, useDisclosure } from '@chakra-ui/react';
+import { FaPlus, FaSearch } from "react-icons/fa";
-import CreateItem from '../pages/modals/CreateItem';
-import CreateUser from '../pages/modals/CreateUser';
+import AddUser from '../modals/AddUser';
+import AddItem from '../modals/AddItem';
interface NavbarProps {
type: string;
}
const Navbar: React.FC = ({ 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 d483a8c8e8..0d281520a6 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 = () => {
-
+
-
+
-
+ {
+ user?.email &&
+ Logged in as: {user.email}
+ }
@@ -33,12 +37,15 @@ const Sidebar: React.FC = () => {
{/* Desktop */}
-
+
-
+
-
+ {
+ 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 e0f9281369..2282aaa3f0 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 ddea6d002c..0000000000
--- 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 0000000000..224af6012e
--- /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 (
+ <>
+
+
+
+ >
+ );
+};
+
+export default UserMenu;
diff --git a/src/new-frontend/src/main.tsx b/src/new-frontend/src/main.tsx
index f9ebbd94f0..146cbb5494 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 d3574353a0..c7967019cc 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 }) => {
-
+
Save
@@ -86,4 +86,4 @@ const CreateItem: React.FC = ({ isOpen, onClose }) => {
);
};
-export default CreateItem;
+export default AddItem;
diff --git a/src/new-frontend/src/pages/modals/CreateUser.tsx b/src/new-frontend/src/modals/AddUser.tsx
similarity index 81%
rename from src/new-frontend/src/pages/modals/CreateUser.tsx
rename to src/new-frontend/src/modals/AddUser.tsx
index 951f683438..33e38b21a8 100644
--- a/src/new-frontend/src/pages/modals/CreateUser.tsx
+++ b/src/new-frontend/src/modals/AddUser.tsx
@@ -1,43 +1,44 @@
import React, { useState } from 'react';
-import { Box, Button, Checkbox, Flex, FormControl, FormLabel, Input, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay, Spinner, useToast } from '@chakra-ui/react';
+import { Button, Checkbox, Flex, FormControl, FormLabel, Input, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay, useToast } from '@chakra-ui/react';
import { SubmitHandler, useForm } from 'react-hook-form';
-import { UserCreate } from '../../client';
-import { useUsersStore } from '../../store/users-store';
+import { UserCreate } from '../client';
+import { useUsersStore } from '../store/users-store';
-interface CreateUserProps {
+interface AddUserProps {
isOpen: boolean;
onClose: () => void;
}
-const CreateUser: React.FC = ({ isOpen, onClose }) => {
+const AddUser: React.FC = ({ isOpen, onClose }) => {
const toast = useToast();
const [isLoading, setIsLoading] = useState(false);
- const { register, handleSubmit } = useForm();
+ const { register, handleSubmit, reset } = useForm();
const { addUser } = useUsersStore();
const onSubmit: SubmitHandler = async (data) => {
+ setIsLoading(true);
try {
- setIsLoading(true);
await addUser(data);
- setIsLoading(false);
toast({
title: 'Success!',
description: 'User created successfully.',
status: 'success',
isClosable: true,
});
+ reset();
onClose();
} catch (err) {
- setIsLoading(false);
toast({
title: 'Something went wrong.',
description: 'Failed to create user. Please try again.',
status: 'error',
isClosable: true,
});
+ } finally {
+ setIsLoading(false);
}
}
@@ -52,7 +53,7 @@ const CreateUser: React.FC = ({ isOpen, onClose }) => {
{/* TODO: Check passwords */}
- Create User
+ Add User
@@ -69,7 +70,7 @@ const CreateUser: React.FC = ({ isOpen, onClose }) => {
Confirm Password
-
+
@@ -93,4 +94,4 @@ const CreateUser: React.FC = ({ isOpen, onClose }) => {
)
}
-export default CreateUser;
\ No newline at end of file
+export default AddUser;
\ No newline at end of file
diff --git a/src/new-frontend/src/pages/modals/DeleteAlert.tsx b/src/new-frontend/src/modals/DeleteAlert.tsx
similarity index 60%
rename from src/new-frontend/src/pages/modals/DeleteAlert.tsx
rename to src/new-frontend/src/modals/DeleteAlert.tsx
index 9524ff330e..665168cf9e 100644
--- a/src/new-frontend/src/pages/modals/DeleteAlert.tsx
+++ b/src/new-frontend/src/modals/DeleteAlert.tsx
@@ -1,33 +1,46 @@
import React, { useState } from 'react';
-import { AlertDialog, AlertDialogBody, AlertDialogContent, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, Button } from '@chakra-ui/react';
+import { AlertDialog, AlertDialogBody, AlertDialogContent, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, Button, useToast } from '@chakra-ui/react';
import { useForm } from 'react-hook-form';
-import { useItemsStore } from '../../store/items-store';
+import { useItemsStore } from '../store/items-store';
+import { useUsersStore } from '../store/users-store';
interface DeleteProps {
- toDelete: string;
+ type: string;
id: number
isOpen: boolean;
onClose: () => void;
}
-const Delete: React.FC = ({ toDelete, id, isOpen, onClose }) => {
+const Delete: React.FC = ({ type, id, isOpen, onClose }) => {
+ const toast = useToast();
const cancelRef = React.useRef(null);
const [isLoading, setIsLoading] = useState(false);
const { handleSubmit } = useForm();
const { deleteItem } = useItemsStore();
+ const { deleteUser } = useUsersStore();
const onSubmit = async () => {
+ setIsLoading(true);
try {
- setIsLoading(true);
- await deleteItem(id);
- setIsLoading(false);
+ type === 'Item' ? await deleteItem(id) : await deleteUser(id);
+ toast({
+ title: "Success",
+ description: `The ${type.toLowerCase()} was deleted successfully.`,
+ status: "success",
+ isClosable: true,
+ });
onClose();
} catch (err) {
+ toast({
+ title: "An error occurred.",
+ description: `An error occurred while deleting the ${type.toLowerCase()}.`,
+ status: "error",
+ isClosable: true,
+ });
+ } finally {
setIsLoading(false);
- console.error(err);
-
}
}
@@ -43,7 +56,7 @@ const Delete: React.FC = ({ toDelete, id, isOpen, onClose }) => {
- Delete {toDelete}
+ Delete {type}
@@ -51,7 +64,7 @@ const Delete: React.FC = ({ toDelete, id, isOpen, onClose }) => {
-
+
Delete
diff --git a/src/new-frontend/src/pages/modals/EditItem.tsx b/src/new-frontend/src/modals/EditItem.tsx
similarity index 90%
rename from src/new-frontend/src/pages/modals/EditItem.tsx
rename to src/new-frontend/src/modals/EditItem.tsx
index cbd001f43c..73753bf461 100644
--- a/src/new-frontend/src/pages/modals/EditItem.tsx
+++ b/src/new-frontend/src/modals/EditItem.tsx
@@ -24,12 +24,12 @@ const EditItem: React.FC = ({ isOpen, onClose }) => {
Item
-
+
Description
-
+
diff --git a/src/new-frontend/src/pages/modals/EditUser.tsx b/src/new-frontend/src/modals/EditUser.tsx
similarity index 86%
rename from src/new-frontend/src/pages/modals/EditUser.tsx
rename to src/new-frontend/src/modals/EditUser.tsx
index 0434fe589b..385d39f034 100644
--- a/src/new-frontend/src/pages/modals/EditUser.tsx
+++ b/src/new-frontend/src/modals/EditUser.tsx
@@ -24,16 +24,16 @@ const EditUser: React.FC = ({ isOpen, onClose }) => {
Email
-
+
Full name
-
+
- Set Password
-
+ Password
+
@@ -46,7 +46,7 @@ const EditUser: React.FC = ({ isOpen, onClose }) => {
-
+
Save
Cancel
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 70fd5eb88c..17b410fabb 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 0000000000..e0a5e07a5b
--- /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 0000000000..f8bd796ec2
--- /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}
+ Go back to Home
+
+ >
+ );
+}
+
+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 7e2a2fb314..bcf1c04dd6 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 bbf1087ce6..0000000000
--- 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 53e01ed224..b9e89803e2 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();
-
+
Log In
diff --git a/src/new-frontend/src/pages/NotFound.tsx b/src/new-frontend/src/pages/NotFound.tsx
deleted file mode 100644
index b6f5dee4eb..0000000000
--- 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.
- Go back to Home
-
- >
-);
-
-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 0000000000..4de1aba194
--- /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.
+
+
+
+
+ Continue
+
+
+ );
+};
+
+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 0000000000..3ebcd9ddcb
--- /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 4ef140f868..a8156a4592 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 3c616a7038..0000000000
--- 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 91%
rename from src/new-frontend/src/pages/panels/Appearance.tsx
rename to src/new-frontend/src/panels/Appearance.tsx
index af16abf6be..71caee6246 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 = () => {
- Save
+ Save
Container>
>
);
diff --git a/src/new-frontend/src/pages/panels/ChangePassword.tsx b/src/new-frontend/src/panels/ChangePassword.tsx
similarity index 92%
rename from src/new-frontend/src/pages/panels/ChangePassword.tsx
rename to src/new-frontend/src/panels/ChangePassword.tsx
index f7437bf54f..1f1f056a20 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
-
+
Save
diff --git a/src/new-frontend/src/pages/panels/DeleteAccount.tsx b/src/new-frontend/src/panels/DeleteAccount.tsx
similarity index 86%
rename from src/new-frontend/src/pages/panels/DeleteAccount.tsx
rename to src/new-frontend/src/panels/DeleteAccount.tsx
index 1616b1d984..793605ccf5 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.
-
+
Delete
Container>
diff --git a/src/new-frontend/src/pages/panels/UserInformation.tsx b/src/new-frontend/src/panels/UserInformation.tsx
similarity index 90%
rename from src/new-frontend/src/pages/panels/UserInformation.tsx
rename to src/new-frontend/src/panels/UserInformation.tsx
index f7673ed007..13f6ba24fb 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 = () => {
}
-
+
{editMode ? "Save" : "Edit"}
Container>
diff --git a/src/new-frontend/src/theme.tsx b/src/new-frontend/src/theme.tsx
new file mode 100644
index 0000000000..cc62ba12ec
--- /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