├── .github └── workflows │ └── main.yml ├── CHANGELOG.md ├── README.md ├── backend └── .gitkeep ├── docker-compose.yml ├── nginx └── nginx.conf └── ui-mantis ├── .env ├── .eslintrc ├── .gitignore ├── .prettierrc ├── Dockerfile ├── LICENSE ├── README.md ├── favicon.svg ├── index.html ├── jsconfig.json ├── package-lock.json ├── package.json ├── src ├── App.jsx ├── api │ └── menu.js ├── assets │ ├── images │ │ ├── auth │ │ │ └── AuthBackground.jsx │ │ ├── icons │ │ │ ├── facebook.svg │ │ │ ├── github.svg │ │ │ ├── google.svg │ │ │ └── twitter.svg │ │ └── users │ │ │ ├── avatar-1.png │ │ │ ├── avatar-2.png │ │ │ ├── avatar-3.png │ │ │ ├── avatar-4.png │ │ │ ├── avatar-5.png │ │ │ └── avatar-group.png │ └── third-party │ │ └── apex-chart.css ├── components │ ├── @extended │ │ ├── AnimateButton.jsx │ │ ├── Avatar.jsx │ │ ├── Breadcrumbs.jsx │ │ ├── Dot.jsx │ │ └── Transitions.jsx │ ├── Loadable.jsx │ ├── Loader.jsx │ ├── MainCard.jsx │ ├── ScrollTop.jsx │ ├── cards │ │ ├── AuthFooter.jsx │ │ └── statistics │ │ │ └── AnalyticEcommerce.jsx │ ├── logo │ │ ├── LogoMain.jsx │ │ └── index.jsx │ └── third-party │ │ └── SimpleBar.jsx ├── config.js ├── contexts │ ├── auth-reducer │ │ ├── actions.js │ │ └── auth.js │ └── authContext.jsx ├── index.jsx ├── layout │ ├── Dashboard │ │ ├── Drawer │ │ │ ├── DrawerContent │ │ │ │ ├── NavCard.jsx │ │ │ │ ├── Navigation │ │ │ │ │ ├── NavGroup.jsx │ │ │ │ │ ├── NavItem.jsx │ │ │ │ │ └── index.jsx │ │ │ │ └── index.jsx │ │ │ ├── DrawerHeader │ │ │ │ ├── DrawerHeaderStyled.js │ │ │ │ └── index.jsx │ │ │ ├── MiniDrawerStyled.js │ │ │ └── index.jsx │ │ ├── Header │ │ │ ├── AppBarStyled.jsx │ │ │ ├── HeaderContent │ │ │ │ ├── MobileSection.jsx │ │ │ │ ├── Notification.jsx │ │ │ │ ├── Profile │ │ │ │ │ ├── ProfileTab.jsx │ │ │ │ │ ├── SettingTab.jsx │ │ │ │ │ └── index.jsx │ │ │ │ ├── Search.jsx │ │ │ │ └── index.jsx │ │ │ └── index.jsx │ │ └── index.jsx │ └── MinimalLayout │ │ └── index.jsx ├── menu-items │ ├── dashboard.jsx │ ├── index.jsx │ ├── page.jsx │ ├── support.jsx │ ├── users.jsx │ └── utilities.jsx ├── pages │ ├── authentication │ │ ├── AuthCard.jsx │ │ ├── AuthWrapper.jsx │ │ ├── auth-forms │ │ │ ├── AuthLogin.jsx │ │ │ ├── AuthRegister.jsx │ │ │ └── FirebaseSocial.jsx │ │ ├── login.jsx │ │ └── register.jsx │ ├── component-overview │ │ ├── ComponentSkeleton.jsx │ │ ├── ComponentWrapper.js │ │ ├── color.jsx │ │ ├── shadows.jsx │ │ └── typography.jsx │ ├── dashboard │ │ ├── IncomeAreaChart.jsx │ │ ├── MonthlyBarChart.jsx │ │ ├── OrdersTable.jsx │ │ ├── ReportAreaChart.jsx │ │ ├── SaleReportCard.jsx │ │ ├── SalesChart.jsx │ │ ├── UniqueVisitorCard.jsx │ │ └── index.jsx │ ├── extra-pages │ │ └── sample-page.jsx │ └── users │ │ ├── Billing.jsx │ │ ├── Detail.jsx │ │ ├── EditProfile.jsx │ │ └── UserManagement.jsx ├── reportWebVitals.js ├── routes │ ├── LoginRoutes.jsx │ ├── MainRoutes.jsx │ └── index.jsx ├── themes │ ├── index.jsx │ ├── overrides │ │ ├── Badge.js │ │ ├── Button.js │ │ ├── CardContent.js │ │ ├── Checkbox.jsx │ │ ├── Chip.js │ │ ├── IconButton.js │ │ ├── InputLabel.js │ │ ├── LinearProgress.js │ │ ├── Link.js │ │ ├── ListItemIcon.jsx │ │ ├── OutlinedInput.js │ │ ├── Tab.js │ │ ├── TableCell.js │ │ ├── Tabs.js │ │ ├── Typography.js │ │ └── index.js │ ├── palette.js │ ├── shadows.jsx │ ├── theme │ │ └── index.js │ └── typography.js ├── utils │ ├── getColors.js │ ├── getShadow.js │ ├── password-strength.js │ └── password-validation.js └── vite-env.d.js ├── tsconfig.node.json ├── vite.config.mjs └── yarn.lock /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: JS - Main 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | deployment: 10 | runs-on: ubuntu-latest 11 | timeout-minutes: 120 12 | steps: 13 | - name: Execute remote SSH commands 14 | uses: appleboy/ssh-action@master 15 | timeout-minutes: 120 16 | with: 17 | host: ${{ secrets.HOST }} 18 | username: ${{ secrets.USER }} 19 | password: ${{ secrets.PASS }} 20 | port: ${{ secrets.PORT }} 21 | timeout: 120m 22 | command_timeout: 120m 23 | script: | 24 | cd ~/api-server-nestjs 25 | git fetch origin main 26 | if [ $(git rev-parse HEAD) != $(git rev-parse @{u}) ]; then 27 | git pull origin main 28 | export DOCKER_BUILDKIT=1 29 | docker compose up -d --build --no-deps --pull always && docker system prune -af 30 | else 31 | echo "No changes detected, skipping deployment." 32 | fi 33 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [0.0.2] 2024-12-15 4 | ### Changes 5 | 6 | - Added Backend 7 | - Added React UI (Mantis Design) 8 | 9 | ## [0.0.1] 2024-11-11 10 | ### Changes 11 | 12 | - REPO Created 13 | - Specs Added (RM) 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Django API Server 2 | 3 | Open-Source API server powered by [Django](https://app-generator.dev/docs/technologies/django/index.html), a progressive Node.js framework for building efficient, reliable, and scalable server-side applications. 4 | 5 | > Status: **Work in progress** 6 | 7 | - 👉 [Django API Server](#) - **Complete Documentation** 8 | - 👉 [Get Support](https://app-generator.dev/ticket/create/) via Email and Discord 9 | 10 |
11 | 12 | ## Features 13 | 14 | - **Best Practices**: Follows industry-standard best practices for building robust APIs. 15 | - **Backend**: Built with Django, a powerful and scalable Node.js framework. 16 | - **UI**: 17 | - React Mantis (optional frontend integration). 18 | 19 |
20 | 21 | ## Backend API 22 | 23 | - **Simple, modular & intuitive structure**: Easy to understand and extend. 24 | - **Toolchain**: 25 | - Usable with the latest Node.js LTS versions: 26 | - v22.x 27 | - v21.x 28 | - v20.x 29 | - Package Managers: 30 | - PNPM, 31 | - Yarn, 32 | - Npm 33 | - **Authentication**: Auth0 for GitHub integration. 34 | - GitHub email pulled during OAuth SignIN. 35 | - Optional: Email validation. 36 | - **Roles**: Admin, Users. 37 | - **ORM**: Prisma for database management. 38 | - **User Profiles**: 39 | - ROLE: Default user. 40 | - Fields: Name, surname, bio, country, address, job. 41 | - **API Features**: 42 | - Search, Pagination. 43 | - Public Access: GET by ID, get all. 44 | - Private access (requires token): 45 | - Create, Update, Delete. 46 | - **Admin**: 47 | - Can search or mutate any user. 48 | - **Users**: 49 | - Can view and mutate only their own information. 50 | 51 | ## Start with Docker 52 | 53 | @Todo 54 | 55 | ## Start Django Backend 56 | 57 | > Edit Environment 58 | 59 | Add a `.env` file to your project root directory and populate as follows: 60 | 61 | ```env 62 | AUTH0_DOMAIN=YOUR_AUTH0_DOMAIN 63 | AUTH0_CLIENT_ID=YOUR_AUTH0_CLIENT_ID 64 | AUTH0_CLIENT_SECRET=YOUR_AUTH0_CLIENT_SECRET 65 | 66 | JWT_SECRET=YOUR_JWT_SECRET 67 | 68 | DATABASE_URL=YOUR_DATABASE_URL 69 | ``` 70 | 71 | Here's how to get the required Auth0 details. You need to register a client (application) in your Auth0 dashboard. 72 | 73 | Follow these steps to register a client with Auth0: 74 | 75 | 1. Open the [Auth0 Applications](https://manage.auth0.com/?_gl=1*1a4zekg*_ga*Mjg3MzE5NzcyLjE3MzcwMjU4MzA.*_ga_QKMSDV5369*MTczNzIwMTkzNy45LjEuMTczNzIwMTk1Ni40MS4wLjA.#/applications) section of the Auth0 Dashboard. 76 | 2. Click on the **Create Application** button. 77 | 3. Provide a **Name**, such as "GitHub Auth". 78 | 4. Choose `Single Page Web Applications` as the application type. 79 | 5. Click on the **Create** button. 80 | 6. Finally, note down your `Domain`, `Client ID`, and `Client Secret` and add them to your `.env` file. Click the settings tab if you do not see them. 81 | 82 | Choose a random string of letters and numbers for your `JWT_SECRET` and populate the `DATABASE_URL` with your database connection string. 83 | 84 | > Install Dependencies 85 | 86 | Run the following to install dependencies: 87 | 88 | ```bash 89 | npm install 90 | ``` 91 | 92 | OR 93 | 94 | ```bash 95 | yarn 96 | ``` 97 | 98 | > Set Up Prisma 99 | 100 | 1. Run the following command to generate the Prisma client and apply migrations: 101 | 102 | ```bash 103 | npx prisma generate 104 | npx prisma migrate dev --name init 105 | ``` 106 | 107 | 2. If you need to seed your database, you can add a `seed` script in the `prisma/seed.ts` file and run: 108 | 109 | ```bash 110 | npx prisma db seed 111 | ``` 112 | 113 | > Run Your Server 114 | 115 | Start the Django server with: 116 | 117 | ```bash 118 | npm run start:dev 119 | ``` 120 | 121 | OR 122 | 123 | ```bash 124 | yarn start:dev 125 | ``` 126 | 127 | ## Compile [React UI](https://github.com/codedthemes/mantis-free-react-admin-template) 128 | 129 | > Edit Environment 130 | 131 | Add your server base URL to your environment variables as follows: 132 | 133 | ```env 134 | VITE_APP_PUBLIC_URL= 135 | ``` 136 | 137 | > Install Dependencies 138 | 139 | ```bash 140 | npm install 141 | ``` 142 | 143 | OR 144 | 145 | ```bash 146 | yarn 147 | ``` 148 | 149 | > Start the React UI 150 | 151 | ```bash 152 | npm run dev 153 | ``` 154 | 155 | OR 156 | 157 | ```bash 158 | yarn dev 159 | ``` 160 | 161 | --- 162 | Django API Starter provided by [App Generator](https://app-generator.dev/) - Open-source service for developers and companies. 163 | -------------------------------------------------------------------------------- /backend/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/app-generator/api-server-django/a6cc878ce93edd5e5cea0d5f4d7c39e22acffc8d/backend/.gitkeep -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | services: 2 | backend: 3 | build: ./backend 4 | container_name: backend 5 | ports: 6 | - "3000:3000" 7 | env_file: 8 | - ./backend/.env 9 | command: > 10 | sh -c " 11 | npx prisma generate 12 | npx prisma migrate deploy 13 | yarn start:dev 14 | " 15 | networks: 16 | - app-network 17 | 18 | frontend: 19 | build: ./ui-mantis 20 | container_name: frontend 21 | ports: 22 | - "4000:4000" 23 | env_file: 24 | - ./ui-mantis/.env 25 | networks: 26 | - app-network 27 | depends_on: 28 | - backend 29 | 30 | # nginx: 31 | # image: nginx:alpine 32 | # container_name: nginx 33 | # ports: 34 | # - "80:80" 35 | # volumes: 36 | # - ./nginx/nginx.conf:/etc/nginx/nginx.conf 37 | # depends_on: 38 | # - backend 39 | # - frontend 40 | # networks: 41 | # - app-network 42 | 43 | networks: 44 | app-network: 45 | driver: bridge 46 | -------------------------------------------------------------------------------- /nginx/nginx.conf: -------------------------------------------------------------------------------- 1 | events {} 2 | 3 | http { 4 | upstream backend { 5 | server backend:3000; 6 | } 7 | 8 | upstream frontend { 9 | server frontend:4000; 10 | } 11 | 12 | server { 13 | listen 80; 14 | 15 | location /api/ { 16 | proxy_pass http://backend; 17 | proxy_set_header Host $host; 18 | proxy_set_header X-Real-IP $remote_addr; 19 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 20 | proxy_set_header X-Forwarded-Proto $scheme; 21 | } 22 | 23 | location / { 24 | proxy_pass http://frontend; 25 | proxy_set_header Host $host; 26 | proxy_set_header X-Real-IP $remote_addr; 27 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 28 | proxy_set_header X-Forwarded-Proto $scheme; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /ui-mantis/.env: -------------------------------------------------------------------------------- 1 | VITE_APP_VERSION=v1.3.0 2 | GENERATE_SOURCEMAP=false 3 | 4 | ## Backend API URL 5 | VITE_APP_PUBLIC_URL = http://0.0.0.0:4000 6 | VITE_APP_BASE_NAME = /free 7 | -------------------------------------------------------------------------------- /ui-mantis/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "env": { 4 | "browser": true, 5 | "es2021": true 6 | }, 7 | "extends": [ 8 | "prettier", 9 | "plugin:react/jsx-runtime", 10 | "plugin:jsx-a11y/recommended", 11 | "plugin:react-hooks/recommended", 12 | "eslint:recommended", 13 | "plugin:react/recommended" 14 | ], 15 | "settings": { 16 | "react": { 17 | "createClass": "createReactClass", // Regex for Component Factory to use, 18 | // default to "createReactClass" 19 | "pragma": "React", // Pragma to use, default to "React" 20 | "fragment": "Fragment", // Fragment to use (may be a property of ), default to "Fragment" 21 | "version": "detect", // React version. "detect" automatically picks the version you have installed. 22 | // You can also use `16.0`, `16.3`, etc, if you want to override the detected value. 23 | // It will default to "latest" and warn if missing, and to "detect" in the future 24 | "flowVersion": "0.53" // Flow version 25 | }, 26 | "import/resolver": { 27 | "node": { 28 | "moduleDirectory": ["node_modules", "src/"] 29 | } 30 | } 31 | }, 32 | "parser": "@babel/eslint-parser", 33 | "parserOptions": { 34 | "ecmaFeatures": { 35 | "experimentalObjectRestSpread": true, 36 | "impliedStrict": true, 37 | "jsx": true 38 | }, 39 | "ecmaVersion": 12 40 | }, 41 | "plugins": ["prettier", "react", "react-hooks"], 42 | "rules": { 43 | "react/jsx-uses-react": "error", 44 | "react/jsx-uses-vars": "error", 45 | "react/react-in-jsx-scope": "off", 46 | "no-undef": "off", 47 | "react/display-name": "off", 48 | "react/jsx-filename-extension": "off", 49 | "no-param-reassign": "off", 50 | "react/prop-types": 1, 51 | "react/require-default-props": "off", 52 | "react/no-array-index-key": "off", 53 | "react/jsx-props-no-spreading": "off", 54 | "react/forbid-prop-types": "off", 55 | "import/order": "off", 56 | "import/no-cycle": "off", 57 | "no-console": "off", 58 | "jsx-a11y/anchor-is-valid": "off", 59 | "prefer-destructuring": "off", 60 | "no-shadow": "off", 61 | "import/no-named-as-default": "off", 62 | "import/no-extraneous-dependencies": "off", 63 | "jsx-a11y/no-autofocus": "off", 64 | "no-restricted-imports": [ 65 | "error", 66 | { 67 | "patterns": ["@mui/*/*/*", "!@mui/material/test-utils/*"] 68 | } 69 | ], 70 | "no-unused-vars": [ 71 | "error", 72 | { 73 | "ignoreRestSiblings": false 74 | } 75 | ], 76 | "prettier/prettier": [ 77 | "warn", 78 | { 79 | "bracketSpacing": true, 80 | "printWidth": 140, 81 | "singleQuote": true, 82 | "trailingComma": "none", 83 | "tabWidth": 2, 84 | "useTabs": false, 85 | "endOfLine": "auto" 86 | } 87 | ] 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /ui-mantis/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | build 40 | 41 | # Dependency directories 42 | node_modules/ 43 | jspm_packages/ 44 | 45 | # TypeScript v1 declaration files 46 | typings/ 47 | 48 | # TypeScript cache 49 | *.tsbuildinfo 50 | 51 | # Optional npm cache directory 52 | .npm 53 | 54 | # Optional eslint cache 55 | .eslintcache 56 | 57 | # Microbundle cache 58 | .rpt2_cache/ 59 | .rts2_cache_cjs/ 60 | .rts2_cache_es/ 61 | .rts2_cache_umd/ 62 | 63 | # Optional REPL history 64 | .node_repl_history 65 | 66 | # Output of 'npm pack' 67 | *.tgz 68 | 69 | # Yarn Integrity file 70 | .yarn-integrity 71 | 72 | # dotenv environment variables file 73 | # .env 74 | .env.test 75 | 76 | # parcel-bundler cache (https://parceljs.org/) 77 | .cache 78 | 79 | # Next.js build output 80 | .next 81 | 82 | # Nuxt.js build / generate output 83 | .nuxt 84 | dist 85 | 86 | # Gatsby files 87 | .cache/ 88 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 89 | # https://nextjs.org/blog/next-9-1#public-directory-support 90 | # public 91 | 92 | # vuepress build output 93 | .vuepress/dist 94 | 95 | # Serverless directories 96 | .serverless/ 97 | 98 | # FuseBox cache 99 | .fusebox/ 100 | 101 | # DynamoDB Local files 102 | .dynamodb/ 103 | 104 | # TernJS port file 105 | .tern-port 106 | 107 | # wincompare file 108 | .bak -------------------------------------------------------------------------------- /ui-mantis/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSpacing": true, 3 | "printWidth": 140, 4 | "singleQuote": true, 5 | "trailingComma": "none", 6 | "tabWidth": 2, 7 | "useTabs": false 8 | } 9 | -------------------------------------------------------------------------------- /ui-mantis/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20-alpine 2 | WORKDIR /app 3 | COPY . . 4 | RUN yarn 5 | RUN yarn build 6 | EXPOSE 4000 7 | CMD [ "yarn", "preview" ] -------------------------------------------------------------------------------- /ui-mantis/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 CodedThemes 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /ui-mantis/README.md: -------------------------------------------------------------------------------- 1 | # Mantis Free React Material UI Dashboard Template [![Tweet](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/intent/tweet?text=Download%20Mantis%20React%20-%20The%20professional%20Material%20designed%20React%20Admin%20Dashboard%20Template%20&url=https://mantisdashboard.io&via=codedthemes&hashtags=reactjs,webdev,developers,javascript) 2 | 3 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 4 | [![Price](https://img.shields.io/badge/price-FREE-0098f7.svg)](https://github.com/codedthemes/mantis-free-react-admin-template/blob/main/LICENSE) 5 | [![GitHub package version](https://img.shields.io/github/package-json/v/codedthemes/mantis-free-react-admin-template)](https://github.com/codedthemes/mantis-free-react-admin-template/) 6 | 7 | This code provides a starter template to quickly setup a react (and Mantis) frontend ready for interaction with your NestJS server. 8 | 9 | It comes with prebuilt UI for logging in with major OAuth providers, managing your profile as a user, and managing all user profiles as an admin. 10 | 11 | Mantis is a free and open source React dashboard template made using the Material UI React component library with aim of flexibility and better customizability. 12 | 13 | ## Getting Started 14 | 15 | 1. Clone the repo 16 | 17 | ``` 18 | git clone https://github.com/app-generator/api-server-nestjs.git 19 | ``` 20 | 21 | 2. Navigate to Mantis UI folder 22 | 23 | ``` 24 | cd ui-mantis/mantis-dashboard 25 | ``` 26 | 27 | 3. Install packages 28 | 29 | ``` 30 | npm install 31 | ``` 32 | 33 | or 34 | 35 | ``` 36 | yarn 37 | ``` 38 | 39 | 4. Update `.env` file 40 | 41 | Enter your server URL in the `PUBLIC_URL` field. 42 | 43 | 5. Start the project 44 | 45 | Run `npm start` and navigate to the appropriate URL (usually localhost:3000). 46 | -------------------------------------------------------------------------------- /ui-mantis/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /ui-mantis/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Mantis React Admin Dashboard 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /ui-mantis/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "commonjs", 5 | "baseUrl": "src" 6 | }, 7 | "include": ["src/**/*"], 8 | "exclude": ["node_modules"] 9 | } 10 | -------------------------------------------------------------------------------- /ui-mantis/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mantis-free-react-admin-template", 3 | "version": "1.3.0", 4 | "private": true, 5 | "homepage": "https://mantisdashboard.io/free", 6 | "author": { 7 | "name": "CodedThemes", 8 | "email": "codedthemes@gmail.com", 9 | "url": "https://codedthemes.com/" 10 | }, 11 | "scripts": { 12 | "start": "vite", 13 | "build": "vite build", 14 | "preview": "vite preview", 15 | "lint": "eslint \"src/**/*.{js,jsx,ts,tsx}\"", 16 | "lint:fix": "eslint --fix \"src/**/*.{js,jsx,ts,tsx}\"", 17 | "prettier": "prettier --write \"src/**/*.{js,jsx,ts,tsx}\"" 18 | }, 19 | "dependencies": { 20 | "@ant-design/colors": "^7.0.2", 21 | "@ant-design/icons": "^5.3.1", 22 | "@emotion/cache": "^11.11.0", 23 | "@emotion/react": "^11.11.4", 24 | "@emotion/styled": "^11.11.0", 25 | "@fontsource/inter": "^5.0.17", 26 | "@fontsource/poppins": "^5.0.12", 27 | "@fontsource/public-sans": "^5.0.17", 28 | "@fontsource/roboto": "^5.0.12", 29 | "@mui/base": "^5.0.0-beta.38", 30 | "@mui/lab": "^5.0.0-alpha.167", 31 | "@mui/material": "^5.15.12", 32 | "@mui/system": "^5.15.12", 33 | "@svgr/webpack": "^8.1.0", 34 | "@vitejs/plugin-react": "^4.2.1", 35 | "apexcharts": "^3.49.0", 36 | "axios": "^1.7.9", 37 | "dotenv": "^16.4.7", 38 | "formik": "^2.4.5", 39 | "framer-motion": "^11.0.8", 40 | "lodash": "^4.17.21", 41 | "process": "^0.11.10", 42 | "prop-types": "^15.8.1", 43 | "react": "^18.2.0", 44 | "react-apexcharts": "^1.4.1", 45 | "react-copy-to-clipboard": "^5.1.0", 46 | "react-device-detect": "^2.2.3", 47 | "react-dom": "^18.2.0", 48 | "react-number-format": "^5.3.3", 49 | "react-router": "^6.22.3", 50 | "react-router-dom": "^6.22.3", 51 | "simplebar-react": "^3.2.4", 52 | "slick-carousel": "^1.8.1", 53 | "swr": "^2.2.5", 54 | "util": "^0.12.5", 55 | "vite": "^5.2.10", 56 | "vite-jsconfig-paths": "^2.0.1", 57 | "web-vitals": "^3.5.2", 58 | "yup": "^1.4.0" 59 | }, 60 | "eslintConfig": { 61 | "extends": [ 62 | "react-app", 63 | "react-app/jest" 64 | ] 65 | }, 66 | "babel": { 67 | "presets": [ 68 | "@babel/preset-react" 69 | ] 70 | }, 71 | "browserslist": { 72 | "production": [ 73 | ">0.2%", 74 | "not dead", 75 | "not op_mini all" 76 | ], 77 | "development": [ 78 | "last 1 chrome version", 79 | "last 1 firefox version", 80 | "last 1 safari version" 81 | ] 82 | }, 83 | "devDependencies": { 84 | "@babel/core": "^7.24.0", 85 | "@babel/eslint-parser": "^7.23.10", 86 | "@babel/plugin-proposal-private-property-in-object": "^7.21.11", 87 | "eslint": "^8.56.0", 88 | "eslint-config-prettier": "^9.1.0", 89 | "eslint-config-react-app": "^7.0.1", 90 | "eslint-plugin-flowtype": "^8.0.3", 91 | "eslint-plugin-import": "^2.29.1", 92 | "eslint-plugin-jsx-a11y": "^6.8.0", 93 | "eslint-plugin-prettier": "^5.1.3", 94 | "eslint-plugin-react": "^7.34.0", 95 | "eslint-plugin-react-hooks": "^4.6.0", 96 | "prettier": "^3.2.5", 97 | "react-error-overlay": "6.0.11" 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /ui-mantis/src/App.jsx: -------------------------------------------------------------------------------- 1 | import { RouterProvider } from 'react-router-dom'; 2 | 3 | // project import 4 | import router from 'routes'; 5 | import ThemeCustomization from 'themes'; 6 | 7 | import ScrollTop from 'components/ScrollTop'; 8 | import { AuthContextProvider } from 'contexts/authContext.jsx'; 9 | 10 | // ==============================|| APP - THEME, ROUTER, LOCAL ||============================== // 11 | 12 | export default function App() { 13 | return ( 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /ui-mantis/src/api/menu.js: -------------------------------------------------------------------------------- 1 | import useSWR, { mutate } from 'swr'; 2 | import { useMemo } from 'react'; 3 | 4 | const initialState = { 5 | openedItem: 'dashboard', 6 | openedComponent: 'buttons', 7 | openedHorizontalItem: null, 8 | isDashboardDrawerOpened: false, 9 | isComponentDrawerOpened: true 10 | }; 11 | 12 | export const endpoints = { 13 | key: 'api/menu', 14 | master: 'master', 15 | dashboard: '/dashboard' // server URL 16 | }; 17 | 18 | export function useGetMenuMaster() { 19 | const { data, isLoading } = useSWR(endpoints.key + endpoints.master, () => initialState, { 20 | revalidateIfStale: false, 21 | revalidateOnFocus: false, 22 | revalidateOnReconnect: false 23 | }); 24 | 25 | const memoizedValue = useMemo( 26 | () => ({ 27 | menuMaster: data, 28 | menuMasterLoading: isLoading 29 | }), 30 | [data, isLoading] 31 | ); 32 | 33 | return memoizedValue; 34 | } 35 | 36 | export function handlerDrawerOpen(isDashboardDrawerOpened) { 37 | // to update local state based on key 38 | 39 | mutate( 40 | endpoints.key + endpoints.master, 41 | (currentMenuMaster) => { 42 | return { ...currentMenuMaster, isDashboardDrawerOpened }; 43 | }, 44 | false 45 | ); 46 | } 47 | 48 | export function handlerActiveItem(openedItem) { 49 | // to update local state based on key 50 | 51 | mutate( 52 | endpoints.key + endpoints.master, 53 | (currentMenuMaster) => { 54 | return { ...currentMenuMaster, openedItem }; 55 | }, 56 | false 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /ui-mantis/src/assets/images/auth/AuthBackground.jsx: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import { useTheme } from '@mui/material/styles'; 3 | import Box from '@mui/material/Box'; 4 | 5 | // ==============================|| AUTH BLUR BACK SVG ||============================== // 6 | 7 | export default function AuthBackground() { 8 | const theme = useTheme(); 9 | return ( 10 | 19 | 20 | 24 | 29 | 34 | 35 | 36 | ); 37 | } 38 | -------------------------------------------------------------------------------- /ui-mantis/src/assets/images/icons/facebook.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ui-mantis/src/assets/images/icons/github.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ui-mantis/src/assets/images/icons/google.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /ui-mantis/src/assets/images/icons/twitter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ui-mantis/src/assets/images/users/avatar-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/app-generator/api-server-django/a6cc878ce93edd5e5cea0d5f4d7c39e22acffc8d/ui-mantis/src/assets/images/users/avatar-1.png -------------------------------------------------------------------------------- /ui-mantis/src/assets/images/users/avatar-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/app-generator/api-server-django/a6cc878ce93edd5e5cea0d5f4d7c39e22acffc8d/ui-mantis/src/assets/images/users/avatar-2.png -------------------------------------------------------------------------------- /ui-mantis/src/assets/images/users/avatar-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/app-generator/api-server-django/a6cc878ce93edd5e5cea0d5f4d7c39e22acffc8d/ui-mantis/src/assets/images/users/avatar-3.png -------------------------------------------------------------------------------- /ui-mantis/src/assets/images/users/avatar-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/app-generator/api-server-django/a6cc878ce93edd5e5cea0d5f4d7c39e22acffc8d/ui-mantis/src/assets/images/users/avatar-4.png -------------------------------------------------------------------------------- /ui-mantis/src/assets/images/users/avatar-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/app-generator/api-server-django/a6cc878ce93edd5e5cea0d5f4d7c39e22acffc8d/ui-mantis/src/assets/images/users/avatar-5.png -------------------------------------------------------------------------------- /ui-mantis/src/assets/images/users/avatar-group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/app-generator/api-server-django/a6cc878ce93edd5e5cea0d5f4d7c39e22acffc8d/ui-mantis/src/assets/images/users/avatar-group.png -------------------------------------------------------------------------------- /ui-mantis/src/assets/third-party/apex-chart.css: -------------------------------------------------------------------------------- 1 | .apexcharts-legend-series .apexcharts-legend-marker { 2 | left: -4px !important; 3 | top: 2px !important; 4 | } 5 | -------------------------------------------------------------------------------- /ui-mantis/src/components/@extended/AnimateButton.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | // third-party 4 | import { motion, useCycle } from 'framer-motion'; 5 | 6 | export default function AnimateButton({ children, type = 'scale', direction = 'right', offset = 10, scale = { hover: 1.05, tap: 0.954 } }) { 7 | let offset1; 8 | let offset2; 9 | switch (direction) { 10 | case 'up': 11 | case 'left': 12 | offset1 = offset; 13 | offset2 = 0; 14 | break; 15 | case 'right': 16 | case 'down': 17 | default: 18 | offset1 = 0; 19 | offset2 = offset; 20 | break; 21 | } 22 | 23 | const [x, cycleX] = useCycle(offset1, offset2); 24 | const [y, cycleY] = useCycle(offset1, offset2); 25 | 26 | switch (type) { 27 | case 'rotate': 28 | return ( 29 | 38 | {children} 39 | 40 | ); 41 | case 'slide': 42 | if (direction === 'up' || direction === 'down') { 43 | return ( 44 | cycleY()} onHoverStart={() => cycleY()}> 45 | {children} 46 | 47 | ); 48 | } 49 | return ( 50 | cycleX()} onHoverStart={() => cycleX()}> 51 | {children} 52 | 53 | ); 54 | 55 | case 'scale': 56 | default: 57 | if (typeof scale === 'number') { 58 | scale = { 59 | hover: scale, 60 | tap: scale 61 | }; 62 | } 63 | return ( 64 | 65 | {children} 66 | 67 | ); 68 | } 69 | } 70 | 71 | AnimateButton.propTypes = { 72 | children: PropTypes.node, 73 | type: PropTypes.oneOf(['slide', 'scale', 'rotate']), 74 | direction: PropTypes.oneOf(['up', 'down', 'left', 'right']), 75 | offset: PropTypes.number, 76 | scale: PropTypes.object 77 | }; 78 | -------------------------------------------------------------------------------- /ui-mantis/src/components/@extended/Avatar.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | // material-ui 4 | import { styled, useTheme } from '@mui/material/styles'; 5 | import MuiAvatar from '@mui/material/Avatar'; 6 | 7 | // project import 8 | import getColors from 'utils/getColors'; 9 | 10 | function getColorStyle({ theme, color, type }) { 11 | const colors = getColors(theme, color); 12 | const { lighter, light, main, contrastText } = colors; 13 | 14 | switch (type) { 15 | case 'filled': 16 | return { 17 | color: contrastText, 18 | background: main 19 | }; 20 | case 'outlined': 21 | return { 22 | color: main, 23 | border: '1px solid', 24 | borderColor: main, 25 | background: 'transparent' 26 | }; 27 | case 'combined': 28 | return { 29 | color: main, 30 | border: '1px solid', 31 | borderColor: light, 32 | background: lighter 33 | }; 34 | default: 35 | return { 36 | color: main, 37 | background: lighter 38 | }; 39 | } 40 | } 41 | 42 | // ==============================|| AVATAR - SIZE STYLE ||============================== // 43 | 44 | function getSizeStyle(size) { 45 | switch (size) { 46 | case 'badge': 47 | return { 48 | border: '2px solid', 49 | fontSize: '0.675rem', 50 | width: 20, 51 | height: 20 52 | }; 53 | case 'xs': 54 | return { 55 | fontSize: '0.75rem', 56 | width: 24, 57 | height: 24 58 | }; 59 | case 'sm': 60 | return { 61 | fontSize: '0.875rem', 62 | width: 32, 63 | height: 32 64 | }; 65 | case 'lg': 66 | return { 67 | fontSize: '1.2rem', 68 | width: 52, 69 | height: 52 70 | }; 71 | case 'xl': 72 | return { 73 | fontSize: '1.5rem', 74 | width: 64, 75 | height: 64 76 | }; 77 | case 'md': 78 | default: 79 | return { 80 | fontSize: '1rem', 81 | width: 40, 82 | height: 40 83 | }; 84 | } 85 | } 86 | 87 | const AvatarStyle = styled(MuiAvatar, { shouldForwardProp: (prop) => prop !== 'color' && prop !== 'type' && prop !== 'size' })( 88 | ({ theme, color, type, size }) => ({ 89 | ...getSizeStyle(size), 90 | ...getColorStyle({ theme, color, type }), 91 | ...(size === 'badge' && { 92 | borderColor: theme.palette.background.default 93 | }) 94 | }) 95 | ); 96 | 97 | export default function Avatar({ children, color = 'primary', type, size = 'md', ...others }) { 98 | const theme = useTheme(); 99 | 100 | return ( 101 | 102 | {children} 103 | 104 | ); 105 | } 106 | 107 | getColorStyle.propTypes = { theme: PropTypes.any, color: PropTypes.any, type: PropTypes.any }; 108 | 109 | Avatar.propTypes = { 110 | children: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), 111 | color: PropTypes.string, 112 | type: PropTypes.any, 113 | size: PropTypes.string, 114 | others: PropTypes.any 115 | }; 116 | -------------------------------------------------------------------------------- /ui-mantis/src/components/@extended/Breadcrumbs.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useEffect, useState } from 'react'; 3 | import { Link, useLocation } from 'react-router-dom'; 4 | 5 | // material-ui 6 | import Grid from '@mui/material/Grid'; 7 | import Typography from '@mui/material/Typography'; 8 | import MuiBreadcrumbs from '@mui/material/Breadcrumbs'; 9 | 10 | // project import 11 | import MainCard from 'components/MainCard'; 12 | 13 | export default function Breadcrumbs({ navigation, title, ...others }) { 14 | const location = useLocation(); 15 | const [main, setMain] = useState(); 16 | const [item, setItem] = useState(); 17 | 18 | // set active item state 19 | const getCollapse = (menu) => { 20 | if (menu.children) { 21 | menu.children.filter((collapse) => { 22 | if (collapse.type && collapse.type === 'collapse') { 23 | getCollapse(collapse); 24 | } else if (collapse.type && collapse.type === 'item') { 25 | if (location.pathname === collapse.url) { 26 | setMain(menu); 27 | setItem(collapse); 28 | } 29 | } 30 | return false; 31 | }); 32 | } 33 | }; 34 | 35 | useEffect(() => { 36 | navigation?.items?.map((menu) => { 37 | if (menu.type && menu.type === 'group') { 38 | getCollapse(menu); 39 | } 40 | return false; 41 | }); 42 | }); 43 | 44 | // only used for component demo breadcrumbs 45 | if (location.pathname === '/breadcrumbs') { 46 | location.pathname = '/dashboard/analytics'; 47 | } 48 | 49 | let mainContent; 50 | let itemContent; 51 | let breadcrumbContent = ; 52 | let itemTitle = ''; 53 | 54 | // collapse item 55 | if (main && main.type === 'collapse') { 56 | mainContent = ( 57 | 58 | {main.title} 59 | 60 | ); 61 | } 62 | 63 | // items 64 | if (item && item.type === 'item') { 65 | itemTitle = item.title; 66 | itemContent = ( 67 | 68 | {itemTitle} 69 | 70 | ); 71 | 72 | // main 73 | if (item.breadcrumbs !== false) { 74 | breadcrumbContent = ( 75 | 76 | 77 | 78 | 79 | 80 | Home 81 | 82 | {mainContent} 83 | {itemContent} 84 | 85 | 86 | {title && ( 87 | 88 | {item.title} 89 | 90 | )} 91 | 92 | 93 | ); 94 | } 95 | } 96 | 97 | return breadcrumbContent; 98 | } 99 | 100 | Breadcrumbs.propTypes = { 101 | card: PropTypes.bool, 102 | custom: PropTypes.bool, 103 | divider: PropTypes.bool, 104 | heading: PropTypes.string, 105 | icon: PropTypes.bool, 106 | icons: PropTypes.bool, 107 | links: PropTypes.array, 108 | maxItems: PropTypes.number, 109 | rightAlign: PropTypes.bool, 110 | separator: PropTypes.any, 111 | title: PropTypes.bool, 112 | titleBottom: PropTypes.bool, 113 | sx: PropTypes.any, 114 | others: PropTypes.any 115 | }; 116 | -------------------------------------------------------------------------------- /ui-mantis/src/components/@extended/Dot.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | // material-ui 3 | import { useTheme } from '@mui/material/styles'; 4 | import Box from '@mui/material/Box'; 5 | 6 | // project import 7 | import getColors from 'utils/getColors'; 8 | 9 | export default function Dot({ color, size, variant, sx }) { 10 | const theme = useTheme(); 11 | const colors = getColors(theme, color || 'primary'); 12 | const { main } = colors; 13 | 14 | return ( 15 | 25 | ); 26 | } 27 | 28 | Dot.propTypes = { color: PropTypes.any, size: PropTypes.number, variant: PropTypes.string, sx: PropTypes.any }; 29 | -------------------------------------------------------------------------------- /ui-mantis/src/components/@extended/Transitions.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { forwardRef } from 'react'; 3 | 4 | // material-ui 5 | import Collapse from '@mui/material/Collapse'; 6 | import Fade from '@mui/material/Fade'; 7 | import Grow from '@mui/material/Grow'; 8 | import Slide from '@mui/material/Slide'; 9 | import Zoom from '@mui/material/Zoom'; 10 | import Box from '@mui/material/Box'; 11 | 12 | function transitions({ children, position = 'top-left', type = 'grow', direction = 'up', ...others }, ref) { 13 | let positionSX = { 14 | transformOrigin: '0 0 0' 15 | }; 16 | 17 | switch (position) { 18 | case 'top-right': 19 | positionSX = { 20 | transformOrigin: 'top right' 21 | }; 22 | break; 23 | case 'top': 24 | positionSX = { 25 | transformOrigin: 'top' 26 | }; 27 | break; 28 | case 'bottom-left': 29 | positionSX = { 30 | transformOrigin: 'bottom left' 31 | }; 32 | break; 33 | case 'bottom-right': 34 | positionSX = { 35 | transformOrigin: 'bottom right' 36 | }; 37 | break; 38 | case 'bottom': 39 | positionSX = { 40 | transformOrigin: 'bottom' 41 | }; 42 | break; 43 | case 'top-left': 44 | default: 45 | positionSX = { 46 | transformOrigin: '0 0 0' 47 | }; 48 | break; 49 | } 50 | 51 | return ( 52 | 53 | {type === 'grow' && ( 54 | 62 | {children} 63 | 64 | )} 65 | 66 | {type === 'collapse' && ( 67 | 68 | {children} 69 | 70 | )} 71 | 72 | {type === 'fade' && ( 73 | 81 | {children} 82 | 83 | )} 84 | 85 | {type === 'slide' && ( 86 | 95 | {children} 96 | 97 | )} 98 | 99 | {type === 'zoom' && ( 100 | 101 | {children} 102 | 103 | )} 104 | 105 | ); 106 | } 107 | 108 | export default forwardRef(transitions); 109 | 110 | function popupTransition(props, ref) { 111 | return ; 112 | } 113 | export const PopupTransition = forwardRef(popupTransition); 114 | 115 | transitions.propTypes = { 116 | children: PropTypes.node, 117 | position: PropTypes.string, 118 | type: PropTypes.string, 119 | direction: PropTypes.oneOf(['up', 'right', 'left', 'down']), 120 | others: PropTypes.any 121 | }; 122 | -------------------------------------------------------------------------------- /ui-mantis/src/components/Loadable.jsx: -------------------------------------------------------------------------------- 1 | import { Suspense } from 'react'; 2 | 3 | // project import 4 | import Loader from './Loader'; 5 | 6 | // ==============================|| LOADABLE - LAZY LOADING ||============================== // 7 | 8 | const Loadable = (Component) => (props) => ( 9 | }> 10 | 11 | 12 | ); 13 | 14 | export default Loadable; 15 | -------------------------------------------------------------------------------- /ui-mantis/src/components/Loader.jsx: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import { styled } from '@mui/material/styles'; 3 | import LinearProgress from '@mui/material/LinearProgress'; 4 | 5 | // loader style 6 | const LoaderWrapper = styled('div')(({ theme }) => ({ 7 | position: 'fixed', 8 | top: 0, 9 | left: 0, 10 | zIndex: 2001, 11 | width: '100%', 12 | '& > * + *': { 13 | marginTop: theme.spacing(2) 14 | } 15 | })); 16 | 17 | // ==============================|| Loader ||============================== // 18 | 19 | const Loader = () => ( 20 | 21 | 22 | 23 | ); 24 | 25 | export default Loader; 26 | -------------------------------------------------------------------------------- /ui-mantis/src/components/MainCard.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { forwardRef } from 'react'; 3 | 4 | // material-ui 5 | import { useTheme } from '@mui/material/styles'; 6 | import Card from '@mui/material/Card'; 7 | import CardContent from '@mui/material/CardContent'; 8 | import CardHeader from '@mui/material/CardHeader'; 9 | import Divider from '@mui/material/Divider'; 10 | import Typography from '@mui/material/Typography'; 11 | 12 | // header style 13 | const headerSX = { 14 | p: 2.5, 15 | '& .MuiCardHeader-action': { m: '0px auto', alignSelf: 'center' } 16 | }; 17 | 18 | function MainCard( 19 | { 20 | border = true, 21 | boxShadow, 22 | children, 23 | content = true, 24 | contentSX = {}, 25 | darkTitle, 26 | elevation, 27 | secondary, 28 | shadow, 29 | sx = {}, 30 | title, 31 | ...others 32 | }, 33 | ref 34 | ) { 35 | const theme = useTheme(); 36 | boxShadow = theme.palette.mode === 'dark' ? boxShadow || true : boxShadow; 37 | 38 | return ( 39 | 60 | {/* card header and action */} 61 | {!darkTitle && title && } 62 | {darkTitle && title && {title}} action={secondary} />} 63 | 64 | {/* card content */} 65 | {content && {children}} 66 | {!content && children} 67 | 68 | ); 69 | } 70 | 71 | export default forwardRef(MainCard); 72 | 73 | MainCard.propTypes = { 74 | border: PropTypes.bool, 75 | boxShadow: PropTypes.bool, 76 | children: PropTypes.node, 77 | subheader: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), 78 | content: PropTypes.bool, 79 | contentSX: PropTypes.object, 80 | darkTitle: PropTypes.bool, 81 | divider: PropTypes.bool, 82 | elevation: PropTypes.number, 83 | secondary: PropTypes.any, 84 | shadow: PropTypes.string, 85 | sx: PropTypes.object, 86 | title: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), 87 | modal: PropTypes.bool, 88 | others: PropTypes.any 89 | }; 90 | -------------------------------------------------------------------------------- /ui-mantis/src/components/ScrollTop.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useEffect } from 'react'; 3 | 4 | // ==============================|| NAVIGATION - SCROLL TO TOP ||============================== // 5 | 6 | const ScrollTop = ({ children }) => { 7 | useEffect(() => { 8 | window.scrollTo({ 9 | top: 0, 10 | left: 0, 11 | behavior: 'smooth' 12 | }); 13 | }, []); 14 | 15 | return children || null; 16 | }; 17 | 18 | ScrollTop.propTypes = { 19 | children: PropTypes.node 20 | }; 21 | 22 | export default ScrollTop; 23 | -------------------------------------------------------------------------------- /ui-mantis/src/components/cards/AuthFooter.jsx: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import Container from '@mui/material/Container'; 3 | import Link from '@mui/material/Link'; 4 | import Typography from '@mui/material/Typography'; 5 | import Stack from '@mui/material/Stack'; 6 | 7 | // ==============================|| FOOTER - AUTHENTICATION ||============================== // 8 | 9 | export default function AuthFooter() { 10 | return ( 11 | 12 | 18 | 19 | This site is protected by{' '} 20 | 21 | Privacy Policy 22 | 23 | 24 | 25 | 26 | 34 | Terms and Conditions 35 | 36 | 44 | Privacy Policy 45 | 46 | 54 | CA Privacy Notice 55 | 56 | 57 | 58 | 59 | ); 60 | } 61 | -------------------------------------------------------------------------------- /ui-mantis/src/components/cards/statistics/AnalyticEcommerce.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | // material-ui 4 | import Chip from '@mui/material/Chip'; 5 | import Grid from '@mui/material/Grid'; 6 | import Stack from '@mui/material/Stack'; 7 | import Typography from '@mui/material/Typography'; 8 | import Box from '@mui/material/Box'; 9 | 10 | // project import 11 | import MainCard from 'components/MainCard'; 12 | 13 | // assets 14 | import RiseOutlined from '@ant-design/icons/RiseOutlined'; 15 | import FallOutlined from '@ant-design/icons/FallOutlined'; 16 | 17 | const iconSX = { fontSize: '0.75rem', color: 'inherit', marginLeft: 0, marginRight: 0 }; 18 | 19 | export default function AnalyticEcommerce({ color = 'primary', title, count, percentage, isLoss, extra }) { 20 | return ( 21 | 22 | 23 | 24 | {title} 25 | 26 | 27 | 28 | 29 | {count} 30 | 31 | 32 | {percentage && ( 33 | 34 | : } 38 | label={`${percentage}%`} 39 | sx={{ ml: 1.25, pl: 1 }} 40 | size="small" 41 | /> 42 | 43 | )} 44 | 45 | 46 | 47 | 48 | You made an extra{' '} 49 | 50 | {extra} 51 | {' '} 52 | this year 53 | 54 | 55 | 56 | ); 57 | } 58 | 59 | AnalyticEcommerce.propTypes = { 60 | color: PropTypes.string, 61 | title: PropTypes.string, 62 | count: PropTypes.string, 63 | percentage: PropTypes.number, 64 | isLoss: PropTypes.bool, 65 | extra: PropTypes.string 66 | }; 67 | -------------------------------------------------------------------------------- /ui-mantis/src/components/logo/LogoMain.jsx: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import { useTheme } from '@mui/material/styles'; 3 | 4 | /** 5 | * if you want to use image instead of uncomment following. 6 | * 7 | * import logoDark from 'assets/images/logo-dark.svg'; 8 | * import logo from 'assets/images/logo.svg'; 9 | * 10 | */ 11 | 12 | // ==============================|| LOGO SVG ||============================== // 13 | 14 | const Logo = () => { 15 | const theme = useTheme(); 16 | 17 | return ( 18 | /** 19 | * if you want to use image instead of svg uncomment following, and comment out element. 20 | * 21 | * Mantis 22 | * 23 | */ 24 | <> 25 | 26 | 30 | 34 | 38 | 42 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | ); 60 | }; 61 | 62 | export default Logo; 63 | -------------------------------------------------------------------------------- /ui-mantis/src/components/logo/index.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { Link } from 'react-router-dom'; 3 | 4 | // material-ui 5 | import { ButtonBase } from '@mui/material'; 6 | import Stack from '@mui/material/Stack'; 7 | import Chip from '@mui/material/Chip'; 8 | 9 | // project import 10 | import Logo from './LogoMain'; 11 | import config from 'config'; 12 | 13 | // ==============================|| MAIN LOGO ||============================== // 14 | 15 | const LogoSection = ({ sx, to }) => { 16 | return ( 17 | 18 | 19 | 20 | 27 | 28 | 29 | ); 30 | }; 31 | 32 | LogoSection.propTypes = { 33 | sx: PropTypes.object, 34 | to: PropTypes.string 35 | }; 36 | 37 | export default LogoSection; 38 | -------------------------------------------------------------------------------- /ui-mantis/src/components/third-party/SimpleBar.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | // material-ui 4 | import { alpha, styled } from '@mui/material/styles'; 5 | import Box from '@mui/material/Box'; 6 | 7 | // third-party 8 | import SimpleBar from 'simplebar-react'; 9 | import { BrowserView, MobileView } from 'react-device-detect'; 10 | 11 | // root style 12 | const RootStyle = styled(BrowserView)({ 13 | flexGrow: 1, 14 | height: '100%', 15 | overflow: 'hidden' 16 | }); 17 | 18 | // scroll bar wrapper 19 | const SimpleBarStyle = styled(SimpleBar)(({ theme }) => ({ 20 | maxHeight: '100%', 21 | '& .simplebar-scrollbar': { 22 | '&:before': { 23 | background: alpha(theme.palette.grey[500], 0.48) 24 | }, 25 | '&.simplebar-visible:before': { 26 | opacity: 1 27 | } 28 | }, 29 | '& .simplebar-track.simplebar-vertical': { 30 | width: 10 31 | }, 32 | '& .simplebar-track.simplebar-horizontal .simplebar-scrollbar': { 33 | height: 6 34 | }, 35 | '& .simplebar-mask': { 36 | zIndex: 'inherit' 37 | } 38 | })); 39 | 40 | // ==============================|| SIMPLE SCROLL BAR ||============================== // 41 | 42 | export default function SimpleBarScroll({ children, sx, ...other }) { 43 | return ( 44 | <> 45 | 46 | 47 | {children} 48 | 49 | 50 | 51 | 52 | {children} 53 | 54 | 55 | 56 | ); 57 | } 58 | 59 | SimpleBarScroll.propTypes = { children: PropTypes.any, sx: PropTypes.any, other: PropTypes.any }; 60 | -------------------------------------------------------------------------------- /ui-mantis/src/config.js: -------------------------------------------------------------------------------- 1 | // ==============================|| THEME CONFIG ||============================== // 2 | 3 | const config = { 4 | defaultPath: '/dashboard/default', 5 | fontFamily: `'Public Sans', sans-serif`, 6 | i18n: 'en', 7 | miniDrawer: false, 8 | container: true, 9 | mode: 'light', 10 | presetColor: 'default', 11 | themeDirection: 'ltr' 12 | }; 13 | 14 | export default config; 15 | export const drawerWidth = 260; 16 | 17 | export const twitterColor = '#1DA1F2'; 18 | export const facebookColor = '#3b5998'; 19 | export const linkedInColor = '#0e76a8'; 20 | -------------------------------------------------------------------------------- /ui-mantis/src/contexts/auth-reducer/actions.js: -------------------------------------------------------------------------------- 1 | // action - account reducer 2 | export const LOGIN = '@auth/LOGIN'; 3 | export const LOGOUT = '@auth/LOGOUT'; 4 | export const REGISTER = '@auth/REGISTER'; 5 | -------------------------------------------------------------------------------- /ui-mantis/src/contexts/auth-reducer/auth.js: -------------------------------------------------------------------------------- 1 | // action - state management 2 | import { REGISTER, LOGIN, LOGOUT } from './actions'; 3 | 4 | // initial state 5 | export const initialState = { 6 | isLoggedIn: false, 7 | isInitialized: false, 8 | user: null 9 | }; 10 | 11 | // ==============================|| AUTH REDUCER ||============================== // 12 | 13 | const auth = (state = initialState, action) => { 14 | switch (action.type) { 15 | case REGISTER: { 16 | const { user } = action.payload; 17 | return { 18 | ...state, 19 | user 20 | }; 21 | } 22 | case LOGIN: { 23 | const { user } = action.payload; 24 | return { 25 | ...state, 26 | isLoggedIn: true, 27 | isInitialized: true, 28 | user 29 | }; 30 | } 31 | case LOGOUT: { 32 | return { 33 | ...state, 34 | isInitialized: true, 35 | isLoggedIn: false, 36 | user: null 37 | }; 38 | } 39 | default: { 40 | return { ...state }; 41 | } 42 | } 43 | }; 44 | 45 | export default auth; 46 | -------------------------------------------------------------------------------- /ui-mantis/src/contexts/authContext.jsx: -------------------------------------------------------------------------------- 1 | // create context for authentication 2 | import { createContext, useContext, useState } from 'react'; 3 | 4 | export const AuthContext = createContext(); 5 | 6 | export const useAuth = () => { 7 | return useContext(AuthContext); 8 | }; 9 | 10 | export const AuthContextProvider = ({ children }) => { 11 | const [user, setUser] = useState(null); 12 | 13 | const logout = () => { 14 | setUser(null) 15 | localStorage.removeItem('mantis_user'); 16 | }; 17 | 18 | return {children}; 19 | }; 20 | 21 | -------------------------------------------------------------------------------- /ui-mantis/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | 4 | // scroll bar 5 | import 'simplebar-react/dist/simplebar.min.css'; 6 | import 'slick-carousel/slick/slick.css'; 7 | import 'slick-carousel/slick/slick-theme.css'; 8 | 9 | // google-fonts 10 | import '@fontsource/roboto/400.css'; 11 | import '@fontsource/roboto/500.css'; 12 | import '@fontsource/roboto/300.css'; 13 | import '@fontsource/roboto/700.css'; 14 | 15 | import '@fontsource/inter/400.css'; 16 | import '@fontsource/inter/500.css'; 17 | import '@fontsource/inter/600.css'; 18 | import '@fontsource/inter/700.css'; 19 | 20 | import '@fontsource/poppins/400.css'; 21 | import '@fontsource/poppins/500.css'; 22 | import '@fontsource/poppins/600.css'; 23 | import '@fontsource/poppins/700.css'; 24 | 25 | import '@fontsource/public-sans/400.css'; 26 | import '@fontsource/public-sans/500.css'; 27 | import '@fontsource/public-sans/600.css'; 28 | import '@fontsource/public-sans/700.css'; 29 | 30 | // project import 31 | import App from './App'; 32 | import reportWebVitals from './reportWebVitals'; 33 | 34 | const root = ReactDOM.createRoot(document.getElementById('root')); 35 | 36 | // ==============================|| MAIN - REACT DOM RENDER ||============================== // 37 | 38 | root.render(); 39 | 40 | // If you want to start measuring performance in your app, pass a function 41 | // to log results (for example: reportWebVitals(console.log)) 42 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 43 | reportWebVitals(); 44 | -------------------------------------------------------------------------------- /ui-mantis/src/layout/Dashboard/Drawer/DrawerContent/NavCard.jsx: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import Button from '@mui/material/Button'; 3 | import CardMedia from '@mui/material/CardMedia'; 4 | import Link from '@mui/material/Link'; 5 | import Stack from '@mui/material/Stack'; 6 | import Typography from '@mui/material/Typography'; 7 | 8 | // project import 9 | import MainCard from 'components/MainCard'; 10 | 11 | // assets 12 | import avatar from 'assets/images/users/avatar-group.png'; 13 | import AnimateButton from 'components/@extended/AnimateButton'; 14 | 15 | // ==============================|| DRAWER CONTENT - NAVIGATION CARD ||============================== // 16 | 17 | export default function NavCard() { 18 | return ( 19 | 20 | 21 | 22 | 23 | Mantis Pro 24 | 25 | Checkout pro features 26 | 27 | 28 | 29 | 32 | 33 | 34 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /ui-mantis/src/layout/Dashboard/Drawer/DrawerContent/Navigation/NavGroup.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | // material-ui 3 | import List from '@mui/material/List'; 4 | import Typography from '@mui/material/Typography'; 5 | import Box from '@mui/material/Box'; 6 | 7 | // project import 8 | import NavItem from './NavItem'; 9 | import { useGetMenuMaster } from 'api/menu'; 10 | 11 | export default function NavGroup({ item }) { 12 | const { menuMaster } = useGetMenuMaster(); 13 | const drawerOpen = menuMaster.isDashboardDrawerOpened; 14 | 15 | const navCollapse = item.children?.map((menuItem) => { 16 | switch (menuItem.type) { 17 | case 'collapse': 18 | return ( 19 | 20 | collapse - only available in paid version 21 | 22 | ); 23 | case 'item': 24 | return ; 25 | default: 26 | return ( 27 | 28 | Fix - Group Collapse or Items 29 | 30 | ); 31 | } 32 | }); 33 | 34 | return ( 35 | 40 | 41 | {item.title} 42 | 43 | {/* only available in paid version */} 44 | 45 | ) 46 | } 47 | sx={{ mb: drawerOpen ? 1.5 : 0, py: 0, zIndex: 0 }} 48 | > 49 | {navCollapse} 50 | 51 | ); 52 | } 53 | 54 | NavGroup.propTypes = { item: PropTypes.object }; 55 | -------------------------------------------------------------------------------- /ui-mantis/src/layout/Dashboard/Drawer/DrawerContent/Navigation/NavItem.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { forwardRef, useEffect } from 'react'; 3 | import { Link, useLocation, matchPath } from 'react-router-dom'; 4 | 5 | // material-ui 6 | import { useTheme } from '@mui/material/styles'; 7 | import Avatar from '@mui/material/Avatar'; 8 | import Chip from '@mui/material/Chip'; 9 | import ListItemButton from '@mui/material/ListItemButton'; 10 | import ListItemIcon from '@mui/material/ListItemIcon'; 11 | import ListItemText from '@mui/material/ListItemText'; 12 | import Typography from '@mui/material/Typography'; 13 | 14 | // project import 15 | import { handlerActiveItem, useGetMenuMaster } from 'api/menu'; 16 | 17 | export default function NavItem({ item, level }) { 18 | const theme = useTheme(); 19 | 20 | const { menuMaster } = useGetMenuMaster(); 21 | const drawerOpen = menuMaster.isDashboardDrawerOpened; 22 | const openItem = menuMaster.openedItem; 23 | 24 | let itemTarget = '_self'; 25 | if (item.target) { 26 | itemTarget = '_blank'; 27 | } 28 | let listItemProps = { component: forwardRef((props, ref) => ) }; 29 | if (item?.external) { 30 | listItemProps = { component: 'a', href: item.url, target: itemTarget }; 31 | } 32 | 33 | const Icon = item.icon; 34 | const itemIcon = item.icon ? : false; 35 | 36 | const { pathname } = useLocation(); 37 | const isSelected = !!matchPath({ path: item.url, end: false }, pathname) || openItem === item.id; 38 | 39 | // active menu item on page load 40 | useEffect(() => { 41 | if (pathname === item.url) handlerActiveItem(item.id); 42 | // eslint-disable-next-line 43 | }, [pathname]); 44 | 45 | const textColor = 'text.primary'; 46 | const iconSelectedColor = 'primary.main'; 47 | 48 | return ( 49 | handlerActiveItem(item.id)} 53 | selected={isSelected} 54 | sx={{ 55 | zIndex: 1201, 56 | pl: drawerOpen ? `${level * 28}px` : 1.5, 57 | py: !drawerOpen && level === 1 ? 1.25 : 1, 58 | ...(drawerOpen && { 59 | '&:hover': { 60 | bgcolor: 'primary.lighter' 61 | }, 62 | '&.Mui-selected': { 63 | bgcolor: 'primary.lighter', 64 | borderRight: `2px solid ${theme.palette.primary.main}`, 65 | color: iconSelectedColor, 66 | '&:hover': { 67 | color: iconSelectedColor, 68 | bgcolor: 'primary.lighter' 69 | } 70 | } 71 | }), 72 | ...(!drawerOpen && { 73 | '&:hover': { 74 | bgcolor: 'transparent' 75 | }, 76 | '&.Mui-selected': { 77 | '&:hover': { 78 | bgcolor: 'transparent' 79 | }, 80 | bgcolor: 'transparent' 81 | } 82 | }) 83 | }} 84 | > 85 | {itemIcon && ( 86 | 109 | {itemIcon} 110 | 111 | )} 112 | {(drawerOpen || (!drawerOpen && level !== 1)) && ( 113 | 116 | {item.title} 117 | 118 | } 119 | /> 120 | )} 121 | {(drawerOpen || (!drawerOpen && level !== 1)) && item.chip && ( 122 | {item.chip.avatar}} 128 | /> 129 | )} 130 | 131 | ); 132 | } 133 | 134 | NavItem.propTypes = { item: PropTypes.object, level: PropTypes.number }; 135 | -------------------------------------------------------------------------------- /ui-mantis/src/layout/Dashboard/Drawer/DrawerContent/Navigation/index.jsx: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import Typography from '@mui/material/Typography'; 3 | import Box from '@mui/material/Box'; 4 | 5 | // project import 6 | import NavGroup from './NavGroup'; 7 | import menuItem from 'menu-items'; 8 | import { useEffect, useState } from 'react'; 9 | import axios from 'axios'; 10 | import { useAuth } from 'contexts/authContext.jsx'; 11 | 12 | // ==============================|| DRAWER CONTENT - NAVIGATION ||============================== // 13 | 14 | export default function Navigation() { 15 | const {user} = useAuth() 16 | 17 | console.log(user); 18 | 19 | 20 | const navGroups = menuItem.items.filter(item => { 21 | if (item.id === 'authentication' && user !== null) { 22 | return 23 | } 24 | 25 | return item 26 | }).map((item) => { 27 | switch (item.type) { 28 | case 'group': 29 | return ; 30 | default: 31 | return ( 32 | 33 | Fix - Navigation Group 34 | 35 | ); 36 | } 37 | }); 38 | 39 | return {navGroups}; 40 | } 41 | -------------------------------------------------------------------------------- /ui-mantis/src/layout/Dashboard/Drawer/DrawerContent/index.jsx: -------------------------------------------------------------------------------- 1 | // project import 2 | import NavCard from './NavCard'; 3 | import Navigation from './Navigation'; 4 | import SimpleBar from 'components/third-party/SimpleBar'; 5 | 6 | // ==============================|| DRAWER CONTENT ||============================== // 7 | 8 | export default function DrawerContent() { 9 | return ( 10 | <> 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /ui-mantis/src/layout/Dashboard/Drawer/DrawerHeader/DrawerHeaderStyled.js: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import { styled } from '@mui/material/styles'; 3 | import Box from '@mui/material/Box'; 4 | 5 | const DrawerHeaderStyled = styled(Box, { shouldForwardProp: (prop) => prop !== 'open' })(({ theme, open }) => ({ 6 | ...theme.mixins.toolbar, 7 | display: 'flex', 8 | alignItems: 'center', 9 | justifyContent: open ? 'flex-start' : 'center', 10 | paddingLeft: theme.spacing(open ? 3 : 0) 11 | })); 12 | 13 | export default DrawerHeaderStyled; 14 | -------------------------------------------------------------------------------- /ui-mantis/src/layout/Dashboard/Drawer/DrawerHeader/index.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | // material-ui 4 | import { useTheme } from '@mui/material/styles'; 5 | 6 | // project import 7 | import DrawerHeaderStyled from './DrawerHeaderStyled'; 8 | import Logo from 'components/logo'; 9 | 10 | // ==============================|| DRAWER HEADER ||============================== // 11 | 12 | export default function DrawerHeader({ open }) { 13 | const theme = useTheme(); 14 | 15 | return ( 16 | 17 | 18 | 19 | ); 20 | } 21 | 22 | DrawerHeader.propTypes = { open: PropTypes.bool }; 23 | -------------------------------------------------------------------------------- /ui-mantis/src/layout/Dashboard/Drawer/MiniDrawerStyled.js: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import { styled } from '@mui/material/styles'; 3 | import Drawer from '@mui/material/Drawer'; 4 | 5 | // project import 6 | import { drawerWidth } from 'config'; 7 | 8 | const openedMixin = (theme) => ({ 9 | width: drawerWidth, 10 | borderRight: '1px solid', 11 | borderRightColor: theme.palette.divider, 12 | 13 | transition: theme.transitions.create('width', { 14 | easing: theme.transitions.easing.sharp, 15 | duration: theme.transitions.duration.enteringScreen 16 | }), 17 | 18 | overflowX: 'hidden', 19 | boxShadow: 'none' 20 | }); 21 | 22 | const closedMixin = (theme) => ({ 23 | transition: theme.transitions.create('width', { 24 | easing: theme.transitions.easing.sharp, 25 | duration: theme.transitions.duration.leavingScreen 26 | }), 27 | 28 | overflowX: 'hidden', 29 | width: 0, 30 | borderRight: 'none', 31 | boxShadow: theme.customShadows.z1 32 | }); 33 | 34 | // ==============================|| DRAWER - MINI STYLED ||============================== // 35 | 36 | const MiniDrawerStyled = styled(Drawer, { shouldForwardProp: (prop) => prop !== 'open' })(({ theme, open }) => ({ 37 | width: drawerWidth, 38 | flexShrink: 0, 39 | whiteSpace: 'nowrap', 40 | boxSizing: 'border-box', 41 | ...(open && { 42 | ...openedMixin(theme), 43 | '& .MuiDrawer-paper': openedMixin(theme) 44 | }), 45 | ...(!open && { 46 | ...closedMixin(theme), 47 | '& .MuiDrawer-paper': closedMixin(theme) 48 | }) 49 | })); 50 | 51 | export default MiniDrawerStyled; 52 | -------------------------------------------------------------------------------- /ui-mantis/src/layout/Dashboard/Drawer/index.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useMemo } from 'react'; 3 | 4 | import useMediaQuery from '@mui/material/useMediaQuery'; 5 | import Drawer from '@mui/material/Drawer'; 6 | import Box from '@mui/material/Box'; 7 | 8 | // project import 9 | import DrawerHeader from './DrawerHeader'; 10 | import DrawerContent from './DrawerContent'; 11 | import MiniDrawerStyled from './MiniDrawerStyled'; 12 | 13 | import { drawerWidth } from 'config'; 14 | import { handlerDrawerOpen, useGetMenuMaster } from 'api/menu'; 15 | 16 | // ==============================|| MAIN LAYOUT - DRAWER ||============================== // 17 | 18 | export default function MainDrawer({ window }) { 19 | const { menuMaster } = useGetMenuMaster(); 20 | const drawerOpen = menuMaster.isDashboardDrawerOpened; 21 | const matchDownMD = useMediaQuery((theme) => theme.breakpoints.down('lg')); 22 | 23 | // responsive drawer container 24 | const container = window !== undefined ? () => window().document.body : undefined; 25 | 26 | // header content 27 | const drawerContent = useMemo(() => , []); 28 | const drawerHeader = useMemo(() => , [drawerOpen]); 29 | 30 | return ( 31 | 32 | {!matchDownMD ? ( 33 | 34 | {drawerHeader} 35 | {drawerContent} 36 | 37 | ) : ( 38 | handlerDrawerOpen(!drawerOpen)} 43 | ModalProps={{ keepMounted: true }} 44 | sx={{ 45 | display: { xs: 'block', lg: 'none' }, 46 | '& .MuiDrawer-paper': { 47 | boxSizing: 'border-box', 48 | width: drawerWidth, 49 | borderRight: '1px solid', 50 | borderRightColor: 'divider', 51 | backgroundImage: 'none', 52 | boxShadow: 'inherit' 53 | } 54 | }} 55 | > 56 | {drawerHeader} 57 | {drawerContent} 58 | 59 | )} 60 | 61 | ); 62 | } 63 | 64 | MainDrawer.propTypes = { window: PropTypes.func }; 65 | -------------------------------------------------------------------------------- /ui-mantis/src/layout/Dashboard/Header/AppBarStyled.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | // material-ui 4 | import { styled } from '@mui/material/styles'; 5 | import AppBar from '@mui/material/AppBar'; 6 | 7 | // project import 8 | import { drawerWidth } from 'config'; 9 | 10 | // ==============================|| HEADER - APP BAR STYLED ||============================== // 11 | 12 | const AppBarStyled = styled(AppBar, { shouldForwardProp: (prop) => prop !== 'open' })(({ theme, open }) => ({ 13 | zIndex: theme.zIndex.drawer + 1, 14 | left: 0, 15 | transition: theme.transitions.create(['width', 'margin'], { 16 | easing: theme.transitions.easing.sharp, 17 | duration: theme.transitions.duration.leavingScreen 18 | }), 19 | ...(!open && { 20 | width: `calc(100%)` 21 | }), 22 | ...(open && { 23 | marginLeft: drawerWidth, 24 | width: `calc(100% - ${drawerWidth}px)`, 25 | transition: theme.transitions.create(['width', 'margin'], { 26 | easing: theme.transitions.easing.sharp, 27 | duration: theme.transitions.duration.enteringScreen 28 | }) 29 | }) 30 | })); 31 | 32 | AppBarStyled.propTypes = { 33 | open: PropTypes.bool 34 | }; 35 | 36 | export default AppBarStyled; 37 | -------------------------------------------------------------------------------- /ui-mantis/src/layout/Dashboard/Header/HeaderContent/MobileSection.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef, useState } from 'react'; 2 | 3 | // material-ui 4 | import { useTheme } from '@mui/material/styles'; 5 | import AppBar from '@mui/material/AppBar'; 6 | import ClickAwayListener from '@mui/material/ClickAwayListener'; 7 | import Paper from '@mui/material/Paper'; 8 | import IconButton from '@mui/material/IconButton'; 9 | import Popper from '@mui/material/Popper'; 10 | import Toolbar from '@mui/material/Toolbar'; 11 | import Box from '@mui/material/Box'; 12 | 13 | // project import 14 | import Search from './Search'; 15 | import Profile from './Profile'; 16 | import Transitions from 'components/@extended/Transitions'; 17 | 18 | // assets 19 | import MoreOutlined from '@ant-design/icons/MoreOutlined'; 20 | 21 | // ==============================|| HEADER CONTENT - MOBILE ||============================== // 22 | 23 | export default function MobileSection() { 24 | const theme = useTheme(); 25 | 26 | const [open, setOpen] = useState(false); 27 | const anchorRef = useRef(null); 28 | 29 | const handleToggle = () => { 30 | setOpen((prevOpen) => !prevOpen); 31 | }; 32 | 33 | const handleClose = (event) => { 34 | if (anchorRef.current && anchorRef.current.contains(event.target)) { 35 | return; 36 | } 37 | 38 | setOpen(false); 39 | }; 40 | 41 | const prevOpen = useRef(open); 42 | useEffect(() => { 43 | if (prevOpen.current === true && open === false) { 44 | anchorRef.current.focus(); 45 | } 46 | 47 | prevOpen.current = open; 48 | }, [open]); 49 | 50 | const iconBackColorOpen = 'grey.300'; 51 | const iconBackColor = 'grey.100'; 52 | 53 | return ( 54 | <> 55 | 56 | 66 | 67 | 68 | 69 | 88 | {({ TransitionProps }) => ( 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | )} 102 | 103 | 104 | ); 105 | } 106 | -------------------------------------------------------------------------------- /ui-mantis/src/layout/Dashboard/Header/HeaderContent/Profile/ProfileTab.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useState, useEffect } from 'react'; 3 | 4 | // material-ui 5 | import List from '@mui/material/List'; 6 | import ListItemButton from '@mui/material/ListItemButton'; 7 | import ListItemIcon from '@mui/material/ListItemIcon'; 8 | import ListItemText from '@mui/material/ListItemText'; 9 | 10 | // assets 11 | import EditOutlined from '@ant-design/icons/EditOutlined'; 12 | import ProfileOutlined from '@ant-design/icons/ProfileOutlined'; 13 | import LogoutOutlined from '@ant-design/icons/LogoutOutlined'; 14 | import UserOutlined from '@ant-design/icons/UserOutlined'; 15 | import WalletOutlined from '@ant-design/icons/WalletOutlined'; 16 | 17 | import { useNavigate } from 'react-router-dom'; 18 | import { useAuth } from 'contexts/authContext.jsx'; 19 | 20 | 21 | // ==============================|| HEADER PROFILE - PROFILE TAB ||============================== // 22 | 23 | export default function ProfileTab({ callback }) { 24 | const [selectedIndex, setSelectedIndex] = useState(0); 25 | const { user, setUser, logout } = useAuth(); 26 | 27 | const navigate = useNavigate(); 28 | 29 | const handleListItemClick = (event, index, path) => { 30 | setSelectedIndex(index); 31 | callback(); 32 | if (path) navigate(path); 33 | }; 34 | 35 | const handleLogout = () => { 36 | logout() 37 | callback(); 38 | navigate('/dashboard/default'); 39 | }; 40 | 41 | useEffect(() => { 42 | const storedUser = JSON.parse(localStorage.getItem('mantis_user')); 43 | if (storedUser) { 44 | setUser(storedUser); 45 | } 46 | }, []); 47 | 48 | return ( 49 | 50 | handleListItemClick(event, 0, `/user/edit-profile/${user.id}`)} 53 | > 54 | 55 | 56 | 57 | 58 | 59 | 60 | handleListItemClick(event, 1, '/apps/profiles/account/' + user.id)} 63 | > 64 | 65 | 66 | 67 | 68 | 69 | 70 | handleListItemClick(event, 2, '/apps/profiles/account/' + user.id)} 73 | > 74 | 75 | 76 | 77 | 78 | 79 | 80 | handleListItemClick(event, 3, '/apps/invoice/details/1')} 83 | > 84 | 85 | 86 | 87 | 88 | 89 | 90 | handleLogout && handleLogout()} 93 | > 94 | 95 | 96 | 97 | 98 | 99 | 100 | ); 101 | } 102 | 103 | ProfileTab.propTypes = { 104 | callback: PropTypes.func 105 | }; 106 | -------------------------------------------------------------------------------- /ui-mantis/src/layout/Dashboard/Header/HeaderContent/Profile/SettingTab.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | 3 | // material-ui 4 | import List from '@mui/material/List'; 5 | import ListItemButton from '@mui/material/ListItemButton'; 6 | import ListItemIcon from '@mui/material/ListItemIcon'; 7 | import ListItemText from '@mui/material/ListItemText'; 8 | 9 | // assets 10 | import { CommentOutlined, LockOutlined, QuestionCircleOutlined, UserOutlined, UnorderedListOutlined } from '@ant-design/icons'; 11 | 12 | // ==============================|| HEADER PROFILE - SETTING TAB ||============================== // 13 | 14 | export default function SettingTab() { 15 | const [selectedIndex, setSelectedIndex] = useState(0); 16 | const handleListItemClick = (event, index) => { 17 | setSelectedIndex(index); 18 | }; 19 | 20 | return ( 21 | 22 | handleListItemClick(event, 0)}> 23 | 24 | 25 | 26 | 27 | 28 | handleListItemClick(event, 1)}> 29 | 30 | 31 | 32 | 33 | 34 | handleListItemClick(event, 2)}> 35 | 36 | 37 | 38 | 39 | 40 | handleListItemClick(event, 3)}> 41 | 42 | 43 | 44 | 45 | 46 | handleListItemClick(event, 4)}> 47 | 48 | 49 | 50 | 51 | 52 | 53 | ); 54 | } 55 | -------------------------------------------------------------------------------- /ui-mantis/src/layout/Dashboard/Header/HeaderContent/Search.jsx: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import FormControl from '@mui/material/FormControl'; 3 | import InputAdornment from '@mui/material/InputAdornment'; 4 | import OutlinedInput from '@mui/material/OutlinedInput'; 5 | import Box from '@mui/material/Box'; 6 | 7 | // assets 8 | import SearchOutlined from '@ant-design/icons/SearchOutlined'; 9 | 10 | // ==============================|| HEADER CONTENT - SEARCH ||============================== // 11 | 12 | export default function Search() { 13 | return ( 14 | 15 | 16 | 21 | 22 | 23 | } 24 | aria-describedby="header-search-text" 25 | inputProps={{ 26 | 'aria-label': 'weight' 27 | }} 28 | placeholder="Ctrl + K" 29 | /> 30 | 31 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /ui-mantis/src/layout/Dashboard/Header/HeaderContent/index.jsx: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import useMediaQuery from '@mui/material/useMediaQuery'; 3 | import IconButton from '@mui/material/IconButton'; 4 | import Link from '@mui/material/Link'; 5 | import Box from '@mui/material/Box'; 6 | 7 | // project import 8 | import Search from './Search'; 9 | import Profile from './Profile'; 10 | import Notification from './Notification'; 11 | import MobileSection from './MobileSection'; 12 | 13 | // project import 14 | import { GithubOutlined } from '@ant-design/icons'; 15 | 16 | // ==============================|| HEADER - CONTENT ||============================== // 17 | 18 | export default function HeaderContent() { 19 | const downLG = useMediaQuery((theme) => theme.breakpoints.down('lg')); 20 | 21 | return ( 22 | <> 23 | {!downLG && } 24 | {downLG && } 25 | 34 | 35 | 36 | 37 | 38 | {!downLG && } 39 | {downLG && } 40 | 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /ui-mantis/src/layout/Dashboard/Header/index.jsx: -------------------------------------------------------------------------------- 1 | import { useMemo } from 'react'; 2 | 3 | // material-ui 4 | import { useTheme } from '@mui/material/styles'; 5 | import useMediaQuery from '@mui/material/useMediaQuery'; 6 | import AppBar from '@mui/material/AppBar'; 7 | import Toolbar from '@mui/material/Toolbar'; 8 | import IconButton from '@mui/material/IconButton'; 9 | 10 | // project import 11 | import AppBarStyled from './AppBarStyled'; 12 | import HeaderContent from './HeaderContent'; 13 | 14 | import { handlerDrawerOpen, useGetMenuMaster } from 'api/menu'; 15 | 16 | // assets 17 | import MenuFoldOutlined from '@ant-design/icons/MenuFoldOutlined'; 18 | import MenuUnfoldOutlined from '@ant-design/icons/MenuUnfoldOutlined'; 19 | 20 | // ==============================|| MAIN LAYOUT - HEADER ||============================== // 21 | 22 | export default function Header() { 23 | const theme = useTheme(); 24 | const downLG = useMediaQuery(theme.breakpoints.down('lg')); 25 | 26 | const { menuMaster } = useGetMenuMaster(); 27 | const drawerOpen = menuMaster.isDashboardDrawerOpened; 28 | 29 | // header content 30 | const headerContent = useMemo(() => , []); 31 | 32 | const iconBackColor = 'grey.100'; 33 | const iconBackColorOpen = 'grey.200'; 34 | 35 | // common header 36 | const mainHeader = ( 37 | 38 | handlerDrawerOpen(!drawerOpen)} 42 | edge="start" 43 | color="secondary" 44 | variant="light" 45 | sx={{ color: 'text.primary', bgcolor: drawerOpen ? iconBackColorOpen : iconBackColor, ml: { xs: 0, lg: -2 } }} 46 | > 47 | {!drawerOpen ? : } 48 | 49 | {headerContent} 50 | 51 | ); 52 | 53 | // app-bar params 54 | const appBar = { 55 | position: 'fixed', 56 | color: 'inherit', 57 | elevation: 0, 58 | sx: { 59 | borderBottom: `1px solid ${theme.palette.divider}` 60 | // boxShadow: theme.customShadows.z1 61 | } 62 | }; 63 | 64 | return ( 65 | <> 66 | {!downLG ? ( 67 | 68 | {mainHeader} 69 | 70 | ) : ( 71 | {mainHeader} 72 | )} 73 | 74 | ); 75 | } 76 | -------------------------------------------------------------------------------- /ui-mantis/src/layout/Dashboard/index.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | import { Outlet } from 'react-router-dom'; 3 | 4 | // material-ui 5 | import useMediaQuery from '@mui/material/useMediaQuery'; 6 | import Toolbar from '@mui/material/Toolbar'; 7 | import Box from '@mui/material/Box'; 8 | 9 | // project import 10 | import Drawer from './Drawer'; 11 | import Header from './Header'; 12 | import navigation from 'menu-items'; 13 | import Loader from 'components/Loader'; 14 | import Breadcrumbs from 'components/@extended/Breadcrumbs'; 15 | 16 | import { handlerDrawerOpen, useGetMenuMaster } from 'api/menu'; 17 | 18 | // ==============================|| MAIN LAYOUT ||============================== // 19 | 20 | export default function DashboardLayout() { 21 | const { menuMasterLoading } = useGetMenuMaster(); 22 | const downXL = useMediaQuery((theme) => theme.breakpoints.down('xl')); 23 | 24 | useEffect(() => { 25 | handlerDrawerOpen(!downXL); 26 | // eslint-disable-next-line react-hooks/exhaustive-deps 27 | }, [downXL]); 28 | 29 | if (menuMasterLoading) return ; 30 | 31 | return ( 32 | 33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | ); 42 | } 43 | -------------------------------------------------------------------------------- /ui-mantis/src/layout/MinimalLayout/index.jsx: -------------------------------------------------------------------------------- 1 | import { Outlet } from 'react-router-dom'; 2 | 3 | // ==============================|| MINIMAL LAYOUT ||============================== // 4 | 5 | export default function MinimalLayout() { 6 | return ( 7 | <> 8 | 9 | 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /ui-mantis/src/menu-items/dashboard.jsx: -------------------------------------------------------------------------------- 1 | // assets 2 | import { DashboardOutlined } from '@ant-design/icons'; 3 | 4 | // icons 5 | const icons = { 6 | DashboardOutlined 7 | }; 8 | 9 | // ==============================|| MENU ITEMS - DASHBOARD ||============================== // 10 | 11 | const dashboard = { 12 | id: 'group-dashboard', 13 | title: 'Navigation', 14 | type: 'group', 15 | children: [ 16 | { 17 | id: 'dashboard', 18 | title: 'Dashboard', 19 | type: 'item', 20 | url: '/dashboard/default', 21 | icon: icons.DashboardOutlined, 22 | breadcrumbs: false 23 | } 24 | ] 25 | }; 26 | 27 | export default dashboard; 28 | -------------------------------------------------------------------------------- /ui-mantis/src/menu-items/index.jsx: -------------------------------------------------------------------------------- 1 | // project import 2 | import dashboard from './dashboard'; 3 | import pages from './page'; 4 | import utilities from './utilities'; 5 | import support from './support'; 6 | import users from './users'; 7 | 8 | // ==============================|| MENU ITEMS ||============================== // 9 | 10 | const menuItems = { 11 | items: [dashboard, users, pages, utilities, support] 12 | }; 13 | 14 | 15 | export default menuItems; 16 | -------------------------------------------------------------------------------- /ui-mantis/src/menu-items/page.jsx: -------------------------------------------------------------------------------- 1 | // assets 2 | import { LoginOutlined, ProfileOutlined } from '@ant-design/icons'; 3 | 4 | // icons 5 | const icons = { 6 | LoginOutlined, 7 | ProfileOutlined 8 | }; 9 | 10 | // ==============================|| MENU ITEMS - EXTRA PAGES ||============================== // 11 | 12 | const pages = { 13 | id: 'authentication', 14 | title: 'Authentication', 15 | type: 'group', 16 | children: [ 17 | { 18 | id: 'login1', 19 | title: 'Login', 20 | type: 'item', 21 | url: '/login', 22 | icon: icons.LoginOutlined, 23 | target: true 24 | }, 25 | { 26 | id: 'register1', 27 | title: 'Register', 28 | type: 'item', 29 | url: '/register', 30 | icon: icons.ProfileOutlined, 31 | target: true 32 | } 33 | ] 34 | }; 35 | 36 | export default pages; 37 | -------------------------------------------------------------------------------- /ui-mantis/src/menu-items/support.jsx: -------------------------------------------------------------------------------- 1 | // assets 2 | import { ChromeOutlined, QuestionOutlined } from '@ant-design/icons'; 3 | 4 | // icons 5 | const icons = { 6 | ChromeOutlined, 7 | QuestionOutlined 8 | }; 9 | 10 | // ==============================|| MENU ITEMS - SAMPLE PAGE & DOCUMENTATION ||============================== // 11 | 12 | const support = { 13 | id: 'support', 14 | title: 'Support', 15 | type: 'group', 16 | children: [ 17 | { 18 | id: 'sample-page', 19 | title: 'Sample Page', 20 | type: 'item', 21 | url: '/sample-page', 22 | icon: icons.ChromeOutlined 23 | }, 24 | { 25 | id: 'documentation', 26 | title: 'Documentation', 27 | type: 'item', 28 | url: 'https://codedthemes.gitbook.io/mantis/', 29 | icon: icons.QuestionOutlined, 30 | external: true, 31 | target: true 32 | } 33 | ] 34 | }; 35 | 36 | export default support; 37 | -------------------------------------------------------------------------------- /ui-mantis/src/menu-items/users.jsx: -------------------------------------------------------------------------------- 1 | import { UserOutlined } from "@ant-design/icons"; 2 | 3 | const icons = { 4 | UserOutlined, 5 | } 6 | 7 | const users = { 8 | id: 'users', 9 | title: 'Users Mangement', 10 | type: 'group', 11 | children: [ 12 | { 13 | id: 'users/management', 14 | title: 'Users', 15 | type: 'item', 16 | url: '/usermanagement', 17 | icon: icons.UserOutlined, 18 | breadcrumbs: false 19 | }, 20 | ] 21 | }; 22 | 23 | export default users; -------------------------------------------------------------------------------- /ui-mantis/src/menu-items/utilities.jsx: -------------------------------------------------------------------------------- 1 | // assets 2 | import { 3 | AppstoreAddOutlined, 4 | AntDesignOutlined, 5 | BarcodeOutlined, 6 | BgColorsOutlined, 7 | FontSizeOutlined, 8 | LoadingOutlined 9 | } from '@ant-design/icons'; 10 | 11 | // icons 12 | const icons = { 13 | FontSizeOutlined, 14 | BgColorsOutlined, 15 | BarcodeOutlined, 16 | AntDesignOutlined, 17 | LoadingOutlined, 18 | AppstoreAddOutlined 19 | }; 20 | 21 | // ==============================|| MENU ITEMS - UTILITIES ||============================== // 22 | 23 | const utilities = { 24 | id: 'utilities', 25 | title: 'Utilities', 26 | type: 'group', 27 | children: [ 28 | { 29 | id: 'util-typography', 30 | title: 'Typography', 31 | type: 'item', 32 | url: '/typography', 33 | icon: icons.FontSizeOutlined 34 | }, 35 | { 36 | id: 'util-color', 37 | title: 'Color', 38 | type: 'item', 39 | url: '/color', 40 | icon: icons.BgColorsOutlined 41 | }, 42 | { 43 | id: 'util-shadow', 44 | title: 'Shadow', 45 | type: 'item', 46 | url: '/shadow', 47 | icon: icons.BarcodeOutlined 48 | } 49 | ] 50 | }; 51 | 52 | export default utilities; 53 | -------------------------------------------------------------------------------- /ui-mantis/src/pages/authentication/AuthCard.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | // material-ui 4 | import Box from '@mui/material/Box'; 5 | 6 | // project import 7 | import MainCard from 'components/MainCard'; 8 | 9 | // ==============================|| AUTHENTICATION - CARD WRAPPER ||============================== // 10 | 11 | export default function AuthCard({ children, ...other }) { 12 | return ( 13 | *': { flexGrow: 1, flexBasis: '50%' } }} 15 | content={false} 16 | {...other} 17 | border={false} 18 | boxShadow 19 | shadow={(theme) => theme.customShadows.z1} 20 | > 21 | {children} 22 | 23 | ); 24 | } 25 | 26 | AuthCard.propTypes = { children: PropTypes.node, other: PropTypes.any }; 27 | -------------------------------------------------------------------------------- /ui-mantis/src/pages/authentication/AuthWrapper.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | // material-ui 4 | import Grid from '@mui/material/Grid'; 5 | import Box from '@mui/material/Box'; 6 | 7 | // project import 8 | import AuthFooter from 'components/cards/AuthFooter'; 9 | import Logo from 'components/logo'; 10 | import AuthCard from './AuthCard'; 11 | 12 | // assets 13 | import AuthBackground from 'assets/images/auth/AuthBackground'; 14 | 15 | // ==============================|| AUTHENTICATION - WRAPPER ||============================== // 16 | 17 | export default function AuthWrapper({ children }) { 18 | return ( 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 34 | 35 | {children} 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | ); 45 | } 46 | 47 | AuthWrapper.propTypes = { children: PropTypes.node }; 48 | -------------------------------------------------------------------------------- /ui-mantis/src/pages/authentication/auth-forms/AuthLogin.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import React from 'react'; 3 | import { Link as RouterLink } from 'react-router-dom'; 4 | 5 | // material-ui 6 | import Button from '@mui/material/Button'; 7 | import Checkbox from '@mui/material/Checkbox'; 8 | import Divider from '@mui/material/Divider'; 9 | import FormControlLabel from '@mui/material/FormControlLabel'; 10 | import FormHelperText from '@mui/material/FormHelperText'; 11 | import Grid from '@mui/material/Grid'; 12 | import Link from '@mui/material/Link'; 13 | import InputAdornment from '@mui/material/InputAdornment'; 14 | import IconButton from '@mui/material/IconButton'; 15 | import InputLabel from '@mui/material/InputLabel'; 16 | import OutlinedInput from '@mui/material/OutlinedInput'; 17 | import Stack from '@mui/material/Stack'; 18 | import Typography from '@mui/material/Typography'; 19 | 20 | // third party 21 | import * as Yup from 'yup'; 22 | import { Formik } from 'formik'; 23 | 24 | // project import 25 | import AnimateButton from 'components/@extended/AnimateButton'; 26 | 27 | // assets 28 | import EyeOutlined from '@ant-design/icons/EyeOutlined'; 29 | import EyeInvisibleOutlined from '@ant-design/icons/EyeInvisibleOutlined'; 30 | import FirebaseSocial from './FirebaseSocial'; 31 | 32 | // ============================|| JWT - LOGIN ||============================ // 33 | 34 | export default function AuthLogin({ isDemo = false }) { 35 | const [checked, setChecked] = React.useState(false); 36 | 37 | const [showPassword, setShowPassword] = React.useState(false); 38 | const handleClickShowPassword = () => { 39 | setShowPassword(!showPassword); 40 | }; 41 | 42 | const handleMouseDownPassword = (event) => { 43 | event.preventDefault(); 44 | }; 45 | 46 | return ( 47 | <> 48 | 59 | {({ errors, handleBlur, handleChange, handleSubmit, isSubmitting, touched, values }) => ( 60 |
61 | 62 | 63 | 64 | {/* 65 | 66 | Email Address 67 | 78 | 79 | {touched.email && errors.email && ( 80 | 81 | {errors.email} 82 | 83 | )} 84 | 85 | 86 | 87 | Password 88 | 99 | 106 | {showPassword ? : } 107 | 108 | 109 | } 110 | placeholder="Enter password" 111 | /> 112 | 113 | {touched.password && errors.password && ( 114 | 115 | {errors.password} 116 | 117 | )} 118 | 119 | 120 | 121 | setChecked(event.target.checked)} 126 | name="checked" 127 | color="primary" 128 | size="small" 129 | /> 130 | } 131 | label={Keep me sign in} 132 | /> 133 | 134 | Forgot Password? 135 | 136 | 137 | 138 | {errors.submit && ( 139 | 140 | {errors.submit} 141 | 142 | )} 143 | 144 | 145 | 148 | 149 | 150 | 151 | 152 | Login with 153 | 154 | */} 155 | 156 | 157 | 158 | 159 | 160 |
161 | )} 162 |
163 | 164 | ); 165 | } 166 | 167 | AuthLogin.propTypes = { isDemo: PropTypes.bool }; 168 | -------------------------------------------------------------------------------- /ui-mantis/src/pages/authentication/auth-forms/FirebaseSocial.jsx: -------------------------------------------------------------------------------- 1 | import useMediaQuery from '@mui/material/useMediaQuery'; 2 | import Button from '@mui/material/Button'; 3 | import Stack from '@mui/material/Stack'; 4 | 5 | // assets 6 | import Google from 'assets/images/icons/google.svg'; 7 | import Twitter from 'assets/images/icons/twitter.svg'; 8 | import Facebook from 'assets/images/icons/facebook.svg'; 9 | import Github from 'assets/images/icons/github.svg' 10 | 11 | import axios from 'axios'; 12 | 13 | // ==============================|| FIREBASE - SOCIAL BUTTON ||============================== // 14 | 15 | export default function FirebaseSocial() { 16 | const downSM = useMediaQuery((theme) => theme.breakpoints.down('sm')); 17 | 18 | // @ts-ignore 19 | const googleHandler = async () => { 20 | // login || singup 21 | }; 22 | 23 | const twitterHandler = async () => { 24 | // login || singup 25 | }; 26 | 27 | const githubHandler = async () => { 28 | try { 29 | window.location.href = `${import.meta.env.VITE_APP_PUBLIC_URL}/auth/login`; 30 | } catch (error) { 31 | console.error('GitHub login failed:', error); 32 | } 33 | }; 34 | 35 | return ( 36 | 42 | {/* 51 | */} 60 | 69 | 70 | ); 71 | } 72 | -------------------------------------------------------------------------------- /ui-mantis/src/pages/authentication/login.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'react-router-dom'; 2 | 3 | // material-ui 4 | import Grid from '@mui/material/Grid'; 5 | import Stack from '@mui/material/Stack'; 6 | import Typography from '@mui/material/Typography'; 7 | 8 | // project import 9 | import AuthWrapper from './AuthWrapper'; 10 | import AuthLogin from './auth-forms/AuthLogin'; 11 | 12 | // ================================|| LOGIN ||================================ // 13 | 14 | export default function Login() { 15 | return ( 16 | 17 | 18 | 19 | 20 | Login 21 | 22 | Don't have an account? 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /ui-mantis/src/pages/authentication/register.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from 'react-router-dom'; 2 | 3 | // material-ui 4 | import Grid from '@mui/material/Grid'; 5 | import Stack from '@mui/material/Stack'; 6 | import Typography from '@mui/material/Typography'; 7 | 8 | // project import 9 | import AuthWrapper from './AuthWrapper'; 10 | import AuthRegister from './auth-forms/AuthRegister'; 11 | 12 | // ================================|| REGISTER ||================================ // 13 | 14 | export default function Register() { 15 | return ( 16 | 17 | 18 | 19 | 20 | Register 21 | 22 | Already have an account? 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /ui-mantis/src/pages/component-overview/ComponentSkeleton.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useEffect, useState } from 'react'; 3 | 4 | // material-ui 5 | import Grid from '@mui/material/Grid'; 6 | import Skeleton from '@mui/material/Skeleton'; 7 | import Stack from '@mui/material/Stack'; 8 | import Typography from '@mui/material/Typography'; 9 | import Box from '@mui/material/Box'; 10 | 11 | // project import 12 | import MainCard from 'components/MainCard'; 13 | import ComponentWrapper from './ComponentWrapper'; 14 | 15 | // ===============================|| COMPONENT - SKELETON ||=============================== // 16 | 17 | export default function ComponentSkeleton({ children }) { 18 | const [isLoading, setLoading] = useState(true); 19 | useEffect(() => { 20 | setLoading(false); 21 | }, []); 22 | 23 | const skeletonCard = ( 24 | } 26 | secondary={} 27 | > 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ); 36 | 37 | return ( 38 | <> 39 | {isLoading && ( 40 | <> 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | {skeletonCard} 73 | 74 | 75 | {skeletonCard} 76 | 77 | 78 | {skeletonCard} 79 | 80 | 81 | {skeletonCard} 82 | 83 | 84 | 85 | 86 | )} 87 | {!isLoading && children} 88 | 89 | ); 90 | } 91 | 92 | ComponentSkeleton.propTypes = { children: PropTypes.node }; 93 | -------------------------------------------------------------------------------- /ui-mantis/src/pages/component-overview/ComponentWrapper.js: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import { styled } from '@mui/material/styles'; 3 | import Box from '@mui/material/Box'; 4 | 5 | // ==============================|| COMPONENTS - CONTENT WRAPPER ||============================== // 6 | 7 | const ComponentWrapper = styled(Box)(({ theme }) => ({ 8 | paddingLeft: theme.spacing(3), 9 | paddingTop: theme.spacing(3), 10 | marginBottom: theme.spacing(3), 11 | [theme.breakpoints.down('md')]: { 12 | padding: theme.spacing(2) 13 | }, 14 | [theme.breakpoints.down('sm')]: { 15 | padding: theme.spacing(1.5) 16 | } 17 | })); 18 | 19 | export default ComponentWrapper; 20 | -------------------------------------------------------------------------------- /ui-mantis/src/pages/component-overview/color.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | // material-ui 3 | import Card from '@mui/material/Card'; 4 | import Grid from '@mui/material/Grid'; 5 | import Stack from '@mui/material/Stack'; 6 | import Typography from '@mui/material/Typography'; 7 | import Box from '@mui/material/Box'; 8 | 9 | // project import 10 | import MainCard from 'components/MainCard'; 11 | import ComponentWrapper from './ComponentWrapper'; 12 | import ComponentSkeleton from './ComponentSkeleton'; 13 | 14 | function ColorBox({ bgcolor, title, data, dark, main }) { 15 | return ( 16 | 17 | 28 | {title && ( 29 | 30 | 31 | {data && ( 32 | 33 | {data.label} 34 | {data.color} 35 | 36 | )} 37 | 38 | 39 | 40 | {title} 41 | 42 | 43 | 44 | )} 45 | 46 | 47 | ); 48 | } 49 | 50 | // ===============================|| COMPONENT - COLOR ||=============================== // 51 | 52 | export default function ComponentColor() { 53 | return ( 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | ); 133 | } 134 | 135 | ColorBox.propTypes = { 136 | bgcolor: PropTypes.string, 137 | title: PropTypes.string, 138 | data: PropTypes.object, 139 | dark: PropTypes.bool, 140 | main: PropTypes.bool 141 | }; 142 | -------------------------------------------------------------------------------- /ui-mantis/src/pages/dashboard/IncomeAreaChart.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useState, useEffect } from 'react'; 3 | 4 | // material-ui 5 | import { useTheme } from '@mui/material/styles'; 6 | 7 | // third-party 8 | import ReactApexChart from 'react-apexcharts'; 9 | 10 | // chart options 11 | const areaChartOptions = { 12 | chart: { 13 | height: 450, 14 | type: 'area', 15 | toolbar: { 16 | show: false 17 | } 18 | }, 19 | dataLabels: { 20 | enabled: false 21 | }, 22 | stroke: { 23 | curve: 'smooth', 24 | width: 2 25 | }, 26 | grid: { 27 | strokeDashArray: 0 28 | } 29 | }; 30 | 31 | // ==============================|| INCOME AREA CHART ||============================== // 32 | 33 | export default function IncomeAreaChart({ slot }) { 34 | const theme = useTheme(); 35 | 36 | const { primary, secondary } = theme.palette.text; 37 | const line = theme.palette.divider; 38 | 39 | const [options, setOptions] = useState(areaChartOptions); 40 | 41 | useEffect(() => { 42 | setOptions((prevState) => ({ 43 | ...prevState, 44 | colors: [theme.palette.primary.main, theme.palette.primary[700]], 45 | xaxis: { 46 | categories: 47 | slot === 'month' 48 | ? ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] 49 | : ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], 50 | labels: { 51 | style: { 52 | colors: [ 53 | secondary, 54 | secondary, 55 | secondary, 56 | secondary, 57 | secondary, 58 | secondary, 59 | secondary, 60 | secondary, 61 | secondary, 62 | secondary, 63 | secondary, 64 | secondary 65 | ] 66 | } 67 | }, 68 | axisBorder: { 69 | show: true, 70 | color: line 71 | }, 72 | tickAmount: slot === 'month' ? 11 : 7 73 | }, 74 | yaxis: { 75 | labels: { 76 | style: { 77 | colors: [secondary] 78 | } 79 | } 80 | }, 81 | grid: { 82 | borderColor: line 83 | } 84 | })); 85 | }, [primary, secondary, line, theme, slot]); 86 | 87 | const [series, setSeries] = useState([ 88 | { 89 | name: 'Page Views', 90 | data: [0, 86, 28, 115, 48, 210, 136] 91 | }, 92 | { 93 | name: 'Sessions', 94 | data: [0, 43, 14, 56, 24, 105, 68] 95 | } 96 | ]); 97 | 98 | useEffect(() => { 99 | setSeries([ 100 | { 101 | name: 'Page Views', 102 | data: slot === 'month' ? [76, 85, 101, 98, 87, 105, 91, 114, 94, 86, 115, 35] : [31, 40, 28, 51, 42, 109, 100] 103 | }, 104 | { 105 | name: 'Sessions', 106 | data: slot === 'month' ? [110, 60, 150, 35, 60, 36, 26, 45, 65, 52, 53, 41] : [11, 32, 45, 32, 34, 52, 41] 107 | } 108 | ]); 109 | }, [slot]); 110 | 111 | return ; 112 | } 113 | 114 | IncomeAreaChart.propTypes = { slot: PropTypes.string }; 115 | -------------------------------------------------------------------------------- /ui-mantis/src/pages/dashboard/MonthlyBarChart.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | // material-ui 4 | import { useTheme } from '@mui/material/styles'; 5 | import Box from '@mui/material/Box'; 6 | 7 | // third-party 8 | import ReactApexChart from 'react-apexcharts'; 9 | 10 | // chart options 11 | const barChartOptions = { 12 | chart: { 13 | type: 'bar', 14 | height: 365, 15 | toolbar: { 16 | show: false 17 | } 18 | }, 19 | plotOptions: { 20 | bar: { 21 | columnWidth: '45%', 22 | borderRadius: 4 23 | } 24 | }, 25 | dataLabels: { 26 | enabled: false 27 | }, 28 | xaxis: { 29 | categories: ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'], 30 | axisBorder: { 31 | show: false 32 | }, 33 | axisTicks: { 34 | show: false 35 | } 36 | }, 37 | yaxis: { 38 | show: false 39 | }, 40 | grid: { 41 | show: false 42 | } 43 | }; 44 | 45 | // ==============================|| MONTHLY BAR CHART ||============================== // 46 | 47 | export default function MonthlyBarChart() { 48 | const theme = useTheme(); 49 | 50 | const { primary, secondary } = theme.palette.text; 51 | const info = theme.palette.info.light; 52 | 53 | const [series] = useState([ 54 | { 55 | data: [80, 95, 70, 42, 65, 55, 78] 56 | } 57 | ]); 58 | 59 | const [options, setOptions] = useState(barChartOptions); 60 | 61 | useEffect(() => { 62 | setOptions((prevState) => ({ 63 | ...prevState, 64 | colors: [info], 65 | xaxis: { 66 | labels: { 67 | style: { 68 | colors: [secondary, secondary, secondary, secondary, secondary, secondary, secondary] 69 | } 70 | } 71 | } 72 | })); 73 | }, [primary, info, secondary]); 74 | 75 | return ( 76 | 77 | 78 | 79 | ); 80 | } 81 | -------------------------------------------------------------------------------- /ui-mantis/src/pages/dashboard/OrdersTable.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | // material-ui 3 | import Link from '@mui/material/Link'; 4 | import Stack from '@mui/material/Stack'; 5 | import Table from '@mui/material/Table'; 6 | import TableBody from '@mui/material/TableBody'; 7 | import TableCell from '@mui/material/TableCell'; 8 | import TableContainer from '@mui/material/TableContainer'; 9 | import TableHead from '@mui/material/TableHead'; 10 | import TableRow from '@mui/material/TableRow'; 11 | import Typography from '@mui/material/Typography'; 12 | import Box from '@mui/material/Box'; 13 | 14 | // third-party 15 | import { NumericFormat } from 'react-number-format'; 16 | 17 | // project import 18 | import Dot from 'components/@extended/Dot'; 19 | 20 | function createData(tracking_no, name, fat, carbs, protein) { 21 | return { tracking_no, name, fat, carbs, protein }; 22 | } 23 | 24 | const rows = [ 25 | createData(84564564, 'Camera Lens', 40, 2, 40570), 26 | createData(98764564, 'Laptop', 300, 0, 180139), 27 | createData(98756325, 'Mobile', 355, 1, 90989), 28 | createData(98652366, 'Handset', 50, 1, 10239), 29 | createData(13286564, 'Computer Accessories', 100, 1, 83348), 30 | createData(86739658, 'TV', 99, 0, 410780), 31 | createData(13256498, 'Keyboard', 125, 2, 70999), 32 | createData(98753263, 'Mouse', 89, 2, 10570), 33 | createData(98753275, 'Desktop', 185, 1, 98063), 34 | createData(98753291, 'Chair', 100, 0, 14001) 35 | ]; 36 | 37 | function descendingComparator(a, b, orderBy) { 38 | if (b[orderBy] < a[orderBy]) { 39 | return -1; 40 | } 41 | if (b[orderBy] > a[orderBy]) { 42 | return 1; 43 | } 44 | return 0; 45 | } 46 | 47 | function getComparator(order, orderBy) { 48 | return order === 'desc' ? (a, b) => descendingComparator(a, b, orderBy) : (a, b) => -descendingComparator(a, b, orderBy); 49 | } 50 | 51 | function stableSort(array, comparator) { 52 | const stabilizedThis = array.map((el, index) => [el, index]); 53 | stabilizedThis.sort((a, b) => { 54 | const order = comparator(a[0], b[0]); 55 | if (order !== 0) { 56 | return order; 57 | } 58 | return a[1] - b[1]; 59 | }); 60 | return stabilizedThis.map((el) => el[0]); 61 | } 62 | 63 | const headCells = [ 64 | { 65 | id: 'tracking_no', 66 | align: 'left', 67 | disablePadding: false, 68 | label: 'Tracking No.' 69 | }, 70 | { 71 | id: 'name', 72 | align: 'left', 73 | disablePadding: true, 74 | label: 'Product Name' 75 | }, 76 | { 77 | id: 'fat', 78 | align: 'right', 79 | disablePadding: false, 80 | label: 'Total Order' 81 | }, 82 | { 83 | id: 'carbs', 84 | align: 'left', 85 | disablePadding: false, 86 | 87 | label: 'Status' 88 | }, 89 | { 90 | id: 'protein', 91 | align: 'right', 92 | disablePadding: false, 93 | label: 'Total Amount' 94 | } 95 | ]; 96 | 97 | // ==============================|| ORDER TABLE - HEADER ||============================== // 98 | 99 | function OrderTableHead({ order, orderBy }) { 100 | return ( 101 | 102 | 103 | {headCells.map((headCell) => ( 104 | 110 | {headCell.label} 111 | 112 | ))} 113 | 114 | 115 | ); 116 | } 117 | 118 | function OrderStatus({ status }) { 119 | let color; 120 | let title; 121 | 122 | switch (status) { 123 | case 0: 124 | color = 'warning'; 125 | title = 'Pending'; 126 | break; 127 | case 1: 128 | color = 'success'; 129 | title = 'Approved'; 130 | break; 131 | case 2: 132 | color = 'error'; 133 | title = 'Rejected'; 134 | break; 135 | default: 136 | color = 'primary'; 137 | title = 'None'; 138 | } 139 | 140 | return ( 141 | 142 | 143 | {title} 144 | 145 | ); 146 | } 147 | 148 | // ==============================|| ORDER TABLE ||============================== // 149 | 150 | export default function OrderTable() { 151 | const order = 'asc'; 152 | const orderBy = 'tracking_no'; 153 | 154 | return ( 155 | 156 | 166 | 167 | 168 | 169 | {stableSort(rows, getComparator(order, orderBy)).map((row, index) => { 170 | const labelId = `enhanced-table-checkbox-${index}`; 171 | 172 | return ( 173 | 180 | 181 | {row.tracking_no} 182 | 183 | {row.name} 184 | {row.fat} 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | ); 193 | })} 194 | 195 |
196 |
197 |
198 | ); 199 | } 200 | 201 | OrderTableHead.propTypes = { order: PropTypes.any, orderBy: PropTypes.string }; 202 | 203 | OrderStatus.propTypes = { status: PropTypes.number }; 204 | -------------------------------------------------------------------------------- /ui-mantis/src/pages/dashboard/ReportAreaChart.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | // material-ui 4 | import { useTheme } from '@mui/material/styles'; 5 | 6 | // third-party 7 | import ReactApexChart from 'react-apexcharts'; 8 | 9 | // chart options 10 | const areaChartOptions = { 11 | chart: { 12 | height: 340, 13 | type: 'line', 14 | toolbar: { 15 | show: false 16 | } 17 | }, 18 | dataLabels: { 19 | enabled: false 20 | }, 21 | stroke: { 22 | curve: 'smooth', 23 | width: 1.5 24 | }, 25 | grid: { 26 | strokeDashArray: 4 27 | }, 28 | xaxis: { 29 | type: 'datetime', 30 | categories: [ 31 | '2018-05-19T00:00:00.000Z', 32 | '2018-06-19T00:00:00.000Z', 33 | '2018-07-19T01:30:00.000Z', 34 | '2018-08-19T02:30:00.000Z', 35 | '2018-09-19T03:30:00.000Z', 36 | '2018-10-19T04:30:00.000Z', 37 | '2018-11-19T05:30:00.000Z', 38 | '2018-12-19T06:30:00.000Z' 39 | ], 40 | labels: { 41 | format: 'MMM' 42 | }, 43 | axisBorder: { 44 | show: false 45 | }, 46 | axisTicks: { 47 | show: false 48 | } 49 | }, 50 | yaxis: { 51 | show: false 52 | }, 53 | tooltip: { 54 | x: { 55 | format: 'MM' 56 | } 57 | } 58 | }; 59 | 60 | // ==============================|| REPORT AREA CHART ||============================== // 61 | 62 | export default function ReportAreaChart() { 63 | const theme = useTheme(); 64 | 65 | const { primary, secondary } = theme.palette.text; 66 | const line = theme.palette.divider; 67 | 68 | const [options, setOptions] = useState(areaChartOptions); 69 | 70 | useEffect(() => { 71 | setOptions((prevState) => ({ 72 | ...prevState, 73 | colors: [theme.palette.warning.main], 74 | xaxis: { 75 | labels: { 76 | style: { 77 | colors: [secondary, secondary, secondary, secondary, secondary, secondary, secondary, secondary] 78 | } 79 | } 80 | }, 81 | grid: { 82 | borderColor: line 83 | }, 84 | legend: { 85 | labels: { 86 | colors: 'grey.500' 87 | } 88 | } 89 | })); 90 | }, [primary, secondary, line, theme]); 91 | 92 | const [series] = useState([ 93 | { 94 | name: 'Series 1', 95 | data: [58, 115, 28, 83, 63, 75, 35, 55] 96 | } 97 | ]); 98 | 99 | return ; 100 | } 101 | -------------------------------------------------------------------------------- /ui-mantis/src/pages/dashboard/SaleReportCard.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | 3 | // material-ui 4 | import Grid from '@mui/material/Grid'; 5 | import MenuItem from '@mui/material/MenuItem'; 6 | import TextField from '@mui/material/TextField'; 7 | import Typography from '@mui/material/Typography'; 8 | 9 | // project import 10 | import SalesChart from './SalesChart'; 11 | 12 | // sales report status 13 | const status = [ 14 | { 15 | value: 'today', 16 | label: 'Today' 17 | }, 18 | { 19 | value: 'month', 20 | label: 'This Month' 21 | }, 22 | { 23 | value: 'year', 24 | label: 'This Year' 25 | } 26 | ]; 27 | 28 | // ==============================|| DEFAULT - SALES REPORT ||============================== // 29 | 30 | export default function SaleReportCard() { 31 | const [value, setValue] = useState('today'); 32 | 33 | return ( 34 | <> 35 | 36 | 37 | Sales Report 38 | 39 | 40 | setValue(e.target.value)} 46 | sx={{ '& .MuiInputBase-input': { py: 0.75, fontSize: '0.875rem' } }} 47 | > 48 | {status.map((option) => ( 49 | 50 | {option.label} 51 | 52 | ))} 53 | 54 | 55 | 56 | 57 | 58 | ); 59 | } 60 | -------------------------------------------------------------------------------- /ui-mantis/src/pages/dashboard/SalesChart.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | // material-ui 4 | import { useTheme } from '@mui/material/styles'; 5 | import useMediaQuery from '@mui/material/useMediaQuery'; 6 | import Checkbox from '@mui/material/Checkbox'; 7 | import FormControl from '@mui/material/FormControl'; 8 | import FormGroup from '@mui/material/FormGroup'; 9 | import FormControlLabel from '@mui/material/FormControlLabel'; 10 | import Stack from '@mui/material/Stack'; 11 | import Typography from '@mui/material/Typography'; 12 | import Box from '@mui/material/Box'; 13 | 14 | // project import 15 | import MainCard from 'components/MainCard'; 16 | 17 | // third-party 18 | import ReactApexChart from 'react-apexcharts'; 19 | 20 | // chart options 21 | const columnChartOptions = { 22 | chart: { 23 | type: 'bar', 24 | height: 430, 25 | toolbar: { 26 | show: false 27 | } 28 | }, 29 | plotOptions: { 30 | bar: { 31 | columnWidth: '30%', 32 | borderRadius: 4 33 | } 34 | }, 35 | dataLabels: { 36 | enabled: false 37 | }, 38 | stroke: { 39 | show: true, 40 | width: 8, 41 | colors: ['transparent'] 42 | }, 43 | xaxis: { 44 | categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'] 45 | }, 46 | yaxis: { 47 | title: { 48 | text: '$ (thousands)' 49 | } 50 | }, 51 | fill: { 52 | opacity: 1 53 | }, 54 | tooltip: { 55 | y: { 56 | formatter(val) { 57 | return `$ ${val} thousands`; 58 | } 59 | } 60 | }, 61 | legend: { 62 | show: false 63 | }, 64 | responsive: [ 65 | { 66 | breakpoint: 600, 67 | options: { 68 | yaxis: { 69 | show: false 70 | } 71 | } 72 | } 73 | ] 74 | }; 75 | 76 | const initialSeries = [ 77 | { 78 | name: 'Income', 79 | data: [180, 90, 135, 114, 120, 145] 80 | }, 81 | { 82 | name: 'Cost Of Sales', 83 | data: [120, 45, 78, 150, 168, 99] 84 | } 85 | ]; 86 | 87 | // ==============================|| SALES COLUMN CHART ||============================== // 88 | 89 | export default function SalesChart() { 90 | const theme = useTheme(); 91 | 92 | const [legend, setLegend] = useState({ 93 | income: true, 94 | cos: true 95 | }); 96 | 97 | const { income, cos } = legend; 98 | 99 | const { primary, secondary } = theme.palette.text; 100 | const line = theme.palette.divider; 101 | 102 | const warning = theme.palette.warning.main; 103 | const primaryMain = theme.palette.primary.main; 104 | const successDark = theme.palette.success.dark; 105 | 106 | const [series, setSeries] = useState(initialSeries); 107 | 108 | const handleLegendChange = (event) => { 109 | setLegend({ ...legend, [event.target.name]: event.target.checked }); 110 | }; 111 | 112 | const xsDown = useMediaQuery(theme.breakpoints.down('sm')); 113 | const [options, setOptions] = useState(columnChartOptions); 114 | 115 | useEffect(() => { 116 | if (income && cos) { 117 | setSeries(initialSeries); 118 | } else if (income) { 119 | setSeries([ 120 | { 121 | name: 'Income', 122 | data: [180, 90, 135, 114, 120, 145] 123 | } 124 | ]); 125 | } else if (cos) { 126 | setSeries([ 127 | { 128 | name: 'Cost Of Sales', 129 | data: [120, 45, 78, 150, 168, 99] 130 | } 131 | ]); 132 | } else { 133 | setSeries([]); 134 | } 135 | }, [income, cos]); 136 | 137 | useEffect(() => { 138 | setOptions((prevState) => ({ 139 | ...prevState, 140 | colors: !(income && cos) && cos ? [primaryMain] : [warning, primaryMain], 141 | xaxis: { 142 | labels: { 143 | style: { 144 | colors: [secondary, secondary, secondary, secondary, secondary, secondary] 145 | } 146 | } 147 | }, 148 | yaxis: { 149 | labels: { 150 | style: { 151 | colors: [secondary] 152 | } 153 | } 154 | }, 155 | grid: { 156 | borderColor: line 157 | }, 158 | plotOptions: { 159 | bar: { 160 | columnWidth: xsDown ? '60%' : '30%' 161 | } 162 | } 163 | })); 164 | }, [primary, secondary, line, warning, primaryMain, successDark, income, cos, xsDown]); 165 | 166 | return ( 167 | 168 | 169 | 170 | 171 | 172 | Net Profit 173 | 174 | $1560 175 | 176 | 177 | 178 | } 180 | label="Income" 181 | /> 182 | } label="Cost of Sales" /> 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | ); 192 | } 193 | -------------------------------------------------------------------------------- /ui-mantis/src/pages/dashboard/UniqueVisitorCard.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react'; 2 | 3 | // material-ui 4 | import Button from '@mui/material/Button'; 5 | import Grid from '@mui/material/Grid'; 6 | import Stack from '@mui/material/Stack'; 7 | import Typography from '@mui/material/Typography'; 8 | import Box from '@mui/material/Box'; 9 | 10 | // project import 11 | import MainCard from 'components/MainCard'; 12 | import IncomeAreaChart from './IncomeAreaChart'; 13 | 14 | // ==============================|| DEFAULT - UNIQUE VISITOR ||============================== // 15 | 16 | export default function UniqueVisitorCard() { 17 | const [slot, setSlot] = useState('week'); 18 | 19 | return ( 20 | <> 21 | 22 | 23 | Unique Visitor 24 | 25 | 26 | 27 | 35 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | ); 53 | } 54 | -------------------------------------------------------------------------------- /ui-mantis/src/pages/extra-pages/sample-page.jsx: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import Typography from '@mui/material/Typography'; 3 | 4 | // project import 5 | import MainCard from 'components/MainCard'; 6 | 7 | // ==============================|| SAMPLE PAGE ||============================== // 8 | 9 | export default function SamplePage() { 10 | return ( 11 | 12 | 13 | Lorem ipsum dolor sit amen, consenter nipissing eli, sed do elusion tempos incident ut laborers et doolie magna alissa. Ut enif ad 14 | minim venice, quin nostrum exercitation illampu laborings nisi ut liquid ex ea commons construal. Duos aube grue dolor in 15 | reprehended in voltage veil esse colum doolie eu fujian bulla parian. Exceptive sin ocean cuspidate non president, sunk in culpa qui 16 | officiate descent molls anim id est labours. 17 | 18 | 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /ui-mantis/src/pages/users/Billing.jsx: -------------------------------------------------------------------------------- 1 | // src/BillingDetail.js 2 | import React, { useEffect, useState } from 'react'; 3 | import { Paper, Typography, Grid } from '@mui/material'; 4 | import { useAuth } from 'contexts/authContext.jsx'; 5 | const BillingDetail = () => { 6 | const [billingData, setBillingData] = useState(null); 7 | const { user } = useAuth(); 8 | 9 | useEffect(() => { 10 | const fetchBillingData = async () => { 11 | const response = await fetch(`${import.meta.env.VITE_APP_PUBLIC_URL}/users/${user.id}`); 12 | const data = await response.json(); 13 | console.log(data); 14 | 15 | 16 | setBillingData(data); 17 | }; 18 | fetchBillingData(); 19 | }, []); 20 | 21 | return ( 22 | 23 | 24 | Billing Details 25 | 26 | 27 | 28 | 29 | Name: {billingData?.firstName} {billingData?.lastName} 30 | 31 | 32 | 33 | 34 | Email: {billingData?.email} 35 | 36 | 37 | 38 | 39 | Address: {billingData?.address}, {billingData?.country} 40 | 41 | 42 | 43 | 44 | Job: {billingData?.job} 45 | 46 | 47 | 48 | 49 | Bio: {billingData?.bio} 50 | 51 | 52 | 53 | 54 | ); 55 | }; 56 | 57 | export default BillingDetail; -------------------------------------------------------------------------------- /ui-mantis/src/pages/users/Detail.jsx: -------------------------------------------------------------------------------- 1 | // src/ProfileDetail.js 2 | import React, { useEffect, useState } from 'react'; 3 | import { Paper, Typography, Grid } from '@mui/material'; 4 | import { useParams } from 'react-router'; 5 | import { useAuth } from 'contexts/authContext'; 6 | 7 | const ProfileDetail = () => { 8 | const { id } = useParams(); 9 | const { user } = useAuth(); 10 | const [profileData, setProfileData] = useState(null); 11 | 12 | 13 | useEffect(() => { 14 | const fetchProfileData = async () => { 15 | const response = await fetch(`${import.meta.env.VITE_APP_PUBLIC_URL}/users/${id}`); 16 | const data = await response.json(); 17 | setProfileData(data); 18 | }; 19 | fetchProfileData(); 20 | }, []); 21 | 22 | 23 | return ( 24 | 25 | 26 | Profile Details 27 | 28 | 29 | 30 | Profile Avatar 40 | 41 | 42 | 43 | Name: {profileData?.firstName} {profileData?.lastName} 44 | 45 | 46 | 47 | 48 | Email: {profileData?.email} 49 | 50 | 51 | 52 | 53 | Job: {profileData?.job} 54 | 55 | 56 | 57 | 58 | Bio: {profileData?.bio} 59 | 60 | 61 | 62 | 63 | Country: {profileData?.country} 64 | 65 | 66 | 67 | 68 | Address: {profileData?.address} 69 | 70 | 71 | 72 | 73 | ); 74 | }; 75 | 76 | export default ProfileDetail; -------------------------------------------------------------------------------- /ui-mantis/src/pages/users/EditProfile.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { useParams } from 'react-router-dom'; 3 | import axios from 'axios'; 4 | import { Box, TextField, Button, Typography, Grid } from '@mui/material'; 5 | 6 | const EditProfile = () => { 7 | const { id } = useParams(); 8 | const [formData, setFormData] = useState({ 9 | firstName: '', 10 | lastName: '', 11 | email: '', 12 | bio: '', 13 | country: '', 14 | address: '', 15 | job: '' 16 | }); 17 | const [loading, setLoading] = useState(true); // Loading state to handle API call status 18 | 19 | // Fetch user data from the API 20 | useEffect(() => { 21 | const fetchUserData = async () => { 22 | try { 23 | const response = await axios.get(`${import.meta.env.VITE_APP_PUBLIC_URL}/users/${id}`); 24 | const user = response.data; 25 | console.log('User Data:', user); 26 | setFormData({ 27 | firstName: user.firstName || '', 28 | lastName: user.lastName || '', 29 | email: user.email || '', 30 | bio: user.bio || '', 31 | country: user.country || '', 32 | address: user.address || '', 33 | job: user.job || '' 34 | }); 35 | } catch (error) { 36 | console.error('Error fetching user data:', error); 37 | } finally { 38 | setLoading(false); 39 | } 40 | }; 41 | 42 | fetchUserData(); 43 | }, [id]); 44 | 45 | // Handle input changes 46 | const handleInputChange = (e) => { 47 | const { name, value } = e.target; 48 | setFormData((prevData) => ({ 49 | ...prevData, 50 | [name]: value 51 | })); 52 | }; 53 | 54 | // Handle form submission 55 | const handleSubmit = async (e) => { 56 | e.preventDefault(); 57 | try { 58 | console.log('Updated User Data:', formData); 59 | const user = JSON.parse(localStorage.getItem('mantis_user')) 60 | console.log(user); 61 | 62 | 63 | if (user.id != id && user.role != "admin") throw new Error("Wrong user signed in") 64 | 65 | const response = await axios.put( 66 | `${import.meta.env.VITE_APP_PUBLIC_URL}/users/${id}`, 67 | formData, 68 | { 69 | headers: { 70 | Authorization: `Bearer ${user.auth_token}`, 71 | }, 72 | } 73 | ); 74 | console.log('Profile updated', response.data); 75 | alert('Profile updated successfully!'); 76 | } catch (error) { 77 | console.error('Error updating user data:', error); 78 | alert('Failed to update profile. Please try again.'); 79 | } 80 | }; 81 | 82 | if (loading) { 83 | return ( 84 | 94 | Loading user data... 95 | 96 | ); 97 | } 98 | 99 | return ( 100 | 112 | 113 | Edit Profile 114 | 115 | 116 |
117 | 118 | 119 | 128 | 129 | 130 | 131 | 140 | 141 | 142 | 143 | 153 | 154 | 155 | 156 | 166 | 167 | 168 | 169 | 177 | 178 | 179 | 180 | 188 | 189 | 190 | 191 | 199 | 200 | 201 | 202 | 211 | 212 | 213 |
214 |
215 | ); 216 | }; 217 | 218 | export default EditProfile; 219 | -------------------------------------------------------------------------------- /ui-mantis/src/pages/users/UserManagement.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from 'react'; 2 | import { 3 | Box, 4 | Table, 5 | TableBody, 6 | TableCell, 7 | TableContainer, 8 | TableHead, 9 | TableRow, 10 | Button, 11 | Pagination, 12 | OutlinedInput, 13 | Stack 14 | } from '@mui/material'; 15 | import { useNavigate } from 'react-router-dom'; 16 | import axios from 'axios'; 17 | import { SearchOutlined } from '@ant-design/icons'; 18 | import { useAuth } from 'contexts/authContext.jsx'; 19 | 20 | const PAGE_SIZE = 5; 21 | const UserManagement = () => { 22 | const [users, setUsers] = useState([]); 23 | const [totalUsers, setTotalUsers] = useState(0); 24 | const [currentPage, setCurrentPage] = useState(1); 25 | 26 | const [searchValue, setSearchValue] = useState(''); 27 | const navigate = useNavigate(); 28 | const { setUser, user: loggedInUser } = useAuth(); 29 | 30 | const handlePageChange = (event, page) => { 31 | setCurrentPage(page); 32 | }; 33 | 34 | const fetchData = async (page, search) => { 35 | try { 36 | 37 | 38 | const response = await axios.get(`${import.meta.env.VITE_APP_PUBLIC_URL}/users?page=${page}&size=${PAGE_SIZE}&search=${search}`, {}); 39 | 40 | setUsers(response.data.data); 41 | setTotalUsers(response.data.meta.totalItems); 42 | 43 | } catch (error) { 44 | console.error('Error fetching profile data:', error); 45 | } 46 | }; 47 | 48 | useEffect(() => { 49 | fetchData(currentPage, searchValue); 50 | }, [currentPage, loggedInUser]); 51 | 52 | 53 | useEffect(() => { 54 | const checkUser = async () => { 55 | const urlParams = new URLSearchParams(window.location.search); 56 | let authUser = urlParams.get('user'); 57 | 58 | if (authUser) { 59 | localStorage.setItem('mantis_user', authUser); 60 | window.history.replaceState({}, document.title, window.location.pathname); 61 | } 62 | 63 | authUser = JSON.parse(localStorage.getItem('mantis_user')); 64 | setUser(authUser) 65 | 66 | } 67 | 68 | checkUser(); 69 | }, []); 70 | 71 | const handleEditUser = (userId) => { 72 | navigate(`/user/edit-profile/${userId}`); 73 | }; 74 | 75 | const handleDeleteUser = async (userId) => { 76 | try { 77 | const response = await axios.delete(`${import.meta.env.VITE_APP_PUBLIC_URL}/users/${userId}`, { 78 | headers: { 79 | Authorization: `Bearer ${user.auth_token}` 80 | } 81 | }); 82 | 83 | if (response.status === 200) { 84 | alert('User deleted successfully'); 85 | fetchData(currentPage, searchValue); 86 | } 87 | } catch (error) { 88 | console.error('Error deleting user:', error); 89 | } 90 | }; 91 | 92 | 93 | return ( 94 | 95 |

User Management

96 | 97 | } 100 | value={searchValue} 101 | onChange={(e) => setSearchValue(e.target.value)} 102 | /> 103 | 106 | 107 | 117 | 118 | 119 | 120 | ID 121 | First Name 122 | Last Name 123 | Email 124 | Bio 125 | Country 126 | Address 127 | Job 128 | Actions 129 | 130 | 131 | 132 | {users.map((user) => { 133 | const isUserRole = loggedInUser?.role === 'user'; 134 | const isCurrentUser = loggedInUser?.id === user.id; 135 | const isButtonEnabled = isUserRole ? isCurrentUser : true; 136 | 137 | return ( 138 | 139 | {user.id} 140 | {user.firstName} 141 | {user.lastName} 142 | {user.email} 143 | {user.bio} 144 | {user.country} 145 | {user.address} 146 | {user.job} 147 | 148 | <> 149 | 158 | 159 | 172 | 173 | 174 | 188 | 189 | 190 | 191 | 192 | ); 193 | })} 194 | 195 |
196 |
197 | 205 |
206 | ); 207 | }; 208 | 209 | export default UserManagement; 210 | -------------------------------------------------------------------------------- /ui-mantis/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = (onPerfEntry) => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /ui-mantis/src/routes/LoginRoutes.jsx: -------------------------------------------------------------------------------- 1 | import { lazy } from 'react'; 2 | 3 | // project import 4 | import Loadable from 'components/Loadable'; 5 | import MinimalLayout from 'layout/MinimalLayout'; 6 | 7 | // render - login 8 | const AuthLogin = Loadable(lazy(() => import('pages/authentication/login'))); 9 | const AuthRegister = Loadable(lazy(() => import('pages/authentication/register'))); 10 | 11 | // ==============================|| AUTH ROUTING ||============================== // 12 | 13 | const LoginRoutes = { 14 | path: '/', 15 | element: , 16 | children: [ 17 | { 18 | path: '/login', 19 | element: 20 | }, 21 | { 22 | path: '/register', 23 | element: 24 | } 25 | ] 26 | }; 27 | 28 | export default LoginRoutes; 29 | -------------------------------------------------------------------------------- /ui-mantis/src/routes/MainRoutes.jsx: -------------------------------------------------------------------------------- 1 | import { lazy } from 'react'; 2 | 3 | // project import 4 | import Loadable from 'components/Loadable'; 5 | import Dashboard from 'layout/Dashboard'; 6 | import EditProfile from 'pages/users/EditProfile'; 7 | import BillingPage from 'pages/users/Billing'; 8 | import ProfileDetail from 'pages/users/Detail'; 9 | 10 | const Color = Loadable(lazy(() => import('pages/component-overview/color'))); 11 | const Typography = Loadable(lazy(() => import('pages/component-overview/typography'))); 12 | const Shadow = Loadable(lazy(() => import('pages/component-overview/shadows'))); 13 | const DashboardDefault = Loadable(lazy(() => import('pages/dashboard/index'))); 14 | 15 | // render - sample page 16 | const SamplePage = Loadable(lazy(() => import('pages/extra-pages/sample-page'))); 17 | const UserManagement = Loadable(lazy(() => import('pages/users/UserManagement'))); 18 | 19 | // ==============================|| MAIN ROUTING ||============================== // 20 | 21 | const MainRoutes = { 22 | path: '/', 23 | element: , 24 | children: [ 25 | { 26 | path: '/', 27 | element: 28 | }, 29 | { 30 | path: 'color', 31 | element: 32 | }, 33 | { 34 | path: 'dashboard', 35 | children: [ 36 | { 37 | path: 'default', 38 | element: 39 | } 40 | ] 41 | }, 42 | { 43 | path: 'sample-page', 44 | element: 45 | }, 46 | { 47 | path: 'shadow', 48 | element: 49 | }, 50 | { 51 | path: 'typography', 52 | element: 53 | }, 54 | { 55 | path: 'usermanagement', 56 | element: 57 | }, 58 | { 59 | path: 'user/edit-profile/:id', 60 | element: 61 | }, 62 | { 63 | path: 'apps/invoice/details/1', 64 | element: 65 | }, 66 | { 67 | path: 'apps/profiles/account/:id', 68 | element: 69 | } 70 | ] 71 | }; 72 | 73 | export default MainRoutes; 74 | -------------------------------------------------------------------------------- /ui-mantis/src/routes/index.jsx: -------------------------------------------------------------------------------- 1 | import { createBrowserRouter } from 'react-router-dom'; 2 | 3 | // project import 4 | import MainRoutes from './MainRoutes'; 5 | import LoginRoutes from './LoginRoutes'; 6 | 7 | // ==============================|| ROUTING RENDER ||============================== // 8 | 9 | const router = createBrowserRouter([MainRoutes, LoginRoutes], { basename: import.meta.env.VITE_APP_BASE_NAME }); 10 | 11 | export default router; 12 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/index.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | import { useMemo } from 'react'; 3 | 4 | // material-ui 5 | import { CssBaseline, StyledEngineProvider } from '@mui/material'; 6 | import { createTheme, ThemeProvider } from '@mui/material/styles'; 7 | 8 | // project import 9 | import Palette from './palette'; 10 | import Typography from './typography'; 11 | import CustomShadows from './shadows'; 12 | import componentsOverride from './overrides'; 13 | 14 | // ==============================|| DEFAULT THEME - MAIN ||============================== // 15 | 16 | export default function ThemeCustomization({ children }) { 17 | const theme = Palette('light', 'default'); 18 | 19 | // eslint-disable-next-line react-hooks/exhaustive-deps 20 | const themeTypography = Typography(`'Public Sans', sans-serif`); 21 | const themeCustomShadows = useMemo(() => CustomShadows(theme), [theme]); 22 | 23 | const themeOptions = useMemo( 24 | () => ({ 25 | breakpoints: { 26 | values: { 27 | xs: 0, 28 | sm: 768, 29 | md: 1024, 30 | lg: 1266, 31 | xl: 1440 32 | } 33 | }, 34 | direction: 'ltr', 35 | mixins: { 36 | toolbar: { 37 | minHeight: 60, 38 | paddingTop: 8, 39 | paddingBottom: 8 40 | } 41 | }, 42 | palette: theme.palette, 43 | customShadows: themeCustomShadows, 44 | typography: themeTypography 45 | }), 46 | [theme, themeTypography, themeCustomShadows] 47 | ); 48 | 49 | const themes = createTheme(themeOptions); 50 | themes.components = componentsOverride(themes); 51 | 52 | return ( 53 | 54 | 55 | 56 | {children} 57 | 58 | 59 | ); 60 | } 61 | 62 | ThemeCustomization.propTypes = { 63 | children: PropTypes.node 64 | }; 65 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/overrides/Badge.js: -------------------------------------------------------------------------------- 1 | // project import 2 | import getColors from 'utils/getColors'; 3 | 4 | // ==============================|| BADGE - COLORS ||============================== // 5 | 6 | function getColorStyle({ color, theme }) { 7 | const colors = getColors(theme, color); 8 | const { lighter, main } = colors; 9 | 10 | return { 11 | color: main, 12 | backgroundColor: lighter 13 | }; 14 | } 15 | 16 | // ==============================|| OVERRIDES - BADGE ||============================== // 17 | 18 | export default function Badge(theme) { 19 | const defaultLightBadge = getColorStyle({ color: 'primary', theme }); 20 | 21 | return { 22 | MuiBadge: { 23 | styleOverrides: { 24 | standard: { 25 | minWidth: theme.spacing(2), 26 | height: theme.spacing(2), 27 | padding: theme.spacing(0.5) 28 | }, 29 | light: { 30 | ...defaultLightBadge, 31 | '&.MuiBadge-colorPrimary': getColorStyle({ color: 'primary', theme }), 32 | '&.MuiBadge-colorSecondary': getColorStyle({ color: 'secondary', theme }), 33 | '&.MuiBadge-colorError': getColorStyle({ color: 'error', theme }), 34 | '&.MuiBadge-colorInfo': getColorStyle({ color: 'info', theme }), 35 | '&.MuiBadge-colorSuccess': getColorStyle({ color: 'success', theme }), 36 | '&.MuiBadge-colorWarning': getColorStyle({ color: 'warning', theme }) 37 | } 38 | } 39 | } 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/overrides/Button.js: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import { alpha } from '@mui/material/styles'; 3 | 4 | // project import 5 | import getColors from 'utils/getColors'; 6 | import getShadow from 'utils/getShadow'; 7 | 8 | function getColorStyle({ variant, color, theme }) { 9 | const colors = getColors(theme, color); 10 | const { lighter, main, dark, darker, contrastText } = colors; 11 | 12 | const buttonShadow = `${color}Button`; 13 | const shadows = getShadow(theme, buttonShadow); 14 | 15 | const commonShadow = { 16 | '&::after': { 17 | boxShadow: `0 0 5px 5px ${alpha(main, 0.9)}` 18 | }, 19 | '&:active::after': { 20 | boxShadow: `0 0 0 0 ${alpha(main, 0.9)}` 21 | }, 22 | '&:focus-visible': { 23 | outline: `2px solid ${dark}`, 24 | outlineOffset: 2 25 | } 26 | }; 27 | 28 | switch (variant) { 29 | case 'contained': 30 | return { 31 | '&:hover': { 32 | backgroundColor: dark 33 | }, 34 | ...commonShadow 35 | }; 36 | case 'shadow': 37 | return { 38 | color: contrastText, 39 | backgroundColor: main, 40 | boxShadow: shadows, 41 | '&:hover': { 42 | boxShadow: 'none', 43 | backgroundColor: dark 44 | }, 45 | ...commonShadow 46 | }; 47 | case 'outlined': 48 | return { 49 | borderColor: main, 50 | '&:hover': { 51 | color: dark, 52 | backgroundColor: 'transparent', 53 | borderColor: dark 54 | }, 55 | ...commonShadow 56 | }; 57 | case 'dashed': 58 | return { 59 | color: main, 60 | borderColor: main, 61 | backgroundColor: lighter, 62 | '&:hover': { 63 | color: dark, 64 | borderColor: dark 65 | }, 66 | ...commonShadow 67 | }; 68 | case 'text': 69 | default: 70 | return { 71 | color: dark, 72 | '&:hover': { 73 | color: darker, 74 | backgroundColor: lighter 75 | }, 76 | ...commonShadow 77 | }; 78 | } 79 | } 80 | 81 | // ==============================|| OVERRIDES - BUTTON ||============================== // 82 | 83 | export default function Button(theme) { 84 | const primaryDashed = getColorStyle({ variant: 'dashed', color: 'primary', theme }); 85 | const primaryShadow = getColorStyle({ variant: 'shadow', color: 'primary', theme }); 86 | 87 | const disabledStyle = { 88 | '&.Mui-disabled': { 89 | backgroundColor: theme.palette.grey[200] 90 | } 91 | }; 92 | const iconStyle = { 93 | '&>*:nth-of-type(1)': { 94 | fontSize: 'inherit' 95 | } 96 | }; 97 | 98 | return { 99 | MuiButton: { 100 | defaultProps: { 101 | disableElevation: true 102 | }, 103 | styleOverrides: { 104 | root: { 105 | fontWeight: 400, 106 | '&::after': { 107 | content: '""', 108 | display: 'block', 109 | position: 'absolute', 110 | left: 0, 111 | top: 0, 112 | width: '100%', 113 | height: '100%', 114 | borderRadius: 4, 115 | opacity: 0, 116 | transition: 'all 0.5s' 117 | }, 118 | 119 | '&:active::after': { 120 | position: 'absolute', 121 | borderRadius: 4, 122 | left: 0, 123 | top: 0, 124 | opacity: 1, 125 | transition: '0s' 126 | } 127 | }, 128 | contained: { 129 | ...disabledStyle 130 | }, 131 | outlined: { 132 | ...disabledStyle 133 | }, 134 | text: { 135 | boxShadow: 'none', 136 | '&:hover': { 137 | boxShadow: 'none' 138 | } 139 | }, 140 | endIcon: { 141 | ...iconStyle 142 | }, 143 | startIcon: { 144 | ...iconStyle 145 | }, 146 | dashed: { 147 | border: '1px dashed', 148 | ...primaryDashed, 149 | '&.MuiButton-dashedPrimary': getColorStyle({ variant: 'dashed', color: 'primary', theme }), 150 | '&.MuiButton-dashedSecondary': getColorStyle({ variant: 'dashed', color: 'secondary', theme }), 151 | '&.MuiButton-dashedError': getColorStyle({ variant: 'dashed', color: 'error', theme }), 152 | '&.MuiButton-dashedSuccess': getColorStyle({ variant: 'dashed', color: 'success', theme }), 153 | '&.MuiButton-dashedInfo': getColorStyle({ variant: 'dashed', color: 'info', theme }), 154 | '&.MuiButton-dashedWarning': getColorStyle({ variant: 'dashed', color: 'warning', theme }), 155 | '&.Mui-disabled': { 156 | color: `${theme.palette.grey[300]} !important`, 157 | borderColor: `${theme.palette.grey[400]} !important`, 158 | backgroundColor: `${theme.palette.grey[200]} !important` 159 | } 160 | }, 161 | shadow: { 162 | ...primaryShadow, 163 | '&.MuiButton-shadowPrimary': getColorStyle({ variant: 'shadow', color: 'primary', theme }), 164 | '&.MuiButton-shadowSecondary': getColorStyle({ variant: 'shadow', color: 'secondary', theme }), 165 | '&.MuiButton-shadowError': getColorStyle({ variant: 'shadow', color: 'error', theme }), 166 | '&.MuiButton-shadowSuccess': getColorStyle({ variant: 'shadow', color: 'success', theme }), 167 | '&.MuiButton-shadowInfo': getColorStyle({ variant: 'shadow', color: 'info', theme }), 168 | '&.MuiButton-shadowWarning': getColorStyle({ variant: 'shadow', color: 'warning', theme }), 169 | '&.Mui-disabled': { 170 | color: `${theme.palette.grey[300]} !important`, 171 | borderColor: `${theme.palette.grey[400]} !important`, 172 | backgroundColor: `${theme.palette.grey[200]} !important` 173 | } 174 | }, 175 | containedPrimary: getColorStyle({ variant: 'contained', color: 'primary', theme }), 176 | containedSecondary: getColorStyle({ variant: 'contained', color: 'secondary', theme }), 177 | containedError: getColorStyle({ variant: 'contained', color: 'error', theme }), 178 | containedSuccess: getColorStyle({ variant: 'contained', color: 'success', theme }), 179 | containedInfo: getColorStyle({ variant: 'contained', color: 'info', theme }), 180 | containedWarning: getColorStyle({ variant: 'contained', color: 'warning', theme }), 181 | outlinedPrimary: getColorStyle({ variant: 'outlined', color: 'primary', theme }), 182 | outlinedSecondary: getColorStyle({ variant: 'outlined', color: 'secondary', theme }), 183 | outlinedError: getColorStyle({ variant: 'outlined', color: 'error', theme }), 184 | outlinedSuccess: getColorStyle({ variant: 'outlined', color: 'success', theme }), 185 | outlinedInfo: getColorStyle({ variant: 'outlined', color: 'info', theme }), 186 | outlinedWarning: getColorStyle({ variant: 'outlined', color: 'warning', theme }), 187 | textPrimary: getColorStyle({ variant: 'text', color: 'primary', theme }), 188 | textSecondary: getColorStyle({ variant: 'text', color: 'secondary', theme }), 189 | textError: getColorStyle({ variant: 'text', color: 'error', theme }), 190 | textSuccess: getColorStyle({ variant: 'text', color: 'success', theme }), 191 | textInfo: getColorStyle({ variant: 'text', color: 'info', theme }), 192 | textWarning: getColorStyle({ variant: 'text', color: 'warning', theme }), 193 | sizeExtraSmall: { 194 | minWidth: 56, 195 | fontSize: '0.625rem', 196 | padding: '2px 8px' 197 | } 198 | } 199 | } 200 | }; 201 | } 202 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/overrides/CardContent.js: -------------------------------------------------------------------------------- 1 | // ==============================|| OVERRIDES - CARD CONTENT ||============================== // 2 | 3 | export default function CardContent() { 4 | return { 5 | MuiCardContent: { 6 | styleOverrides: { 7 | root: { 8 | padding: 20, 9 | '&:last-child': { 10 | paddingBottom: 20 11 | } 12 | } 13 | } 14 | } 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/overrides/Checkbox.jsx: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | // project import 4 | import getColors from 'utils/getColors'; 5 | 6 | // assets 7 | import BorderOutlined from '@ant-design/icons/BorderOutlined'; 8 | import CheckSquareFilled from '@ant-design/icons/CheckSquareFilled'; 9 | import MinusSquareFilled from '@ant-design/icons/MinusSquareFilled'; 10 | 11 | // ==============================|| RADIO - COLORS ||============================== // 12 | 13 | function getColorStyle({ color, theme }) { 14 | const colors = getColors(theme, color); 15 | const { lighter, main, dark } = colors; 16 | 17 | return { 18 | '&:hover': { 19 | backgroundColor: lighter, 20 | '& .icon': { 21 | borderColor: main 22 | } 23 | }, 24 | '&.Mui-focusVisible': { 25 | outline: `2px solid ${dark}`, 26 | outlineOffset: -4 27 | } 28 | }; 29 | } 30 | 31 | function getSizeStyle(size) { 32 | switch (size) { 33 | case 'small': 34 | return { fontSize: 1.15 }; 35 | case 'large': 36 | return { fontSize: 1.6 }; 37 | case 'medium': 38 | default: 39 | return { fontSize: 1.35 }; 40 | } 41 | } 42 | 43 | // ==============================|| CHECKBOX - STYLE ||============================== // 44 | 45 | function checkboxStyle(size) { 46 | const sizes = getSizeStyle(size); 47 | 48 | return { 49 | '& .icon': { 50 | fontSize: `${sizes.fontSize}rem` 51 | } 52 | }; 53 | } 54 | 55 | // ==============================|| OVERRIDES - CHECKBOX ||============================== // 56 | 57 | export default function Checkbox(theme) { 58 | const { palette } = theme; 59 | 60 | return { 61 | MuiCheckbox: { 62 | defaultProps: { 63 | className: 'size-small', 64 | icon: , 65 | checkedIcon: , 66 | indeterminateIcon: 67 | }, 68 | styleOverrides: { 69 | root: { 70 | borderRadius: 0, 71 | color: palette.secondary[300], 72 | '&.size-small': { 73 | ...checkboxStyle('small') 74 | }, 75 | '&.size-medium': { 76 | ...checkboxStyle('medium') 77 | }, 78 | '&.size-large': { 79 | ...checkboxStyle('large') 80 | } 81 | }, 82 | colorPrimary: getColorStyle({ color: 'primary', theme }), 83 | colorSecondary: getColorStyle({ color: 'secondary', theme }), 84 | colorSuccess: getColorStyle({ color: 'success', theme }), 85 | colorWarning: getColorStyle({ color: 'warning', theme }), 86 | colorInfo: getColorStyle({ color: 'info', theme }), 87 | colorError: getColorStyle({ color: 'error', theme }) 88 | } 89 | } 90 | }; 91 | } 92 | 93 | getColorStyle.propTypes = { color: PropTypes.any, theme: PropTypes.any }; 94 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/overrides/Chip.js: -------------------------------------------------------------------------------- 1 | // project import 2 | import getColors from 'utils/getColors'; 3 | 4 | // ==============================|| CHIP - COLORS ||============================== // 5 | 6 | function getColor({ color, theme }) { 7 | const colors = getColors(theme, color); 8 | const { dark } = colors; 9 | 10 | return { 11 | '&.Mui-focusVisible': { 12 | outline: `2px solid ${dark}`, 13 | outlineOffset: 2 14 | } 15 | }; 16 | } 17 | 18 | function getColorStyle({ color, theme }) { 19 | const colors = getColors(theme, color); 20 | const { light, lighter, main } = colors; 21 | 22 | return { 23 | color: main, 24 | backgroundColor: lighter, 25 | borderColor: light, 26 | '& .MuiChip-deleteIcon': { 27 | color: main, 28 | '&:hover': { 29 | color: light 30 | } 31 | } 32 | }; 33 | } 34 | 35 | // ==============================|| OVERRIDES - CHIP ||============================== // 36 | 37 | export default function Chip(theme) { 38 | const defaultLightChip = getColorStyle({ color: 'secondary', theme }); 39 | return { 40 | MuiChip: { 41 | styleOverrides: { 42 | root: { 43 | borderRadius: 4, 44 | '&:active': { 45 | boxShadow: 'none' 46 | }, 47 | '&.MuiChip-colorPrimary': getColor({ color: 'primary', theme }), 48 | '&.MuiChip-colorSecondary': getColor({ color: 'secondary', theme }), 49 | '&.MuiChip-colorError': getColor({ color: 'error', theme }), 50 | '&.MuiChip-colorInfo': getColor({ color: 'info', theme }), 51 | '&.MuiChip-colorSuccess': getColor({ color: 'success', theme }), 52 | '&.MuiChip-colorWarning': getColor({ color: 'warning', theme }) 53 | }, 54 | sizeLarge: { 55 | fontSize: '1rem', 56 | height: 40 57 | }, 58 | light: { 59 | ...defaultLightChip, 60 | '&.MuiChip-lightPrimary': getColorStyle({ color: 'primary', theme }), 61 | '&.MuiChip-lightSecondary': getColorStyle({ color: 'secondary', theme }), 62 | '&.MuiChip-lightError': getColorStyle({ color: 'error', theme }), 63 | '&.MuiChip-lightInfo': getColorStyle({ color: 'info', theme }), 64 | '&.MuiChip-lightSuccess': getColorStyle({ color: 'success', theme }), 65 | '&.MuiChip-lightWarning': getColorStyle({ color: 'warning', theme }) 66 | }, 67 | combined: { 68 | border: '1px solid', 69 | ...defaultLightChip, 70 | '&.MuiChip-combinedPrimary': getColorStyle({ color: 'primary', theme }), 71 | '&.MuiChip-combinedSecondary': getColorStyle({ color: 'secondary', theme }), 72 | '&.MuiChip-combinedError': getColorStyle({ color: 'error', theme }), 73 | '&.MuiChip-combinedInfo': getColorStyle({ color: 'info', theme }), 74 | '&.MuiChip-combinedSuccess': getColorStyle({ color: 'success', theme }), 75 | '&.MuiChip-combinedWarning': getColorStyle({ color: 'warning', theme }) 76 | } 77 | } 78 | } 79 | }; 80 | } 81 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/overrides/IconButton.js: -------------------------------------------------------------------------------- 1 | // ==============================|| OVERRIDES - ICON BUTTON ||============================== // 2 | 3 | export default function IconButton(theme) { 4 | return { 5 | MuiIconButton: { 6 | styleOverrides: { 7 | root: { 8 | borderRadius: 4 9 | }, 10 | sizeLarge: { 11 | width: theme.spacing(5.5), 12 | height: theme.spacing(5.5), 13 | fontSize: '1.25rem' 14 | }, 15 | sizeMedium: { 16 | width: theme.spacing(4.5), 17 | height: theme.spacing(4.5), 18 | fontSize: '1rem' 19 | }, 20 | sizeSmall: { 21 | width: theme.spacing(3.75), 22 | height: theme.spacing(3.75), 23 | fontSize: '0.75rem' 24 | } 25 | } 26 | } 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/overrides/InputLabel.js: -------------------------------------------------------------------------------- 1 | // ==============================|| OVERRIDES - INPUT LABEL ||============================== // 2 | 3 | export default function InputLabel(theme) { 4 | return { 5 | MuiInputLabel: { 6 | styleOverrides: { 7 | root: { 8 | color: theme.palette.grey[600] 9 | }, 10 | outlined: { 11 | lineHeight: '1rem', 12 | top: -4, 13 | '&.MuiInputLabel-sizeSmall': { 14 | lineHeight: '1em' 15 | }, 16 | '&.MuiInputLabel-shrink': { 17 | background: theme.palette.background.paper, 18 | padding: '0 8px', 19 | marginLeft: -6, 20 | top: 2, 21 | lineHeight: '1rem' 22 | } 23 | } 24 | } 25 | } 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/overrides/LinearProgress.js: -------------------------------------------------------------------------------- 1 | // ==============================|| OVERRIDES - LINER PROGRESS ||============================== // 2 | 3 | export default function LinearProgress() { 4 | return { 5 | MuiLinearProgress: { 6 | styleOverrides: { 7 | root: { 8 | height: 6, 9 | borderRadius: 100 10 | }, 11 | bar: { 12 | borderRadius: 100 13 | } 14 | } 15 | } 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/overrides/Link.js: -------------------------------------------------------------------------------- 1 | // ==============================|| OVERRIDES - LINK ||============================== // 2 | 3 | export default function Link() { 4 | return { 5 | MuiLink: { 6 | defaultProps: { 7 | underline: 'hover' 8 | } 9 | } 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/overrides/ListItemIcon.jsx: -------------------------------------------------------------------------------- 1 | // ==============================|| OVERRIDES - LIST ITEM ICON ||============================== // 2 | 3 | export default function ListItemIcon() { 4 | return { 5 | MuiListItemIcon: { 6 | styleOverrides: { 7 | root: { 8 | minWidth: 24 9 | } 10 | } 11 | } 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/overrides/OutlinedInput.js: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import { alpha } from '@mui/material/styles'; 3 | 4 | // ==============================|| OVERRIDES - OUTLINED INPUT ||============================== // 5 | 6 | export default function OutlinedInput(theme) { 7 | return { 8 | MuiOutlinedInput: { 9 | styleOverrides: { 10 | input: { 11 | padding: '10.5px 14px 10.5px 12px' 12 | }, 13 | notchedOutline: { 14 | borderColor: theme.palette.grey[300] 15 | }, 16 | root: { 17 | '&:hover .MuiOutlinedInput-notchedOutline': { 18 | borderColor: theme.palette.primary.light 19 | }, 20 | '&.Mui-focused': { 21 | boxShadow: `0 0 0 2px ${alpha(theme.palette.primary.main, 0.2)}`, 22 | '& .MuiOutlinedInput-notchedOutline': { 23 | border: `1px solid ${theme.palette.primary.light}` 24 | } 25 | }, 26 | '&.Mui-error': { 27 | '&:hover .MuiOutlinedInput-notchedOutline': { 28 | borderColor: theme.palette.error.light 29 | }, 30 | '&.Mui-focused': { 31 | boxShadow: `0 0 0 2px ${alpha(theme.palette.error.main, 0.2)}`, 32 | '& .MuiOutlinedInput-notchedOutline': { 33 | border: `1px solid ${theme.palette.error.light}` 34 | } 35 | } 36 | } 37 | }, 38 | inputSizeSmall: { 39 | padding: '7.5px 8px 7.5px 12px' 40 | }, 41 | inputMultiline: { 42 | padding: 0 43 | } 44 | } 45 | } 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/overrides/Tab.js: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import { alpha } from '@mui/material/styles'; 3 | 4 | // ==============================|| OVERRIDES - TAB ||============================== // 5 | 6 | export default function Tab(theme) { 7 | return { 8 | MuiTab: { 9 | styleOverrides: { 10 | root: { 11 | minHeight: 46, 12 | color: theme.palette.text.primary, 13 | borderRadius: 4, 14 | '&:hover': { 15 | backgroundColor: alpha(theme.palette.primary.lighter, 0.6), 16 | color: theme.palette.primary.main 17 | }, 18 | '&:focus-visible': { 19 | borderRadius: 4, 20 | outline: `2px solid ${theme.palette.secondary.dark}`, 21 | outlineOffset: -3 22 | } 23 | } 24 | } 25 | } 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/overrides/TableCell.js: -------------------------------------------------------------------------------- 1 | // ==============================|| OVERRIDES - TABLE CELL ||============================== // 2 | 3 | export default function TableCell(theme) { 4 | const commonCell = { 5 | '&:not(:last-of-type)': { 6 | position: 'relative', 7 | '&:after': { 8 | position: 'absolute', 9 | content: '""', 10 | backgroundColor: theme.palette.divider, 11 | width: 1, 12 | height: 'calc(100% - 30px)', 13 | right: 0, 14 | top: 16 15 | } 16 | } 17 | }; 18 | 19 | return { 20 | MuiTableCell: { 21 | styleOverrides: { 22 | root: { 23 | fontSize: '0.875rem', 24 | padding: 12, 25 | borderColor: theme.palette.divider, 26 | '&.cell-right': { 27 | justifyContent: 'flex-end', 28 | textAlign: 'right', 29 | '& > *': { 30 | justifyContent: 'flex-end', 31 | margin: '0 0 0 auto' 32 | }, 33 | '& .MuiOutlinedInput-input': { 34 | textAlign: 'right' 35 | } 36 | }, 37 | '&.cell-center': { 38 | justifyContent: 'center', 39 | textAlign: 'center', 40 | '& > *': { 41 | justifyContent: 'center', 42 | margin: '0 auto' 43 | } 44 | } 45 | }, 46 | sizeSmall: { 47 | padding: 8 48 | }, 49 | head: { 50 | fontSize: '0.75rem', 51 | fontWeight: 700, 52 | textTransform: 'uppercase', 53 | ...commonCell 54 | }, 55 | footer: { 56 | fontSize: '0.75rem', 57 | textTransform: 'uppercase', 58 | ...commonCell 59 | } 60 | } 61 | } 62 | }; 63 | } 64 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/overrides/Tabs.js: -------------------------------------------------------------------------------- 1 | // ==============================|| OVERRIDES - TABS ||============================== // 2 | 3 | export default function Tabs() { 4 | return { 5 | MuiTabs: { 6 | styleOverrides: { 7 | vertical: { 8 | overflow: 'visible' 9 | } 10 | } 11 | } 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/overrides/Typography.js: -------------------------------------------------------------------------------- 1 | // ==============================|| OVERRIDES - TYPOGRAPHY ||============================== // 2 | 3 | export default function Typography() { 4 | return { 5 | MuiTypography: { 6 | styleOverrides: { 7 | gutterBottom: { 8 | marginBottom: 12 9 | } 10 | } 11 | } 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/overrides/index.js: -------------------------------------------------------------------------------- 1 | // third-party 2 | import { merge } from 'lodash'; 3 | 4 | // project import 5 | import Badge from './Badge'; 6 | import Button from './Button'; 7 | import CardContent from './CardContent'; 8 | import Checkbox from './Checkbox'; 9 | import Chip from './Chip'; 10 | import IconButton from './IconButton'; 11 | import InputLabel from './InputLabel'; 12 | import LinearProgress from './LinearProgress'; 13 | import Link from './Link'; 14 | import ListItemIcon from './ListItemIcon'; 15 | import OutlinedInput from './OutlinedInput'; 16 | import Tab from './Tab'; 17 | import TableCell from './TableCell'; 18 | import Tabs from './Tabs'; 19 | import Typography from './Typography'; 20 | 21 | // ==============================|| OVERRIDES - MAIN ||============================== // 22 | 23 | export default function ComponentsOverrides(theme) { 24 | return merge( 25 | Button(theme), 26 | Badge(theme), 27 | CardContent(), 28 | Checkbox(theme), 29 | Chip(theme), 30 | IconButton(theme), 31 | InputLabel(theme), 32 | LinearProgress(), 33 | Link(), 34 | ListItemIcon(), 35 | OutlinedInput(theme), 36 | Tab(theme), 37 | TableCell(theme), 38 | Tabs(), 39 | Typography() 40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/palette.js: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import { createTheme } from '@mui/material/styles'; 3 | 4 | // third-party 5 | import { presetPalettes } from '@ant-design/colors'; 6 | 7 | // project import 8 | import ThemeOption from './theme'; 9 | 10 | // ==============================|| DEFAULT THEME - PALETTE ||============================== // 11 | 12 | export default function Palette(mode, presetColor) { 13 | const colors = presetPalettes; 14 | 15 | let greyPrimary = [ 16 | '#ffffff', 17 | '#fafafa', 18 | '#f5f5f5', 19 | '#f0f0f0', 20 | '#d9d9d9', 21 | '#bfbfbf', 22 | '#8c8c8c', 23 | '#595959', 24 | '#262626', 25 | '#141414', 26 | '#000000' 27 | ]; 28 | let greyAscent = ['#fafafa', '#bfbfbf', '#434343', '#1f1f1f']; 29 | let greyConstant = ['#fafafb', '#e6ebf1']; 30 | 31 | colors.grey = [...greyPrimary, ...greyAscent, ...greyConstant]; 32 | 33 | const paletteColor = ThemeOption(colors, presetColor, mode); 34 | 35 | return createTheme({ 36 | palette: { 37 | mode, 38 | common: { 39 | black: '#000', 40 | white: '#fff' 41 | }, 42 | ...paletteColor, 43 | text: { 44 | primary: paletteColor.grey[700], 45 | secondary: paletteColor.grey[500], 46 | disabled: paletteColor.grey[400] 47 | }, 48 | action: { 49 | disabled: paletteColor.grey[300] 50 | }, 51 | divider: paletteColor.grey[200], 52 | background: { 53 | paper: paletteColor.grey[0], 54 | default: paletteColor.grey.A50 55 | } 56 | } 57 | }); 58 | } 59 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/shadows.jsx: -------------------------------------------------------------------------------- 1 | // material-ui 2 | import { alpha } from '@mui/material/styles'; 3 | 4 | // ==============================|| DEFAULT THEME - CUSTOM SHADOWS ||============================== // 5 | 6 | export default function CustomShadows(theme) { 7 | return { 8 | button: `0 2px #0000000b`, 9 | text: `0 -1px 0 rgb(0 0 0 / 12%)`, 10 | z1: `0px 2px 8px ${alpha(theme.palette.grey[900], 0.15)}` 11 | // only available in paid version 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/theme/index.js: -------------------------------------------------------------------------------- 1 | // ==============================|| PRESET THEME - THEME SELECTOR ||============================== // 2 | 3 | export default function Theme(colors) { 4 | const { blue, red, gold, cyan, green, grey } = colors; 5 | const greyColors = { 6 | 0: grey[0], 7 | 50: grey[1], 8 | 100: grey[2], 9 | 200: grey[3], 10 | 300: grey[4], 11 | 400: grey[5], 12 | 500: grey[6], 13 | 600: grey[7], 14 | 700: grey[8], 15 | 800: grey[9], 16 | 900: grey[10], 17 | A50: grey[15], 18 | A100: grey[11], 19 | A200: grey[12], 20 | A400: grey[13], 21 | A700: grey[14], 22 | A800: grey[16] 23 | }; 24 | const contrastText = '#fff'; 25 | 26 | return { 27 | primary: { 28 | lighter: blue[0], 29 | 100: blue[1], 30 | 200: blue[2], 31 | light: blue[3], 32 | 400: blue[4], 33 | main: blue[5], 34 | dark: blue[6], 35 | 700: blue[7], 36 | darker: blue[8], 37 | 900: blue[9], 38 | contrastText 39 | }, 40 | secondary: { 41 | lighter: greyColors[100], 42 | 100: greyColors[100], 43 | 200: greyColors[200], 44 | light: greyColors[300], 45 | 400: greyColors[400], 46 | main: greyColors[500], 47 | 600: greyColors[600], 48 | dark: greyColors[700], 49 | 800: greyColors[800], 50 | darker: greyColors[900], 51 | A100: greyColors[0], 52 | A200: greyColors.A400, 53 | A300: greyColors.A700, 54 | contrastText: greyColors[0] 55 | }, 56 | error: { 57 | lighter: red[0], 58 | light: red[2], 59 | main: red[4], 60 | dark: red[7], 61 | darker: red[9], 62 | contrastText 63 | }, 64 | warning: { 65 | lighter: gold[0], 66 | light: gold[3], 67 | main: gold[5], 68 | dark: gold[7], 69 | darker: gold[9], 70 | contrastText: greyColors[100] 71 | }, 72 | info: { 73 | lighter: cyan[0], 74 | light: cyan[3], 75 | main: cyan[5], 76 | dark: cyan[7], 77 | darker: cyan[9], 78 | contrastText 79 | }, 80 | success: { 81 | lighter: green[0], 82 | light: green[3], 83 | main: green[5], 84 | dark: green[7], 85 | darker: green[9], 86 | contrastText 87 | }, 88 | grey: greyColors 89 | }; 90 | } 91 | -------------------------------------------------------------------------------- /ui-mantis/src/themes/typography.js: -------------------------------------------------------------------------------- 1 | // ==============================|| DEFAULT THEME - TYPOGRAPHY ||============================== // 2 | 3 | export default function Typography(fontFamily) { 4 | return { 5 | htmlFontSize: 16, 6 | fontFamily, 7 | fontWeightLight: 300, 8 | fontWeightRegular: 400, 9 | fontWeightMedium: 500, 10 | fontWeightBold: 600, 11 | h1: { 12 | fontWeight: 600, 13 | fontSize: '2.375rem', 14 | lineHeight: 1.21 15 | }, 16 | h2: { 17 | fontWeight: 600, 18 | fontSize: '1.875rem', 19 | lineHeight: 1.27 20 | }, 21 | h3: { 22 | fontWeight: 600, 23 | fontSize: '1.5rem', 24 | lineHeight: 1.33 25 | }, 26 | h4: { 27 | fontWeight: 600, 28 | fontSize: '1.25rem', 29 | lineHeight: 1.4 30 | }, 31 | h5: { 32 | fontWeight: 600, 33 | fontSize: '1rem', 34 | lineHeight: 1.5 35 | }, 36 | h6: { 37 | fontWeight: 400, 38 | fontSize: '0.875rem', 39 | lineHeight: 1.57 40 | }, 41 | caption: { 42 | fontWeight: 400, 43 | fontSize: '0.75rem', 44 | lineHeight: 1.66 45 | }, 46 | body1: { 47 | fontSize: '0.875rem', 48 | lineHeight: 1.57 49 | }, 50 | body2: { 51 | fontSize: '0.75rem', 52 | lineHeight: 1.66 53 | }, 54 | subtitle1: { 55 | fontSize: '0.875rem', 56 | fontWeight: 600, 57 | lineHeight: 1.57 58 | }, 59 | subtitle2: { 60 | fontSize: '0.75rem', 61 | fontWeight: 500, 62 | lineHeight: 1.66 63 | }, 64 | overline: { 65 | lineHeight: 1.66 66 | }, 67 | button: { 68 | textTransform: 'capitalize' 69 | } 70 | }; 71 | } 72 | -------------------------------------------------------------------------------- /ui-mantis/src/utils/getColors.js: -------------------------------------------------------------------------------- 1 | // ==============================|| CUSTOM FUNCTION - COLORS ||============================== // 2 | 3 | const getColors = (theme, color) => { 4 | switch (color) { 5 | case 'secondary': 6 | return theme.palette.secondary; 7 | case 'error': 8 | return theme.palette.error; 9 | case 'warning': 10 | return theme.palette.warning; 11 | case 'info': 12 | return theme.palette.info; 13 | case 'success': 14 | return theme.palette.success; 15 | default: 16 | return theme.palette.primary; 17 | } 18 | }; 19 | 20 | export default getColors; 21 | -------------------------------------------------------------------------------- /ui-mantis/src/utils/getShadow.js: -------------------------------------------------------------------------------- 1 | import PropTypes from 'prop-types'; 2 | 3 | // ==============================|| CUSTOM FUNCTION - COLOR SHADOWS ||============================== // 4 | 5 | const getShadow = (theme, shadow) => { 6 | switch (shadow) { 7 | case 'secondary': 8 | return theme.customShadows.secondary; 9 | case 'error': 10 | return theme.customShadows.error; 11 | case 'warning': 12 | return theme.customShadows.warning; 13 | case 'info': 14 | return theme.customShadows.info; 15 | case 'success': 16 | return theme.customShadows.success; 17 | case 'primaryButton': 18 | return theme.customShadows.primaryButton; 19 | case 'secondaryButton': 20 | return theme.customShadows.secondaryButton; 21 | case 'errorButton': 22 | return theme.customShadows.errorButton; 23 | case 'warningButton': 24 | return theme.customShadows.warningButton; 25 | case 'infoButton': 26 | return theme.customShadows.infoButton; 27 | case 'successButton': 28 | return theme.customShadows.successButton; 29 | default: 30 | return theme.customShadows.primary; 31 | } 32 | }; 33 | 34 | getShadow.propTypes = { 35 | theme: PropTypes.object, 36 | shadow: PropTypes.string 37 | }; 38 | 39 | export default getShadow; 40 | -------------------------------------------------------------------------------- /ui-mantis/src/utils/password-strength.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Password validator for login pages 3 | */ 4 | 5 | // has number 6 | const hasNumber = (number) => new RegExp(/[0-9]/).test(number); 7 | 8 | // has mix of small and capitals 9 | const hasMixed = (number) => new RegExp(/[a-z]/).test(number) && new RegExp(/[A-Z]/).test(number); 10 | 11 | // has special chars 12 | const hasSpecial = (number) => new RegExp(/[!#@$%^&*)(+=._-]/).test(number); 13 | 14 | // set color based on password strength 15 | export const strengthColor = (count) => { 16 | if (count < 2) return { label: 'Poor', color: 'error.main' }; 17 | if (count < 3) return { label: 'Weak', color: 'warning.main' }; 18 | if (count < 4) return { label: 'Normal', color: 'warning.dark' }; 19 | if (count < 5) return { label: 'Good', color: 'success.main' }; 20 | if (count < 6) return { label: 'Strong', color: 'success.dark' }; 21 | return { label: 'Poor', color: 'error.main' }; 22 | }; 23 | 24 | // password strength indicator 25 | export const strengthIndicator = (number) => { 26 | let strengths = 0; 27 | if (number.length > 5) strengths += 1; 28 | if (number.length > 7) strengths += 1; 29 | if (hasNumber(number)) strengths += 1; 30 | if (hasSpecial(number)) strengths += 1; 31 | if (hasMixed(number)) strengths += 1; 32 | return strengths; 33 | }; 34 | -------------------------------------------------------------------------------- /ui-mantis/src/utils/password-validation.js: -------------------------------------------------------------------------------- 1 | function isNumber(value) { 2 | return new RegExp('^(?=.*[0-9]).+$').test(value); 3 | } 4 | 5 | function isLowercaseChar(value) { 6 | return new RegExp('^(?=.*[a-z]).+$').test(value); 7 | } 8 | 9 | function isUppercaseChar(value) { 10 | return new RegExp('^(?=.*[A-Z]).+$').test(value); 11 | } 12 | 13 | function isSpecialChar(value) { 14 | return new RegExp('^(?=.*[-+_!@#$%^&*.,?]).+$').test(value); 15 | } 16 | 17 | function minLength(value) { 18 | return value.length > 7; 19 | } 20 | 21 | export { isNumber, isLowercaseChar, isUppercaseChar, isSpecialChar, minLength }; 22 | -------------------------------------------------------------------------------- /ui-mantis/src/vite-env.d.js: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /ui-mantis/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "composite": true, 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "allowSyntheticDefaultImports": true 7 | }, 8 | "include": ["vite.config.js"] 9 | } 10 | -------------------------------------------------------------------------------- /ui-mantis/vite.config.mjs: -------------------------------------------------------------------------------- 1 | // https://github.com/vitejs/vite/discussions/3448 2 | import path from 'path'; 3 | import { defineConfig } from 'vite'; 4 | import react from '@vitejs/plugin-react'; 5 | import jsconfigPaths from 'vite-jsconfig-paths'; 6 | 7 | // ---------------------------------------------------------------------- 8 | 9 | export default defineConfig({ 10 | plugins: [react(), jsconfigPaths()], 11 | // https://github.com/jpuri/react-draft-wysiwyg/issues/1317 12 | base: '/free', // accessing env variable is not possible here. So hard coding this. 13 | define: { 14 | global: 'window' 15 | }, 16 | resolve: { 17 | alias: [ 18 | { 19 | find: /^~(.+)/, 20 | replacement: path.join(process.cwd(), 'node_modules/$1') 21 | }, 22 | { 23 | find: /^src(.+)/, 24 | replacement: path.join(process.cwd(), 'src/$1') 25 | } 26 | ] 27 | }, 28 | server: { 29 | strictPort: true, 30 | host: true, 31 | origin: 'http://0.0.0.0:4000', 32 | port: 4000 33 | }, 34 | preview: { 35 | strictPort: true, 36 | host: true, 37 | origin: 'http://0.0.0.0:4000', 38 | port: 4000 39 | } 40 | }); 41 | --------------------------------------------------------------------------------