diff --git a/.env.development b/.env.development index 55315b6..e8066b5 100644 --- a/.env.development +++ b/.env.development @@ -1,2 +1,2 @@ -VITE_APP_NAME=App Development +# Config avaliable on development environment VITE_API_URL=http://localhost:7082 \ No newline at end of file diff --git a/.env.production b/.env.production index b61c784..1e9012e 100644 --- a/.env.production +++ b/.env.production @@ -1,2 +1,2 @@ -VITE_APP_NAME=App Production +# Config avaliable on production VITE_API_URL=http://192.168.179.36:7082 \ No newline at end of file diff --git a/README.md b/README.md index c38c468..9e709f5 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,12 @@ -# DaisyUI-React-Starter +# TailwindElements-React-Starter -[![Build Status](https://jenkins.bigoscloud.com/job/LuPa2/lastBuild/badge/icon)](https://jenkins.bigoscloud.com/job/LuPa2/lastBuild/) -Toolstack for my UI projects. I try to use `bun`. -> It was challenging stuff to configure, but now it works like a charm... I think. - - - -Used technologies: - -| Name | Description | -|--------|---| -| [TypeScript](https://www.typescriptlang.org/) | Main Language | -| [Vite](https://vitejs.dev/) | Bundler | -| [React](https://reactjs.org/) | Framework | -| [TailwindCSS](https://tailwindcss.com/) | CSS Framework | -| [PostCSS](https://postcss.org/) | CSS Processor | -| [DaisyUI](https://daisyui.com/) | A tool for transforming CSS with JavaScript | -| [RadixUI](https://www.radix-ui.com/) | Unstyled, accessible components for building high‑quality design systems and web apps in React | -| [Zod](https://zod.dev/) | TypeScript-first schema validation with static type inference | -| [React Router](https://reactrouter.com/) | Routing. Docs are lame, use [github](https://github.com/remix-run/react-router/tree/main) | -> Planned: [React Hook Form](https://react-hook-form.com/) Forms - -Linting, formatting and code editor: - -- [VSCode](https://code.visualstudio.com/) -- [ESlint](https://eslint.org/) -- [Prettier](https://prettier.io/) - -> Always up-to-date tools rather than stable old. -> It's not intended to be shared, but you can use it if you want. - -ToDo: -[ ] Add tests -[?] Add CI/CD -[?] Add SSR (Server Side Rendering) +- [Tailwind Elements](https://tw-elements.com/) - main styling +- [react-icons](https://react-icons.github.io/react-icons/) - big icon library +- [recharts](https://echarts.apache.org/) - charts library +- [wouter](https://github.com/molefrog/wouter) - router library +- [react-hook-form](https://github.com/react-hook-form/resolvers#zod) with [zod](https://zod.dev/) resolver - forms library +- [axios](https://axios-http.com/) - http request library +- [@tanstack/react-table](https://tanstack.com/table/v8/docs/adapters/react-table) - advanced table library ## Usage @@ -41,8 +14,6 @@ ToDo: 2. run: `bun run dev` 3. To build for production, run: `bun run build` -> Use for components styling and for components - ### Contact If you have any suggestions/opinions, please let me know in issues @@ -50,3 +21,5 @@ If you have any suggestions/opinions, please let me know in issues #### Dev notes [notes](docs/notes.md) + +> UI inspiration: diff --git a/bun.lockb b/bun.lockb index d8780bd..d0a65d1 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 6339e66..65b30a7 100644 --- a/package.json +++ b/package.json @@ -12,15 +12,14 @@ "dependencies": { "@hookform/resolvers": "^3.3.2", "@tanstack/react-table": "^8.10.7", - "@types/react-router-dom": "^5.3.3", "axios": "^1.6.0", + "echarts": "^5.4.3", "react": "^18.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.47.0", - "react-router-dom": "^6.17.0", - "recharts": "^2.9.2", "tw-elements": "^1.0.0", "uuid": "^9.0.1", + "wouter": "^2.12.1", "zod": "^3.22.4" }, "devDependencies": { diff --git a/src/components/Breadcrumbs.tsx b/src/components/Breadcrumbs.tsx deleted file mode 100644 index 29a993f..0000000 --- a/src/components/Breadcrumbs.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { Link, useLocation, useParams } from "react-router-dom"; -import { findElementInFlatRoutes } from "../utils/RoutingTableUtils"; -import { capitalizeFirstLetter } from "../utils/StringTransformationUtils"; - -const BREADCRUMB_BAR_CLASSES = - "text-sm breadcrumbs max-w pl-6 shadow-neutral-focus shadow-sm sticky top-2 z-10 bg-neutral transition-all rounded-md m-2 w-auto"; - -const Breadcrumbs = () => { - const location = useLocation(); - const pathnames = location.pathname.split("/").filter((x) => x); - const pathParams = useParams(); - - const hideBreadcrumbBar = (path: string) => { - // if (Object.keys(pathParams).length !== 0) return true; - const _route = findElementInFlatRoutes(path); - return _route?.disableBreadcrumbBar || false; - }; - - const findRouteNameByPath = (path: string) => { - const _route = findElementInFlatRoutes(path); - return _route?.name || path; - }; - - const renderLinkBreadcrumb = ( - value: string, - index: number, - pathnames: string[], - ) => { - if (value === pathParams.id) return null; - const to = `/${pathnames.slice(0, index + 1).join("/")}`; - const routeName = capitalizeFirstLetter(findRouteNameByPath(value)); - return ( -
  • - {routeName} -
  • - ); - }; - - const renderTextBreadcrumb = (value: string) => { - if (value === pathParams.id) return null; - const routeName = capitalizeFirstLetter(findRouteNameByPath(value)); - return ( -
  • - {routeName} -
  • - ); - }; - - if (hideBreadcrumbBar(location.pathname)) { - return ( -
    {pathnames[0].toUpperCase()}
    - ); - } - - return ( -
    -
      -
    • - Home -
    • - {pathnames.map((value, index) => { - const isLast = index === pathnames.length - 1; - return isLast - ? renderTextBreadcrumb(value) - : renderLinkBreadcrumb(value, index, pathnames); - })} -
    -
    - ); -}; - -export default Breadcrumbs; diff --git a/src/components/Card.tsx b/src/components/Card.tsx deleted file mode 100644 index 8eb8223..0000000 --- a/src/components/Card.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { Link } from "react-router-dom"; - -interface CardProps { - title: string; - description: string; - bgImage?: string; - link: string; -} -/** - * Card component - * @param {string} title - Card title - * @param {string} description - Card description - * @param {string} bgImage - Background image - * @param {string} link - Link to open on button click - */ -export function Card({ title, description, bgImage, link }: CardProps) { - return ( -
    - {!!bgImage && ( -
    - {title -
    - )} -
    -

    {title}

    -

    {description}

    -
    - - Go - -
    -
    -
    - ); -} diff --git a/src/components/CardGrid.tsx b/src/components/CardGrid.tsx deleted file mode 100644 index 9956d7a..0000000 --- a/src/components/CardGrid.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { ReactNode } from "react"; - -const CardGrid = ({ children }: { children: ReactNode }) => { - return ( -
    -
    - {children} -
    -
    - ); -}; - -export default CardGrid; diff --git a/src/components/ConfirmationDialog/ConfirmationDialog.tsx b/src/components/ConfirmationDialog/ConfirmationDialog.tsx deleted file mode 100644 index 2afad34..0000000 --- a/src/components/ConfirmationDialog/ConfirmationDialog.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import Modal from "../Modal"; -import useConfirmationDialog from "./useConfirmationDialog"; - -/** - * @description ConfirmationDialog component displays a confirmation dialog/modal with a message and two buttons: Yes and No. - * Actions of buttons are definded via hook. - * State of dialog is based on react context. - * @returns ConfirmationDialog component - */ -const ConfirmationDialog = () => { - const { - isConfirmationDialogVisible, - handleConfirm, - handleCancel, - customModalBoxStyles, - customModalStyles, - } = useConfirmationDialog(); - - return ( - <> - {isConfirmationDialogVisible && ( - - - - - )} - - ); -}; - -export default ConfirmationDialog; diff --git a/src/components/ConfirmationDialog/ConfirmationDialogProvider.tsx b/src/components/ConfirmationDialog/ConfirmationDialogProvider.tsx deleted file mode 100644 index 7b76f23..0000000 --- a/src/components/ConfirmationDialog/ConfirmationDialogProvider.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { useState } from "react"; -import { ConfirmationDialogContext } from "../../contexts/ConfirmationDialogContext"; - -export const ConfirmationDialogProvider = ({ - children, -}: { - children: React.ReactNode; -}) => { - const [isConfirmationDialogVisible, setIsConfirmationDialogVisible] = - useState(false); - const [customModalBoxStyles, setCustomModalBoxStyles] = useState(""); - const [customModalStyles, setCustomModalStyles] = useState(""); - - const showDialog = () => { - setIsConfirmationDialogVisible(true); - }; - - const hideDialog = () => { - setIsConfirmationDialogVisible(false); - }; - - const handleConfirm = () => { - // Logic for when the user confirms - // You can call external functions or dispatch actions here - hideDialog(); - }; - - const handleCancel = () => { - // Logic for when the user cancels - hideDialog(); - }; - - return ( - - {children} - - ); -}; - -export default ConfirmationDialogProvider; diff --git a/src/components/ConfirmationDialog/useConfirmationDialog.ts b/src/components/ConfirmationDialog/useConfirmationDialog.ts deleted file mode 100644 index 4363baf..0000000 --- a/src/components/ConfirmationDialog/useConfirmationDialog.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { useContext } from "react"; -import { - ConfirmationDialogContext, - ConfirmationDialogContextType, -} from "../../contexts/ConfirmationDialogContext"; - -/** - * @description Hook to manage the confirmation dialog, only passes the controls to specyfic dialog component - * @param onConfirm Function to be called when the user confirms the action - * @param onCancel Function to be called when the user cancels the action - * @returns Hook controls - */ -export const useConfirmationDialog = (): ConfirmationDialogContextType => { - const context = useContext(ConfirmationDialogContext); - if (!context) { - throw new Error( - "useConfirmationDialog must be used within a ConfirmationDialogProvider", - ); - } - return context; -}; - -export default useConfirmationDialog; diff --git a/src/components/Loader.tsx b/src/components/Loader.tsx deleted file mode 100644 index aed735a..0000000 --- a/src/components/Loader.tsx +++ /dev/null @@ -1,17 +0,0 @@ -function Loader() { - return ( - - ); -} - -export default Loader; diff --git a/src/components/Modal.tsx b/src/components/Modal.tsx deleted file mode 100644 index 7802a2a..0000000 --- a/src/components/Modal.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import { useCallback, useEffect } from "react"; -import { useNavigate } from "react-router-dom"; -import useConfirmationDialog from "./ConfirmationDialog/useConfirmationDialog"; -import { Cross1Icon } from "@radix-ui/react-icons"; - -interface ModalProps { - modalId: string; - title?: string; - subTitle?: string; - content?: string; - navigatePathOnClose?: string; - children?: React.ReactNode; - customModalStyles?: string; - customModalBoxStyles?: string; -} -/** - * @description A modal component that can be used to display a fairly custom modal/dialog - * @param modalId The id of the modal - * @param title The title of the modal - * @param subTitle The subtitle of the modal - * @param content The content of the modal - * @param navigatePathOnClose The path to navigate to when the modal is closed - * @param children The children of the modal - * @param customModalStyles Custom styles for the modal - * @param customModalBoxStyles Custom styles for the modal box - * @returns A modal component - */ -export const Modal = ({ - modalId, - navigatePathOnClose, - title, - subTitle, - content, - children, - customModalStyles, - customModalBoxStyles, -}: ModalProps) => { - const navigate = useNavigate(); - const { isConfirmationDialogVisible, hideDialog } = useConfirmationDialog(); - - const handleClose = useCallback(() => { - if (navigatePathOnClose) navigate(navigatePathOnClose); - if (isConfirmationDialogVisible) - (document.getElementById(modalId) as HTMLDialogElement).close(); - hideDialog(); - }, [ - hideDialog, - isConfirmationDialogVisible, - modalId, - navigate, - navigatePathOnClose, - ]); - - const handleKeyPress = useCallback( - (event: KeyboardEvent) => { - if (event.key === "Escape") { - handleClose(); - } - }, - [handleClose], - ); - // Handle modal open - useEffect(() => { - if (!modalId) return; - (document.getElementById(modalId) as HTMLDialogElement).showModal(); - document.addEventListener("keydown", handleKeyPress); - // Handle modal close - return () => { - document.removeEventListener("keydown", handleKeyPress); - handleClose; - }; - }, [handleClose, handleKeyPress, modalId]); - - const composeModalStyles = useCallback(() => { - const _baseStyles = "modal modal-bottom sm:modal-middle w-screen z-50"; - if (customModalStyles) return _baseStyles + " " + customModalStyles; - return _baseStyles; - }, [customModalStyles]); - const comopseModalBoxStyles = useCallback(() => { - const _baseStyles = "modal-box"; - if (customModalBoxStyles) return _baseStyles + " " + customModalBoxStyles; - return _baseStyles; - }, [customModalBoxStyles]); - - return ( - -
    -

    {title ?? "Hello!"}

    -

    - {subTitle ?? "Press ESC key or click the button below to close"} -

    -

    {content}

    -
    -
    - - {children} -
    -
    -
    -
    - ); -}; - -export default Modal; diff --git a/src/components/NavigationTree.tsx b/src/components/NavigationTree.tsx deleted file mode 100644 index 89d45ce..0000000 --- a/src/components/NavigationTree.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import { CustomRouteObject } from "../configure"; -import { Link, useLocation } from "react-router-dom"; -import { - clearMultiplePathSlashes, - trimPathOfParameters, -} from "../utils/StringTransformationUtils"; - -/** - * @returns Navigation tree elements, require to be used like in example below - * @example - * ```tsx - *
      - * - *
    - * ``` - */ -function NavigationTree(props: { - routes: CustomRouteObject[]; -}): React.JSX.Element { - const locationHook = useLocation(); // Used to highlight active link in navigation tree - - const GenerateNavigationEntries = ( - routes: CustomRouteObject[], - parentPath?: string, - ): React.ReactNode => { - return ( - routes.map((route) => { - // Prepare path for links - let combinedPath = undefined; - if (parentPath !== undefined && route.path !== undefined) - combinedPath = trimPathOfParameters( - clearMultiplePathSlashes(`/${parentPath}/${route.path}`), - ); - else combinedPath = route.path; - // Does it have children and enabled? Make entry with `/{parent.path}/{route.path}` - if (route.children && !route.additionalProps.disableInNavbar) { - return ( -
      -
    • - - {route.additionalProps.name} - - {route.children ? ( -
        {GenerateNavigationEntries(route.children, combinedPath)}
      - ) : null} -
    • -
    - ); - } - // Does it have children and not visible? Skip this entry and call this function for children passing path. - else if (route.children && route.additionalProps.disableInNavbar) { - return GenerateNavigationEntries(route.children, combinedPath); - } else if (route.additionalProps.disableInNavbar) { - return null; - } - // Make entry with `/{route.path}` - else { - return ( -
  • - - {route.additionalProps.name} - -
  • - ); - } - }) || <>empty navigation tree - ); - }; - - return
    {GenerateNavigationEntries(props.routes)}
    ; -} - -export default NavigationTree; diff --git a/src/components/Notification/Notification.tsx b/src/components/Notification/Notification.tsx deleted file mode 100644 index d5048e5..0000000 --- a/src/components/Notification/Notification.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import { useEffect, useState } from "react"; -import { INotification, NotificationStatus } from "./NotificationType"; - -enum NotificationColorsClasses { - "info" = "alert alert-info", - "success" = "alert alert-success", - "warning" = "alert alert-warning", - "error" = "alert alert-error", -} - -const selectIcon = (status: NotificationStatus) => { - switch (status) { - case "error": - return ( - - - - ); - case "success": - return ( - - - - ); - break; - case "info": - return ( - - - - ); - break; - case "warning": - return ( - - - - ); - break; - default: - return null; - break; - } -}; - -interface NotificationProps { - notification: INotification; - removeNotification: (id: number) => void; -} - -function Notification({ notification, removeNotification }: NotificationProps) { - const [counter, setCounter] = useState( - notification.duration, - ); - const isCloseable = !!!notification.duration; - - useEffect(() => { - // Skip if counter is undefined - if (counter === undefined) return; - const intervalId = setInterval(() => { - setCounter(counter - 1); - if (counter === 0) { - removeNotification(notification.id); - } - }, 1000); - return () => { - clearInterval(intervalId); - }; - }, [counter]); - return ( -
    - {selectIcon(notification.status)} - {notification.message} - {isCloseable ? ( - - ) : null} - {isCloseable ? null : ( -
    - - - -
    - )} -
    - ); -} - -export default Notification; diff --git a/src/components/Notification/NotificationProvider.tsx b/src/components/Notification/NotificationProvider.tsx deleted file mode 100644 index c48ee17..0000000 --- a/src/components/Notification/NotificationProvider.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React, { useState } from "react"; -import { INotification } from "./NotificationType"; - -interface INotificationStore { - notifications: INotification[] | []; - setNotifications: React.Dispatch>; - duration?: number; -} -// Store for notifications -export const NotificationContext = React.createContext({ - notifications: [], - setNotifications: () => {}, - duration: undefined, -}); - -// Just store for notifications, logic is in useNotification hook -export const NotificationProvider: React.FC<{ children: React.ReactNode }> = ({ - children, -}) => { - // Queue for notifications - const [notifications, setNotifications] = useState | []>( - [], - ); - NotificationContext.displayName = "Notifications"; - return ( - - {children} - - ); -}; - -export default NotificationProvider; diff --git a/src/components/Notification/NotificationStack.tsx b/src/components/Notification/NotificationStack.tsx deleted file mode 100644 index cf0e9c6..0000000 --- a/src/components/Notification/NotificationStack.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import Notification from "./Notification"; -import { useNotification } from "./useNotification"; -// ----------------------------------------------------------- -// Component that renders notification stack -// ----------------------------------------------------------- -function NotificationStack() { - const { notifications, removeNotification } = useNotification(); - - // It takes notification array from hook and renders it - const renderNotifications = () => { - return notifications.map((notification) => { - return ( - - ); - }); - }; - - return
    {renderNotifications()}
    ; -} - -export default NotificationStack; diff --git a/src/components/Notification/NotificationType.ts b/src/components/Notification/NotificationType.ts deleted file mode 100644 index 4064dcf..0000000 --- a/src/components/Notification/NotificationType.ts +++ /dev/null @@ -1,9 +0,0 @@ -export type NotificationStatus = "success" | "error" | "warning" | "info"; -export interface INotificationBase { - message: string; - status: NotificationStatus; - duration?: number; -} -export interface INotification extends INotificationBase { - id: number; -} diff --git a/src/components/Notification/README.md b/src/components/Notification/README.md deleted file mode 100644 index 5fefc38..0000000 --- a/src/components/Notification/README.md +++ /dev/null @@ -1,2 +0,0 @@ - # Notification - I wrote own notification module but its little bit laggy and buggy so I don't use it. diff --git a/src/components/Notification/useNotification.ts b/src/components/Notification/useNotification.ts deleted file mode 100644 index 8d1ee63..0000000 --- a/src/components/Notification/useNotification.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { useContext } from "react"; -import { NotificationContext } from "./NotificationProvider"; -import { INotification, NotificationStatus } from "./NotificationType"; -// ----------------------------------------------------------- -// Hook for adding notifications to the queue in local storage -// ----------------------------------------------------------- -export function useNotification() { - const { notifications, setNotifications } = useContext(NotificationContext); - - const addNotificationToQueue = ( - message: string, - status: NotificationStatus, - duration?: number, - ) => { - const id = notifications.length + 1; - const notification: INotification = { id, message, status, duration }; - setNotifications([...notifications, notification]); - }; - const removeNotificationFromQueue = (id: number) => { - setNotifications( - notifications.filter((notification) => notification.id !== id), - ); - }; - const clearNotificationsQueue = () => { - setNotifications([]); - }; - - return { - notifications: notifications, - addNotification: addNotificationToQueue, - removeNotification: removeNotificationFromQueue, - clearNotifications: clearNotificationsQueue, - }; -} diff --git a/src/configure.tsx b/src/configure.tsx index 5edc7fd..843d440 100644 --- a/src/configure.tsx +++ b/src/configure.tsx @@ -1,124 +1,4 @@ -/* eslint-disable react-refresh/only-export-components */ -import { Suspense, lazy } from "react"; -import { RouteObject } from "react-router-dom"; -import Loader from "./components/Loader"; -import AboutPage from "./features/About/AboutPage"; -import App from "./features/App"; -import LoginPage from "./features/Login/LoginPage"; -import { flatternRoutingTable } from "./utils/RoutingTableUtils"; -import Debugger from "./features/Debugger"; -//---- -const HomePageLazy = lazy(() => import("./features/Home/HomePage")); - export const viteEnv = import.meta.env; - -// Based on https://reactrouter.com/en/main/start/overview#nested-routes with additional props -export const navigation: CustomRouteObject[] = [ - // root page, mainframe for all pages, skipped in navigation tree generation (inly childs are used) - { - path: "/", - element: , - additionalProps: { - name: "Root", // used for breadcrumbs and navigation tree - disableRedirect: false, //entry will not be included in the react-router redirect list, will cut out childs - disableInNavbar: true, //entry will not be rendered in the navbar - disableBreadcrumbBar: false, //entry will be directly under root in routing table - }, - children: [ - // home page - { - path: "/", - index: true, //if true will be used as a default route for parent, dont declare path if use this - element: ( - }> - - - ), - additionalProps: { - name: "Home", - disableRedirect: false, - disableInNavbar: false, - disableBreadcrumbBar: false, - }, - }, - // about page - { - path: "about", - element: , - additionalProps: { - name: "About", - disableRedirect: false, - disableInNavbar: false, - disableBreadcrumbBar: false, - }, - children: [ - { - path: "child", - element:
    DUPA CHILD
    , - additionalProps: { - name: "About Child", - disableRedirect: false, - disableInNavbar: false, - disableBreadcrumbBar: false, - }, - }, - ], - }, - // login page - { - path: "login", - element: , - additionalProps: { - name: "Login", - disableRedirect: false, - disableInNavbar: false, - disableBreadcrumbBar: false, - }, - }, - ], - }, -]; -// --- - -if (viteEnv.DEV) { - // Add Test page - // Test page is outside of mainframe, will be rendered in root (withius App where is entire navigation frame) - navigation.push({ - path: "/Test", - element:
    Test
    , - additionalProps: { - name: "Test", - disableRedirect: false, - disableInNavbar: false, - disableBreadcrumbBar: false, - }, - }); - // Add debugger page - navigation[0].children?.push({ - path: "debug_variables", - element: , - additionalProps: { - name: "Debug Variables", - disableRedirect: false, - disableInNavbar: false, - disableBreadcrumbBar: false, - }, - }); -} - -// --- -//Custom Route Object for handling custom behaviours on app navigation -export interface RouteObjectAdditionalProps { - name: string; - disableRedirect: boolean; - disableInNavbar: boolean; - disableBreadcrumbBar: boolean; -} -export interface CustomRouteObject extends Omit { - additionalProps: RouteObjectAdditionalProps; - children?: CustomRouteObject[]; -} -//---- //Main configuration, static data, mostly used here export const main = { program_name: viteEnv.VITE_APP_NAME, @@ -129,5 +9,3 @@ export const about = { program_description: `This is a ${main.program_name} for .`, program_authors: [{ name: "Author Name", email: "email@example.com" }], }; -//---- -export const flatRoutes = flatternRoutingTable(navigation); diff --git a/src/contexts/ConfirmationDialogContext.tsx b/src/contexts/ConfirmationDialogContext.tsx deleted file mode 100644 index 5bdbb68..0000000 --- a/src/contexts/ConfirmationDialogContext.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { createContext } from "react"; - -// Define the shape of the context -export type ConfirmationDialogContextType = { - isConfirmationDialogVisible: boolean; - showDialog: () => void; - hideDialog: () => void; - handleConfirm: () => void; - handleCancel: () => void; - customModalStyles: string; - customModalBoxStyles: string; - setCustomModalBoxStyles: React.Dispatch>; - setCustomModalStyles: React.Dispatch>; -}; -// Create the context with default values -export const ConfirmationDialogContext = createContext< - ConfirmationDialogContextType | undefined ->(undefined); -ConfirmationDialogContext.displayName = "ConfirmationDialog"; diff --git a/src/features/About/AboutPage.tsx b/src/features/About/AboutPage.tsx deleted file mode 100644 index 5ecd399..0000000 --- a/src/features/About/AboutPage.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { about } from "../../configure"; - -/** Here is located about page where you can find information about this application: - * - short description of this application - * - how to use it - * - information about persons responsible for maintaining this application - */ -function AboutPage() { - return ( -
    -
    -
    -

    About

    -

    {about.program_description}

    -

    Authors

    -
    - {about.program_authors.map((author) => ( -
    - {author.name} -{" "} - - {author.email} - -
    - ))} -
    -
    -
    -
    - ); -} - -export default AboutPage; diff --git a/src/features/App.tsx b/src/features/App.tsx index fc136c9..d4a7bb5 100644 --- a/src/features/App.tsx +++ b/src/features/App.tsx @@ -1,94 +1,15 @@ -import { HamburgerMenuIcon, SunIcon } from "@radix-ui/react-icons"; -import { useEffect, useState } from "react"; -import { Outlet } from "react-router-dom"; -import { main, navigation } from "../configure.tsx"; -import NavigationTree from "../components/NavigationTree.tsx"; -import Breadcrumbs from "../components/Breadcrumbs.tsx"; -import ConfirmationDialog from "../components/ConfirmationDialog/ConfirmationDialog.tsx"; +import { main } from "../configure"; +import Debugger from "./Debugger"; -/** Here is located global wrapper for entire application, here you canfind: - * - Drawer - contains navigation buttons - * - Navbar - contains hamburger menu and theme selector - * - Outlet - contains active page content - * - App theme controll - */ function App() { - const [theme, setTheme] = useState("adient"); - const [openDrawer, setOpenDrawer] = useState(false); - - useEffect(() => { - document.querySelector("html")?.setAttribute("data-theme", theme); - // To resolve this issue, you can use the import.meta.env object instead of process.env. The import.meta.env object is provided by Vite.js and allows you to access environment variables in your code. - document.title = import.meta.env.VITE_APP_NAME; - }, [theme, openDrawer]); - - // Function on click drawer hamburger button - const handleDrawerStatus = () => { - setOpenDrawer(!openDrawer); - }; - return (
    - - {/* Root drawer container */} - {/* Drawer opening is controlled directly via css prop and next via local useState variable */} -
    - {/* A hidden checkbox to toggle the visibility of the drawer */} - - {/* The actual drawer content */} -
    - {/* Navbar */} -
    - {/* Left side navbar */} -
    - -

    {main.program_name}

    -
    - {/* Right side navbar */} -
    -
    - -
      - THEMEs HERE -
    -
    - -
    -
    - {/* App/active_drawer content */} -
    - {/*Automatically generated breadcrumbs based on routing table from configuration file and active path*/} - {/*Get active route and find it in routing file*/} - - -
    -
    - {/* Drawer sidebar wrapper */} -
    - {/* Dark overlay on mobile devices, clickable to close drawer */} - -
      - -
    -
    -
    +

    App

    +

    App

    + +

    + {main.program_name} v{main.program_version} +

    ); } diff --git a/src/features/Debugger.tsx b/src/features/Debugger.tsx index 3388869..6c543c2 100644 --- a/src/features/Debugger.tsx +++ b/src/features/Debugger.tsx @@ -1,5 +1,4 @@ -import { useLocation } from "react-router-dom"; -import { flatRoutes } from "../configure"; +import { useLocation } from "wouter"; function Debugger() { const windowLocation = window.location.pathname; @@ -10,7 +9,6 @@ function Debugger() { Flat Routes - {JSON.stringify(flatRoutes)}
    Locations @@ -22,7 +20,6 @@ function Debugger() {
    Routes - {JSON.stringify(flatRoutes)}
    ); diff --git a/src/features/Home/HomePage.tsx b/src/features/Home/HomePage.tsx deleted file mode 100644 index 2d4d6bf..0000000 --- a/src/features/Home/HomePage.tsx +++ /dev/null @@ -1,5 +0,0 @@ -function HomePage() { - return <>HOME; -} - -export default HomePage; diff --git a/src/features/Login/LoginPage.tsx b/src/features/Login/LoginPage.tsx deleted file mode 100644 index 770d52b..0000000 --- a/src/features/Login/LoginPage.tsx +++ /dev/null @@ -1,102 +0,0 @@ -import { zodResolver } from "@hookform/resolvers/zod"; -import { useState } from "react"; -import { SubmitErrorHandler, SubmitHandler, useForm } from "react-hook-form"; -import { useNavigate } from "react-router-dom"; -import { z } from "zod"; - -type Input = { - username: string; - password: string; -}; -const InputSchema = z.object({ - username: z.string().min(4, "Username must be at least 4 characters"), - password: z - .string() - .regex(/[A-Za-z\d@$!%*#?&]{4,}/, "Minimum four characters") - .regex(/(?=.*[A-Z])/, "At least one big letter") - .regex(/(?=.*\d)/, "At least one number") - .regex(/(?=.*[@$!%*#?&])/, "At least one special character"), -}); - -function LoginPage() { - const [isSubmitting, setIsSubmitting] = useState(false); - const { - register, - handleSubmit, - formState: { errors }, - } = useForm({ - resolver: zodResolver(InputSchema), - }); - const navigate = useNavigate(); - const onSubmit: SubmitHandler = (data) => { - if (data.username === "admin" && data.password === "A0m!n") { - console.log("Login successful!", 3); - navigate("/products"); - } else { - console.log("Wrong username or password"); - } - setIsSubmitting(false); - }; - const onError: SubmitErrorHandler = () => { - console.log("Errors in form fields"); - }; - - return ( -
    -
    -
    -
    - - {errors.username && ( - - )} -
    -
    - - {errors.password && ( - - )} -
    - -
    -
    -
    - ); -} - -export default LoginPage; diff --git a/src/utils/Redirect.tsx b/src/utils/Redirect.tsx deleted file mode 100644 index 64a35d7..0000000 --- a/src/utils/Redirect.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { useEffect } from "react"; -import { useNavigate } from "react-router-dom"; - -/** - * @description Redirects to the given page - * @param {string} to - The page to redirect to - */ -function Redirect({ to }: { to: string }) { - // The navigate function from useNavigate is used to navigate to the given page - const navigate = useNavigate(); - // useEffect is used to navigate to the given page when the component mounts - useEffect(() => { - navigate(to); - }); - // A null element is returned because the component does not need to render anything - return null; -} -export default Redirect;