├── backend
├── .gitignore
├── config
│ ├── index.js
│ └── passport.js
├── libs
│ └── db-connection.js
├── README.md
├── server.js
├── package.json
├── validation
│ ├── login.js
│ ├── update.js
│ └── register.js
└── models
│ └── User.js
└── frontend
├── public
├── _redirects
├── assets
│ ├── preview.jpg
│ ├── transparent.png
│ ├── images
│ │ ├── covers
│ │ │ ├── cover_1.jpg
│ │ │ ├── cover_2.jpg
│ │ │ ├── cover_3.jpg
│ │ │ ├── cover_4.jpg
│ │ │ ├── cover_5.jpg
│ │ │ ├── cover_6.jpg
│ │ │ ├── cover_7.jpg
│ │ │ ├── cover_8.jpg
│ │ │ ├── cover_9.jpg
│ │ │ ├── cover_10.jpg
│ │ │ ├── cover_11.jpg
│ │ │ ├── cover_12.jpg
│ │ │ ├── cover_13.jpg
│ │ │ ├── cover_14.jpg
│ │ │ ├── cover_15.jpg
│ │ │ ├── cover_16.jpg
│ │ │ ├── cover_17.jpg
│ │ │ ├── cover_18.jpg
│ │ │ ├── cover_19.jpg
│ │ │ ├── cover_20.jpg
│ │ │ ├── cover_21.jpg
│ │ │ ├── cover_22.jpg
│ │ │ ├── cover_23.jpg
│ │ │ └── cover_24.jpg
│ │ ├── avatars
│ │ │ ├── avatar_1.jpg
│ │ │ ├── avatar_2.jpg
│ │ │ ├── avatar_3.jpg
│ │ │ ├── avatar_4.jpg
│ │ │ ├── avatar_5.jpg
│ │ │ ├── avatar_6.jpg
│ │ │ ├── avatar_7.jpg
│ │ │ ├── avatar_8.jpg
│ │ │ ├── avatar_9.jpg
│ │ │ ├── avatar_10.jpg
│ │ │ ├── avatar_11.jpg
│ │ │ ├── avatar_12.jpg
│ │ │ ├── avatar_13.jpg
│ │ │ ├── avatar_14.jpg
│ │ │ ├── avatar_15.jpg
│ │ │ ├── avatar_16.jpg
│ │ │ ├── avatar_17.jpg
│ │ │ ├── avatar_18.jpg
│ │ │ ├── avatar_19.jpg
│ │ │ ├── avatar_20.jpg
│ │ │ ├── avatar_21.jpg
│ │ │ ├── avatar_22.jpg
│ │ │ ├── avatar_23.jpg
│ │ │ ├── avatar_24.jpg
│ │ │ └── avatar_default.jpg
│ │ └── products
│ │ │ ├── product_1.jpg
│ │ │ ├── product_10.jpg
│ │ │ ├── product_11.jpg
│ │ │ ├── product_12.jpg
│ │ │ ├── product_13.jpg
│ │ │ ├── product_14.jpg
│ │ │ ├── product_15.jpg
│ │ │ ├── product_16.jpg
│ │ │ ├── product_17.jpg
│ │ │ ├── product_18.jpg
│ │ │ ├── product_19.jpg
│ │ │ ├── product_2.jpg
│ │ │ ├── product_20.jpg
│ │ │ ├── product_21.jpg
│ │ │ ├── product_22.jpg
│ │ │ ├── product_23.jpg
│ │ │ ├── product_24.jpg
│ │ │ ├── product_3.jpg
│ │ │ ├── product_4.jpg
│ │ │ ├── product_5.jpg
│ │ │ ├── product_6.jpg
│ │ │ ├── product_7.jpg
│ │ │ ├── product_8.jpg
│ │ │ └── product_9.jpg
│ ├── illustrations
│ │ ├── illustration_avatar.png
│ │ └── illustration_login.png
│ ├── icons
│ │ ├── shape-avatar.svg
│ │ ├── ic_flag_fr.svg
│ │ ├── navbar
│ │ │ ├── ic_disabled.svg
│ │ │ ├── ic_user.svg
│ │ │ ├── ic_blog.svg
│ │ │ ├── ic_lock.svg
│ │ │ ├── ic_cart.svg
│ │ │ └── ic_analytics.svg
│ │ ├── ic_flag_en.svg
│ │ ├── ic_flag_de.svg
│ │ ├── ic_notification_mail.svg
│ │ ├── ic_notification_shipping.svg
│ │ ├── ic_notification_chat.svg
│ │ └── ic_notification_package.svg
│ ├── placeholder.svg
│ └── logo.svg
├── favicon
│ ├── favicon.ico
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── apple-touch-icon.png
│ ├── android-chrome-192x192.png
│ └── android-chrome-512x512.png
├── manifest.json
└── index.html
├── src
├── components
│ ├── label
│ │ ├── index.js
│ │ ├── Label.js
│ │ └── styles.js
│ ├── logo
│ │ ├── index.js
│ │ └── Logo.js
│ ├── iconify
│ │ ├── index.js
│ │ └── Iconify.js
│ ├── nav-section
│ │ ├── index.js
│ │ └── styles.js
│ ├── scrollbar
│ │ ├── index.js
│ │ ├── styles.js
│ │ └── Scrollbar.js
│ ├── svg-color
│ │ ├── index.js
│ │ └── SvgColor.js
│ ├── scroll-to-top
│ │ ├── index.js
│ │ └── ScrollToTop.js
│ ├── color-utils
│ │ ├── index.js
│ │ ├── ColorSinglePicker.js
│ │ ├── ColorPreview.js
│ │ ├── ColorMultiPicker.js
│ │ └── Icon.js
│ └── chart
│ │ ├── index.js
│ │ └── styles.js
├── layouts
│ ├── simple
│ │ ├── index.js
│ │ └── SimpleLayout.js
│ └── dashboard
│ │ ├── index.js
│ │ ├── nav
│ │ └── config.js
│ │ ├── DashboardLayout.js
│ │ └── header
│ │ ├── index.js
│ │ ├── Searchbar.js
│ │ ├── LanguagePopover.js
│ │ └── AccountPopover.js
├── sections
│ ├── Error
│ │ ├── Error.css
│ │ └── Error.jsx
│ ├── auth
│ │ └── login
│ │ │ ├── index.js
│ │ │ └── login.js
│ └── @dashboard
│ │ ├── user
│ │ ├── index.js
│ │ ├── UserListHead.js
│ │ └── UserListToolbar.js
│ │ ├── blog
│ │ ├── index.js
│ │ ├── BlogPostsSort.js
│ │ └── BlogPostsSearch.js
│ │ ├── products
│ │ ├── index.js
│ │ ├── ProductList.js
│ │ ├── ProductCartWidget.js
│ │ ├── ProductSort.js
│ │ └── ProductCard.js
│ │ └── app
│ │ ├── index.js
│ │ ├── AppTrafficBySite.js
│ │ ├── AppWebsiteVisits.js
│ │ ├── AppConversionRates.js
│ │ ├── AppWidgetSummary.js
│ │ ├── AppCurrentSubject.js
│ │ ├── AppOrderTimeline.js
│ │ ├── AppNewsUpdate.js
│ │ └── AppCurrentVisits.js
├── pages
│ ├── style.css
│ ├── ProductsPage.js
│ ├── BlogPage.js
│ ├── Page404.js
│ ├── ProfilePage.js
│ ├── LoginPage.js
│ ├── RegisterPage.js
│ ├── styles
│ │ └── styles.css
│ └── EditPage.js
├── style.css
├── utils
│ ├── setAuthToken.js
│ ├── formatTime.js
│ ├── formatNumber.js
│ └── cssStyles.js
├── _mock
│ ├── account.js
│ ├── Dashboards.js
│ ├── user.js
│ ├── blog.js
│ └── products.js
├── redux
│ ├── actions
│ │ ├── types.js
│ │ └── authActions.js
│ ├── reducers
│ │ ├── errorReducer.js
│ │ ├── getReducer.js
│ │ ├── updateReducer.js
│ │ ├── checkedReducer.js
│ │ ├── authReducer.js
│ │ └── index.js
│ └── store.js
├── theme
│ ├── overrides
│ │ ├── Autocomplete.js
│ │ ├── Paper.js
│ │ ├── Table.js
│ │ ├── Tooltip.js
│ │ ├── Typography.js
│ │ ├── Backdrop.js
│ │ ├── index.js
│ │ ├── Card.js
│ │ ├── Button.js
│ │ └── Input.js
│ ├── index.js
│ ├── customShadows.js
│ ├── globalStyles.js
│ ├── palette.js
│ ├── typography.js
│ └── shadows.js
├── reportWebVitals.js
├── index.js
├── App.js
├── hooks
│ └── useResponsive.js
└── routes.js
├── .prettierrc
├── jsconfig.json
├── .gitignore
├── LICENSE.md
├── CHANGELOG.md
├── README.md
├── .eslintrc
└── package.json
/backend/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/frontend/public/_redirects:
--------------------------------------------------------------------------------
1 | /* /index.html 200
--------------------------------------------------------------------------------
/frontend/src/components/label/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './Label';
2 |
--------------------------------------------------------------------------------
/frontend/src/components/logo/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './Logo';
2 |
--------------------------------------------------------------------------------
/frontend/src/components/iconify/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './Iconify';
2 |
--------------------------------------------------------------------------------
/frontend/src/layouts/simple/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './SimpleLayout';
2 |
--------------------------------------------------------------------------------
/frontend/src/components/nav-section/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './NavSection';
2 |
--------------------------------------------------------------------------------
/frontend/src/components/scrollbar/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './Scrollbar';
2 |
--------------------------------------------------------------------------------
/frontend/src/components/svg-color/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './SvgColor';
2 |
--------------------------------------------------------------------------------
/frontend/src/layouts/dashboard/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './DashboardLayout';
2 |
--------------------------------------------------------------------------------
/frontend/src/components/scroll-to-top/index.js:
--------------------------------------------------------------------------------
1 | export { default } from './ScrollToTop';
2 |
--------------------------------------------------------------------------------
/frontend/src/sections/Error/Error.css:
--------------------------------------------------------------------------------
1 | .Error-Output {
2 | color: red;
3 | font-size: 12px;
4 | padding: 3px 15px;
5 | }
--------------------------------------------------------------------------------
/backend/config/index.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | MONGO_URL: "mongodb://localhost:27017/tmp",
3 | jwtSecret: "abc123",
4 | };
5 |
--------------------------------------------------------------------------------
/frontend/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "printWidth": 120,
3 | "singleQuote": true,
4 | "trailingComma": "es5",
5 | "tabWidth": 2
6 | }
7 |
--------------------------------------------------------------------------------
/frontend/public/assets/preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/preview.jpg
--------------------------------------------------------------------------------
/frontend/public/favicon/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/favicon/favicon.ico
--------------------------------------------------------------------------------
/frontend/public/assets/transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/transparent.png
--------------------------------------------------------------------------------
/frontend/src/pages/style.css:
--------------------------------------------------------------------------------
1 | html, body, #root, #root > div {
2 | height: 100%;
3 | margin: 0;
4 | box-sizing: border-box;
5 | }
--------------------------------------------------------------------------------
/frontend/public/favicon/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/favicon/favicon-16x16.png
--------------------------------------------------------------------------------
/frontend/public/favicon/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/favicon/favicon-32x32.png
--------------------------------------------------------------------------------
/frontend/public/favicon/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/favicon/apple-touch-icon.png
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_1.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_2.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_3.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_4.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_5.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_6.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_7.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_8.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_9.jpg
--------------------------------------------------------------------------------
/frontend/src/sections/auth/login/index.js:
--------------------------------------------------------------------------------
1 | export { default as LoginForm } from './LoginForm';
2 | export { default as RegisterForm } from './RegisterForm';
3 |
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_1.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_2.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_3.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_4.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_5.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_6.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_7.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_8.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_9.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_10.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_11.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_12.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_12.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_13.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_13.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_14.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_14.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_15.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_15.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_16.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_16.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_17.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_17.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_18.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_18.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_19.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_19.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_20.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_20.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_21.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_21.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_22.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_22.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_23.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_23.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/covers/cover_24.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/covers/cover_24.jpg
--------------------------------------------------------------------------------
/frontend/public/favicon/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/favicon/android-chrome-192x192.png
--------------------------------------------------------------------------------
/frontend/public/favicon/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/favicon/android-chrome-512x512.png
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_10.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_11.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_12.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_12.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_13.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_13.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_14.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_14.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_15.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_15.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_16.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_16.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_17.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_17.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_18.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_18.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_19.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_19.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_20.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_20.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_21.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_21.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_22.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_22.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_23.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_23.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_24.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_24.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_1.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_10.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_11.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_12.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_12.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_13.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_13.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_14.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_14.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_15.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_15.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_16.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_16.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_17.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_17.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_18.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_18.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_19.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_19.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_2.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_20.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_20.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_21.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_21.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_22.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_22.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_23.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_23.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_24.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_24.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_3.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_4.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_5.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_6.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_7.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_8.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/images/products/product_9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/products/product_9.jpg
--------------------------------------------------------------------------------
/frontend/src/style.css:
--------------------------------------------------------------------------------
1 | html, body, #root, #root > div {
2 | height: 100%;
3 | margin: 0;
4 | box-sizing: border-box;
5 | background-repeat: repeat;
6 | }
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/user/index.js:
--------------------------------------------------------------------------------
1 | export { default as UserListHead } from './UserListHead';
2 | export { default as UserListToolbar } from './UserListToolbar';
3 |
--------------------------------------------------------------------------------
/frontend/public/assets/images/avatars/avatar_default.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/images/avatars/avatar_default.jpg
--------------------------------------------------------------------------------
/frontend/public/assets/illustrations/illustration_avatar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/illustrations/illustration_avatar.png
--------------------------------------------------------------------------------
/frontend/public/assets/illustrations/illustration_login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/frozen-dev71/Social_Dashboard/master/frontend/public/assets/illustrations/illustration_login.png
--------------------------------------------------------------------------------
/frontend/src/sections/Error/Error.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import './Error.css';
3 |
4 | const Error = props =>
{ props.children }
;
5 |
6 | export default Error;
7 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/blog/index.js:
--------------------------------------------------------------------------------
1 | export { default as BlogPostCard } from './BlogPostCard';
2 | export { default as BlogPostsSearch } from './BlogPostsSearch';
3 | export { default as BlogPostsSort } from './BlogPostsSort';
4 |
--------------------------------------------------------------------------------
/frontend/src/components/color-utils/index.js:
--------------------------------------------------------------------------------
1 | export { default as ColorPreview } from './ColorPreview';
2 | export { default as ColorMultiPicker } from './ColorMultiPicker';
3 | export { default as ColorSinglePicker } from './ColorSinglePicker';
4 |
--------------------------------------------------------------------------------
/frontend/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6",
4 | "module": "commonjs",
5 | "baseUrl": "."
6 | },
7 | "include": [
8 | "src/**/*"
9 | ],
10 | "exclude": [
11 | "node_modules"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/src/utils/setAuthToken.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 | const setAuthToken = (token) => {
4 | if (token) axios.defaults.headers.common.Authorization = token;
5 | else delete axios.defaults.headers.common.Authorization;
6 | };
7 |
8 | export default setAuthToken;
9 |
--------------------------------------------------------------------------------
/frontend/src/_mock/account.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | const account = {
4 | displayName: 'Jaydon Frankie',
5 | email: 'demo@minimals.cc',
6 | photoURL: '/assets/images/avatars/avatar_default.jpg',
7 | };
8 |
9 | export default account;
10 |
--------------------------------------------------------------------------------
/frontend/src/redux/actions/types.js:
--------------------------------------------------------------------------------
1 | export const TEST_DISPATCH = 'TEST_DISPATCH';
2 | export const GET_ERRORS = 'GET_ERRORS';
3 | export const SET_CURRENT_USER = 'SET_CURRENT_USER';
4 | export const CHECKED_USER = 'CHECKED_USER';
5 | export const UPDATE_USER = 'UPDATE_USER';
6 | export const GET_USER = 'GET_USER';
--------------------------------------------------------------------------------
/frontend/src/components/chart/index.js:
--------------------------------------------------------------------------------
1 | import Chart from 'react-apexcharts';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export { default as StyledChart } from './styles';
6 |
7 | export { default as useChart } from './useChart';
8 |
9 | export default Chart;
10 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/shape-avatar.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/src/redux/reducers/errorReducer.js:
--------------------------------------------------------------------------------
1 | import { GET_ERRORS } from "../actions/types";
2 |
3 | const initialState = {};
4 |
5 | export default (state = initialState, action) => {
6 | switch (action.type) {
7 | case GET_ERRORS:
8 | return action.payload;
9 | default:
10 | return state;
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/products/index.js:
--------------------------------------------------------------------------------
1 | export { default as ProductCard } from './ProductCard';
2 | export { default as ProductList } from './ProductList';
3 | export { default as ProductSort } from './ProductSort';
4 | export { default as ProductCartWidget } from './ProductCartWidget';
5 | export { default as ProductFilterSidebar } from './ProductFilterSidebar';
6 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Autocomplete.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Autocomplete(theme) {
4 | return {
5 | MuiAutocomplete: {
6 | styleOverrides: {
7 | paper: {
8 | boxShadow: theme.customShadows.z20,
9 | },
10 | },
11 | },
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/src/redux/store.js:
--------------------------------------------------------------------------------
1 | import { configureStore } from '@reduxjs/toolkit';
2 | import thunk from 'redux-thunk';
3 | import rootReducer from './reducers';
4 |
5 | const store = configureStore({
6 | reducer: rootReducer,
7 | middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(thunk),
8 | devTools: process.env.NODE_ENV !== 'production',
9 | });
10 |
11 | export default store;
12 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Paper.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Paper() {
4 | return {
5 | MuiPaper: {
6 | defaultProps: {
7 | elevation: 0,
8 | },
9 | styleOverrides: {
10 | root: {
11 | backgroundImage: 'none',
12 | },
13 | },
14 | },
15 | };
16 | }
17 |
--------------------------------------------------------------------------------
/frontend/src/redux/reducers/getReducer.js:
--------------------------------------------------------------------------------
1 | import { GET_USER } from '../actions/types';
2 |
3 | const initialState = {
4 | user: {},
5 | };
6 |
7 | export default (state = initialState, action) => {
8 | switch (action.type) {
9 | case GET_USER:
10 | return {
11 | ...state,
12 | user: action.payload,
13 | };
14 | default:
15 | return state;
16 | }
17 | };
18 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Table.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Table(theme) {
4 | return {
5 | MuiTableCell: {
6 | styleOverrides: {
7 | head: {
8 | color: theme.palette.text.secondary,
9 | backgroundColor: theme.palette.background.neutral,
10 | },
11 | },
12 | },
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/frontend/src/components/scroll-to-top/ScrollToTop.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react';
2 | import { useLocation } from 'react-router-dom';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | export default function ScrollToTop() {
7 | const { pathname } = useLocation();
8 |
9 | useEffect(() => {
10 | window.scrollTo(0, 0);
11 | }, [pathname]);
12 |
13 | return null;
14 | }
15 |
--------------------------------------------------------------------------------
/frontend/public/assets/placeholder.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/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 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Tooltip.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Tooltip(theme) {
4 | return {
5 | MuiTooltip: {
6 | styleOverrides: {
7 | tooltip: {
8 | backgroundColor: theme.palette.grey[800],
9 | },
10 | arrow: {
11 | color: theme.palette.grey[800],
12 | },
13 | },
14 | },
15 | };
16 | }
17 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Typography.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Typography(theme) {
4 | return {
5 | MuiTypography: {
6 | styleOverrides: {
7 | paragraph: {
8 | marginBottom: theme.spacing(2),
9 | },
10 | gutterBottom: {
11 | marginBottom: theme.spacing(1),
12 | },
13 | },
14 | },
15 | };
16 | }
17 |
--------------------------------------------------------------------------------
/frontend/src/redux/reducers/updateReducer.js:
--------------------------------------------------------------------------------
1 | import { UPDATE_USER } from '../actions/types';
2 |
3 | // const currentUser = await axios.get('http://localhost:5000/api/users/register');
4 |
5 | const initialState = {}
6 |
7 | export default (state = initialState, action) => {
8 | switch (action.type) {
9 | case UPDATE_USER:
10 | return {
11 | user: action.payload
12 | };
13 | default:
14 | return state;
15 | }
16 | };
17 |
--------------------------------------------------------------------------------
/backend/libs/db-connection.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 | const { MONGO_URL } = require('../config/index');
3 | // Allow Promises
4 | mongoose.Promise = global.Promise;
5 | // Connection
6 | mongoose.connect(MONGO_URL, { useNewUrlParser: true });
7 | // Validation
8 | mongoose.connection
9 | .on('open', () => console.info('Database connected!'))
10 | .on('error', err => console.info('Create a database and put the link into config/index.js/MONGO_URL'));
--------------------------------------------------------------------------------
/frontend/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | /.env
17 | /.env.local
18 | /.env.development.local
19 | /.env.test.local
20 | /.env.production.local
21 |
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
26 | .eslintcache
27 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/ic_flag_fr.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/src/redux/reducers/checkedReducer.js:
--------------------------------------------------------------------------------
1 | import { CHECKED_USER } from "../actions/types";
2 |
3 | const initialState = {
4 | checked: false,
5 | password: '',
6 | };
7 |
8 | export default (state = initialState, action) => {
9 | switch (action.type) {
10 | case CHECKED_USER:
11 | return {
12 | ...state,
13 | checked: action.payload.result,
14 | password: action.payload.pwd,
15 | };
16 | default:
17 | return state;
18 | }
19 | };
20 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Backdrop.js:
--------------------------------------------------------------------------------
1 | import { alpha } from '@mui/material/styles';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export default function Backdrop(theme) {
6 | return {
7 | MuiBackdrop: {
8 | styleOverrides: {
9 | root: {
10 | backgroundColor: alpha(theme.palette.grey[800], 0.8),
11 | },
12 | invisible: {
13 | background: 'transparent',
14 | },
15 | },
16 | },
17 | };
18 | }
19 |
--------------------------------------------------------------------------------
/frontend/src/redux/reducers/authReducer.js:
--------------------------------------------------------------------------------
1 | import { SET_CURRENT_USER } from '../actions/types';
2 |
3 | const initialState = {
4 | isAuthenticated: false,
5 | user: {},
6 | };
7 |
8 | export default (state = initialState, action) => {
9 | switch (action.type) {
10 | case SET_CURRENT_USER:
11 | return {
12 | ...state,
13 | isAuthenticated: Object.keys(action.payload).length > 0,
14 | user: action.payload,
15 | };
16 | default:
17 | return state;
18 | }
19 | };
20 |
--------------------------------------------------------------------------------
/frontend/src/redux/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import authReducer from './authReducer';
3 | import errorReducer from './errorReducer';
4 | import checkedReducer from './checkedReducer';
5 | import updateReducer from './updateReducer';
6 | import getReducer from './getReducer';
7 |
8 | const rootReducer = combineReducers({
9 | auth: authReducer,
10 | checked: checkedReducer,
11 | errors: errorReducer,
12 | update: updateReducer,
13 | get: getReducer,
14 | });
15 |
16 | export default rootReducer;
--------------------------------------------------------------------------------
/frontend/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Minimal App",
3 | "name": "React Material Minimal UI Kit",
4 | "icons": [
5 | {
6 | "src": "favicon/android-chrome-192x192.png",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | },
10 | {
11 | "src": "favicon/android-chrome-512x512.png",
12 | "sizes": "512x512",
13 | "type": "image/png"
14 | }
15 | ],
16 | "start_url": ".",
17 | "display": "standalone",
18 | "theme_color": "#000000",
19 | "background_color": "#ffffff"
20 | }
21 |
--------------------------------------------------------------------------------
/frontend/src/_mock/Dashboards.js:
--------------------------------------------------------------------------------
1 | const Dashboards = {
2 | "dashboards": [
3 | {
4 | "name": "facebook",
5 | "favorite": true,
6 | },
7 | {
8 | "name": "Google",
9 | "favorite": true,
10 | },
11 | {
12 | "name": "Google Analytics",
13 | "favorite": false,
14 | },
15 | {
16 | "name": "Instagram",
17 | "favorite": false,
18 | },
19 | {
20 | "name": "twitter",
21 | "favorite": false,
22 | },
23 | ]
24 | };
25 |
26 | export default Dashboards;
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/app/index.js:
--------------------------------------------------------------------------------
1 | export { default as AppTasks } from './AppTasks';
2 | export { default as AppNewsUpdate } from './AppNewsUpdate';
3 | export { default as AppCurrentVisits } from './AppCurrentVisits';
4 | export { default as AppOrderTimeline } from './AppOrderTimeline';
5 | export { default as AppTrafficBySite } from './AppTrafficBySite';
6 | export { default as AppWebsiteVisits } from './AppWebsiteVisits';
7 | export { default as AppWidgetSummary } from './AppWidgetSummary';
8 | export { default as AppCurrentSubject } from './AppCurrentSubject';
9 | export { default as AppConversionRates } from './AppConversionRates';
10 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/blog/BlogPostsSort.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // @mui
3 | import { MenuItem, TextField } from '@mui/material';
4 |
5 | // ----------------------------------------------------------------------
6 |
7 | BlogPostsSort.propTypes = {
8 | options: PropTypes.array,
9 | onSort: PropTypes.func,
10 | };
11 |
12 | export default function BlogPostsSort({ options, onSort }) {
13 | return (
14 |
15 | {options.map((option) => (
16 |
19 | ))}
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/products/ProductList.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // @mui
3 | import { Grid } from '@mui/material';
4 | import ShopProductCard from './ProductCard';
5 |
6 | // ----------------------------------------------------------------------
7 |
8 | ProductList.propTypes = {
9 | products: PropTypes.array.isRequired,
10 | };
11 |
12 | export default function ProductList({ products, ...other }) {
13 | return (
14 |
15 | {products.map((product) => (
16 |
17 |
18 |
19 | ))}
20 |
21 | );
22 | }
23 |
--------------------------------------------------------------------------------
/backend/README.md:
--------------------------------------------------------------------------------
1 | # MERN Authentication System
2 |
3 | 🔐 Authentication System with JWT using the MERN Stack: MongoDB, Express.js, Reactjs & Node.js
4 |
5 | ## Installation
6 |
7 | ```bash
8 | # Install dependencies for server
9 | npm install
10 |
11 | # Install dependencies for client
12 | npm run client-install
13 |
14 | # Run the client & server with concurrently
15 | npm run dev
16 |
17 | # Run the Express server only
18 | npm run server
19 |
20 | # Run the React client only
21 | npm run client
22 |
23 | # Server runs on http://localhost:5000 and client on http://localhost:3000
24 | ```
25 |
26 | ## Author
27 |
28 | **germancutraro**
29 |
30 | ## Why
31 |
32 | * Practice
33 | * Reuse code, earn time
34 | * MERN Lover
35 |
--------------------------------------------------------------------------------
/frontend/src/components/iconify/Iconify.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { forwardRef } from 'react';
3 | // icons
4 | import { Icon } from '@iconify/react';
5 | // @mui
6 | import { Box } from '@mui/material';
7 |
8 | // ----------------------------------------------------------------------
9 |
10 | const Iconify = forwardRef(({ icon, width = 20, sx, ...other }, ref) => (
11 |
12 | ));
13 |
14 | Iconify.propTypes = {
15 | sx: PropTypes.object,
16 | width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
17 | icon: PropTypes.oneOfType([PropTypes.element, PropTypes.string]),
18 | };
19 |
20 | export default Iconify;
21 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/navbar/ic_disabled.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/index.js:
--------------------------------------------------------------------------------
1 | //
2 | import Card from './Card';
3 | import Paper from './Paper';
4 | import Input from './Input';
5 | import Table from './Table';
6 | import Button from './Button';
7 | import Tooltip from './Tooltip';
8 | import Backdrop from './Backdrop';
9 | import Typography from './Typography';
10 | import Autocomplete from './Autocomplete';
11 |
12 | // ----------------------------------------------------------------------
13 |
14 | export default function ComponentsOverrides(theme) {
15 | return Object.assign(
16 | Card(theme),
17 | Table(theme),
18 | Input(theme),
19 | Paper(theme),
20 | Button(theme),
21 | Tooltip(theme),
22 | Backdrop(theme),
23 | Typography(theme),
24 | Autocomplete(theme)
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/frontend/src/utils/formatTime.js:
--------------------------------------------------------------------------------
1 | import { format, getTime, formatDistanceToNow } from 'date-fns';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export function fDate(date, newFormat) {
6 | const fm = newFormat || 'dd MMM yyyy';
7 |
8 | return date ? format(new Date(date), fm) : '';
9 | }
10 |
11 | export function fDateTime(date, newFormat) {
12 | const fm = newFormat || 'dd MMM yyyy p';
13 |
14 | return date ? format(new Date(date), fm) : '';
15 | }
16 |
17 | export function fTimestamp(date) {
18 | return date ? getTime(new Date(date)) : '';
19 | }
20 |
21 | export function fToNow(date) {
22 | return date
23 | ? formatDistanceToNow(new Date(date), {
24 | addSuffix: true,
25 | })
26 | : '';
27 | }
28 |
--------------------------------------------------------------------------------
/frontend/src/layouts/dashboard/nav/config.js:
--------------------------------------------------------------------------------
1 | // component
2 | import SvgColor from '../../../components/svg-color';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | const icon = (name) => ;
7 |
8 | const navConfig = [
9 | {
10 | title: 'teams',
11 | path: '/user',
12 | icon: icon('ic_user'),
13 | },
14 | {
15 | title: 'Setting',
16 | path: '/edit',
17 | icon: icon('ic_cart'),
18 | },
19 | {
20 | title: 'Sign Out',
21 | path: '/login',
22 | icon: icon('ic_lock'),
23 | },
24 | {
25 | title: 'Not found',
26 | path: '/404',
27 | icon: icon('ic_disabled'),
28 | },
29 | ];
30 |
31 | export default navConfig;
32 |
--------------------------------------------------------------------------------
/frontend/src/components/nav-section/styles.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { styled } from '@mui/material/styles';
3 | import { ListItemIcon, ListItemButton } from '@mui/material';
4 |
5 | // ----------------------------------------------------------------------
6 |
7 | export const StyledNavItem = styled((props) => )(({ theme }) => ({
8 | ...theme.typography.body2,
9 | height: 48,
10 | position: 'relative',
11 | textTransform: 'capitalize',
12 | color: theme.palette.text.secondary,
13 | borderRadius: theme.shape.borderRadius,
14 | }));
15 |
16 | export const StyledNavItemIcon = styled(ListItemIcon)({
17 | width: 22,
18 | height: 22,
19 | color: 'inherit',
20 | display: 'flex',
21 | alignItems: 'center',
22 | justifyContent: 'center',
23 | });
24 |
--------------------------------------------------------------------------------
/backend/config/passport.js:
--------------------------------------------------------------------------------
1 | const JwtStrategy = require('passport-jwt').Strategy,
2 | ExtractJwt = require('passport-jwt').ExtractJwt;
3 | const mongoose = require('mongoose');
4 |
5 | const User = require('../models/User');
6 | const { jwtSecret } = require('./index');
7 |
8 | const opts = {};
9 | opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
10 | opts.secretOrKey = jwtSecret;
11 |
12 | module.exports = passport => {
13 | passport.use(
14 | new JwtStrategy(opts, (jwt_payload, done) => {
15 | User.findById(jwt_payload.id)
16 | .then(user => {
17 | if (user) {
18 | return done(null, user);
19 | }
20 | return done(null, false);
21 | })
22 | .catch(err => console.log(err));
23 | })
24 | );
25 | };
26 |
27 |
--------------------------------------------------------------------------------
/frontend/src/_mock/user.js:
--------------------------------------------------------------------------------
1 | import { faker } from '@faker-js/faker';
2 | import { sample } from 'lodash';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | const users = [...Array(24)].map((_, index) => ({
7 | id: faker.datatype.uuid(),
8 | avatarUrl: `/assets/images/avatars/avatar_${index + 1}.jpg`,
9 | name: faker.name.fullName(),
10 | company: faker.company.name(),
11 | isVerified: faker.datatype.boolean(),
12 | status: sample(['active', 'banned']),
13 | role: sample([
14 | 'Leader',
15 | 'Hr Manager',
16 | 'UI Designer',
17 | 'UX Designer',
18 | 'UI/UX Designer',
19 | 'Project Manager',
20 | 'Backend Developer',
21 | 'Full Stack Designer',
22 | 'Front End Developer',
23 | 'Full Stack Developer',
24 | ]),
25 | }));
26 |
27 | export default users;
28 |
--------------------------------------------------------------------------------
/frontend/src/components/svg-color/SvgColor.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { forwardRef } from 'react';
3 | // @mui
4 | import { Box } from '@mui/material';
5 |
6 | // ----------------------------------------------------------------------
7 |
8 | const SvgColor = forwardRef(({ src, sx, ...other }, ref) => (
9 |
24 | ));
25 |
26 | SvgColor.propTypes = {
27 | src: PropTypes.string,
28 | sx: PropTypes.object,
29 | };
30 |
31 | export default SvgColor;
32 |
--------------------------------------------------------------------------------
/frontend/src/layouts/simple/SimpleLayout.js:
--------------------------------------------------------------------------------
1 | import { Outlet } from 'react-router-dom';
2 | // @mui
3 | import { styled } from '@mui/material/styles';
4 | // components
5 | import Logo from '../../components/logo';
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | const StyledHeader = styled('header')(({ theme }) => ({
10 | top: 0,
11 | left: 0,
12 | lineHeight: 0,
13 | width: '100%',
14 | position: 'absolute',
15 | padding: theme.spacing(3, 3, 0),
16 | [theme.breakpoints.up('sm')]: {
17 | padding: theme.spacing(5, 5, 0),
18 | },
19 | }));
20 |
21 | // ----------------------------------------------------------------------
22 |
23 | export default function SimpleLayout() {
24 | return (
25 | <>
26 |
27 |
28 |
29 |
30 |
31 | >
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/frontend/src/index.js:
--------------------------------------------------------------------------------
1 | import ReactDOM from 'react-dom/client';
2 | import { Provider } from 'react-redux';
3 | import App from './App';
4 | import store from './redux/store';
5 | import "./style.css";
6 | import * as serviceWorker from './serviceWorker';
7 | import reportWebVitals from './reportWebVitals';
8 |
9 | // ----------------------------------------------------------------------
10 |
11 | const root = ReactDOM.createRoot(document.getElementById('root'));
12 |
13 | root.render(
14 |
15 |
16 |
17 | );
18 |
19 | // If you want to enable client cache, register instead.
20 | serviceWorker.unregister();
21 |
22 | // If you want to start measuring performance in your app, pass a function
23 | // to log results (for example: reportWebVitals(console.log))
24 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
25 | reportWebVitals();
26 |
--------------------------------------------------------------------------------
/frontend/src/components/scrollbar/styles.js:
--------------------------------------------------------------------------------
1 | import SimpleBar from 'simplebar-react';
2 | // @mui
3 | import { alpha, styled } from '@mui/material/styles';
4 |
5 | // ----------------------------------------------------------------------
6 |
7 | export const StyledRootScrollbar = styled('div')(() => ({
8 | flexGrow: 1,
9 | height: '100%',
10 | overflow: 'hidden',
11 | }));
12 |
13 | export const StyledScrollbar = styled(SimpleBar)(({ theme }) => ({
14 | maxHeight: '100%',
15 | '& .simplebar-scrollbar': {
16 | '&:before': {
17 | backgroundColor: alpha(theme.palette.grey[600], 0.48),
18 | },
19 | '&.simplebar-visible:before': {
20 | opacity: 1,
21 | },
22 | },
23 | '& .simplebar-track.simplebar-vertical': {
24 | width: 10,
25 | },
26 | '& .simplebar-track.simplebar-horizontal .simplebar-scrollbar': {
27 | height: 6,
28 | },
29 | '& .simplebar-mask': {
30 | zIndex: 'inherit',
31 | },
32 | }));
33 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Card.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Card(theme) {
4 | return {
5 | MuiCard: {
6 | styleOverrides: {
7 | root: {
8 | boxShadow: theme.customShadows.card,
9 | borderRadius: Number(theme.shape.borderRadius) * 2,
10 | position: 'relative',
11 | zIndex: 0, // Fix Safari overflow: hidden with border radius
12 | },
13 | },
14 | },
15 | MuiCardHeader: {
16 | defaultProps: {
17 | titleTypographyProps: { variant: 'h6' },
18 | subheaderTypographyProps: { variant: 'body2' },
19 | },
20 | styleOverrides: {
21 | root: {
22 | padding: theme.spacing(3, 3, 0),
23 | },
24 | },
25 | },
26 | MuiCardContent: {
27 | styleOverrides: {
28 | root: {
29 | padding: theme.spacing(3),
30 | },
31 | },
32 | },
33 | };
34 | }
35 |
--------------------------------------------------------------------------------
/frontend/src/utils/formatNumber.js:
--------------------------------------------------------------------------------
1 | import numeral from 'numeral';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export function fNumber(number) {
6 | return numeral(number).format();
7 | }
8 |
9 | export function fCurrency(number) {
10 | const format = number ? numeral(number).format('$0,0.00') : '';
11 |
12 | return result(format, '.00');
13 | }
14 |
15 | export function fPercent(number) {
16 | const format = number ? numeral(Number(number) / 100).format('0.0%') : '';
17 |
18 | return result(format, '.0');
19 | }
20 |
21 | export function fShortenNumber(number) {
22 | const format = number ? numeral(number).format('0.00a') : '';
23 |
24 | return result(format, '.00');
25 | }
26 |
27 | export function fData(number) {
28 | const format = number ? numeral(number).format('0.0 b') : '';
29 |
30 | return result(format, '.0');
31 | }
32 |
33 | function result(format, key = '.00') {
34 | const isInteger = format.includes(key);
35 |
36 | return isInteger ? format.replace(key, '') : format;
37 | }
38 |
--------------------------------------------------------------------------------
/backend/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const bodyParser = require('body-parser');
3 | const path = require('path');
4 | const passport = require('passport');
5 | const morgan = require('morgan');
6 |
7 | const app = express();
8 |
9 | const PORT = process.env.PORT || 5000;
10 |
11 | // Middlewares
12 | app.use(require('cors')());
13 | app.use(require('helmet')());
14 | app.use(morgan('dev'));
15 | app.use(bodyParser.urlencoded({ extended: false }));
16 | app.use(bodyParser.json());
17 | app.use(passport.initialize());
18 | // DB Connection
19 | require('./libs/db-connection');
20 | // Passport
21 | require('./config/passport')(passport);
22 |
23 | // Routes
24 | app.use('/api/users', require('./routes/users'));
25 |
26 | // Production
27 | if (process.env.NODE_ENV === 'production') {
28 | // Set static folder
29 | app.use(express.static('client/build'));
30 |
31 | app.get('*', (req, res) => {
32 | res.sendfile(path.resolve(__dirname, 'client', 'build', 'index.html'));
33 | });
34 | }
35 |
36 | app.listen(PORT, () => console.log(`Server Running on port ${PORT}`));
--------------------------------------------------------------------------------
/frontend/src/components/scrollbar/Scrollbar.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { memo } from 'react';
3 | // @mui
4 | import { Box } from '@mui/material';
5 | //
6 | import { StyledRootScrollbar, StyledScrollbar } from './styles';
7 |
8 | // ----------------------------------------------------------------------
9 |
10 | Scrollbar.propTypes = {
11 | sx: PropTypes.object,
12 | children: PropTypes.node,
13 | };
14 |
15 | function Scrollbar({ children, sx, ...other }) {
16 | const userAgent = typeof navigator === 'undefined' ? 'SSR' : navigator.userAgent;
17 |
18 | const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
19 |
20 | if (isMobile) {
21 | return (
22 |
23 | {children}
24 |
25 | );
26 | }
27 |
28 | return (
29 |
30 |
31 | {children}
32 |
33 |
34 | );
35 | }
36 |
37 | export default memo(Scrollbar);
38 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/navbar/ic_user.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/frontend/src/components/color-utils/ColorSinglePicker.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { forwardRef } from 'react';
3 | // @mui
4 | import { Radio, RadioGroup } from '@mui/material';
5 | //
6 | import Icon from './Icon';
7 |
8 | // ----------------------------------------------------------------------
9 |
10 | const ColorSinglePicker = forwardRef(({ colors, ...other }, ref) => (
11 |
12 | {colors.map((color) => {
13 | const whiteColor = color === '#FFFFFF' || color === 'white';
14 |
15 | return (
16 | }
21 | checkedIcon={}
22 | sx={{
23 | color,
24 | '&:hover': { opacity: 0.72 },
25 | '& svg': { width: 12, height: 12 },
26 | }}
27 | />
28 | );
29 | })}
30 |
31 | ));
32 |
33 | ColorSinglePicker.propTypes = {
34 | colors: PropTypes.arrayOf(PropTypes.string),
35 | };
36 |
37 | export default ColorSinglePicker;
38 |
--------------------------------------------------------------------------------
/backend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "MERN-Auth-System",
3 | "version": "1.0.0",
4 | "description": "Authentication System",
5 | "main": "server.js",
6 | "scripts": {
7 | "client-install": "cd client && npm install",
8 | "start": "nodemon server.js",
9 | "server": "nodemon server.js",
10 | "client": "npm start --prefix client",
11 | "dev": "concurrently \"npm run server\" \"npm run client\"",
12 | "heroku-postbuild": "NPM_CONFIG_PRODUCTION=false npm install --prefix client && npm run build --prefix client"
13 | },
14 | "keywords": [],
15 | "author": "",
16 | "license": "ISC",
17 | "dependencies": {
18 | "bcrypt": "^5.0.0",
19 | "body-parser": "^1.18.3",
20 | "classnames": "^2.2.6",
21 | "concurrently": "^3.6.0",
22 | "cors": "^2.8.4",
23 | "express": "^4.16.3",
24 | "gravatar": "^1.6.0",
25 | "helmet": "^3.12.2",
26 | "joi": "^13.4.0",
27 | "jsonwebtoken": "^8.3.0",
28 | "mongoose": "^5.2.3",
29 | "morgan": "^1.10.0",
30 | "passport": "^0.4.0",
31 | "passport-jwt": "^4.0.0",
32 | "validator": "^10.4.0"
33 | },
34 | "devDependencies": {
35 | "nodemon": "^1.18.2"
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/backend/validation/login.js:
--------------------------------------------------------------------------------
1 | const Validator = require('validator');
2 |
3 | const lengthInput = function (inputName, min, max, errorMessage) {
4 | if (!Validator.isLength(inputName, { min, max }))
5 | return errorMessage;
6 | }
7 |
8 | const loginValidation = data => {
9 |
10 | const { email, password } = data;
11 | let errors = {};
12 |
13 | // Length input value validation
14 | errors.email = lengthInput(email, 5, 100, 'The email field must be greater than 5 characters');
15 | errors.password = lengthInput(password, 5, 1024, 'The password field must be greater than 5 characters');
16 | // Email validate format
17 | if (!Validator.isEmail(email)) errors.email = 'Email format is incorrect';
18 | // Empty validation
19 | if (Validator.isEmpty(email)) errors.email = 'Email field is required';
20 | if (Validator.isEmpty(password)) errors.password = 'Password field is required';
21 |
22 | // if each key of errors is undefined, we must empty the objects
23 | if (!errors.email && !errors.password)
24 | errors = {};
25 |
26 | return {
27 | errors,
28 | isValid: Object.keys(errors).length
29 | }
30 |
31 | };
32 |
33 | module.exports = loginValidation;
--------------------------------------------------------------------------------
/frontend/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Minimal UI ([https://minimals.cc/](https://minimals.cc/))
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 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/ic_flag_en.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backend/models/User.js:
--------------------------------------------------------------------------------
1 | const mongoose = require("mongoose");
2 | //import mongoose from 'mongoose';
3 | const { Schema } = mongoose;
4 |
5 | const userSchema = new Schema({
6 | firstName: {
7 | type: String,
8 | required: true,
9 | trim: true,
10 | minlength: 3,
11 | maxlength: 30,
12 | },
13 | lastName: {
14 | type: String,
15 | required: true,
16 | trim: true,
17 | minlength: 3,
18 | maxlength: 30,
19 | },
20 | email: {
21 | type: String,
22 | required: true,
23 | unique: true,
24 | trim: true,
25 | minlength: 5,
26 | maxlength: 100,
27 | },
28 | company: {
29 | type: String,
30 | required: true,
31 | trim: true,
32 | },
33 | company_size: {
34 | type: String,
35 | required: true,
36 | enum: ['Self-employed', '1-10 employees', '11-50 employees', '51-200 employees', '201-500 employees', '501-1000 employees', '1001-5000 employees', '5001-10000 employees', '10001+ employees'],
37 | default: '11-50 employees'
38 | },
39 | avatar: {
40 | type: String,
41 | },
42 | password: {
43 | type: String,
44 | required: true,
45 | minlength: 5,
46 | maxlength: 1024,
47 | },
48 | });
49 |
50 | module.exports = mongoose.model("User", userSchema);
51 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/ic_flag_de.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Button.js:
--------------------------------------------------------------------------------
1 | import { alpha } from '@mui/material/styles';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export default function Button(theme) {
6 | return {
7 | MuiButton: {
8 | styleOverrides: {
9 | root: {
10 | '&:hover': {
11 | boxShadow: 'none',
12 | },
13 | },
14 | sizeLarge: {
15 | height: 48,
16 | },
17 | containedInherit: {
18 | color: theme.palette.grey[800],
19 | boxShadow: theme.customShadows.z8,
20 | '&:hover': {
21 | backgroundColor: theme.palette.grey[400],
22 | },
23 | },
24 | containedPrimary: {
25 | boxShadow: theme.customShadows.primary,
26 | },
27 | containedSecondary: {
28 | boxShadow: theme.customShadows.secondary,
29 | },
30 | outlinedInherit: {
31 | border: `1px solid ${alpha(theme.palette.grey[500], 0.32)}`,
32 | '&:hover': {
33 | backgroundColor: theme.palette.action.hover,
34 | },
35 | },
36 | textInherit: {
37 | '&:hover': {
38 | backgroundColor: theme.palette.action.hover,
39 | },
40 | },
41 | },
42 | },
43 | };
44 | }
45 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/navbar/ic_blog.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/frontend/src/theme/index.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { useMemo } from 'react';
3 | // @mui
4 | import { CssBaseline } from '@mui/material';
5 | import { ThemeProvider as MUIThemeProvider, createTheme, StyledEngineProvider } from '@mui/material/styles';
6 | //
7 | import palette from './palette';
8 | import shadows from './shadows';
9 | import typography from './typography';
10 | import GlobalStyles from './globalStyles';
11 | import customShadows from './customShadows';
12 | import componentsOverride from './overrides';
13 |
14 | // ----------------------------------------------------------------------
15 |
16 | ThemeProvider.propTypes = {
17 | children: PropTypes.node,
18 | };
19 |
20 | export default function ThemeProvider({ children }) {
21 | const themeOptions = useMemo(
22 | () => ({
23 | palette,
24 | shape: { borderRadius: 6 },
25 | typography,
26 | shadows: shadows(),
27 | customShadows: customShadows(),
28 | }),
29 | []
30 | );
31 |
32 | const theme = createTheme(themeOptions);
33 | theme.components = componentsOverride(theme);
34 |
35 | return (
36 |
37 |
38 |
39 |
40 | {children}
41 |
42 |
43 | );
44 | }
45 |
--------------------------------------------------------------------------------
/frontend/src/components/color-utils/ColorPreview.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // @mui
3 | import { alpha } from '@mui/material/styles';
4 | import { Box, Typography, Stack } from '@mui/material';
5 |
6 | // ----------------------------------------------------------------------
7 |
8 | ColorPreview.propTypes = {
9 | sx: PropTypes.object,
10 | limit: PropTypes.number,
11 | colors: PropTypes.arrayOf(PropTypes.string),
12 | };
13 |
14 | export default function ColorPreview({ colors, limit = 3, sx }) {
15 | const showColor = colors.slice(0, limit);
16 |
17 | const moreColor = colors.length - limit;
18 |
19 | return (
20 |
21 | {showColor.map((color, index) => (
22 | `solid 2px ${theme.palette.background.paper}`,
30 | boxShadow: (theme) => `inset -1px 1px 2px ${alpha(theme.palette.common.black, 0.24)}`,
31 | bgcolor: color,
32 | }}
33 | />
34 | ))}
35 |
36 | {colors.length > limit && {`+${moreColor}`}}
37 |
38 | );
39 | }
40 |
--------------------------------------------------------------------------------
/frontend/src/layouts/dashboard/DashboardLayout.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import { Outlet } from 'react-router-dom';
3 | // @mui
4 | import { styled } from '@mui/material/styles';
5 | //
6 | import Header from './header';
7 | import Nav from './nav';
8 |
9 | // ----------------------------------------------------------------------
10 |
11 | const APP_BAR_MOBILE = 64;
12 | const APP_BAR_DESKTOP = 92;
13 |
14 | const StyledRoot = styled('div')({
15 | display: 'flex',
16 | minHeight: '100%',
17 | overflow: 'hidden',
18 | });
19 |
20 | const Main = styled('div')(({ theme }) => ({
21 | flexGrow: 1,
22 | overflow: 'auto',
23 | minHeight: '100%',
24 | paddingTop: APP_BAR_MOBILE + 24,
25 | paddingBottom: theme.spacing(10),
26 | [theme.breakpoints.up('lg')]: {
27 | paddingTop: APP_BAR_DESKTOP + 24,
28 | paddingLeft: theme.spacing(2),
29 | paddingRight: theme.spacing(2),
30 | },
31 | }));
32 |
33 | // ----------------------------------------------------------------------
34 |
35 | export default function DashboardLayout() {
36 | const [open, setOpen] = useState(false);
37 |
38 | return (
39 |
40 | setOpen(true)} />
41 |
42 |
48 | );
49 | }
50 |
--------------------------------------------------------------------------------
/frontend/src/theme/customShadows.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { alpha } from '@mui/material/styles';
3 | //
4 | import palette from './palette';
5 |
6 | // ----------------------------------------------------------------------
7 |
8 | const color = palette.grey[500];
9 |
10 | export default function customShadows() {
11 | const transparent = alpha(color, 0.16);
12 | return {
13 | z1: `0 1px 2px 0 ${transparent}`,
14 | z4: `0 4px 8px 0 ${transparent}`,
15 | z8: `0 8px 16px 0 ${transparent}`,
16 | z12: `0 12px 24px -4px ${transparent}`,
17 | z16: `0 16px 32px -4px ${transparent}`,
18 | z20: `0 20px 40px -4px ${transparent}`,
19 | z24: `0 24px 48px 0 ${transparent}`,
20 | //
21 | primary: `0 8px 16px 0 ${alpha(palette.primary.main, 0.24)}`,
22 | info: `0 8px 16px 0 ${alpha(palette.info.main, 0.24)}`,
23 | secondary: `0 8px 16px 0 ${alpha(palette.secondary.main, 0.24)}`,
24 | success: `0 8px 16px 0 ${alpha(palette.success.main, 0.24)}`,
25 | warning: `0 8px 16px 0 ${alpha(palette.warning.main, 0.24)}`,
26 | error: `0 8px 16px 0 ${alpha(palette.error.main, 0.24)}`,
27 | //
28 | card: `0 0 2px 0 ${alpha(color, 0.2)}, 0 12px 24px -4px ${alpha(color, 0.12)}`,
29 | dialog: `-40px 40px 80px -8px ${alpha(color, 0.24)}`,
30 | dropdown: `0 0 2px 0 ${alpha(color, 0.24)}, -20px 20px 40px -4px ${alpha(color, 0.24)}`,
31 | };
32 | }
33 |
--------------------------------------------------------------------------------
/frontend/src/App.js:
--------------------------------------------------------------------------------
1 | import { BrowserRouter } from 'react-router-dom';
2 | import { HelmetProvider } from 'react-helmet-async';
3 | // eslint-disable-next-line camelcase
4 | import jwt_decode from 'jwt-decode';
5 | import Router from './routes';
6 | import ThemeProvider from './theme';
7 | import { StyledChart } from './components/chart';
8 | import setAuthToken from './utils/setAuthToken';
9 | import ScrollToTop from './components/scroll-to-top';
10 | import { setCurrentUser, logoutUser } from './redux/actions/authActions';
11 | import store from './redux/store';
12 |
13 | if (localStorage.getItem('jwtToken')) {
14 | setAuthToken(localStorage.getItem('jwtToken'));
15 | const userDecoded = jwt_decode(localStorage.getItem('jwtToken'));
16 | store.dispatch(setCurrentUser(userDecoded));
17 | // Check for expired time
18 | const currentTime = Date.now() / 1000;
19 | if (userDecoded.exp < currentTime) {
20 | // Logout
21 | store.dispatch(logoutUser());
22 | // User
23 | store.dispatch(setCurrentUser({}));
24 | window.location.href = '/';
25 | }
26 | }
27 |
28 | export default function App() {
29 | return (
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | );
40 | }
41 |
--------------------------------------------------------------------------------
/frontend/src/components/color-utils/ColorMultiPicker.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // @mui
3 | import { Box, Checkbox } from '@mui/material';
4 | //
5 | import Icon from './Icon';
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | ColorMultiPicker.propTypes = {
10 | sx: PropTypes.object,
11 | colors: PropTypes.array,
12 | onChangeColor: PropTypes.func,
13 | selected: PropTypes.arrayOf(PropTypes.string),
14 | };
15 |
16 | export default function ColorMultiPicker({ colors, selected, onChangeColor, sx, ...other }) {
17 | return (
18 |
19 | {colors.map((color) => {
20 | const whiteColor = color === '#FFFFFF' || color === 'white';
21 |
22 | return (
23 | onChangeColor(color)}
30 | icon={}
31 | checkedIcon={}
32 | sx={{
33 | color,
34 | '&:hover': { opacity: 0.72 },
35 | '& svg': { width: 12, height: 12 },
36 | }}
37 | {...other}
38 | />
39 | );
40 | })}
41 |
42 | );
43 | }
44 |
--------------------------------------------------------------------------------
/frontend/src/hooks/useResponsive.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { useTheme } from '@mui/material/styles';
3 | import useMediaQuery from '@mui/material/useMediaQuery';
4 |
5 | // ----------------------------------------------------------------------
6 |
7 | export default function useResponsive(query, start, end) {
8 | const theme = useTheme();
9 |
10 | const mediaUp = useMediaQuery(theme.breakpoints.up(start));
11 |
12 | const mediaDown = useMediaQuery(theme.breakpoints.down(start));
13 |
14 | const mediaBetween = useMediaQuery(theme.breakpoints.between(start, end));
15 |
16 | const mediaOnly = useMediaQuery(theme.breakpoints.only(start));
17 |
18 | if (query === 'up') {
19 | return mediaUp;
20 | }
21 |
22 | if (query === 'down') {
23 | return mediaDown;
24 | }
25 |
26 | if (query === 'between') {
27 | return mediaBetween;
28 | }
29 |
30 | return mediaOnly;
31 | }
32 |
33 | // ----------------------------------------------------------------------
34 |
35 | export function useWidth() {
36 | const theme = useTheme();
37 |
38 | const keys = [...theme.breakpoints.keys].reverse();
39 |
40 | return (
41 | keys.reduce((output, key) => {
42 | // eslint-disable-next-line react-hooks/rules-of-hooks
43 | const matches = useMediaQuery(theme.breakpoints.up(key));
44 |
45 | return !output && matches ? key : output;
46 | }, null) || 'xs'
47 | );
48 | }
49 |
--------------------------------------------------------------------------------
/frontend/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ### v1.7.0
2 |
3 | ###### Feb 21, 2023
4 |
5 | - Upgrade some dependencies to the latest versions
6 |
7 | ---
8 |
9 | ### v1.6.0
10 |
11 | ###### Oct 17, 2022
12 |
13 | - Upgrade and restructure the directory.
14 | - Upgrade some dependencies to the latest versions
15 |
16 | ---
17 |
18 | ### v1.5.0
19 |
20 | ###### Jul 04, 2022
21 |
22 | - Support react 18.
23 | - Upgrade some dependencies to the latest versions
24 |
25 | ---
26 |
27 | ### v1.4.0
28 |
29 | ###### Apr 12, 2022
30 |
31 | - Update `src/components`.
32 | - Update `src/sections`.
33 | - Update `src/pages`.
34 | - Update `src/layouts`.
35 | - Update `src/theme`.
36 | - Upgrade some dependencies to the latest versions
37 |
38 | ---
39 |
40 | ### v1.3.0
41 |
42 | ###### Feb 21, 2022
43 |
44 | - Support react-script v5.0.0
45 | - Source code improvement
46 | - Upgrade some dependencies to the latest versions
47 |
48 | ---
49 |
50 | ### v1.2.0
51 |
52 | ###### Sep 18, 2021
53 |
54 | - Support MIU v5.0.0 official release
55 | - Upgrade some dependencies to the latest versions
56 | - Update `src/theme/typography.js`
57 | - Upgrade some dependencies to the latest versions
58 |
59 | ---
60 |
61 | ### v1.1.0
62 |
63 | ###### Jul 23, 2021
64 |
65 | - Support MUI v5.0.0-beta.1
66 | - Upgrade some dependencies to the latest versions
67 |
68 | ---
69 |
70 | ### v1.0.0
71 |
72 | ###### Jun 28, 2021
73 |
74 | Initial release.
75 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/products/ProductCartWidget.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { styled } from '@mui/material/styles';
3 | import { Badge } from '@mui/material';
4 | // component
5 | import Iconify from '../../../components/iconify';
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | const StyledRoot = styled('div')(({ theme }) => ({
10 | zIndex: 999,
11 | right: 0,
12 | display: 'flex',
13 | cursor: 'pointer',
14 | position: 'fixed',
15 | alignItems: 'center',
16 | top: theme.spacing(16),
17 | height: theme.spacing(5),
18 | paddingLeft: theme.spacing(2),
19 | paddingRight: theme.spacing(2),
20 | paddingTop: theme.spacing(1.25),
21 | boxShadow: theme.customShadows.z20,
22 | color: theme.palette.text.primary,
23 | backgroundColor: theme.palette.background.paper,
24 | borderTopLeftRadius: Number(theme.shape.borderRadius) * 2,
25 | borderBottomLeftRadius: Number(theme.shape.borderRadius) * 2,
26 | transition: theme.transitions.create('opacity'),
27 | '&:hover': { opacity: 0.72 },
28 | }));
29 |
30 | // ----------------------------------------------------------------------
31 |
32 | export default function CartWidget() {
33 | return (
34 |
35 |
36 |
37 |
38 |
39 | );
40 | }
41 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/app/AppTrafficBySite.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import PropTypes from 'prop-types';
3 | import { Box, Card, Paper, Typography, CardHeader, CardContent } from '@mui/material';
4 | // utils
5 | import { fShortenNumber } from '../../../utils/formatNumber';
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | AppTrafficBySite.propTypes = {
10 | title: PropTypes.string,
11 | subheader: PropTypes.string,
12 | list: PropTypes.array.isRequired,
13 | };
14 |
15 | export default function AppTrafficBySite({ title, subheader, list, ...other }) {
16 | return (
17 |
18 |
19 |
20 |
21 |
28 | {list.map((site) => (
29 |
30 | {site.icon}
31 |
32 | {fShortenNumber(site.value)}
33 |
34 |
35 | {site.name}
36 |
37 |
38 | ))}
39 |
40 |
41 |
42 | );
43 | }
44 |
--------------------------------------------------------------------------------
/frontend/public/assets/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/src/theme/globalStyles.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { GlobalStyles as MUIGlobalStyles } from '@mui/material';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | export default function GlobalStyles() {
7 | const inputGlobalStyles = (
8 |
53 | );
54 |
55 | return inputGlobalStyles;
56 | }
57 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/app/AppWebsiteVisits.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import ReactApexChart from 'react-apexcharts';
3 | // @mui
4 | import { Card, CardHeader, Box } from '@mui/material';
5 | // components
6 | import { useChart } from '../../../components/chart';
7 |
8 | // ----------------------------------------------------------------------
9 |
10 | AppWebsiteVisits.propTypes = {
11 | title: PropTypes.string,
12 | subheader: PropTypes.string,
13 | chartData: PropTypes.array.isRequired,
14 | chartLabels: PropTypes.arrayOf(PropTypes.string).isRequired,
15 | };
16 |
17 | export default function AppWebsiteVisits({ title, subheader, chartLabels, chartData, ...other }) {
18 | const chartOptions = useChart({
19 | plotOptions: { bar: { columnWidth: '16%' } },
20 | fill: { type: chartData.map((i) => i.fill) },
21 | labels: chartLabels,
22 | xaxis: { type: 'datetime' },
23 | tooltip: {
24 | shared: true,
25 | intersect: false,
26 | y: {
27 | formatter: (y) => {
28 | if (typeof y !== 'undefined') {
29 | return `${y.toFixed(0)} visits`;
30 | }
31 | return y;
32 | },
33 | },
34 | },
35 | });
36 |
37 | return (
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | );
46 | }
47 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/ic_notification_mail.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/src/components/label/Label.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { forwardRef } from 'react';
3 | // @mui
4 | import { useTheme } from '@mui/material/styles';
5 | import { Box } from '@mui/material';
6 | //
7 | import { StyledLabel } from './styles';
8 |
9 | // ----------------------------------------------------------------------
10 |
11 | const Label = forwardRef(({ children, color = 'default', variant = 'soft', startIcon, endIcon, sx, ...other }, ref) => {
12 | const theme = useTheme();
13 |
14 | const iconStyle = {
15 | width: 16,
16 | height: 16,
17 | '& svg, img': { width: 1, height: 1, objectFit: 'cover' },
18 | };
19 |
20 | return (
21 |
33 | {startIcon && {startIcon} }
34 |
35 | {children}
36 |
37 | {endIcon && {endIcon} }
38 |
39 | );
40 | });
41 |
42 | Label.propTypes = {
43 | sx: PropTypes.object,
44 | endIcon: PropTypes.node,
45 | children: PropTypes.node,
46 | startIcon: PropTypes.node,
47 | variant: PropTypes.oneOf(['filled', 'outlined', 'ghost', 'soft']),
48 | color: PropTypes.oneOf(['default', 'primary', 'secondary', 'info', 'success', 'warning', 'error']),
49 | };
50 |
51 | export default Label;
52 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/app/AppConversionRates.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import ReactApexChart from 'react-apexcharts';
3 | // @mui
4 | import { Box, Card, CardHeader } from '@mui/material';
5 | // utils
6 | import { fNumber } from '../../../utils/formatNumber';
7 | // components
8 | import { useChart } from '../../../components/chart';
9 |
10 | // ----------------------------------------------------------------------
11 |
12 | AppConversionRates.propTypes = {
13 | title: PropTypes.string,
14 | subheader: PropTypes.string,
15 | chartData: PropTypes.array.isRequired,
16 | };
17 |
18 | export default function AppConversionRates({ title, subheader, chartData, ...other }) {
19 | const chartLabels = chartData.map((i) => i.label);
20 |
21 | const chartSeries = chartData.map((i) => i.value);
22 |
23 | const chartOptions = useChart({
24 | tooltip: {
25 | marker: { show: false },
26 | y: {
27 | formatter: (seriesName) => fNumber(seriesName),
28 | title: {
29 | formatter: () => '',
30 | },
31 | },
32 | },
33 | plotOptions: {
34 | bar: { horizontal: true, barHeight: '28%', borderRadius: 2 },
35 | },
36 | xaxis: {
37 | categories: chartLabels,
38 | },
39 | });
40 |
41 | return (
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | );
50 | }
51 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/blog/BlogPostsSearch.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 |
3 | // @mui
4 | import { styled } from '@mui/material/styles';
5 | import { Autocomplete, InputAdornment, Popper, TextField } from '@mui/material';
6 | // components
7 | import Iconify from '../../../components/iconify';
8 |
9 | // ----------------------------------------------------------------------
10 |
11 | const StyledPopper = styled((props) => )({
12 | width: '280px !important',
13 | });
14 |
15 | // ----------------------------------------------------------------------
16 |
17 | BlogPostsSearch.propTypes = {
18 | posts: PropTypes.array.isRequired,
19 | };
20 |
21 | export default function BlogPostsSearch({ posts }) {
22 | return (
23 | post.title}
30 | isOptionEqualToValue={(option, value) => option.id === value.id}
31 | renderInput={(params) => (
32 |
39 |
40 |
41 | ),
42 | }}
43 | />
44 | )}
45 | />
46 | );
47 | }
48 |
--------------------------------------------------------------------------------
/frontend/src/pages/ProductsPage.js:
--------------------------------------------------------------------------------
1 | import { Helmet } from 'react-helmet-async';
2 | import { useState } from 'react';
3 | // @mui
4 | import { Container, Stack, Typography } from '@mui/material';
5 | // components
6 | import { ProductSort, ProductList, ProductCartWidget, ProductFilterSidebar } from '../sections/@dashboard/products';
7 | // mock
8 | import PRODUCTS from '../_mock/products';
9 |
10 | // ----------------------------------------------------------------------
11 |
12 | export default function ProductsPage() {
13 | const [openFilter, setOpenFilter] = useState(false);
14 |
15 | const handleOpenFilter = () => {
16 | setOpenFilter(true);
17 | };
18 |
19 | const handleCloseFilter = () => {
20 | setOpenFilter(false);
21 | };
22 |
23 | return (
24 | <>
25 |
26 | Dashboard: Products | Minimal UI
27 |
28 |
29 |
30 |
31 | Products
32 |
33 |
34 |
35 |
36 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | >
49 | );
50 | }
51 |
--------------------------------------------------------------------------------
/frontend/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Minimal UI Kit
26 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/navbar/ic_lock.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/frontend/src/pages/BlogPage.js:
--------------------------------------------------------------------------------
1 | import { Helmet } from 'react-helmet-async';
2 | // @mui
3 | import { Grid, Button, Container, Stack, Typography } from '@mui/material';
4 | // components
5 | import Iconify from '../components/iconify';
6 | import { BlogPostCard, BlogPostsSort, BlogPostsSearch } from '../sections/@dashboard/blog';
7 | // mock
8 | import POSTS from '../_mock/blog';
9 |
10 | // ----------------------------------------------------------------------
11 |
12 | const SORT_OPTIONS = [
13 | { value: 'latest', label: 'Latest' },
14 | { value: 'popular', label: 'Popular' },
15 | { value: 'oldest', label: 'Oldest' },
16 | ];
17 |
18 | // ----------------------------------------------------------------------
19 |
20 | export default function BlogPage() {
21 | return (
22 | <>
23 |
24 | Dashboard: Blog | Minimal UI
25 |
26 |
27 |
28 |
29 |
30 | Blog
31 |
32 | }>
33 | New Post
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | {POSTS.map((post, index) => (
44 |
45 | ))}
46 |
47 |
48 | >
49 | );
50 | }
51 |
--------------------------------------------------------------------------------
/frontend/src/pages/Page404.js:
--------------------------------------------------------------------------------
1 | import { Helmet } from 'react-helmet-async';
2 | import { Link as RouterLink } from 'react-router-dom';
3 | // @mui
4 | import { styled } from '@mui/material/styles';
5 | import { Button, Typography, Container, Box } from '@mui/material';
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | const StyledContent = styled('div')(({ theme }) => ({
10 | maxWidth: 480,
11 | margin: 'auto',
12 | minHeight: '100vh',
13 | display: 'flex',
14 | justifyContent: 'center',
15 | flexDirection: 'column',
16 | padding: theme.spacing(12, 0),
17 | }));
18 |
19 | // ----------------------------------------------------------------------
20 |
21 | export default function Page404() {
22 | return (
23 | <>
24 |
25 | 404 Page Not Found | Minimal UI
26 |
27 |
28 |
29 |
30 |
31 | Sorry, page not found!
32 |
33 |
34 |
35 | Sorry, we couldn’t find the page you’re looking for. Perhaps you’ve mistyped the URL? Be sure to check your
36 | spelling.
37 |
38 |
39 |
44 |
45 |
48 |
49 |
50 | >
51 | );
52 | }
53 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/navbar/ic_cart.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/products/ProductSort.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | // @mui
3 | import { Menu, Button, MenuItem, Typography } from '@mui/material';
4 | // component
5 | import Iconify from '../../../components/iconify';
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | const SORT_BY_OPTIONS = [
10 | { value: 'featured', label: 'Featured' },
11 | { value: 'newest', label: 'Newest' },
12 | { value: 'priceDesc', label: 'Price: High-Low' },
13 | { value: 'priceAsc', label: 'Price: Low-High' },
14 | ];
15 |
16 | export default function ShopProductSort() {
17 | const [open, setOpen] = useState(null);
18 |
19 | const handleOpen = (event) => {
20 | setOpen(event.currentTarget);
21 | };
22 |
23 | const handleClose = () => {
24 | setOpen(null);
25 | };
26 |
27 | return (
28 | <>
29 | }
34 | >
35 | Sort By:
36 |
37 | Newest
38 |
39 |
40 |
59 | >
60 | );
61 | }
62 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Input.js:
--------------------------------------------------------------------------------
1 | import { alpha } from '@mui/material/styles';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export default function Input(theme) {
6 | return {
7 | MuiInputBase: {
8 | styleOverrides: {
9 | root: {
10 | '&.Mui-disabled': {
11 | '& svg': { color: theme.palette.text.disabled },
12 | },
13 | },
14 | input: {
15 | '&::placeholder': {
16 | opacity: 1,
17 | color: theme.palette.text.disabled,
18 | },
19 | },
20 | },
21 | },
22 | MuiInput: {
23 | styleOverrides: {
24 | underline: {
25 | '&:before': {
26 | borderBottomColor: alpha(theme.palette.grey[500], 0.56),
27 | },
28 | },
29 | },
30 | },
31 | MuiFilledInput: {
32 | styleOverrides: {
33 | root: {
34 | backgroundColor: alpha(theme.palette.grey[500], 0.12),
35 | '&:hover': {
36 | backgroundColor: alpha(theme.palette.grey[500], 0.16),
37 | },
38 | '&.Mui-focused': {
39 | backgroundColor: theme.palette.action.focus,
40 | },
41 | '&.Mui-disabled': {
42 | backgroundColor: theme.palette.action.disabledBackground,
43 | },
44 | },
45 | underline: {
46 | '&:before': {
47 | borderBottomColor: alpha(theme.palette.grey[500], 0.56),
48 | },
49 | },
50 | },
51 | },
52 | MuiOutlinedInput: {
53 | styleOverrides: {
54 | root: {
55 | '& .MuiOutlinedInput-notchedOutline': {
56 | borderColor: alpha(theme.palette.grey[500], 0.32),
57 | },
58 | '&.Mui-disabled': {
59 | '& .MuiOutlinedInput-notchedOutline': {
60 | borderColor: theme.palette.action.disabledBackground,
61 | },
62 | },
63 | },
64 | },
65 | },
66 | };
67 | }
68 |
--------------------------------------------------------------------------------
/frontend/src/components/color-utils/Icon.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // @mui
3 | import { alpha } from '@mui/material/styles';
4 | import { Box } from '@mui/material';
5 | //
6 | import Iconify from '../iconify';
7 |
8 | // ----------------------------------------------------------------------
9 |
10 | Icon.propTypes = {
11 | sx: PropTypes.object,
12 | checked: PropTypes.bool,
13 | whiteColor: PropTypes.bool,
14 | };
15 |
16 | export default function Icon({ checked, whiteColor, sx, ...other }) {
17 | const shadow = (
18 |
28 | );
29 |
30 | const icon = (
31 |
44 | );
45 |
46 | return (
47 |
58 | theme.transitions.create('all', {
59 | duration: theme.transitions.duration.shortest,
60 | }),
61 | ...(whiteColor && {
62 | border: (theme) => `solid 1px ${theme.palette.divider}`,
63 | boxShadow: (theme) => `4px 4px 8px 0 ${alpha(theme.palette.grey[500], 0.24)}`,
64 | }),
65 | ...(checked && {
66 | transform: 'scale(1.4)',
67 | }),
68 | ...sx,
69 | }}
70 | {...other}
71 | >
72 | {checked && shadow}
73 |
74 | {icon}
75 |
76 | );
77 | }
78 |
--------------------------------------------------------------------------------
/frontend/src/_mock/blog.js:
--------------------------------------------------------------------------------
1 | import { faker } from '@faker-js/faker';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | const POST_TITLES = [
6 | 'Whiteboard Templates By Industry Leaders',
7 | 'Tesla Cybertruck-inspired camper trailer for Tesla fans who can’t just wait for the truck!',
8 | 'Designify Agency Landing Page Design',
9 | '✨What is Done is Done ✨',
10 | 'Fresh Prince',
11 | 'Six Socks Studio',
12 | 'vincenzo de cotiis’ crossing over showcases a research on contamination',
13 | 'Simple, Great Looking Animations in Your Project | Video Tutorial',
14 | '40 Free Serif Fonts for Digital Designers',
15 | 'Examining the Evolution of the Typical Web Design Client',
16 | 'Katie Griffin loves making that homey art',
17 | 'The American Dream retold through mid-century railroad graphics',
18 | 'Illustration System Design',
19 | 'CarZio-Delivery Driver App SignIn/SignUp',
20 | 'How to create a client-serverless Jamstack app using Netlify, Gatsby and Fauna',
21 | 'Tylko Organise effortlessly -3D & Motion Design',
22 | 'RAYO ?? A expanded visual arts festival identity',
23 | 'Anthony Burrill and Wired mag’s Andrew Diprose discuss how they made January’s Change Everything cover',
24 | 'Inside the Mind of Samuel Day',
25 | 'Portfolio Review: Is This Portfolio Too Creative?',
26 | 'Akkers van Margraten',
27 | 'Gradient Ticket icon',
28 | 'Here’s a Dyson motorcycle concept that doesn’t ‘suck’!',
29 | 'How to Animate a SVG with border-image',
30 | ];
31 |
32 | const posts = [...Array(23)].map((_, index) => ({
33 | id: faker.datatype.uuid(),
34 | cover: `/assets/images/covers/cover_${index + 1}.jpg`,
35 | title: POST_TITLES[index + 1],
36 | createdAt: faker.date.past(),
37 | view: faker.datatype.number(),
38 | comment: faker.datatype.number(),
39 | share: faker.datatype.number(),
40 | favorite: faker.datatype.number(),
41 | author: {
42 | name: faker.name.fullName(),
43 | avatarUrl: `/assets/images/avatars/avatar_${index + 1}.jpg`,
44 | },
45 | }));
46 |
47 | export default posts;
48 |
--------------------------------------------------------------------------------
/backend/validation/update.js:
--------------------------------------------------------------------------------
1 | const Validator = require("validator");
2 |
3 | const lengthInput = function (inputName, min, max, errorMessage) {
4 | if (!Validator.isLength(inputName, { min, max })) return errorMessage;
5 | };
6 |
7 | const updateValidation = (data) => {
8 | const { firstName, lastName, email, company, company_size, password } = data;
9 | let errors = {};
10 |
11 | // Length input value validation
12 | errors.firstName = lengthInput(
13 | firstName,
14 | 3,
15 | 30,
16 | "Name should be between 2 and 30 characters"
17 | );
18 | errors.lastName = lengthInput(
19 | lastName,
20 | 3,
21 | 30,
22 | "Name should be between 2 and 30 characters"
23 | );
24 | errors.email = lengthInput(
25 | email,
26 | 5,
27 | 100,
28 | "The email field must be greater than 5 characters"
29 | );
30 | errors.password = lengthInput(
31 | password,
32 | 5,
33 | 1024,
34 | "The password field must be greater than 5 characters"
35 | );
36 | // Email validate format
37 | if (!Validator.isEmail(email)) errors.email = "Email format is incorrect";
38 | // Empty validation
39 | if (Validator.isEmpty(firstName)) errors.firstName = "Name field is required";
40 | if (Validator.isEmpty(lastName)) errors.lastName = "Name field is required";
41 | if (Validator.isEmpty(email)) errors.email = "Email field is required";
42 | if (Validator.isEmpty(company)) errors.company = "Company field is required";
43 | if (Validator.isEmpty(company_size)) errors.company_size = "Company size field is required";
44 | if (Validator.isEmpty(password))
45 | errors.password = "Password field is required";
46 |
47 | // if each key of errors is undefined, we must empty the objects
48 | if (
49 | !errors.firstName &&
50 | !errors.lastName &&
51 | !errors.email &&
52 | !errors.password &&
53 | !errors.company &&
54 | !errors.company_size
55 | )
56 | errors = {};
57 |
58 | return {
59 | errors,
60 | isValid: Object.keys(errors).length,
61 | };
62 | };
63 |
64 | module.exports = updateValidation;
65 |
--------------------------------------------------------------------------------
/backend/validation/register.js:
--------------------------------------------------------------------------------
1 | const Validator = require("validator");
2 |
3 | const lengthInput = function (inputName, min, max, errorMessage) {
4 | if (!Validator.isLength(inputName, { min, max })) return errorMessage;
5 | };
6 |
7 | const registerValidation = (data) => {
8 | const { firstName, lastName, email, company, company_size, password } = data;
9 | let errors = {};
10 |
11 | // Length input value validation
12 | errors.firstName = lengthInput(
13 | firstName,
14 | 3,
15 | 30,
16 | "Name should be between 2 and 30 characters"
17 | );
18 | errors.lastName = lengthInput(
19 | lastName,
20 | 3,
21 | 30,
22 | "Name should be between 2 and 30 characters"
23 | );
24 | errors.email = lengthInput(
25 | email,
26 | 5,
27 | 100,
28 | "The email field must be greater than 5 characters"
29 | );
30 | errors.password = lengthInput(
31 | password,
32 | 5,
33 | 1024,
34 | "The password field must be greater than 5 characters"
35 | );
36 | // Email validate format
37 | if (!Validator.isEmail(email)) errors.email = "Email format is incorrect";
38 | // Empty validation
39 | if (Validator.isEmpty(firstName)) errors.firstName = "Name field is required";
40 | if (Validator.isEmpty(lastName)) errors.lastName = "Name field is required";
41 | if (Validator.isEmpty(email)) errors.email = "Email field is required";
42 | if (Validator.isEmpty(company)) errors.company = "Company field is required";
43 | if (Validator.isEmpty(company_size)) errors.company_size = "Company size field is required";
44 | if (Validator.isEmpty(password))
45 | errors.password = "Password field is required";
46 |
47 | // if each key of errors is undefined, we must empty the objects
48 | if (
49 | !errors.firstName &&
50 | !errors.lastName &&
51 | !errors.email &&
52 | !errors.password &&
53 | !errors.company &&
54 | !errors.company_size
55 | )
56 | errors = {};
57 |
58 | return {
59 | errors,
60 | isValid: Object.keys(errors).length,
61 | };
62 | };
63 |
64 | module.exports = registerValidation;
65 |
--------------------------------------------------------------------------------
/frontend/src/routes.js:
--------------------------------------------------------------------------------
1 | import { Navigate, useRoutes } from 'react-router-dom';
2 | import { useSelector } from 'react-redux';
3 | import DashboardLayout from './layouts/dashboard';
4 | import SimpleLayout from './layouts/simple';
5 | import BlogPage from './pages/BlogPage';
6 | import UserPage from './pages/UserPage';
7 | import LoginPage from './pages/LoginPage';
8 | import RegisterPage from './pages/RegisterPage';
9 | import Page404 from './pages/Page404';
10 | import ProductsPage from './pages/ProductsPage';
11 | import DashboardAppPage from './pages/DashboardAppPage';
12 | import EditPage from './pages/EditPage';
13 | import ProfilePage from './pages/ProfilePage';
14 | import EditProfilePage from './pages/EditProfilePage';
15 |
16 | export default function Router() {
17 | const { isAuthenticated } = useSelector((state) => state.auth);
18 |
19 | const routes = useRoutes([
20 | {
21 | path: '/',
22 | element: isAuthenticated ? : ,
23 | children: [
24 | { element: , index: true },
25 | { path: 'app', element: },
26 | { path: 'user', element: },
27 | { path: 'products', element: },
28 | { path: 'blog', element: },
29 | { path: 'edit', element: },
30 | { path: 'profile', element: },
31 | { path: 'editprofile', element: },
32 | ],
33 | },
34 | {
35 | path: 'login',
36 | element: isAuthenticated ? : ,
37 | },
38 | {
39 | path: 'register',
40 | element: isAuthenticated ? : ,
41 | },
42 | {
43 | element: isAuthenticated ? : ,
44 | children: [
45 | { path: '404', element: },
46 | { path: '*', element: },
47 | ],
48 | },
49 | {
50 | path: '*',
51 | element: ,
52 | },
53 | ]);
54 |
55 | return routes;
56 | }
57 |
--------------------------------------------------------------------------------
/frontend/src/_mock/products.js:
--------------------------------------------------------------------------------
1 | import { faker } from '@faker-js/faker';
2 | import { sample } from 'lodash';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | const PRODUCT_NAME = [
7 | 'Nike Air Force 1 NDESTRUKT',
8 | 'Nike Space Hippie 04',
9 | 'Nike Air Zoom Pegasus 37 A.I.R. Chaz Bear',
10 | 'Nike Blazer Low 77 Vintage',
11 | 'Nike ZoomX SuperRep Surge',
12 | 'Zoom Freak 2',
13 | 'Nike Air Max Zephyr',
14 | 'Jordan Delta',
15 | 'Air Jordan XXXV PF',
16 | 'Nike Waffle Racer Crater',
17 | 'Kyrie 7 EP Sisterhood',
18 | 'Nike Air Zoom BB NXT',
19 | 'Nike Air Force 1 07 LX',
20 | 'Nike Air Force 1 Shadow SE',
21 | 'Nike Air Zoom Tempo NEXT%',
22 | 'Nike DBreak-Type',
23 | 'Nike Air Max Up',
24 | 'Nike Air Max 270 React ENG',
25 | 'NikeCourt Royale',
26 | 'Nike Air Zoom Pegasus 37 Premium',
27 | 'Nike Air Zoom SuperRep',
28 | 'NikeCourt Royale',
29 | 'Nike React Art3mis',
30 | 'Nike React Infinity Run Flyknit A.I.R. Chaz Bear',
31 | ];
32 | const PRODUCT_COLOR = ['#00AB55', '#000000', '#FFFFFF', '#FFC0CB', '#FF4842', '#1890FF', '#94D82D', '#FFC107'];
33 |
34 | // ----------------------------------------------------------------------
35 |
36 | const products = [...Array(24)].map((_, index) => {
37 | const setIndex = index + 1;
38 |
39 | return {
40 | id: faker.datatype.uuid(),
41 | cover: `/assets/images/products/product_${setIndex}.jpg`,
42 | name: PRODUCT_NAME[index],
43 | price: faker.datatype.number({ min: 4, max: 99, precision: 0.01 }),
44 | priceSale: setIndex % 3 ? null : faker.datatype.number({ min: 19, max: 29, precision: 0.01 }),
45 | colors:
46 | (setIndex === 1 && PRODUCT_COLOR.slice(0, 2)) ||
47 | (setIndex === 2 && PRODUCT_COLOR.slice(1, 3)) ||
48 | (setIndex === 3 && PRODUCT_COLOR.slice(2, 4)) ||
49 | (setIndex === 4 && PRODUCT_COLOR.slice(3, 6)) ||
50 | (setIndex === 23 && PRODUCT_COLOR.slice(4, 6)) ||
51 | (setIndex === 24 && PRODUCT_COLOR.slice(5, 6)) ||
52 | PRODUCT_COLOR,
53 | status: sample(['sale', 'new', '', '']),
54 | };
55 | });
56 |
57 | export default products;
58 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/app/AppWidgetSummary.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import PropTypes from 'prop-types';
3 | import { alpha, styled } from '@mui/material/styles';
4 | import { Card, Typography } from '@mui/material';
5 | // utils
6 | import { fShortenNumber } from '../../../utils/formatNumber';
7 | // components
8 | import Iconify from '../../../components/iconify';
9 |
10 | // ----------------------------------------------------------------------
11 |
12 | const StyledIcon = styled('div')(({ theme }) => ({
13 | margin: 'auto',
14 | display: 'flex',
15 | borderRadius: '50%',
16 | alignItems: 'center',
17 | width: theme.spacing(8),
18 | height: theme.spacing(8),
19 | justifyContent: 'center',
20 | marginBottom: theme.spacing(3),
21 | }));
22 |
23 | // ----------------------------------------------------------------------
24 |
25 | AppWidgetSummary.propTypes = {
26 | color: PropTypes.string,
27 | icon: PropTypes.string,
28 | title: PropTypes.string.isRequired,
29 | total: PropTypes.number.isRequired,
30 | sx: PropTypes.object,
31 | };
32 |
33 | export default function AppWidgetSummary({ title, total, icon, color = 'primary', sx, ...other }) {
34 | return (
35 | theme.palette[color].darker,
41 | bgcolor: (theme) => theme.palette[color].lighter,
42 | ...sx,
43 | }}
44 | {...other}
45 | >
46 | theme.palette[color].dark,
49 | backgroundImage: (theme) =>
50 | `linear-gradient(135deg, ${alpha(theme.palette[color].dark, 0)} 0%, ${alpha(
51 | theme.palette[color].dark,
52 | 0.24
53 | )} 100%)`,
54 | }}
55 | >
56 |
57 |
58 |
59 | {fShortenNumber(total)}
60 |
61 |
62 | {title}
63 |
64 |
65 | );
66 | }
67 |
--------------------------------------------------------------------------------
/frontend/src/pages/ProfilePage.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import Avatar from '@mui/material/Avatar';
3 | import CssBaseline from '@mui/material/CssBaseline';
4 | import Box from '@mui/material/Box';
5 | import Rating from '@mui/material/Rating';
6 | import Container from '@mui/material/Container';
7 | import Typography from '@mui/material/Typography';
8 | import { createTheme, ThemeProvider } from '@mui/material/styles';
9 | import { useDispatch, useSelector } from 'react-redux';
10 | import { Stack } from '@mui/material';
11 |
12 | const defaultTheme = createTheme();
13 |
14 | function ProfilePage() {
15 |
16 | const dispatch = useDispatch();
17 |
18 | const users = useSelector((state) => state.auth.user);
19 |
20 | useEffect(() => {
21 | console.log(users)
22 | }, [dispatch, users])
23 |
24 | return (
25 |
26 |
27 |
28 |
36 |
37 |
38 |
39 |
40 | {users.firstName}
41 |
42 |
43 | {users.lastName}
44 |
45 |
46 |
47 |
48 |
49 | {users.userEmail}
50 |
51 |
52 | {users.company} ({users.company_size_min} ~ {users.company_size_max})
53 |
54 |
55 |
56 |
57 |
58 | );
59 | }
60 |
61 | export default ProfilePage;
62 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/app/AppCurrentSubject.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import ReactApexChart from 'react-apexcharts';
3 | // @mui
4 | import { styled } from '@mui/material/styles';
5 | import { Card, CardHeader } from '@mui/material';
6 | // components
7 | import { useChart } from '../../../components/chart';
8 |
9 | // ----------------------------------------------------------------------
10 |
11 | const CHART_HEIGHT = 392;
12 |
13 | const LEGEND_HEIGHT = 72;
14 |
15 | const StyledChartWrapper = styled('div')(({ theme }) => ({
16 | height: CHART_HEIGHT,
17 | marginTop: theme.spacing(2),
18 | '& .apexcharts-canvas svg': {
19 | height: CHART_HEIGHT,
20 | },
21 | '& .apexcharts-canvas svg,.apexcharts-canvas foreignObject': {
22 | overflow: 'visible',
23 | },
24 | '& .apexcharts-legend': {
25 | height: LEGEND_HEIGHT,
26 | alignContent: 'center',
27 | position: 'relative !important',
28 | borderTop: `solid 1px ${theme.palette.divider}`,
29 | top: `calc(${CHART_HEIGHT - LEGEND_HEIGHT}px) !important`,
30 | },
31 | }));
32 |
33 | // ----------------------------------------------------------------------
34 |
35 | AppCurrentSubject.propTypes = {
36 | title: PropTypes.string,
37 | subheader: PropTypes.string,
38 | chartData: PropTypes.array.isRequired,
39 | chartColors: PropTypes.arrayOf(PropTypes.string).isRequired,
40 | chartLabels: PropTypes.arrayOf(PropTypes.string).isRequired,
41 | };
42 |
43 | export default function AppCurrentSubject({ title, subheader, chartData, chartColors, chartLabels, ...other }) {
44 | const chartOptions = useChart({
45 | stroke: { width: 2 },
46 | fill: { opacity: 0.48 },
47 | legend: { floating: true, horizontalAlign: 'center' },
48 | xaxis: {
49 | categories: chartLabels,
50 | labels: {
51 | style: {
52 | colors: chartColors,
53 | },
54 | },
55 | },
56 | });
57 |
58 | return (
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | );
67 | }
68 |
--------------------------------------------------------------------------------
/frontend/src/layouts/dashboard/header/index.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // @mui
3 | import { styled } from '@mui/material/styles';
4 | import { Box, Stack, AppBar, Toolbar, IconButton } from '@mui/material';
5 | // utils
6 | import { bgBlur } from '../../../utils/cssStyles';
7 | // components
8 | import Iconify from '../../../components/iconify';
9 | //
10 | import Searchbar from './Searchbar';
11 | import AccountPopover from './AccountPopover';
12 | import LanguagePopover from './LanguagePopover';
13 | import NotificationsPopover from './NotificationsPopover';
14 |
15 | // ----------------------------------------------------------------------
16 |
17 | const NAV_WIDTH = 280;
18 |
19 | const HEADER_MOBILE = 64;
20 |
21 | const HEADER_DESKTOP = 92;
22 |
23 | const StyledRoot = styled(AppBar)(({ theme }) => ({
24 | ...bgBlur({ color: theme.palette.background.default }),
25 | boxShadow: 'none',
26 | [theme.breakpoints.up('lg')]: {
27 | width: `calc(100% - ${NAV_WIDTH + 1}px)`,
28 | },
29 | }));
30 |
31 | const StyledToolbar = styled(Toolbar)(({ theme }) => ({
32 | minHeight: HEADER_MOBILE,
33 | [theme.breakpoints.up('lg')]: {
34 | minHeight: HEADER_DESKTOP,
35 | padding: theme.spacing(0, 5),
36 | },
37 | }));
38 |
39 | // ----------------------------------------------------------------------
40 |
41 | Header.propTypes = {
42 | onOpenNav: PropTypes.func,
43 | };
44 |
45 | export default function Header({ onOpenNav }) {
46 | return (
47 |
48 |
49 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | );
78 | }
79 |
--------------------------------------------------------------------------------
/frontend/src/components/chart/styles.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { alpha, useTheme } from '@mui/material/styles';
3 | import { GlobalStyles } from '@mui/material';
4 | // utils
5 | import { bgBlur } from '../../utils/cssStyles';
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | export default function StyledChart() {
10 | const theme = useTheme();
11 |
12 | const inputGlobalStyles = (
13 |
58 | );
59 |
60 | return inputGlobalStyles;
61 | }
62 |
--------------------------------------------------------------------------------
/frontend/README.md:
--------------------------------------------------------------------------------
1 | ## Minimal [(Free version)](https://minimal-kit-react.vercel.app/)
2 |
3 | 
4 |
5 | > Free React Admin Dashboard made with Material-UI components and React.
6 |
7 | 
8 |
9 | | [Minimal Free](https://minimal-kit-react.vercel.app/) | [Minimal](https://material-ui.com/store/items/minimal-dashboard/) |
10 | | ----------------------------------------------------- | :---------------------------------------------------------------- |
11 | | **6** Demo pages | **50+** demo pages |
12 | | - | ✓ Multi-language |
13 | | - | ✓ Dark/Light Mode 🌓 |
14 | | - | ✓ [More components](https://minimals.cc/components) |
15 | | - | ✓ Next.js version |
16 | | - | ✓ TypeScript version |
17 | | - | ✓ Design files (Figma & Sketch) |
18 |
19 | ## Page demo
20 |
21 | - [Dashboard](https://minimal-kit-react.vercel.app/dashboard/app)
22 | - [Users](https://minimal-kit-react.vercel.app/dashboard/user)
23 | - [Product](https://minimal-kit-react.vercel.app/dashboard/products)
24 | - [Blog](https://minimal-kit-react.vercel.app/dashboard/blog)
25 | - [Login](https://minimal-kit-react.vercel.app/login)
26 | - [Not Found](https://minimal-kit-react.vercel.app/404)
27 |
28 | ## Getting started
29 |
30 | - Recommended `node js 16.x` and `npm 6+`. (suggestion v16.15.0)
31 | - Install dependencies: `npm install` / `yarn install`
32 | - Start the project: `npm run start` / `yarn start`
33 |
34 | ## License
35 |
36 | Distributed under the MIT License. See [LICENSE](https://github.com/minimal-ui-kit/minimal.free/blob/main/LICENSE.md) for more information.
37 |
38 | ## Contact us
39 |
40 | Email Us: support@minimals.cc
41 |
--------------------------------------------------------------------------------
/frontend/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "env": {
4 | "browser": true,
5 | "es2021": true
6 | },
7 | "extends": [
8 | "airbnb",
9 | "plugin:jsx-a11y/recommended",
10 | "plugin:react-hooks/recommended",
11 | "prettier"
12 | ],
13 | "plugins": [
14 | "react",
15 | "react-hooks",
16 | "prettier"
17 | ],
18 | "parser": "@babel/eslint-parser",
19 | "parserOptions": {
20 | "ecmaVersion": 8,
21 | "requireConfigFile": false,
22 | "ecmaFeatures": {
23 | "experimentalObjectRestSpread": true,
24 | "impliedStrict": true
25 | }
26 | },
27 | "rules": {
28 | "no-new": 0,
29 | "no-alert": 0,
30 | "no-shadow": 0,
31 | "no-console": 0,
32 | "react/jsx-key": 1,
33 | "import/no-cycle": 0,
34 | "arrow-body-style": 1,
35 | "react/prop-types": 1,
36 | "no-param-reassign": 0,
37 | "no-nested-ternary": 0,
38 | "default-param-last": 0,
39 | "no-use-before-define": 0,
40 | "no-underscore-dangle": 0,
41 | "no-extra-boolean-cast": 1,
42 | "react/button-has-type": 1,
43 | "no-restricted-exports": 0,
44 | "react/no-children-prop": 0,
45 | "react/forbid-prop-types": 0,
46 | "jsx-a11y/anchor-is-valid": 0,
47 | "react/react-in-jsx-scope": 0,
48 | "react/no-array-index-key": 0,
49 | "react/no-unused-prop-types": 1,
50 | "react-hooks/rules-of-hooks": 2,
51 | "no-promise-executor-return": 0,
52 | "no-unsafe-optional-chaining": 0,
53 | "react/require-default-props": 0,
54 | "react/no-unescaped-entities": 0,
55 | "import/prefer-default-export": 0,
56 | "react/jsx-props-no-spreading": 0,
57 | "react/jsx-filename-extension": 0,
58 | "react/jsx-no-duplicate-props": 0,
59 | "react/jsx-no-useless-fragment": 0,
60 | "react/jsx-curly-brace-presence": 0,
61 | "react/destructuring-assignment": 0,
62 | "import/no-extraneous-dependencies": 0,
63 | "react/no-unstable-nested-components": 0,
64 | "react/function-component-definition": 0,
65 | "react/jsx-no-constructed-context-values": 0,
66 | "no-unused-vars": [
67 | 1,
68 | {
69 | "ignoreRestSiblings": false
70 | }
71 | ],
72 | "prefer-destructuring": [
73 | 1,
74 | {
75 | "object": true,
76 | "array": false
77 | }
78 | ]
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/user/UserListHead.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // @mui
3 | import { Box, Checkbox, TableRow, TableCell, TableHead, TableSortLabel } from '@mui/material';
4 |
5 | // ----------------------------------------------------------------------
6 |
7 | const visuallyHidden = {
8 | border: 0,
9 | margin: -1,
10 | padding: 0,
11 | width: '1px',
12 | height: '1px',
13 | overflow: 'hidden',
14 | position: 'absolute',
15 | whiteSpace: 'nowrap',
16 | clip: 'rect(0 0 0 0)',
17 | };
18 |
19 | UserListHead.propTypes = {
20 | order: PropTypes.oneOf(['asc', 'desc']),
21 | orderBy: PropTypes.string,
22 | rowCount: PropTypes.number,
23 | headLabel: PropTypes.array,
24 | numSelected: PropTypes.number,
25 | onRequestSort: PropTypes.func,
26 | onSelectAllClick: PropTypes.func,
27 | };
28 |
29 | export default function UserListHead({
30 | order,
31 | orderBy,
32 | rowCount,
33 | headLabel,
34 | numSelected,
35 | onRequestSort,
36 | onSelectAllClick,
37 | }) {
38 | const createSortHandler = (property) => (event) => {
39 | onRequestSort(event, property);
40 | };
41 |
42 | return (
43 |
44 |
45 |
46 | 0 && numSelected < rowCount}
48 | checked={rowCount > 0 && numSelected === rowCount}
49 | onChange={onSelectAllClick}
50 | />
51 |
52 | {headLabel.map((headCell) => (
53 |
58 |
64 | {headCell.label}
65 | {orderBy === headCell.id ? (
66 | {order === 'desc' ? 'sorted descending' : 'sorted ascending'}
67 | ) : null}
68 |
69 |
70 | ))}
71 |
72 |
73 | );
74 | }
75 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/app/AppOrderTimeline.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import PropTypes from 'prop-types';
3 | import { Card, Typography, CardHeader, CardContent } from '@mui/material';
4 | import { Timeline, TimelineDot, TimelineItem, TimelineContent, TimelineSeparator, TimelineConnector } from '@mui/lab';
5 | // utils
6 | import { fDateTime } from '../../../utils/formatTime';
7 |
8 | // ----------------------------------------------------------------------
9 |
10 | AppOrderTimeline.propTypes = {
11 | title: PropTypes.string,
12 | subheader: PropTypes.string,
13 | list: PropTypes.array.isRequired,
14 | };
15 |
16 | export default function AppOrderTimeline({ title, subheader, list, ...other }) {
17 | return (
18 |
19 |
20 |
21 |
28 |
29 | {list.map((item, index) => (
30 |
31 | ))}
32 |
33 |
34 |
35 | );
36 | }
37 |
38 | // ----------------------------------------------------------------------
39 |
40 | OrderItem.propTypes = {
41 | isLast: PropTypes.bool,
42 | item: PropTypes.shape({
43 | time: PropTypes.instanceOf(Date),
44 | title: PropTypes.string,
45 | type: PropTypes.string,
46 | }),
47 | };
48 |
49 | function OrderItem({ item, isLast }) {
50 | const { type, title, time } = item;
51 | return (
52 |
53 |
54 |
63 | {isLast ? null : }
64 |
65 |
66 |
67 | {title}
68 |
69 |
70 | {fDateTime(time)}
71 |
72 |
73 |
74 | );
75 | }
76 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/ic_notification_shipping.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/src/layouts/dashboard/header/Searchbar.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | // @mui
3 | import { styled } from '@mui/material/styles';
4 | import { Input, Slide, Button, IconButton, InputAdornment, ClickAwayListener } from '@mui/material';
5 | // utils
6 | import { bgBlur } from '../../../utils/cssStyles';
7 | // component
8 | import Iconify from '../../../components/iconify';
9 |
10 | // ----------------------------------------------------------------------
11 |
12 | const HEADER_MOBILE = 64;
13 | const HEADER_DESKTOP = 92;
14 |
15 | const StyledSearchbar = styled('div')(({ theme }) => ({
16 | ...bgBlur({ color: theme.palette.background.default }),
17 | top: 0,
18 | left: 0,
19 | zIndex: 99,
20 | width: '100%',
21 | display: 'flex',
22 | position: 'absolute',
23 | alignItems: 'center',
24 | height: HEADER_MOBILE,
25 | padding: theme.spacing(0, 3),
26 | boxShadow: theme.customShadows.z8,
27 | [theme.breakpoints.up('md')]: {
28 | height: HEADER_DESKTOP,
29 | padding: theme.spacing(0, 5),
30 | },
31 | }));
32 |
33 | // ----------------------------------------------------------------------
34 |
35 | export default function Searchbar() {
36 | const [open, setOpen] = useState(false);
37 |
38 | const handleOpen = () => {
39 | setOpen(!open);
40 | };
41 |
42 | const handleClose = () => {
43 | setOpen(false);
44 | };
45 |
46 | return (
47 |
48 |
49 | {!open && (
50 |
51 |
52 |
53 | )}
54 |
55 |
56 |
57 |
64 |
65 |
66 | }
67 | sx={{ mr: 1, fontWeight: 'fontWeightBold' }}
68 | />
69 |
72 |
73 |
74 |
75 |
76 | );
77 | }
78 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/app/AppNewsUpdate.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import PropTypes from 'prop-types';
3 | import { Box, Stack, Link, Card, Button, Divider, Typography, CardHeader } from '@mui/material';
4 | // utils
5 | import { fToNow } from '../../../utils/formatTime';
6 | // components
7 | import Iconify from '../../../components/iconify';
8 | import Scrollbar from '../../../components/scrollbar';
9 |
10 | // ----------------------------------------------------------------------
11 |
12 | AppNewsUpdate.propTypes = {
13 | title: PropTypes.string,
14 | subheader: PropTypes.string,
15 | list: PropTypes.array.isRequired,
16 | };
17 |
18 | export default function AppNewsUpdate({ title, subheader, list, ...other }) {
19 | return (
20 |
21 |
22 |
23 |
24 |
25 | {list.map((news) => (
26 |
27 | ))}
28 |
29 |
30 |
31 |
32 |
33 |
34 | }>
35 | View all
36 |
37 |
38 |
39 | );
40 | }
41 |
42 | // ----------------------------------------------------------------------
43 |
44 | NewsItem.propTypes = {
45 | news: PropTypes.shape({
46 | description: PropTypes.string,
47 | image: PropTypes.string,
48 | postedAt: PropTypes.instanceOf(Date),
49 | title: PropTypes.string,
50 | }),
51 | };
52 |
53 | function NewsItem({ news }) {
54 | const { image, title, description, postedAt } = news;
55 |
56 | return (
57 |
58 |
59 |
60 |
61 |
62 | {title}
63 |
64 |
65 |
66 | {description}
67 |
68 |
69 |
70 |
71 | {fToNow(postedAt)}
72 |
73 |
74 | );
75 | }
76 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/products/ProductCard.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // @mui
3 | import { Box, Card, Link, Typography, Stack } from '@mui/material';
4 | import { styled } from '@mui/material/styles';
5 | // utils
6 | import { fCurrency } from '../../../utils/formatNumber';
7 | // components
8 | import Label from '../../../components/label';
9 | import { ColorPreview } from '../../../components/color-utils';
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | const StyledProductImg = styled('img')({
14 | top: 0,
15 | width: '100%',
16 | height: '100%',
17 | objectFit: 'cover',
18 | position: 'absolute',
19 | });
20 |
21 | // ----------------------------------------------------------------------
22 |
23 | ShopProductCard.propTypes = {
24 | product: PropTypes.object,
25 | };
26 |
27 | export default function ShopProductCard({ product }) {
28 | const { name, cover, price, colors, status, priceSale } = product;
29 |
30 | return (
31 |
32 |
33 | {status && (
34 |
47 | )}
48 |
49 |
50 |
51 |
52 |
53 |
54 | {name}
55 |
56 |
57 |
58 |
59 |
60 |
61 |
69 | {priceSale && fCurrency(priceSale)}
70 |
71 |
72 | {fCurrency(price)}
73 |
74 |
75 |
76 |
77 | );
78 | }
79 |
--------------------------------------------------------------------------------
/frontend/src/theme/palette.js:
--------------------------------------------------------------------------------
1 | import { alpha } from '@mui/material/styles';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | // SETUP COLORS
6 | const GREY = {
7 | 0: '#FFFFFF',
8 | 100: '#F9FAFB',
9 | 200: '#F4F6F8',
10 | 300: '#DFE3E8',
11 | 400: '#C4CDD5',
12 | 500: '#919EAB',
13 | 600: '#637381',
14 | 700: '#454F5B',
15 | 800: '#212B36',
16 | 900: '#161C24',
17 | };
18 |
19 | const PRIMARY = {
20 | lighter: '#D1E9FC',
21 | light: '#76B0F1',
22 | main: '#2065D1',
23 | dark: '#103996',
24 | darker: '#061B64',
25 | contrastText: '#fff',
26 | };
27 |
28 | const SECONDARY = {
29 | lighter: '#D6E4FF',
30 | light: '#84A9FF',
31 | main: '#3366FF',
32 | dark: '#1939B7',
33 | darker: '#091A7A',
34 | contrastText: '#fff',
35 | };
36 |
37 | const INFO = {
38 | lighter: '#D0F2FF',
39 | light: '#74CAFF',
40 | main: '#1890FF',
41 | dark: '#0C53B7',
42 | darker: '#04297A',
43 | contrastText: '#fff',
44 | };
45 |
46 | const SUCCESS = {
47 | lighter: '#E9FCD4',
48 | light: '#AAF27F',
49 | main: '#54D62C',
50 | dark: '#229A16',
51 | darker: '#08660D',
52 | contrastText: GREY[800],
53 | };
54 |
55 | const WARNING = {
56 | lighter: '#FFF7CD',
57 | light: '#FFE16A',
58 | main: '#FFC107',
59 | dark: '#B78103',
60 | darker: '#7A4F01',
61 | contrastText: GREY[800],
62 | };
63 |
64 | const ERROR = {
65 | lighter: '#FFE7D9',
66 | light: '#FFA48D',
67 | main: '#FF4842',
68 | dark: '#B72136',
69 | darker: '#7A0C2E',
70 | contrastText: '#fff',
71 | };
72 |
73 | const palette = {
74 | common: { black: '#000', white: '#fff' },
75 | primary: PRIMARY,
76 | secondary: SECONDARY,
77 | info: INFO,
78 | success: SUCCESS,
79 | warning: WARNING,
80 | error: ERROR,
81 | grey: GREY,
82 | divider: alpha(GREY[500], 0.24),
83 | text: {
84 | primary: GREY[800],
85 | secondary: GREY[600],
86 | disabled: GREY[500],
87 | },
88 | background: {
89 | paper: '#fff',
90 | default: GREY[100],
91 | neutral: GREY[200],
92 | },
93 | action: {
94 | active: GREY[600],
95 | hover: alpha(GREY[500], 0.08),
96 | selected: alpha(GREY[500], 0.16),
97 | disabled: alpha(GREY[500], 0.8),
98 | disabledBackground: alpha(GREY[500], 0.24),
99 | focus: alpha(GREY[500], 0.24),
100 | hoverOpacity: 0.08,
101 | disabledOpacity: 0.48,
102 | },
103 | };
104 |
105 | export default palette;
106 |
--------------------------------------------------------------------------------
/frontend/src/components/label/styles.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { alpha, styled } from '@mui/material/styles';
3 | import { Box } from '@mui/material';
4 |
5 | // ----------------------------------------------------------------------
6 |
7 | export const StyledLabel = styled(Box)(({ theme, ownerState }) => {
8 | const isLight = theme.palette.mode === 'light';
9 |
10 | const filledVariant = ownerState.variant === 'filled';
11 |
12 | const outlinedVariant = ownerState.variant === 'outlined';
13 |
14 | const softVariant = ownerState.variant === 'soft';
15 |
16 | const defaultStyle = {
17 | ...(ownerState.color === 'default' && {
18 | // OUTLINED
19 | ...(outlinedVariant && {
20 | backgroundColor: 'transparent',
21 | color: theme.palette.text.primary,
22 | border: `1px solid ${alpha(theme.palette.grey[500], 0.32)}`,
23 | }),
24 | // SOFT
25 | ...(softVariant && {
26 | color: isLight ? theme.palette.text.primary : theme.palette.common.white,
27 | backgroundColor: alpha(theme.palette.grey[500], 0.16),
28 | }),
29 | }),
30 | };
31 |
32 | const colorStyle = {
33 | ...(ownerState.color !== 'default' && {
34 | // FILLED
35 | ...(filledVariant && {
36 | color: theme.palette[ownerState.color].contrastText,
37 | backgroundColor: theme.palette[ownerState.color].main,
38 | }),
39 | // OUTLINED
40 | ...(outlinedVariant && {
41 | backgroundColor: 'transparent',
42 | color: theme.palette[ownerState.color].main,
43 | border: `1px solid ${theme.palette[ownerState.color].main}`,
44 | }),
45 | // SOFT
46 | ...(softVariant && {
47 | color: theme.palette[ownerState.color][isLight ? 'dark' : 'light'],
48 | backgroundColor: alpha(theme.palette[ownerState.color].main, 0.16),
49 | }),
50 | }),
51 | };
52 |
53 | return {
54 | height: 24,
55 | minWidth: 22,
56 | lineHeight: 0,
57 | borderRadius: 6,
58 | cursor: 'default',
59 | alignItems: 'center',
60 | whiteSpace: 'nowrap',
61 | display: 'inline-flex',
62 | justifyContent: 'center',
63 | textTransform: 'capitalize',
64 | padding: theme.spacing(0, 1),
65 | color: theme.palette.grey[800],
66 | fontSize: theme.typography.pxToRem(12),
67 | fontFamily: theme.typography.fontFamily,
68 | backgroundColor: theme.palette.grey[300],
69 | fontWeight: theme.typography.fontWeightBold,
70 | ...colorStyle,
71 | ...defaultStyle,
72 | };
73 | });
74 |
--------------------------------------------------------------------------------
/frontend/src/layouts/dashboard/header/LanguagePopover.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | // @mui
3 | import { alpha } from '@mui/material/styles';
4 | import { Box, MenuItem, Stack, IconButton, Popover } from '@mui/material';
5 |
6 | // ----------------------------------------------------------------------
7 |
8 | const LANGS = [
9 | {
10 | value: 'en',
11 | label: 'English',
12 | icon: '/assets/icons/ic_flag_en.svg',
13 | },
14 | {
15 | value: 'de',
16 | label: 'German',
17 | icon: '/assets/icons/ic_flag_de.svg',
18 | },
19 | {
20 | value: 'fr',
21 | label: 'French',
22 | icon: '/assets/icons/ic_flag_fr.svg',
23 | },
24 | ];
25 |
26 | // ----------------------------------------------------------------------
27 |
28 | export default function LanguagePopover() {
29 | const [open, setOpen] = useState(null);
30 |
31 | const handleOpen = (event) => {
32 | setOpen(event.currentTarget);
33 | };
34 |
35 | const handleClose = () => {
36 | setOpen(null);
37 | };
38 |
39 | return (
40 | <>
41 | alpha(theme.palette.primary.main, theme.palette.action.focusOpacity),
49 | }),
50 | }}
51 | >
52 |
53 |
54 |
55 |
75 |
76 | {LANGS.map((option) => (
77 |
82 | ))}
83 |
84 |
85 | >
86 | );
87 | }
88 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/navbar/ic_analytics.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/app/AppCurrentVisits.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import ReactApexChart from 'react-apexcharts';
3 | // @mui
4 | import { useTheme, styled } from '@mui/material/styles';
5 | import { Card, CardHeader } from '@mui/material';
6 | // utils
7 | import { fNumber } from '../../../utils/formatNumber';
8 | // components
9 | import { useChart } from '../../../components/chart';
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | const CHART_HEIGHT = 372;
14 | const LEGEND_HEIGHT = 72;
15 |
16 | const StyledChartWrapper = styled('div')(({ theme }) => ({
17 | height: CHART_HEIGHT,
18 | marginTop: theme.spacing(5),
19 | '& .apexcharts-canvas svg': { height: CHART_HEIGHT },
20 | '& .apexcharts-canvas svg,.apexcharts-canvas foreignObject': {
21 | overflow: 'visible',
22 | },
23 | '& .apexcharts-legend': {
24 | height: LEGEND_HEIGHT,
25 | alignContent: 'center',
26 | position: 'relative !important',
27 | borderTop: `solid 1px ${theme.palette.divider}`,
28 | top: `calc(${CHART_HEIGHT - LEGEND_HEIGHT}px) !important`,
29 | },
30 | }));
31 |
32 | // ----------------------------------------------------------------------
33 |
34 | AppCurrentVisits.propTypes = {
35 | title: PropTypes.string,
36 | subheader: PropTypes.string,
37 | chartColors: PropTypes.arrayOf(PropTypes.string),
38 | chartData: PropTypes.array,
39 | };
40 |
41 | export default function AppCurrentVisits({ title, subheader, chartColors, chartData, ...other }) {
42 | const theme = useTheme();
43 |
44 | const chartLabels = chartData.map((i) => i.label);
45 |
46 | const chartSeries = chartData.map((i) => i.value);
47 |
48 | const chartOptions = useChart({
49 | colors: chartColors,
50 | labels: chartLabels,
51 | stroke: { colors: [theme.palette.background.paper] },
52 | legend: { floating: true, horizontalAlign: 'center' },
53 | dataLabels: { enabled: true, dropShadow: { enabled: false } },
54 | tooltip: {
55 | fillSeriesColor: false,
56 | y: {
57 | formatter: (seriesName) => fNumber(seriesName),
58 | title: {
59 | formatter: (seriesName) => `${seriesName}`,
60 | },
61 | },
62 | },
63 | plotOptions: {
64 | pie: { donut: { labels: { show: false } } },
65 | },
66 | });
67 |
68 | return (
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | );
77 | }
78 |
--------------------------------------------------------------------------------
/frontend/src/pages/LoginPage.js:
--------------------------------------------------------------------------------
1 | import { Helmet } from 'react-helmet-async';
2 | // @mui
3 | import { styled } from '@mui/material/styles';
4 | import { Link, Container, Typography, Divider } from '@mui/material';
5 | // hooks
6 | import useResponsive from '../hooks/useResponsive';
7 | // components
8 | import Logo from '../components/logo';
9 | // sections
10 | import { LoginForm } from '../sections/auth/login';
11 |
12 | // ----------------------------------------------------------------------
13 |
14 | const StyledRoot = styled('div')(({ theme }) => ({
15 | [theme.breakpoints.up('md')]: {
16 | display: 'flex',
17 | },
18 | }));
19 |
20 | const StyledSection = styled('div')(({ theme }) => ({
21 | width: '100%',
22 | maxWidth: 480,
23 | display: 'flex',
24 | flexDirection: 'column',
25 | justifyContent: 'center',
26 | boxShadow: theme.customShadows.card,
27 | backgroundColor: theme.palette.background.default,
28 | }));
29 |
30 | const StyledContent = styled('div')(({ theme }) => ({
31 | maxWidth: 480,
32 | margin: 'auto',
33 | minHeight: '100vh',
34 | display: 'flex',
35 | justifyContent: 'center',
36 | flexDirection: 'column',
37 | padding: theme.spacing(12, 0),
38 | }));
39 |
40 | // ----------------------------------------------------------------------
41 |
42 | export default function LoginPage() {
43 | const mdUp = useResponsive('up', 'md');
44 |
45 | return (
46 | <>
47 |
48 | Login | Minimal UI
49 |
50 |
51 |
52 |
59 |
60 | {mdUp && (
61 |
62 |
63 | Hi, Welcome Back
64 |
65 |
66 |
67 | )}
68 |
69 |
70 |
71 |
72 | Sign in to Minimal
73 |
74 |
75 | Don’t have an account? {''}
76 |
77 | Get started
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | >
86 | );
87 | }
88 |
--------------------------------------------------------------------------------
/frontend/src/pages/RegisterPage.js:
--------------------------------------------------------------------------------
1 | import { Helmet } from 'react-helmet-async';
2 | // @mui
3 | import { styled } from '@mui/material/styles';
4 | import { Link, Container, Typography, Divider } from '@mui/material';
5 | // hooks
6 | import useResponsive from '../hooks/useResponsive';
7 | // components
8 | import Logo from '../components/logo';
9 | // sections
10 | import RegisterForm from '../sections/auth/login/RegisterForm';
11 |
12 | // ----------------------------------------------------------------------
13 |
14 | const StyledRoot = styled('div')(({ theme }) => ({
15 | [theme.breakpoints.up('md')]: {
16 | display: 'flex',
17 | },
18 | }));
19 |
20 | const StyledSection = styled('div')(({ theme }) => ({
21 | width: '100%',
22 | maxWidth: 480,
23 | display: 'flex',
24 | flexDirection: 'column',
25 | justifyContent: 'center',
26 | boxShadow: theme.customShadows.card,
27 | backgroundColor: theme.palette.background.default,
28 | }));
29 |
30 | const StyledContent = styled('div')(({ theme }) => ({
31 | maxWidth: 480,
32 | margin: 'auto',
33 | minHeight: '100vh',
34 | display: 'flex',
35 | justifyContent: 'center',
36 | flexDirection: 'column',
37 | padding: theme.spacing(12, 0),
38 | }));
39 |
40 | // ----------------------------------------------------------------------
41 |
42 | export default function LoginPage() {
43 | const mdUp = useResponsive('up', 'md');
44 |
45 | return (
46 | <>
47 |
48 | Login | Minimal UI
49 |
50 |
51 |
52 |
59 |
60 | {mdUp && (
61 |
62 |
63 | Hi, Welcome Back
64 |
65 |
66 |
67 | )}
68 |
69 |
70 |
71 |
72 | Create Account to Minimal
73 |
74 |
75 | Already have an account? {''}
76 |
77 | Sign in
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | >
86 | );
87 | }
88 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/user/UserListToolbar.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // @mui
3 | import { styled, alpha } from '@mui/material/styles';
4 | import { Toolbar, Tooltip, IconButton, Typography, OutlinedInput, InputAdornment } from '@mui/material';
5 | // component
6 | import Iconify from '../../../components/iconify';
7 |
8 | // ----------------------------------------------------------------------
9 |
10 | const StyledRoot = styled(Toolbar)(({ theme }) => ({
11 | height: 96,
12 | display: 'flex',
13 | justifyContent: 'space-between',
14 | padding: theme.spacing(0, 1, 0, 3),
15 | }));
16 |
17 | const StyledSearch = styled(OutlinedInput)(({ theme }) => ({
18 | width: 240,
19 | transition: theme.transitions.create(['box-shadow', 'width'], {
20 | easing: theme.transitions.easing.easeInOut,
21 | duration: theme.transitions.duration.shorter,
22 | }),
23 | '&.Mui-focused': {
24 | width: 320,
25 | boxShadow: theme.customShadows.z8,
26 | },
27 | '& fieldset': {
28 | borderWidth: `1px !important`,
29 | borderColor: `${alpha(theme.palette.grey[500], 0.32)} !important`,
30 | },
31 | }));
32 |
33 | // ----------------------------------------------------------------------
34 |
35 | UserListToolbar.propTypes = {
36 | numSelected: PropTypes.number,
37 | filterName: PropTypes.string,
38 | onFilterName: PropTypes.func,
39 | };
40 |
41 | export default function UserListToolbar({ numSelected, filterName, onFilterName }) {
42 | return (
43 | 0 && {
46 | color: 'primary.main',
47 | bgcolor: 'primary.lighter',
48 | }),
49 | }}
50 | >
51 | {numSelected > 0 ? (
52 |
53 | {numSelected} selected
54 |
55 | ) : (
56 |
62 |
63 |
64 | }
65 | />
66 | )}
67 |
68 | {numSelected > 0 ? (
69 |
70 |
71 |
72 |
73 |
74 | ) : (
75 |
76 |
77 |
78 |
79 |
80 | )}
81 |
82 | );
83 | }
84 |
--------------------------------------------------------------------------------
/frontend/src/theme/typography.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export function remToPx(value) {
4 | return Math.round(parseFloat(value) * 16);
5 | }
6 |
7 | export function pxToRem(value) {
8 | return `${value / 16}rem`;
9 | }
10 |
11 | export function responsiveFontSizes({ sm, md, lg }) {
12 | return {
13 | '@media (min-width:600px)': {
14 | fontSize: pxToRem(sm),
15 | },
16 | '@media (min-width:900px)': {
17 | fontSize: pxToRem(md),
18 | },
19 | '@media (min-width:1200px)': {
20 | fontSize: pxToRem(lg),
21 | },
22 | };
23 | }
24 |
25 | // ----------------------------------------------------------------------
26 |
27 | const FONT_PRIMARY = 'Public Sans, sans-serif'; // Google Font
28 | // const FONT_SECONDARY = 'CircularStd, sans-serif'; // Local Font
29 |
30 | const typography = {
31 | fontFamily: FONT_PRIMARY,
32 | fontWeightRegular: 400,
33 | fontWeightMedium: 600,
34 | fontWeightBold: 700,
35 | h1: {
36 | fontWeight: 800,
37 | lineHeight: 80 / 64,
38 | fontSize: pxToRem(40),
39 | ...responsiveFontSizes({ sm: 52, md: 58, lg: 64 }),
40 | },
41 | h2: {
42 | fontWeight: 800,
43 | lineHeight: 64 / 48,
44 | fontSize: pxToRem(32),
45 | ...responsiveFontSizes({ sm: 40, md: 44, lg: 48 }),
46 | },
47 | h3: {
48 | fontWeight: 700,
49 | lineHeight: 1.5,
50 | fontSize: pxToRem(24),
51 | ...responsiveFontSizes({ sm: 26, md: 30, lg: 32 }),
52 | },
53 | h4: {
54 | fontWeight: 700,
55 | lineHeight: 1.5,
56 | fontSize: pxToRem(20),
57 | ...responsiveFontSizes({ sm: 20, md: 24, lg: 24 }),
58 | },
59 | h5: {
60 | fontWeight: 700,
61 | lineHeight: 1.5,
62 | fontSize: pxToRem(18),
63 | ...responsiveFontSizes({ sm: 19, md: 20, lg: 20 }),
64 | },
65 | h6: {
66 | fontWeight: 700,
67 | lineHeight: 28 / 18,
68 | fontSize: pxToRem(17),
69 | ...responsiveFontSizes({ sm: 18, md: 18, lg: 18 }),
70 | },
71 | subtitle1: {
72 | fontWeight: 600,
73 | lineHeight: 1.5,
74 | fontSize: pxToRem(16),
75 | },
76 | subtitle2: {
77 | fontWeight: 600,
78 | lineHeight: 22 / 14,
79 | fontSize: pxToRem(14),
80 | },
81 | body1: {
82 | lineHeight: 1.5,
83 | fontSize: pxToRem(16),
84 | },
85 | body2: {
86 | lineHeight: 22 / 14,
87 | fontSize: pxToRem(14),
88 | },
89 | caption: {
90 | lineHeight: 1.5,
91 | fontSize: pxToRem(12),
92 | },
93 | overline: {
94 | fontWeight: 700,
95 | lineHeight: 1.5,
96 | fontSize: pxToRem(12),
97 | textTransform: 'uppercase',
98 | },
99 | button: {
100 | fontWeight: 700,
101 | lineHeight: 24 / 14,
102 | fontSize: pxToRem(14),
103 | textTransform: 'capitalize',
104 | },
105 | };
106 |
107 | export default typography;
108 |
--------------------------------------------------------------------------------
/frontend/src/utils/cssStyles.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { alpha } from '@mui/material/styles';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | export function bgBlur(props) {
7 | const color = props?.color || '#000000';
8 | const blur = props?.blur || 6;
9 | const opacity = props?.opacity || 0.8;
10 | const imgUrl = props?.imgUrl;
11 |
12 | if (imgUrl) {
13 | return {
14 | position: 'relative',
15 | backgroundImage: `url(${imgUrl})`,
16 | '&:before': {
17 | position: 'absolute',
18 | top: 0,
19 | left: 0,
20 | zIndex: 9,
21 | content: '""',
22 | width: '100%',
23 | height: '100%',
24 | backdropFilter: `blur(${blur}px)`,
25 | WebkitBackdropFilter: `blur(${blur}px)`,
26 | backgroundColor: alpha(color, opacity),
27 | },
28 | };
29 | }
30 |
31 | return {
32 | backdropFilter: `blur(${blur}px)`,
33 | WebkitBackdropFilter: `blur(${blur}px)`,
34 | backgroundColor: alpha(color, opacity),
35 | };
36 | }
37 |
38 | // ----------------------------------------------------------------------
39 |
40 | export function bgGradient(props) {
41 | const direction = props?.direction || 'to bottom';
42 | const startColor = props?.startColor;
43 | const endColor = props?.endColor;
44 | const imgUrl = props?.imgUrl;
45 | const color = props?.color;
46 |
47 | if (imgUrl) {
48 | return {
49 | background: `linear-gradient(${direction}, ${startColor || color}, ${endColor || color}), url(${imgUrl})`,
50 | backgroundSize: 'cover',
51 | backgroundRepeat: 'no-repeat',
52 | backgroundPosition: 'center center',
53 | };
54 | }
55 |
56 | return {
57 | background: `linear-gradient(${direction}, ${startColor}, ${endColor})`,
58 | };
59 | }
60 |
61 | // ----------------------------------------------------------------------
62 |
63 | export function textGradient(value) {
64 | return {
65 | background: `-webkit-linear-gradient(${value})`,
66 | WebkitBackgroundClip: 'text',
67 | WebkitTextFillColor: 'transparent',
68 | };
69 | }
70 |
71 | // ----------------------------------------------------------------------
72 |
73 | export function filterStyles(value) {
74 | return {
75 | filter: value,
76 | WebkitFilter: value,
77 | MozFilter: value,
78 | };
79 | }
80 |
81 | // ----------------------------------------------------------------------
82 |
83 | export const hideScrollbarY = {
84 | msOverflowStyle: 'none',
85 | scrollbarWidth: 'none',
86 | overflowY: 'scroll',
87 | '&::-webkit-scrollbar': {
88 | display: 'none',
89 | },
90 | };
91 |
92 | // ----------------------------------------------------------------------
93 |
94 | export const hideScrollbarX = {
95 | msOverflowStyle: 'none',
96 | scrollbarWidth: 'none',
97 | overflowX: 'scroll',
98 | '&::-webkit-scrollbar': {
99 | display: 'none',
100 | },
101 | };
102 |
--------------------------------------------------------------------------------
/frontend/src/theme/shadows.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { alpha } from '@mui/material/styles';
3 | //
4 | import palette from './palette';
5 |
6 | // ----------------------------------------------------------------------
7 |
8 | const color = palette.grey[500];
9 |
10 | export default function shadows() {
11 | const transparent1 = alpha(color, 0.2);
12 | const transparent2 = alpha(color, 0.14);
13 | const transparent3 = alpha(color, 0.12);
14 | return [
15 | 'none',
16 | `0px 2px 1px -1px ${transparent1},0px 1px 1px 0px ${transparent2},0px 1px 3px 0px ${transparent3}`,
17 | `0px 3px 1px -2px ${transparent1},0px 2px 2px 0px ${transparent2},0px 1px 5px 0px ${transparent3}`,
18 | `0px 3px 3px -2px ${transparent1},0px 3px 4px 0px ${transparent2},0px 1px 8px 0px ${transparent3}`,
19 | `0px 2px 4px -1px ${transparent1},0px 4px 5px 0px ${transparent2},0px 1px 10px 0px ${transparent3}`,
20 | `0px 3px 5px -1px ${transparent1},0px 5px 8px 0px ${transparent2},0px 1px 14px 0px ${transparent3}`,
21 | `0px 3px 5px -1px ${transparent1},0px 6px 10px 0px ${transparent2},0px 1px 18px 0px ${transparent3}`,
22 | `0px 4px 5px -2px ${transparent1},0px 7px 10px 1px ${transparent2},0px 2px 16px 1px ${transparent3}`,
23 | `0px 5px 5px -3px ${transparent1},0px 8px 10px 1px ${transparent2},0px 3px 14px 2px ${transparent3}`,
24 | `0px 5px 6px -3px ${transparent1},0px 9px 12px 1px ${transparent2},0px 3px 16px 2px ${transparent3}`,
25 | `0px 6px 6px -3px ${transparent1},0px 10px 14px 1px ${transparent2},0px 4px 18px 3px ${transparent3}`,
26 | `0px 6px 7px -4px ${transparent1},0px 11px 15px 1px ${transparent2},0px 4px 20px 3px ${transparent3}`,
27 | `0px 7px 8px -4px ${transparent1},0px 12px 17px 2px ${transparent2},0px 5px 22px 4px ${transparent3}`,
28 | `0px 7px 8px -4px ${transparent1},0px 13px 19px 2px ${transparent2},0px 5px 24px 4px ${transparent3}`,
29 | `0px 7px 9px -4px ${transparent1},0px 14px 21px 2px ${transparent2},0px 5px 26px 4px ${transparent3}`,
30 | `0px 8px 9px -5px ${transparent1},0px 15px 22px 2px ${transparent2},0px 6px 28px 5px ${transparent3}`,
31 | `0px 8px 10px -5px ${transparent1},0px 16px 24px 2px ${transparent2},0px 6px 30px 5px ${transparent3}`,
32 | `0px 8px 11px -5px ${transparent1},0px 17px 26px 2px ${transparent2},0px 6px 32px 5px ${transparent3}`,
33 | `0px 9px 11px -5px ${transparent1},0px 18px 28px 2px ${transparent2},0px 7px 34px 6px ${transparent3}`,
34 | `0px 9px 12px -6px ${transparent1},0px 19px 29px 2px ${transparent2},0px 7px 36px 6px ${transparent3}`,
35 | `0px 10px 13px -6px ${transparent1},0px 20px 31px 3px ${transparent2},0px 8px 38px 7px ${transparent3}`,
36 | `0px 10px 13px -6px ${transparent1},0px 21px 33px 3px ${transparent2},0px 8px 40px 7px ${transparent3}`,
37 | `0px 10px 14px -6px ${transparent1},0px 22px 35px 3px ${transparent2},0px 8px 42px 7px ${transparent3}`,
38 | `0px 11px 14px -7px ${transparent1},0px 23px 36px 3px ${transparent2},0px 9px 44px 8px ${transparent3}`,
39 | `0px 11px 15px -7px ${transparent1},0px 24px 38px 3px ${transparent2},0px 9px 46px 8px ${transparent3}`,
40 | ];
41 | }
42 |
--------------------------------------------------------------------------------
/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@minimal/material-kit-react",
3 | "author": "minimals.cc",
4 | "licence": "MIT",
5 | "version": "1.7.0",
6 | "private": false,
7 | "scripts": {
8 | "start": "react-scripts start",
9 | "build": "react-scripts build",
10 | "test": "react-scripts test",
11 | "eject": "react-scripts eject",
12 | "lint": "eslint --ext .js,.jsx ./src",
13 | "lint:fix": "eslint --fix --ext .js,.jsx ./src",
14 | "clear-all": "rm -rf build node_modules",
15 | "re-start": "rm -rf build node_modules && yarn install && yarn start",
16 | "re-build": "rm -rf build node_modules && yarn install && yarn build"
17 | },
18 | "eslintConfig": {
19 | "extends": [
20 | "react-app"
21 | ]
22 | },
23 | "babel": {
24 | "presets": [
25 | "@babel/preset-react"
26 | ]
27 | },
28 | "browserslist": {
29 | "production": [
30 | ">0.2%",
31 | "not dead",
32 | "not op_mini all"
33 | ],
34 | "development": [
35 | "last 1 chrome version",
36 | "last 1 firefox version",
37 | "last 1 safari version"
38 | ]
39 | },
40 | "dependencies": {
41 | "@emotion/react": "^11.10.6",
42 | "@emotion/styled": "^11.10.6",
43 | "@faker-js/faker": "^7.6.0",
44 | "@iconify/react": "^4.1.0",
45 | "@mui/icons-material": "^5.14.1",
46 | "@mui/lab": "^5.0.0-alpha.103",
47 | "@mui/material": "^5.11.10",
48 | "@mui/styles": "^5.14.1",
49 | "@mui/x-date-pickers": "^6.10.1",
50 | "@reduxjs/toolkit": "^1.9.5",
51 | "apexcharts": "^3.37.0",
52 | "axios": "^0.18.0",
53 | "change-case": "^4.1.2",
54 | "classnames": "^2.3.2",
55 | "date-fns": "^2.29.3",
56 | "highcharts-react-official": "^3.2.0",
57 | "history": "^5.3.0",
58 | "jwt-decode": "^2.2.0",
59 | "lodash": "^4.17.21",
60 | "numeral": "^2.0.6",
61 | "prop-types": "^15.8.1",
62 | "react": "^18.2.0",
63 | "react-apexcharts": "^1.4.0",
64 | "react-dom": "^18.2.0",
65 | "react-grid-layout": "^1.3.4",
66 | "react-helmet-async": "^1.3.0",
67 | "react-hook-form": "^7.43.1",
68 | "react-redux": "^8.1.1",
69 | "react-resizable": "^3.0.5",
70 | "react-rnd": "^10.4.1",
71 | "react-router-dom": "^6.14.2",
72 | "react-scripts": "^5.0.1",
73 | "redux": "^4.2.1",
74 | "redux-thunk": "^2.4.2",
75 | "simplebar-react": "^3.2.1",
76 | "styled-components": "^6.0.5",
77 | "web-vitals": "^3.1.1"
78 | },
79 | "devDependencies": {
80 | "@babel/core": "^7.21.0",
81 | "@babel/eslint-parser": "^7.19.1",
82 | "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
83 | "eslint": "^8.34.0",
84 | "eslint-config-airbnb": "^19.0.4",
85 | "eslint-config-prettier": "^8.6.0",
86 | "eslint-config-react-app": "^7.0.1",
87 | "eslint-plugin-flowtype": "^8.0.3",
88 | "eslint-plugin-import": "^2.27.5",
89 | "eslint-plugin-jsx-a11y": "^6.7.1",
90 | "eslint-plugin-prettier": "^4.2.1",
91 | "eslint-plugin-react": "^7.32.2",
92 | "eslint-plugin-react-hooks": "^4.6.0",
93 | "prettier": "^2.8.4"
94 | },
95 | "overrides": {
96 | "nth-check": "2.1.1"
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/frontend/src/pages/styles/styles.css:
--------------------------------------------------------------------------------
1 | html {
2 | background-color: #eeeeee;
3 | }
4 | body {
5 | font-family: Roboto, sans-serif;
6 | }
7 | .react-grid-layout {
8 | position: relative;
9 | transition: height 200ms ease;
10 | }
11 | .react-grid-item {
12 | transition: all 200ms ease;
13 | transition-property: left, top;
14 | }
15 | .react-grid-item.cssTransforms {
16 | transition-property: transform;
17 | }
18 | .react-grid-item.resizing {
19 | z-index: 1;
20 | will-change: width, height;
21 | }
22 |
23 | .react-grid-item.react-draggable-dragging {
24 | transition: none;
25 | z-index: 3;
26 | will-change: transform;
27 | }
28 |
29 | .react-grid-item.react-grid-placeholder {
30 | background: blue;
31 | opacity: 0.2;
32 | transition-duration: 100ms;
33 | z-index: 2;
34 | -webkit-user-select: none;
35 | -moz-user-select: none;
36 | -ms-user-select: none;
37 | -o-user-select: none;
38 | user-select: none;
39 | }
40 |
41 | .react-grid-item > .react-resizable-handle {
42 | position: absolute;
43 | width: 20px;
44 | height: 20px;
45 | bottom: 0;
46 | right: 0;
47 | cursor: se-resize;
48 | }
49 |
50 | .react-grid-item > .react-resizable-handle::after {
51 | content: "";
52 | position: absolute;
53 | right: 3px;
54 | bottom: 3px;
55 | width: 5px;
56 | height: 5px;
57 | border-right: 2px solid rgba(0, 0, 0, 0.4);
58 | border-bottom: 2px solid rgba(0, 0, 0, 0.4);
59 | }
60 |
61 | .react-grid-item:not(.react-grid-placeholder) {
62 | background: grey;
63 | }
64 |
65 | .window-header {
66 | background-color: lightblue;
67 | display: flex;
68 | justify-content: space-between;
69 | height: 25px;
70 | }
71 |
72 | .logo-container {
73 | overflow: hidden;
74 | }
75 |
76 | .app-name {
77 | color: black;
78 | font-size: 14px;
79 | margin-bottom: 5px;
80 | padding-left: 8px;
81 | }
82 |
83 | .actions-container {
84 | display: flex;
85 | padding-top: 3px;
86 | }
87 |
88 | .icon {
89 | color: black;
90 | font-size: 20px;
91 | padding-top: 5px;
92 | }
93 |
94 | .window-button-style {
95 | background-color: transparent;
96 | border: none;
97 | width: 20px;
98 | height: 20px;
99 | padding: 0;
100 | margin: 0;
101 | transition: background-color 150ms ease;
102 | }
103 |
104 | .window-controls-icon {
105 | pointer-events: none;
106 | user-select: none;
107 | width: 20px;
108 | height: 20px;
109 | transition: fill 150ms ease;
110 | }
111 |
112 | .settings-window:hover {
113 | background-color: orange;
114 | }
115 |
116 | .close-window:hover {
117 | background-color: #e6004c;
118 | }
119 |
120 | .settings-window:focus {
121 | outline: none;
122 | }
123 |
124 | .close-window:focus {
125 | outline: none;
126 | }
127 |
128 | html, body, #root, #root > div {
129 | height: 100%;
130 | margin: 0;
131 | box-sizing: border-box;
132 | background: url('bg.png');
133 | background-repeat: repeat;
134 | }
--------------------------------------------------------------------------------
/frontend/public/assets/icons/ic_notification_chat.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/src/sections/auth/login/login.js:
--------------------------------------------------------------------------------
1 | import React, {useState} from 'react';
2 | import { TextField, Button, Container, Stack } from '@mui/material';
3 | import { Link } from "react-router-dom"
4 | import { DateField } from '@mui/x-date-pickers/DateField';
5 |
6 |
7 | const LoginForm = () => {
8 | const [firstName, setFirstName] = useState('')
9 | const [lastName, setLastName] = useState('')
10 | const [email, setEmail] = useState('')
11 | const [dateOfBirth, setDateOfBirth] = useState('')
12 | const [password, setPassword] = useState('')
13 |
14 | function handleSubmit(event) {
15 | event.preventDefault();
16 | console.log(firstName, lastName, email, dateOfBirth, password)
17 | }
18 |
19 | return (
20 | <>
21 | Register Form
22 | }>
23 |
24 | setFirstName(e.target.value)}
30 | value={firstName}
31 | fullWidth
32 | required
33 | />
34 | setLastName(e.target.value)}
40 | value={lastName}
41 | fullWidth
42 | required
43 | />
44 |
45 | setEmail(e.target.value)}
51 | value={email}
52 | fullWidth
53 | required
54 | sx={{mb: 4}}
55 | />
56 | setPassword(e.target.value)}
62 | value={password}
63 | required
64 | fullWidth
65 | sx={{mb: 4}}
66 | />
67 | setDateOfBirth(e.target.value)}
73 | value={dateOfBirth}
74 | fullWidth
75 | required
76 | sx={{mb: 4}}
77 | />
78 |
79 |
80 | Already have an account? Login Here
81 |
82 | >
83 | )
84 | }
85 |
86 | export default LoginForm;
--------------------------------------------------------------------------------
/frontend/src/pages/EditPage.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState} from 'react';
2 | import Avatar from '@mui/material/Avatar';
3 | import Button from '@mui/material/Button';
4 | import CssBaseline from '@mui/material/CssBaseline';
5 | import TextField from '@mui/material/TextField';
6 | import Grid from '@mui/material/Grid';
7 | import Box from '@mui/material/Box';
8 | import Typography from '@mui/material/Typography';
9 | import Container from '@mui/material/Container';
10 | import { createTheme, ThemeProvider } from '@mui/material/styles';
11 | import { useDispatch, useSelector } from 'react-redux';
12 | import { useNavigate } from 'react-router-dom';
13 | import { checkPassword } from '../redux/actions/authActions';
14 |
15 | const defaultTheme = createTheme();
16 |
17 | function EditPage() {
18 |
19 | const navigate = useNavigate();
20 | const dispatch = useDispatch();
21 |
22 | const users = useSelector((state) => state.auth.user);
23 | const checked = useSelector((state) => state.checked.checked);
24 | const errors = useSelector((state) => state.errors);
25 |
26 | useEffect(() => {
27 | console.log(users)
28 | }, [dispatch, users])
29 |
30 | useEffect(() => {
31 | console.log(errors, "aa")
32 | }, [dispatch, errors])
33 |
34 | useEffect(() => {
35 | if (checked) {
36 | navigate('/editprofile');
37 | }
38 | }, [dispatch, checked])
39 |
40 | const handleSubmit = async (event) => {
41 | event.preventDefault();
42 | const data = new FormData(event.currentTarget);
43 |
44 | // Dispatch the loginUser action
45 | try {
46 | const resultAction = await dispatch(
47 | checkPassword({
48 | password: data.get('password'),
49 | prepwd: users.pwd,
50 | })
51 | );
52 |
53 | } catch (error) {
54 | console.error('Failed to log in:', error);
55 | }
56 | };
57 |
58 | return (
59 |
60 |
61 |
62 |
70 |
71 |
72 | Setting profile
73 |
74 |
75 |
76 |
88 |
89 |
92 |
93 |
94 |
95 |
96 | );
97 | }
98 |
99 | export default EditPage;
100 |
--------------------------------------------------------------------------------
/frontend/src/layouts/dashboard/header/AccountPopover.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 | import { alpha } from '@mui/material/styles';
3 | import { Box, Divider, Typography, Stack, MenuItem, Avatar, IconButton, Popover } from '@mui/material';
4 | import { useDispatch, useSelector } from 'react-redux';
5 | import { logoutUser } from '../../../redux/actions/authActions';
6 |
7 | const MENU_OPTIONS = [
8 | {
9 | label: 'Home',
10 | icon: 'eva:home-fill',
11 | href: '/',
12 | },
13 | {
14 | label: 'Edit Profile',
15 | icon: 'eva:settings-2-fill',
16 | href: '/edit',
17 | },
18 | ];
19 |
20 | // ----------------------------------------------------------------------
21 |
22 | export default function AccountPopover() {
23 | const [open, setOpen] = useState(null);
24 | const dispatch = useDispatch();
25 |
26 | const users = useSelector((state) => state.auth.user);
27 |
28 | useEffect(() => {
29 | console.log(users)
30 | }, [dispatch, users])
31 |
32 | const handleOpen = (event) => {
33 | setOpen(event.currentTarget);
34 | };
35 |
36 | const handleClose = () => {
37 | setOpen(null);
38 | };
39 |
40 | const handleLogout = () => {
41 | dispatch(logoutUser());
42 | };
43 |
44 | return (
45 | <>
46 | alpha(theme.palette.grey[900], 0.8),
59 | },
60 | }),
61 | }}
62 | >
63 |
64 |
65 |
66 |
85 |
86 |
87 | {users.firstName} {users.lastName}
88 |
89 |
90 | {users.userEmail}
91 |
92 |
93 |
94 |
95 |
96 |
97 | {MENU_OPTIONS.map((option) => (
98 |
101 | ))}
102 |
103 |
104 |
105 |
106 |
109 |
110 | >
111 | );
112 | }
113 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/ic_notification_package.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/src/redux/actions/authActions.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | // eslint-disable-next-line camelcase
3 | import jwt_decode from 'jwt-decode';
4 | import { GET_ERRORS, SET_CURRENT_USER, CHECKED_USER, GET_USER } from './types';
5 | import setAuthToken from '../../utils/setAuthToken';
6 |
7 | export const registerUser = (userData, navigate) => async (dispatch) => {
8 | try {
9 | const newUser = await axios.post('http://localhost:5000/api/users/register', userData);
10 | if (newUser) navigate('/login');
11 | } catch (err) {
12 | dispatch({
13 | type: GET_ERRORS,
14 | payload: err.response.data,
15 | });
16 | }
17 | };
18 |
19 | export const getUser = (id) => async (dispatch) => {
20 | try {
21 | const user = await axios.get(`http://localhost:5000/api/users/${id}`);
22 | dispatch({
23 | type: GET_USER,
24 | payload: user.data,
25 | });
26 | return Promise.resolve();
27 | } catch (err) {
28 | dispatch({
29 | type: GET_ERRORS,
30 | payload: err.response.data,
31 | });
32 | return Promise.reject();
33 | }
34 | }
35 |
36 | export const updateUser = (userData) => async (dispatch) => {
37 | try {
38 | const user = await axios.put(`http://localhost:5000/api/users/${userData.id}`, userData);
39 | // Get the token
40 | const { token } = user.data;
41 | // Save the token in localStorage
42 | localStorage.setItem('jwtToken', token);
43 | // Set token to Authentication header
44 | setAuthToken(token);
45 | // Get the user by the token
46 | const userDecoded = jwt_decode(token);
47 | // Get the user by the token
48 | dispatch(setCurrentUser(userDecoded));
49 | return Promise.resolve();
50 | } catch (err) {
51 | dispatch({
52 | type: GET_ERRORS,
53 | payload: err.response.data,
54 | });
55 | return Promise.reject();
56 | }
57 | }
58 |
59 | export const loginUser = (userData) => async (dispatch) => {
60 | try {
61 | const user = await axios.post('http://localhost:5000/api/users/login', userData);
62 | // Get the token
63 | const { token } = user.data;
64 | // Save the token in localStorage
65 | localStorage.setItem('jwtToken', token);
66 | // Set token to Authentication header
67 | setAuthToken(token);
68 | // Get the user by the token
69 | const userDecoded = jwt_decode(token);
70 | // Set current user
71 | dispatch(setCurrentUser(userDecoded));
72 | return Promise.resolve();
73 | } catch (err) {
74 | dispatch({
75 | type: GET_ERRORS,
76 | payload: err.response.data,
77 | });
78 | return Promise.reject();
79 | }
80 | };
81 |
82 | export const checkPassword = (userData) => async (dispatch) => {
83 | try {
84 | const user = await axios.post('http://localhost:5000/api/users/checkpassword', userData);
85 | // Get the token
86 | const { result, pwd } = user.data;
87 | dispatch({
88 | type: CHECKED_USER,
89 | payload: { result, pwd }
90 | });
91 | return Promise.resolve();
92 | } catch (err) {
93 | dispatch({
94 | type: GET_ERRORS,
95 | payload: err.response.data,
96 | });
97 | return Promise.reject();
98 | }
99 | };
100 |
101 | export const setCurrentUser = (userDecoded) => ({
102 | type: SET_CURRENT_USER,
103 | payload: userDecoded,
104 | });
105 |
106 | export const logoutUser = () => (dispatch) => {
107 | // Remove token from localStorage
108 | localStorage.removeItem('jwtToken');
109 | // Remove auth header
110 | setAuthToken(false);
111 | // Set user to {}
112 | dispatch(setCurrentUser({}));
113 | };
114 |
--------------------------------------------------------------------------------
/frontend/src/components/logo/Logo.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { forwardRef } from 'react';
3 | import { Link as RouterLink } from 'react-router-dom';
4 | // @mui
5 | import { useTheme } from '@mui/material/styles';
6 | import { Box, Link } from '@mui/material';
7 |
8 | // ----------------------------------------------------------------------
9 |
10 | const Logo = forwardRef(({ disabledLink = false, sx, ...other }, ref) => {
11 | const theme = useTheme();
12 |
13 | const PRIMARY_LIGHT = theme.palette.primary.light;
14 |
15 | const PRIMARY_MAIN = theme.palette.primary.main;
16 |
17 | const PRIMARY_DARK = theme.palette.primary.dark;
18 |
19 | // OR using local (public folder)
20 | // -------------------------------------------------------
21 | // const logo = (
22 | // your path
25 | // sx={{ width: 40, height: 40, cursor: 'pointer', ...sx }}
26 | // />
27 | // );
28 |
29 | const logo = (
30 |
41 |
74 |
75 | );
76 |
77 | if (disabledLink) {
78 | return <>{logo}>;
79 | }
80 |
81 | return (
82 |
83 | {logo}
84 |
85 | );
86 | });
87 |
88 | Logo.propTypes = {
89 | sx: PropTypes.object,
90 | disabledLink: PropTypes.bool,
91 | };
92 |
93 | export default Logo;
94 |
--------------------------------------------------------------------------------