├── .circleci
└── config.yml
├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── backend
├── .gitignore
├── Procfile
├── accounts
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── serializers.py
│ ├── tests.py
│ ├── token.py
│ ├── urls.py
│ └── views.py
├── config
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── conftest.py
├── db.sqlite3
├── manage.py
├── media
│ └── users
│ │ └── placeholder.png
├── pytest.ini
├── requirements
│ ├── base.txt
│ ├── local.txt
│ └── production.txt
├── static
│ └── test.js
└── templates
│ └── index.html
├── frontend
├── .eslintignore
├── .gitignore
├── LICENSE
├── README.md
├── config-overrides.js
├── jsconfig.json
├── package.json
├── public
│ ├── _redirects
│ ├── assets
│ │ ├── bg_card.png
│ │ ├── bg_gradient.jpeg
│ │ ├── icons
│ │ │ ├── flags
│ │ │ │ ├── ic_flag_cn.svg
│ │ │ │ ├── ic_flag_de.svg
│ │ │ │ ├── ic_flag_en.svg
│ │ │ │ ├── ic_flag_fr.svg
│ │ │ │ ├── ic_flag_kr.svg
│ │ │ │ ├── ic_flag_sa.svg
│ │ │ │ ├── ic_flag_us.svg
│ │ │ │ └── ic_flag_vn.svg
│ │ │ └── navbar
│ │ │ │ ├── ic_analytics.svg
│ │ │ │ ├── ic_banking.svg
│ │ │ │ ├── ic_blog.svg
│ │ │ │ ├── ic_booking.svg
│ │ │ │ ├── ic_calendar.svg
│ │ │ │ ├── ic_cart.svg
│ │ │ │ ├── ic_chat.svg
│ │ │ │ ├── ic_dashboard.svg
│ │ │ │ ├── ic_ecommerce.svg
│ │ │ │ ├── ic_invoice.svg
│ │ │ │ ├── ic_kanban.svg
│ │ │ │ ├── ic_mail.svg
│ │ │ │ ├── ic_menu_item.svg
│ │ │ │ └── ic_user.svg
│ │ ├── illustrations
│ │ │ ├── illustration_components.png
│ │ │ ├── illustration_dashboard.png
│ │ │ ├── illustration_empty_cart.svg
│ │ │ ├── illustration_empty_content.svg
│ │ │ ├── illustration_empty_mail.svg
│ │ │ ├── illustration_invite.png
│ │ │ ├── illustration_login.png
│ │ │ └── illustration_register.png
│ │ ├── overlay.svg
│ │ └── placeholder.svg
│ ├── favicon
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── apple-touch-icon.png
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ └── favicon.ico
│ ├── fonts
│ │ ├── CircularStd-Bold.otf
│ │ ├── CircularStd-Book.otf
│ │ ├── CircularStd-Medium.otf
│ │ ├── Roboto-Bold.ttf
│ │ ├── Roboto-Regular.ttf
│ │ └── index.css
│ ├── index.html
│ ├── logo
│ │ ├── logo_full.jpg
│ │ ├── logo_full.svg
│ │ └── logo_single.svg
│ ├── manifest.json
│ └── robots.txt
├── src
│ ├── App.js
│ ├── _mock
│ │ ├── _analytics.js
│ │ ├── _app.js
│ │ ├── _banking.js
│ │ ├── _booking.js
│ │ ├── _calenderViewOptions.js
│ │ ├── _countries.js
│ │ ├── _countriesAndStates.js
│ │ ├── _ecommerce.js
│ │ ├── _invoice.js
│ │ ├── _mock.js
│ │ ├── _others.js
│ │ ├── _plans.js
│ │ ├── _roles.js
│ │ ├── _timeZoneOptions.js
│ │ ├── _top100Films.js
│ │ ├── _user.js
│ │ ├── address.js
│ │ ├── boolean.js
│ │ ├── company.js
│ │ ├── email.js
│ │ ├── funcs.js
│ │ ├── index.js
│ │ ├── map
│ │ │ ├── cities.js
│ │ │ ├── countries.js
│ │ │ └── map-style-basic-v8.json
│ │ ├── name.js
│ │ ├── number.js
│ │ ├── phoneNumber.js
│ │ ├── role.js
│ │ └── text.js
│ ├── assets
│ │ ├── icon_plan_free.js
│ │ ├── icon_plan_premium.js
│ │ ├── icon_plan_starter.js
│ │ ├── icon_sent.js
│ │ ├── illustration_403.js
│ │ ├── illustration_404.js
│ │ ├── illustration_500.js
│ │ ├── illustration_background.js
│ │ ├── illustration_booking.js
│ │ ├── illustration_checkin.js
│ │ ├── illustration_checkout.js
│ │ ├── illustration_coming_soon.js
│ │ ├── illustration_doc.js
│ │ ├── illustration_maintenance.js
│ │ ├── illustration_motivation.js
│ │ ├── illustration_order_complete.js
│ │ ├── illustration_seo.js
│ │ ├── illustration_upload.js
│ │ └── index.js
│ ├── components
│ │ ├── Avatar.js
│ │ ├── BadgeStatus.js
│ │ ├── Breadcrumbs.js
│ │ ├── CopyClipboard.js
│ │ ├── EmptyContent.js
│ │ ├── HeaderBreadcrumbs.js
│ │ ├── Iconify.js
│ │ ├── Image.js
│ │ ├── InputStyle.js
│ │ ├── Label.js
│ │ ├── LightboxModal.js
│ │ ├── LoadingScreen.js
│ │ ├── Logo.js
│ │ ├── Markdown.js
│ │ ├── MenuPopover.js
│ │ ├── MyAvatar.js
│ │ ├── NotistackProvider.js
│ │ ├── Page.js
│ │ ├── ProgressBar.js
│ │ ├── ScrollToTop.js
│ │ ├── Scrollbar.js
│ │ ├── SearchNotFound.js
│ │ ├── SocialsButton.js
│ │ ├── SvgIconStyle.js
│ │ ├── TextIconLabel.js
│ │ ├── TextMaxLine.js
│ │ ├── animate
│ │ │ ├── DialogAnimate.js
│ │ │ ├── FabButtonAnimate.js
│ │ │ ├── IconButtonAnimate.js
│ │ │ ├── MotionContainer.js
│ │ │ ├── MotionLazyContainer.js
│ │ │ ├── MotionViewport.js
│ │ │ ├── TextAnimate.js
│ │ │ ├── features.js
│ │ │ ├── index.js
│ │ │ └── variants
│ │ │ │ ├── actions.js
│ │ │ │ ├── background.js
│ │ │ │ ├── bounce.js
│ │ │ │ ├── container.js
│ │ │ │ ├── fade.js
│ │ │ │ ├── flip.js
│ │ │ │ ├── index.js
│ │ │ │ ├── path.js
│ │ │ │ ├── rotate.js
│ │ │ │ ├── scale.js
│ │ │ │ ├── slide.js
│ │ │ │ ├── transition.js
│ │ │ │ └── zoom.js
│ │ ├── carousel
│ │ │ ├── CarouselArrowIndex.js
│ │ │ ├── CarouselArrows.js
│ │ │ ├── CarouselDots.js
│ │ │ └── index.js
│ │ ├── chart
│ │ │ ├── BaseOptionChart.js
│ │ │ ├── ChartStyle.js
│ │ │ └── index.js
│ │ ├── color-utils
│ │ │ ├── ColorManyPicker.js
│ │ │ ├── ColorPreview.js
│ │ │ ├── ColorSinglePicker.js
│ │ │ └── index.js
│ │ ├── editor
│ │ │ ├── EditorToolbar.js
│ │ │ ├── EditorToolbarStyle.js
│ │ │ └── index.js
│ │ ├── emoji-picker
│ │ │ ├── EmojiPicker.js
│ │ │ └── index.js
│ │ ├── hook-form
│ │ │ ├── FormProvider.js
│ │ │ ├── RHFCheckbox.js
│ │ │ ├── RHFEditor.js
│ │ │ ├── RHFNumberField.js
│ │ │ ├── RHFRadioGroup.js
│ │ │ ├── RHFSelect.js
│ │ │ ├── RHFSlider.js
│ │ │ ├── RHFSwitch.js
│ │ │ ├── RHFTextField.js
│ │ │ ├── RHFUpload.js
│ │ │ └── index.js
│ │ ├── map
│ │ │ ├── MapControl.js
│ │ │ ├── MapMarker.js
│ │ │ ├── MapPopup.js
│ │ │ ├── index.js
│ │ │ └── style.js
│ │ ├── mega-menu
│ │ │ ├── MegaMenuDesktopHorizon.js
│ │ │ ├── MegaMenuDesktopVertical.js
│ │ │ ├── MegaMenuMobile.js
│ │ │ ├── MenuCarousel.js
│ │ │ ├── MenuConfig.js
│ │ │ ├── MenuHotProducts.js
│ │ │ └── index.js
│ │ ├── nav-section
│ │ │ ├── horizontal
│ │ │ │ ├── NavItem.js
│ │ │ │ ├── NavList.js
│ │ │ │ ├── index.js
│ │ │ │ └── style.js
│ │ │ ├── index.js
│ │ │ └── vertical
│ │ │ │ ├── NavItem.js
│ │ │ │ ├── NavList.js
│ │ │ │ ├── index.js
│ │ │ │ └── style.js
│ │ ├── organizational-chart
│ │ │ ├── index.js
│ │ │ └── node
│ │ │ │ ├── GroupNode.js
│ │ │ │ ├── SimpleNode.js
│ │ │ │ ├── StandardNode.js
│ │ │ │ └── index.js
│ │ ├── settings
│ │ │ ├── ThemeColorPresets.js
│ │ │ ├── ThemeContrast.js
│ │ │ ├── ThemeLocalization.js
│ │ │ ├── ThemeRtlLayout.js
│ │ │ ├── drawer
│ │ │ │ ├── BoxMask.js
│ │ │ │ ├── SettingColorPresets.js
│ │ │ │ ├── SettingContrast.js
│ │ │ │ ├── SettingDirection.js
│ │ │ │ ├── SettingFullscreen.js
│ │ │ │ ├── SettingLayout.js
│ │ │ │ ├── SettingMode.js
│ │ │ │ ├── SettingStretch.js
│ │ │ │ ├── ToggleButton.js
│ │ │ │ └── index.js
│ │ │ └── index.js
│ │ ├── skeleton
│ │ │ ├── SkeletonConversationItem.js
│ │ │ ├── SkeletonKanbanColumn.js
│ │ │ ├── SkeletonMailSidebarItem.js
│ │ │ ├── SkeletonMap.js
│ │ │ ├── SkeletonPost.js
│ │ │ ├── SkeletonPostItem.js
│ │ │ ├── SkeletonProduct.js
│ │ │ ├── SkeletonProductItem.js
│ │ │ └── index.js
│ │ ├── table
│ │ │ ├── TableEmptyRows.js
│ │ │ ├── TableHeadCustom.js
│ │ │ ├── TableMoreMenu.js
│ │ │ ├── TableNoData.js
│ │ │ ├── TableSelectedActions.js
│ │ │ ├── TableSkeleton.js
│ │ │ └── index.js
│ │ └── upload
│ │ │ ├── BlockContent.js
│ │ │ ├── MultiFilePreview.js
│ │ │ ├── RejectionFiles.js
│ │ │ ├── UploadAvatar.js
│ │ │ ├── UploadMultiFile.js
│ │ │ ├── UploadSingleFile.js
│ │ │ └── index.js
│ ├── config.js
│ ├── contexts
│ │ ├── CollapseDrawerContext.js
│ │ ├── JWTContext.js
│ │ └── SettingsContext.js
│ ├── guards
│ │ ├── AuthGuard.js
│ │ ├── GuestGuard.js
│ │ └── RoleBasedGuard.js
│ ├── hooks
│ │ ├── useAuth.js
│ │ ├── useCollapseDrawer.js
│ │ ├── useCountdown.js
│ │ ├── useDateRangePicker.js
│ │ ├── useIsMountedRef.js
│ │ ├── useLocalStorage.js
│ │ ├── useLocales.js
│ │ ├── useOffSetTop.js
│ │ ├── useResponsive.js
│ │ ├── useSettings.js
│ │ ├── useTable.js
│ │ ├── useTabs.js
│ │ └── useToggle.js
│ ├── index.js
│ ├── layouts
│ │ ├── LogoOnlyLayout.js
│ │ ├── dashboard
│ │ │ ├── header
│ │ │ │ ├── AccountPopover.js
│ │ │ │ ├── ContactsPopover.js
│ │ │ │ ├── LanguagePopover.js
│ │ │ │ ├── NotificationsPopover.js
│ │ │ │ ├── Searchbar.js
│ │ │ │ └── index.js
│ │ │ ├── index.js
│ │ │ └── navbar
│ │ │ │ ├── CollapseButton.js
│ │ │ │ ├── NavConfig.js
│ │ │ │ ├── NavbarAccount.js
│ │ │ │ ├── NavbarDocs.js
│ │ │ │ ├── NavbarHorizontal.js
│ │ │ │ └── NavbarVertical.js
│ │ └── main
│ │ │ ├── MainFooter.js
│ │ │ ├── MainHeader.js
│ │ │ ├── MenuConfig.js
│ │ │ ├── MenuDesktop.js
│ │ │ ├── MenuMobile.js
│ │ │ └── index.js
│ ├── locales
│ │ ├── ar.js
│ │ ├── cn.js
│ │ ├── en.js
│ │ ├── fr.js
│ │ ├── i18n.js
│ │ └── vn.js
│ ├── pages
│ │ ├── Page403.js
│ │ ├── Page404.js
│ │ ├── Page500.js
│ │ ├── auth
│ │ │ ├── Login.js
│ │ │ ├── NewPassword.js
│ │ │ ├── Register.js
│ │ │ ├── ResetPassword.js
│ │ │ └── VerifyCode.js
│ │ └── dashboard
│ │ │ ├── GeneralApp.js
│ │ │ ├── UserAccount.js
│ │ │ └── UserProfile.js
│ ├── redux
│ │ ├── rootReducer.js
│ │ ├── slices
│ │ │ └── user.js
│ │ └── store.js
│ ├── reportWebVitals.js
│ ├── routes
│ │ ├── index.js
│ │ └── paths.js
│ ├── sections
│ │ ├── @dashboard
│ │ │ └── user
│ │ │ │ └── account
│ │ │ │ ├── AccountBilling.js
│ │ │ │ ├── AccountBillingAddressBook.js
│ │ │ │ ├── AccountBillingInvoiceHistory.js
│ │ │ │ ├── AccountBillingPaymentMethod.js
│ │ │ │ ├── AccountChangePassword.js
│ │ │ │ ├── AccountGeneral.js
│ │ │ │ ├── AccountNotifications.js
│ │ │ │ ├── AccountSocialLinks.js
│ │ │ │ └── index.js
│ │ └── auth
│ │ │ ├── login
│ │ │ ├── LoginForm.js
│ │ │ └── index.js
│ │ │ ├── new-password
│ │ │ ├── NewPasswordForm.js
│ │ │ └── index.js
│ │ │ ├── register
│ │ │ ├── RegisterForm.js
│ │ │ └── index.js
│ │ │ ├── reset-password
│ │ │ ├── ResetPasswordForm.js
│ │ │ └── index.js
│ │ │ └── verify-code
│ │ │ ├── VerifyCodeForm.js
│ │ │ └── index.js
│ ├── service-worker.js
│ ├── serviceWorkerRegistration.js
│ ├── theme
│ │ ├── breakpoints.js
│ │ ├── index.js
│ │ ├── overrides
│ │ │ ├── Accordion.js
│ │ │ ├── Alert.js
│ │ │ ├── Autocomplete.js
│ │ │ ├── Avatar.js
│ │ │ ├── Backdrop.js
│ │ │ ├── Badge.js
│ │ │ ├── Breadcrumbs.js
│ │ │ ├── Button.js
│ │ │ ├── ButtonGroup.js
│ │ │ ├── Card.js
│ │ │ ├── Checkbox.js
│ │ │ ├── Chip.js
│ │ │ ├── ControlLabel.js
│ │ │ ├── CssBaseline.js
│ │ │ ├── CustomIcons.js
│ │ │ ├── DataGrid.js
│ │ │ ├── Dialog.js
│ │ │ ├── Drawer.js
│ │ │ ├── Fab.js
│ │ │ ├── Input.js
│ │ │ ├── Link.js
│ │ │ ├── List.js
│ │ │ ├── LoadingButton.js
│ │ │ ├── Menu.js
│ │ │ ├── Pagination.js
│ │ │ ├── Paper.js
│ │ │ ├── Popover.js
│ │ │ ├── Progress.js
│ │ │ ├── Radio.js
│ │ │ ├── Rating.js
│ │ │ ├── Select.js
│ │ │ ├── Skeleton.js
│ │ │ ├── Slider.js
│ │ │ ├── Stepper.js
│ │ │ ├── SvgIcon.js
│ │ │ ├── Switch.js
│ │ │ ├── Table.js
│ │ │ ├── Tabs.js
│ │ │ ├── Timeline.js
│ │ │ ├── ToggleButton.js
│ │ │ ├── Tooltip.js
│ │ │ ├── TreeView.js
│ │ │ ├── Typography.js
│ │ │ └── index.js
│ │ ├── palette.js
│ │ ├── shadows.js
│ │ └── typography.js
│ └── utils
│ │ ├── axios.js
│ │ ├── createAvatar.js
│ │ ├── cssStyles.js
│ │ ├── flattenArray.js
│ │ ├── formatNumber.js
│ │ ├── formatTime.js
│ │ ├── getColorName.js
│ │ ├── getColorPresets.js
│ │ ├── getFileData.js
│ │ ├── getFileFormat.js
│ │ ├── getFontValue.js
│ │ ├── highlight.js
│ │ ├── jwt.js
│ │ ├── loadColorOptions.js
│ │ ├── roleOptions.js
│ │ └── uuidv4.js
└── yarn.lock
└── image
└── README
├── 1671452013971.png
└── 1671452027931.png
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2.1
2 |
3 | orbs:
4 | python: circleci/python@1.5.0
5 |
6 | jobs:
7 | build-and-test:
8 | docker:
9 | - image: cimg/python:3.10.2
10 | steps:
11 | - checkout
12 | - run:
13 | command: |
14 | python3 -m venv venv
15 | . venv/bin/activate
16 | - python/install-packages:
17 | pkg-manager: pip
18 | pip-dependency-file: backend/requirements/local.txt
19 | - run:
20 | name: Running tests
21 | command: |
22 | python3 backend/manage.py test
23 | - store_artifacts:
24 | path: test-reports/
25 | destination: python_app
26 |
27 | workflows:
28 | sample:
29 | jobs:
30 | - build-and-test
31 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Faisal Nazik
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 |
--------------------------------------------------------------------------------
/backend/Procfile:
--------------------------------------------------------------------------------
1 | web: gunicorn config.wsgi
--------------------------------------------------------------------------------
/backend/accounts/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/backend/accounts/__init__.py
--------------------------------------------------------------------------------
/backend/accounts/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class AccountsConfig(AppConfig):
5 | default_auto_field = 'django.db.models.BigAutoField'
6 | name = 'accounts'
7 |
--------------------------------------------------------------------------------
/backend/accounts/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/backend/accounts/migrations/__init__.py
--------------------------------------------------------------------------------
/backend/accounts/serializers.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 | from rest_framework.validators import UniqueValidator
3 | from django.core.validators import EmailValidator
4 | from rest_framework_simplejwt.tokens import RefreshToken
5 | from .models import User
6 |
7 | logger = __import__("logging").getLogger(__name__)
8 |
9 |
10 | class RegisterUserSerializer(serializers.ModelSerializer):
11 | token = serializers.SerializerMethodField()
12 | email = serializers.EmailField(
13 | validators=[EmailValidator(), UniqueValidator(queryset=User.objects.all())]
14 | )
15 |
16 | class Meta:
17 | model = User
18 | fields = ["name", "email", "password", "token"]
19 | extra_kwargs = {
20 | "password": {"write_only": True, "min_length": 8},
21 | }
22 |
23 | def get_token(self, user):
24 | token = RefreshToken.for_user(user)
25 | data = {"refresh": str(token), "access": str(token.access_token)}
26 | return data
27 |
28 |
29 | class UserProfileSeralizer(serializers.ModelSerializer):
30 | """Use this serializer to get the user profile"""
31 |
32 | class Meta:
33 | model = User
34 | fields = ["id", "name", "email", "avatar"]
35 |
36 | def update(self, instance, validated_data):
37 | instance.name = validated_data.get("name", instance.name)
38 | instance.email = validated_data.get("email", instance.email)
39 | instance.avatar = validated_data.get("avatar", instance.avatar)
40 | instance.save()
41 | return instance
42 |
--------------------------------------------------------------------------------
/backend/accounts/tests.py:
--------------------------------------------------------------------------------
1 | import pytest
2 | from django.contrib.auth import get_user_model
3 | from .models import User
4 | import json
5 | from django.test import Client
6 |
7 |
8 | @pytest.mark.django_db
9 | def test_user_creation():
10 | # Create a new user using the create_user method of the UserManager
11 | user = User.objects.create_user(
12 | email="test@example.com", name="Test User", password="password"
13 | )
14 |
15 | # Get the user model
16 | UserModel = get_user_model()
17 |
18 | # Check that the created user is an instance of the user model
19 | assert isinstance(user, UserModel)
20 |
21 |
22 | @pytest.mark.django_db
23 | def test_superuser_creation():
24 | # Create a new superuser using the create_superuser method of the UserManager
25 | superuser = User.objects.create_superuser(
26 | email="test@example.com", name="Test Superuser", password="password"
27 | )
28 |
29 | # Check that the created user is a superuser
30 | assert superuser.is_superuser
31 |
32 |
33 | @pytest.mark.django_db
34 | def test_user_string_representation():
35 | # Create a new user
36 | user = User.objects.create_user(
37 | email="test@example.com", name="Test User", password="password"
38 | )
39 |
40 | # Check that the string representation of the user is the name
41 | assert str(user) == "Test User"
42 |
--------------------------------------------------------------------------------
/backend/accounts/token.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/backend/accounts/token.py
--------------------------------------------------------------------------------
/backend/accounts/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 | from rest_framework_simplejwt import views as jwt_views
3 | from .views import RegisterUserView, UserProfileView
4 |
5 | urlpatterns = [
6 | path("register/", RegisterUserView.as_view(), name="register"),
7 | path("login/", jwt_views.TokenObtainPairView.as_view(), name="token_obtain_pair"),
8 | path("token/refresh/", jwt_views.TokenRefreshView.as_view(), name="token_refresh"),
9 | path("profile/", UserProfileView.as_view(), name="user_profile"),
10 | ]
11 |
--------------------------------------------------------------------------------
/backend/accounts/views.py:
--------------------------------------------------------------------------------
1 | from .models import User
2 | from rest_framework import generics
3 | from rest_framework import permissions
4 | from rest_framework.views import APIView
5 | from rest_framework.response import Response
6 | from .serializers import RegisterUserSerializer, UserProfileSeralizer
7 | from rest_framework.throttling import UserRateThrottle, AnonRateThrottle
8 |
9 | # import ValidationError from rest_framework.exceptions
10 | from rest_framework.exceptions import ValidationError
11 | from rest_framework_simplejwt.tokens import RefreshToken
12 | from rest_framework_simplejwt.views import TokenObtainPairView
13 |
14 |
15 | class RegisterUserView(generics.CreateAPIView):
16 | """Register a new user and return a token for the user"""
17 |
18 | permission_classes = [permissions.AllowAny]
19 | throttle_classes = [AnonRateThrottle]
20 | serializer_class = RegisterUserSerializer
21 |
22 | def perform_create(self, serializer):
23 | user = serializer.save()
24 | token = serializer.get_token(user)
25 | serializer.validated_data["token"] = token
26 | return super().perform_create(serializer)
27 |
28 |
29 | class UserProfileView(generics.RetrieveUpdateAPIView):
30 | """Get and update user profile"""
31 |
32 | serializer_class = UserProfileSeralizer
33 | permission_classes = [permissions.IsAuthenticated]
34 | throttle_classes = [UserRateThrottle]
35 |
36 | def get_object(self):
37 | return self.request.user
38 |
--------------------------------------------------------------------------------
/backend/config/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/backend/config/__init__.py
--------------------------------------------------------------------------------
/backend/config/asgi.py:
--------------------------------------------------------------------------------
1 | """
2 | ASGI config for config project.
3 |
4 | It exposes the ASGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.asgi import get_asgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
15 |
16 | application = get_asgi_application()
17 |
--------------------------------------------------------------------------------
/backend/config/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for config project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/backend/conftest.py:
--------------------------------------------------------------------------------
1 | from rest_framework.test import APIClient
2 | import pytest
3 | import django
4 |
5 | django.setup()
6 |
7 |
8 | @pytest.mark.django_db
9 | @pytest.fixture(autouse=True)
10 | def enable_db_access_for_all_tests(db):
11 | pass
12 |
13 |
14 | @pytest.fixture
15 | def client():
16 | django.setup()
17 | return APIClient()
18 |
--------------------------------------------------------------------------------
/backend/db.sqlite3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/backend/db.sqlite3
--------------------------------------------------------------------------------
/backend/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | """Django's command-line utility for administrative tasks."""
3 | import os
4 | import sys
5 |
6 |
7 | def main():
8 | """Run administrative tasks."""
9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings')
10 | try:
11 | from django.core.management import execute_from_command_line
12 | except ImportError as exc:
13 | raise ImportError(
14 | "Couldn't import Django. Are you sure it's installed and "
15 | "available on your PYTHONPATH environment variable? Did you "
16 | "forget to activate a virtual environment?"
17 | ) from exc
18 | execute_from_command_line(sys.argv)
19 |
20 |
21 | if __name__ == '__main__':
22 | main()
23 |
--------------------------------------------------------------------------------
/backend/media/users/placeholder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/backend/media/users/placeholder.png
--------------------------------------------------------------------------------
/backend/pytest.ini:
--------------------------------------------------------------------------------
1 | [pytest]
2 | DJANGO_SETTINGS_MODULE = config.settings
3 | python_files = tests.py test_*.py *_tests.py
4 | addopts = --maxfail=1 --disable-pytest-warnings -p no:warnings
--------------------------------------------------------------------------------
/backend/requirements/base.txt:
--------------------------------------------------------------------------------
1 | aniso8601==9.0.1
2 | argon2-cffi==21.3.0
3 | argon2-cffi-bindings==21.2.0
4 | asgiref==3.5.2
5 | attrs==22.1.0
6 | black==22.3.0
7 | certifi==2023.7.22
8 | cffi==1.15.1
9 | charset-normalizer==2.1.1
10 | click==8.1.3
11 | colorama==0.4.6
12 | coreapi==2.3.3
13 | coreschema==0.0.4
14 | Django==4.1.13
15 | django-cors-headers==3.13.0
16 | djangorestframework==3.14.0
17 | djangorestframework-simplejwt==5.2.2
18 | drf-spectacular==0.25.1
19 | drf-yasg==1.21.4
20 | exceptiongroup==1.0.4
21 | Flask==2.2.5
22 | Flask-Cors==3.0.10
23 | flask-restplus==0.13.0
24 | idna==3.4
25 | inflection==0.5.1
26 | iniconfig==1.1.1
27 | itsdangerous==2.1.2
28 | itypes==1.2.0
29 | Jinja2==3.1.3
30 | jsonschema==4.17.3
31 | MarkupSafe==2.1.1
32 | mypy-extensions==0.4.3
33 | packaging==22.0
34 | pathspec==0.10.3
35 | Pillow==10.0.1
36 | platformdirs==2.6.0
37 | pluggy==1.0.0
38 | psycopg2-binary==2.9.5
39 | pycparser==2.21
40 | PyJWT==2.6.0
41 | pyrsistent==0.19.2
42 | pytest==7.2.0
43 | pytest-django==4.5.2
44 | pytz==2022.7
45 | PyYAML==6.0
46 | requests==2.31.0
47 | ruamel.yaml==0.17.21
48 | ruamel.yaml.clib==0.2.7
49 | six==1.16.0
50 | sqlparse==0.4.4
51 | swagger-ui==0.1.2
52 | tomli==2.0.1
53 | tzdata==2022.7
54 | uritemplate==4.1.1
55 | urllib3==1.26.18
56 | Werkzeug==3.0.1
57 | whitenoise==6.2.0
58 |
--------------------------------------------------------------------------------
/backend/requirements/local.txt:
--------------------------------------------------------------------------------
1 | -r ./base.txt
2 |
3 | black==22.3.0
--------------------------------------------------------------------------------
/backend/requirements/production.txt:
--------------------------------------------------------------------------------
1 | -r ./base.txt
2 |
3 | gunicorn
--------------------------------------------------------------------------------
/backend/static/test.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/backend/static/test.js
--------------------------------------------------------------------------------
/backend/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | API
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/frontend/.eslintignore:
--------------------------------------------------------------------------------
1 | *
--------------------------------------------------------------------------------
/frontend/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/frontend/LICENSE:
--------------------------------------------------------------------------------
1 | We do not want anyone to see our source code, but if for any reason our code
2 | is stolen or otherwise obtained, we want to have a license that does not
3 | allow disclosure of any kind
--------------------------------------------------------------------------------
/frontend/README.md:
--------------------------------------------------------------------------------
1 | Project is running live on the link
2 |
3 | https://main.d8xxd1waej5k1.amplifyapp.com/
4 |
5 |
6 |
7 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
8 |
9 | ## 1.Install
10 |
11 | ### npm
12 |
13 | ```
14 | npm i
15 | or
16 | npm i --legacy-peer-deps
17 | ```
18 |
19 | ### yarn
20 |
21 | ```
22 | yarn install
23 | ```
24 |
25 | ## 2.Start
26 |
27 | ```sh
28 | npm start
29 | or
30 | yarn start
31 | ```
32 |
33 | ## 3.Build
34 |
35 | ```sh
36 | npm run build or yarn build
37 | ```
38 |
39 | Builds the app for production to the `build` folder.`
`
40 | It correctly bundles React in production mode and optimizes the build for the best performance.
41 |
42 | The build is minified and the filenames include the hashes.`
`
43 |
44 | Your app is ready to be deployed.
45 |
46 | ## User Guide
47 |
48 | You can find detailed instructions on using Create React App and many tips in [its documentation](https://facebook.github.io/create-react-app/).
49 |
--------------------------------------------------------------------------------
/frontend/config-overrides.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const WorkBoxPlugin = require('workbox-webpack-plugin');
3 |
4 | module.exports = function override(config) {
5 | config.resolve.fallback = {
6 | process: require.resolve('process/browser'),
7 | zlib: require.resolve('browserify-zlib'),
8 | stream: require.resolve('stream-browserify'),
9 | util: require.resolve('util'),
10 | buffer: require.resolve('buffer'),
11 | asset: require.resolve('assert'),
12 | };
13 |
14 | // https://stackoverflow.com/questions/69135310/workaround-for-cache-size-limit-in-create-react-app-pwa-service-worker
15 | config.plugins.forEach((plugin) => {
16 | if (plugin instanceof WorkBoxPlugin.InjectManifest) {
17 | plugin.config.maximumFileSizeToCacheInBytes = 50 * 1024 * 1024;
18 | }
19 | });
20 |
21 | config.plugins = [
22 | ...config.plugins,
23 | new webpack.ProvidePlugin({
24 | process: 'process/browser.js',
25 | Buffer: ['buffer', 'Buffer'],
26 | }),
27 | ];
28 |
29 | return config;
30 | };
31 |
--------------------------------------------------------------------------------
/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/public/_redirects:
--------------------------------------------------------------------------------
1 | /* /index.html 200
--------------------------------------------------------------------------------
/frontend/public/assets/bg_card.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/public/assets/bg_card.png
--------------------------------------------------------------------------------
/frontend/public/assets/bg_gradient.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/public/assets/bg_gradient.jpeg
--------------------------------------------------------------------------------
/frontend/public/assets/icons/flags/ic_flag_cn.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/flags/ic_flag_de.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/flags/ic_flag_en.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/flags/ic_flag_fr.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/flags/ic_flag_vn.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/navbar/ic_banking.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/navbar/ic_blog.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/navbar/ic_booking.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/navbar/ic_calendar.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/navbar/ic_cart.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/navbar/ic_chat.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/navbar/ic_dashboard.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/navbar/ic_invoice.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/navbar/ic_kanban.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/navbar/ic_mail.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/navbar/ic_menu_item.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/frontend/public/assets/icons/navbar/ic_user.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/public/assets/illustrations/illustration_components.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/public/assets/illustrations/illustration_components.png
--------------------------------------------------------------------------------
/frontend/public/assets/illustrations/illustration_dashboard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/public/assets/illustrations/illustration_dashboard.png
--------------------------------------------------------------------------------
/frontend/public/assets/illustrations/illustration_invite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/public/assets/illustrations/illustration_invite.png
--------------------------------------------------------------------------------
/frontend/public/assets/illustrations/illustration_login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/public/assets/illustrations/illustration_login.png
--------------------------------------------------------------------------------
/frontend/public/assets/illustrations/illustration_register.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/public/assets/illustrations/illustration_register.png
--------------------------------------------------------------------------------
/frontend/public/assets/overlay.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/public/assets/placeholder.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/public/favicon/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/public/favicon/android-chrome-192x192.png
--------------------------------------------------------------------------------
/frontend/public/favicon/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/public/favicon/android-chrome-512x512.png
--------------------------------------------------------------------------------
/frontend/public/favicon/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/public/favicon/apple-touch-icon.png
--------------------------------------------------------------------------------
/frontend/public/favicon/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/public/favicon/favicon-16x16.png
--------------------------------------------------------------------------------
/frontend/public/favicon/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/public/favicon/favicon-32x32.png
--------------------------------------------------------------------------------
/frontend/public/favicon/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/public/favicon/favicon.ico
--------------------------------------------------------------------------------
/frontend/public/fonts/CircularStd-Bold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/public/fonts/CircularStd-Bold.otf
--------------------------------------------------------------------------------
/frontend/public/fonts/CircularStd-Book.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/public/fonts/CircularStd-Book.otf
--------------------------------------------------------------------------------
/frontend/public/fonts/CircularStd-Medium.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/public/fonts/CircularStd-Medium.otf
--------------------------------------------------------------------------------
/frontend/public/fonts/Roboto-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/public/fonts/Roboto-Bold.ttf
--------------------------------------------------------------------------------
/frontend/public/fonts/Roboto-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/public/fonts/Roboto-Regular.ttf
--------------------------------------------------------------------------------
/frontend/public/fonts/index.css:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'CircularStd';
3 | font-weight: 400;
4 | font-style: normal;
5 | src: local('CircularStd'), url('CircularStd-Book.otf') format('opentype');
6 | }
7 | @font-face {
8 | font-family: 'CircularStd';
9 | font-weight: 500;
10 | font-style: normal;
11 | src: local('CircularStd'), url('CircularStd-Medium.otf') format('opentype');
12 | }
13 | @font-face {
14 | font-family: 'CircularStd';
15 | font-weight: 700;
16 | font-style: normal;
17 | src: local('CircularStd'), url('CircularStd-Bold.otf') format('opentype');
18 | }
19 |
--------------------------------------------------------------------------------
/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 | Project Title
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/frontend/public/logo/logo_full.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/public/logo/logo_full.jpg
--------------------------------------------------------------------------------
/frontend/public/logo/logo_single.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "name",
3 | "short_name": "shortname",
4 | "display": "standalone",
5 | "start_url": "/dashboard/app",
6 | "theme_color": "#000000",
7 | "background_color": "#ffffff",
8 | "icons": [
9 | {
10 | "src": "favicon/android-chrome-192x192.png",
11 | "sizes": "192x192",
12 | "type": "image/png"
13 | },
14 | {
15 | "src": "favicon/android-chrome-512x512.png",
16 | "sizes": "512x512",
17 | "type": "image/png"
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/frontend/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/frontend/src/App.js:
--------------------------------------------------------------------------------
1 | // routes
2 | import Router from './routes';
3 | // theme
4 | import ThemeProvider from './theme';
5 | // components
6 | import ThemeSettings from './components/settings';
7 | import { ChartStyle } from './components/chart';
8 | import ScrollToTop from './components/ScrollToTop';
9 | import { ProgressBarStyle } from './components/ProgressBar';
10 | import NotistackProvider from './components/NotistackProvider';
11 | import MotionLazyContainer from './components/animate/MotionLazyContainer';
12 |
13 | // ----------------------------------------------------------------------
14 |
15 | export default function App() {
16 | return (
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/frontend/src/_mock/_analytics.js:
--------------------------------------------------------------------------------
1 | // components
2 | import Iconify from '../components/Iconify';
3 | //
4 | import _mock from './_mock';
5 |
6 | // ----------------------------------------------------------------------
7 |
8 | export const _analyticPost = [...Array(5)].map((_, index) => ({
9 | id: _mock.id(index),
10 | title: _mock.text.title(index),
11 | description: _mock.text.description(index),
12 | image: _mock.image.cover(index),
13 | postedAt: _mock.time(index),
14 | }));
15 |
16 | export const _analyticOrderTimeline = [...Array(5)].map((_, index) => ({
17 | id: _mock.id(index),
18 | title: [
19 | '1983, orders, $4220',
20 | '12 Invoices have been paid',
21 | 'Order #37745 from September',
22 | 'New order placed #XF-2356',
23 | 'New order placed #XF-2346',
24 | ][index],
25 | type: `order${index + 1}`,
26 | time: _mock.time(index),
27 | }));
28 |
29 | export const _analyticTraffic = [
30 | {
31 | name: 'FaceBook',
32 | value: 323234,
33 | icon: ,
34 | },
35 | {
36 | name: 'Google',
37 | value: 341212,
38 | icon: ,
39 | },
40 | {
41 | name: 'Linkedin',
42 | value: 411213,
43 | icon: ,
44 | },
45 | {
46 | name: 'Twitter',
47 | value: 443232,
48 | icon: ,
49 | },
50 | ];
51 |
--------------------------------------------------------------------------------
/frontend/src/_mock/_booking.js:
--------------------------------------------------------------------------------
1 | import _mock from './_mock';
2 | import { randomInArray } from './funcs';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | export const _bookings = [...Array(5)].map((_, index) => ({
7 | id: _mock.id(index),
8 | name: _mock.name.fullName(index),
9 | avatar: _mock.image.avatar(index),
10 | checkIn: _mock.time(index),
11 | checkOut: _mock.time(index),
12 | phoneNumber: _mock.phoneNumber(index),
13 | status: randomInArray(['pending', 'un_paid', 'paid']),
14 | roomType: randomInArray(['double', 'king', 'single']),
15 | }));
16 |
17 | export const _bookingsOverview = [...Array(3)].map((_, index) => ({
18 | status: ['Pending', 'Cancel', 'Done'][index],
19 | quantity: _mock.number.percent(index) * 1000,
20 | value: _mock.number.percent(index),
21 | }));
22 |
23 | export const _bookingReview = [...Array(5)].map((_, index) => ({
24 | id: _mock.id(index),
25 | name: _mock.name.fullName(index),
26 | description: _mock.text.description(index),
27 | avatar: _mock.image.avatar(index),
28 | rating: _mock.number.rating(index),
29 | postedAt: _mock.time(index),
30 | tags: ['Great Sevice', 'Recommended', 'Best Price'],
31 | }));
32 |
33 | export const _bookingNew = [...Array(5)].map((_, index) => ({
34 | id: _mock.id(index),
35 | name: _mock.name.fullName(index),
36 | avatar: _mock.image.avatar(index),
37 | bookdAt: _mock.time(index),
38 | roomNumber: 'A-21',
39 | roomType: randomInArray(['double', 'king', 'single']),
40 | person: '3-5',
41 | cover: `https://minimal-assets-api-dev.vercel.app/assets/images/rooms/room-${index + 1}.jpg`,
42 | }));
43 |
--------------------------------------------------------------------------------
/frontend/src/_mock/_calenderViewOptions.js:
--------------------------------------------------------------------------------
1 | export const calenderViewOptions = [
2 | { value: 'daily', label: 'Daily' },
3 | { value: 'weekly', label: 'Weekly' },
4 | { value: 'monthly', label: 'Monthly' }
5 | ]
6 |
--------------------------------------------------------------------------------
/frontend/src/_mock/_roles.js:
--------------------------------------------------------------------------------
1 | export const roles = [
2 | { value: 2, label: 'Administator' },
3 | { value: 3, label: 'Sales Representative' },
4 | { value: 4, label: 'Dispatcher' },
5 | { value: 5, label: 'Carrier' },
6 | { value: 6, label: 'Customer' },
7 | { value: 7, label: 'Accountant' }
8 | ]
9 |
--------------------------------------------------------------------------------
/frontend/src/_mock/_timeZoneOptions.js:
--------------------------------------------------------------------------------
1 | export const timeZoneOptions = [
2 | { value: 'UTC', label: 'Eastern Time Zone' },
3 | { value: 'UTC + 3.0', label: '(UTC + 3.0) New FoundLand Time Zone' },
4 | { value: 'UTC - 1', label: '(UTC - 1) Central Standard Time' },
5 | { value: 'UTC - 2', label: '(UTC - 2) Mountain Standard Time' },
6 | { value: 'UTC - 3', label: '(UTC - 3) Pacific Standard Time' }
7 | ]
8 |
--------------------------------------------------------------------------------
/frontend/src/_mock/boolean.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export const boolean = [
4 | true,
5 | true,
6 | true,
7 | false,
8 | false,
9 | true,
10 | false,
11 | false,
12 | false,
13 | false,
14 | true,
15 | true,
16 | true,
17 | false,
18 | false,
19 | false,
20 | true,
21 | false,
22 | false,
23 | false,
24 | true,
25 | false,
26 | false,
27 | true,
28 | true,
29 | true,
30 | false,
31 | false,
32 | true,
33 | true,
34 | false,
35 | true,
36 | false,
37 | true,
38 | true,
39 | true,
40 | false,
41 | true,
42 | false,
43 | false
44 | ];
45 |
--------------------------------------------------------------------------------
/frontend/src/_mock/company.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export const company = [
4 | 'Lueilwitz and Sons',
5 | 'Gleichner, Mueller and Tromp',
6 | 'Nikolaus - Leuschke',
7 | 'Hegmann, Kreiger and Bayer',
8 | 'Grimes Inc',
9 | 'Durgan - Murazik',
10 | 'Altenwerth, Medhurst and Roberts',
11 | 'Raynor Group',
12 | 'Mraz, Donnelly and Collins',
13 | 'Padberg - Bailey',
14 | 'Heidenreich, Stokes and Parker',
15 | 'Pagac and Sons',
16 | 'Rempel, Hand and Herzog',
17 | 'Dare - Treutel',
18 | 'Kihn, Marquardt and Crist',
19 | 'Nolan - Kunde',
20 | 'Wuckert Inc',
21 | 'Dibbert Inc',
22 | 'Goyette and Sons',
23 | 'Feest Group',
24 | 'Bosco and Sons',
25 | 'Bartell - Kovacek',
26 | 'Schimmel - Raynor',
27 | 'Tremblay LLC',
28 | 'Hills - Mitchell',
29 | 'Rogahn LLC',
30 | 'Kuhn, Osinski and Morar',
31 | 'Schmitt Inc',
32 | 'Breitenberg - Rosenbaum',
33 | "O'Keefe, Schneider and Mraz",
34 | 'Rohan, Langworth and Kling',
35 | 'Morar and Sons',
36 | 'Mraz LLC',
37 | 'Rowe, Parisian and Kub',
38 | 'Marquardt - Hane',
39 | 'Medhurst Group',
40 | 'Nikolaus - Lang',
41 | 'Effertz, Mohr and Olson',
42 | 'Anderson - Kris',
43 | 'Runolfsson Group'
44 | ];
45 |
--------------------------------------------------------------------------------
/frontend/src/_mock/email.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export const email = [
4 | 'nannie_abernathy70@yahoo.com',
5 | 'ashlynn_ohara62@gmail.com',
6 | 'milo.farrell@hotmail.com',
7 | 'violet.ratke86@yahoo.com',
8 | 'letha_lubowitz24@yahoo.com',
9 | 'aditya_greenfelder31@gmail.com',
10 | 'lenna_bergnaum27@hotmail.com',
11 | 'luella.ryan33@gmail.com',
12 | 'joana.simonis84@gmail.com',
13 | 'marjolaine_white94@gmail.com',
14 | 'vergie_block82@hotmail.com',
15 | 'vito.hudson@hotmail.com',
16 | 'tyrel_greenholt@gmail.com',
17 | 'dwight.block85@yahoo.com',
18 | 'mireya13@hotmail.com',
19 | 'dasia_jenkins@hotmail.com',
20 | 'benny89@yahoo.com',
21 | 'dawn.goyette@gmail.com',
22 | 'zella_hickle4@yahoo.com',
23 | 'avery43@hotmail.com',
24 | 'olen_legros@gmail.com',
25 | 'jimmie.gerhold73@hotmail.com',
26 | 'genevieve.powlowski@hotmail.com',
27 | 'louie.kuphal39@gmail.com',
28 | 'enoch.cruickshank@gmail.com',
29 | 'arlo_mccullough@gmail.com',
30 | 'sadie18@yahoo.com',
31 | 'aric67@gmail.com',
32 | 'mack_deckow53@gmail.com',
33 | 'constantin91@yahoo.com',
34 | 'lonny84@hotmail.com',
35 | 'gus56@hotmail.com',
36 | 'brennon64@yahoo.com',
37 | 'hortense.streich@hotmail.com',
38 | 'kallie_powlowski57@hotmail.com',
39 | 'meghan.kemmer@hotmail.com',
40 | 'bella.mraz14@yahoo.com',
41 | 'barney88@gmail.com',
42 | 'diamond_johns@hotmail.com',
43 | 'gus80@hotmail.com'
44 | ];
45 |
--------------------------------------------------------------------------------
/frontend/src/_mock/funcs.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export function randomNumber(number) {
4 | return Math.floor(Math.random() * number) + 1;
5 | }
6 |
7 | export function randomNumberRange(min, max) {
8 | return Math.floor(Math.random() * (max - min + 1)) + min;
9 | }
10 |
11 | export function randomInArray(array) {
12 | return array[Math.floor(Math.random() * array.length)];
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/src/_mock/index.js:
--------------------------------------------------------------------------------
1 | import _mock from './_mock';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export * from './_app';
6 | export * from './_user';
7 | export * from './_plans';
8 | export * from './_others';
9 | export * from './_booking';
10 | export * from './_banking';
11 | export * from './_invoice';
12 | export * from './_ecommerce';
13 | export * from './_analytics';
14 | export * from './_countries';
15 | export * from './_top100Films';
16 |
17 | export default _mock;
18 |
--------------------------------------------------------------------------------
/frontend/src/_mock/number.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export const price = [
4 | 16.19, 35.71, 34.3, 93.1, 55.47, 89.09, 44.39, 26.92, 45.35, 26.96, 78.22, 35.54, 90.69, 63.61,
5 | 67.55, 94.75, 75.78, 39.6, 52.84, 72.8, 83.08, 85.02, 69.22, 60.96, 84.7, 16.68, 78.83, 58.07,
6 | 65.8, 55.69, 87.55, 44.74, 27.42, 84, 76.17, 43.83, 76.39, 17.42, 42.3, 12.45
7 | ];
8 |
9 | export const rating = [
10 | 2.5, 2, 4.9, 2, 4, 5, 4.9, 5, 3.7, 2.5, 2, 4.9, 4.8, 4, 2, 3.7, 1.4, 2.4, 1.8, 5, 2.9, 3.9, 3.9,
11 | 1.8, 5, 2.6, 3.1, 3.9, 1.2, 3.2, 4.1, 5, 4.5, 4.1, 2.3, 2.4, 5, 3.1, 4.9, 1.7
12 | ];
13 |
14 | export const age = [
15 | 52, 43, 56, 25, 22, 53, 38, 50, 55, 37, 16, 27, 55, 41, 52, 32, 34, 52, 31, 53, 23, 48, 43, 41,
16 | 19, 21, 17, 29, 32, 54, 38, 34, 49, 33, 55, 50, 24, 27, 23, 23
17 | ];
18 |
19 | export const percent = [
20 | 8.62, 86.36, 73.99, 79, 63.41, 58.79, 12.32, 88.44, 45.06, 91.64, 88.41, 73.08, 39.14, 89.34,
21 | 43.37, 34.45, 24.04, 80.96, 72.91, 47.59, 2.46, 3.33, 99.31, 47.6, 34.09, 50.61, 66.13, 46.69,
22 | 92.43, 31.41, 90.85, 36.32, 38.84, 25.6, 87.61, 1.31, 89.32, 41.23, 85.9, 62.63
23 | ];
24 |
--------------------------------------------------------------------------------
/frontend/src/_mock/phoneNumber.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export const phoneNumber = [
4 | '365-374-4961',
5 | '904-966-2836',
6 | '399-757-9909',
7 | '692-767-2903',
8 | '990-588-5716',
9 | '955-439-2578',
10 | '226-924-4058',
11 | '552-917-1454',
12 | '285-840-9338',
13 | '306-269-2446',
14 | '883-373-6253',
15 | '476-509-8866',
16 | '201-465-1954',
17 | '538-295-9408',
18 | '531-492-6028',
19 | '981-699-7588',
20 | '500-268-4826',
21 | '205-952-3828',
22 | '222-255-5190',
23 | '408-439-8033',
24 | '272-940-8266',
25 | '812-685-8057',
26 | '353-801-5212',
27 | '606-285-8928',
28 | '202-767-8621',
29 | '222-830-0731',
30 | '964-940-3166',
31 | '262-702-2396',
32 | '886-261-9789',
33 | '352-390-5069',
34 | '343-907-8334',
35 | '575-347-2399',
36 | '749-228-5604',
37 | '774-452-2071',
38 | '607-841-0447',
39 | '395-619-2157',
40 | '233-834-0373',
41 | '586-880-2602',
42 | '746-772-0722',
43 | '638-615-3365,'
44 | ];
45 |
--------------------------------------------------------------------------------
/frontend/src/_mock/role.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export const role = [
4 | 'ux designer',
5 | 'full stack designer',
6 | 'backend developer',
7 | 'ux designer',
8 | 'ux designer',
9 | 'project manager',
10 | 'leader',
11 | 'backend developer',
12 | 'project manager',
13 | 'ui designer',
14 | 'ui/ux designer',
15 | 'ui/ux designer',
16 | 'ui designer',
17 | 'backend developer',
18 | 'backend developer',
19 | 'front end developer',
20 | 'backend developer',
21 | 'full stack designer',
22 | 'full stack developer',
23 | 'backend developer',
24 | 'ux designer',
25 | 'ui designer',
26 | 'project manager',
27 | 'ui/ux designer',
28 | 'ui designer',
29 | 'project manager',
30 | 'full stack developer',
31 | 'hr manager',
32 | 'hr manager',
33 | 'ui/ux designer',
34 | 'project manager',
35 | 'full stack designer',
36 | 'ui designer',
37 | 'leader',
38 | 'front end developer',
39 | 'ui/ux designer',
40 | 'project manager',
41 | 'ui/ux designer',
42 | 'ui designer',
43 | 'full stack designer',
44 | ];
45 |
--------------------------------------------------------------------------------
/frontend/src/assets/illustration_background.js:
--------------------------------------------------------------------------------
1 | import { memo } from 'react';
2 | // @mui
3 | import { useTheme } from '@mui/material/styles';
4 |
5 | // ----------------------------------------------------------------------
6 |
7 | function BackgroundIllustration() {
8 | const theme = useTheme();
9 |
10 | const PRIMARY_MAIN = theme.palette.primary.main;
11 |
12 | return (
13 | <>
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
27 | >
28 | );
29 | }
30 |
31 | export default memo(BackgroundIllustration);
32 |
--------------------------------------------------------------------------------
/frontend/src/assets/index.js:
--------------------------------------------------------------------------------
1 | export { default as DocIllustration } from './illustration_doc';
2 | export { default as SeoIllustration } from './illustration_seo';
3 | export { default as UploadIllustration } from './illustration_upload';
4 | export { default as ForbiddenIllustration } from './illustration_403';
5 | export { default as SeverErrorIllustration } from './illustration_500';
6 | export { default as BookingIllustration } from './illustration_booking';
7 | export { default as CheckInIllustration } from './illustration_checkin';
8 | export { default as PageNotFoundIllustration } from './illustration_404';
9 | export { default as CheckOutIllustration } from './illustration_checkout';
10 | export { default as MotivationIllustration } from './illustration_motivation';
11 | export { default as ComingSoonIllustration } from './illustration_coming_soon';
12 | export { default as MaintenanceIllustration } from './illustration_maintenance';
13 | export { default as OrderCompleteIllustration } from './illustration_order_complete';
14 |
15 | export { default as SentIcon } from './icon_sent';
16 | export { default as PlanFreeIcon } from './icon_plan_free';
17 | export { default as PlanStarterIcon } from './icon_plan_starter';
18 | export { default as PlanPremiumIcon } from './icon_plan_premium';
19 |
--------------------------------------------------------------------------------
/frontend/src/components/Avatar.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { forwardRef } from 'react';
3 | import { useTheme } from '@mui/material/styles';
4 | import { Avatar as MUIAvatar } from '@mui/material';
5 |
6 | // ----------------------------------------------------------------------
7 |
8 | const Avatar = forwardRef(({ color = 'default', children, sx, ...other }, ref) => {
9 | const theme = useTheme();
10 |
11 | if (color === 'default') {
12 | return (
13 |
14 | {children}
15 |
16 | );
17 | }
18 |
19 | return (
20 |
30 | {children}
31 |
32 | );
33 | });
34 |
35 | Avatar.propTypes = {
36 | children: PropTypes.node,
37 | sx: PropTypes.object,
38 | color: PropTypes.oneOf(['default', 'primary', 'secondary', 'info', 'success', 'warning', 'error']),
39 | };
40 |
41 | export default Avatar;
42 |
--------------------------------------------------------------------------------
/frontend/src/components/CopyClipboard.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import PropTypes from 'prop-types';
3 | import { useSnackbar } from 'notistack';
4 | import { CopyToClipboard } from 'react-copy-to-clipboard';
5 | // @mui
6 | import { Tooltip, TextField, IconButton, InputAdornment } from '@mui/material';
7 | //
8 | import Iconify from './Iconify';
9 |
10 | // ----------------------------------------------------------------------
11 |
12 | CopyClipboard.propTypes = {
13 | value: PropTypes.string,
14 | };
15 |
16 | export default function CopyClipboard({ value, ...other }) {
17 | const { enqueueSnackbar } = useSnackbar();
18 | const [state, setState] = useState({
19 | value,
20 | copied: false,
21 | });
22 |
23 | const handleChange = (event) => {
24 | setState({ value: event.target.value, copied: false });
25 | };
26 |
27 | const onCopy = () => {
28 | setState({ ...state, copied: true });
29 | if (state.value) {
30 | enqueueSnackbar('Copied!');
31 | }
32 | };
33 |
34 | return (
35 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | ),
51 | }}
52 | {...other}
53 | />
54 | );
55 | }
56 |
--------------------------------------------------------------------------------
/frontend/src/components/EmptyContent.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // @mui
3 | import { styled } from '@mui/material/styles';
4 | import { Typography } from '@mui/material';
5 | //
6 | import Image from './Image';
7 |
8 | // ----------------------------------------------------------------------
9 |
10 | const RootStyle = styled('div')(({ theme }) => ({
11 | height: '100%',
12 | display: 'flex',
13 | textAlign: 'center',
14 | alignItems: 'center',
15 | flexDirection: 'column',
16 | justifyContent: 'center',
17 | padding: theme.spacing(8, 2),
18 | }));
19 |
20 | // ----------------------------------------------------------------------
21 |
22 | EmptyContent.propTypes = {
23 | title: PropTypes.string.isRequired,
24 | img: PropTypes.string,
25 | description: PropTypes.string,
26 | };
27 |
28 | export default function EmptyContent({ title, description, img, ...other }) {
29 | return (
30 |
31 |
38 |
39 |
40 | {title}
41 |
42 |
43 | {description && (
44 |
45 | {description}
46 |
47 | )}
48 |
49 | );
50 | }
51 |
--------------------------------------------------------------------------------
/frontend/src/components/HeaderBreadcrumbs.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // @mui
3 | import { Box, Typography, Link } from '@mui/material';
4 | //
5 | import Breadcrumbs from './Breadcrumbs';
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | HeaderBreadcrumbs.propTypes = {
10 | links: PropTypes.array,
11 | action: PropTypes.node,
12 | heading: PropTypes.string.isRequired,
13 | moreLink: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
14 | sx: PropTypes.object,
15 | };
16 |
17 | export default function HeaderBreadcrumbs({ links, action, heading, moreLink = '' || [], sx, ...other }) {
18 | return (
19 |
20 |
21 |
22 |
23 | {heading}
24 |
25 |
26 |
27 |
28 | {action && {action}}
29 |
30 |
31 |
32 | {typeof moreLink === 'string' ? (
33 |
34 | {moreLink}
35 |
36 | ) : (
37 | moreLink.map((href) => (
38 |
47 | {href}
48 |
49 | ))
50 | )}
51 |
52 |
53 | );
54 | }
55 |
--------------------------------------------------------------------------------
/frontend/src/components/Iconify.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // icons
3 | import { Icon } from '@iconify/react';
4 | // @mui
5 | import { Box } from '@mui/material';
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | Iconify.propTypes = {
10 | icon: PropTypes.oneOfType([PropTypes.element, PropTypes.string]),
11 | sx: PropTypes.object,
12 | };
13 |
14 | export default function Iconify({ icon, sx, ...other }) {
15 | return ;
16 | }
17 |
--------------------------------------------------------------------------------
/frontend/src/components/InputStyle.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { styled } from '@mui/material/styles';
3 | import { TextField } from '@mui/material';
4 |
5 | // ----------------------------------------------------------------------
6 |
7 | const InputStyle = styled(TextField, {
8 | shouldForwardProp: (prop) => prop !== 'stretchStart',
9 | })(({ stretchStart, theme }) => ({
10 | '& .MuiOutlinedInput-root': {
11 | transition: theme.transitions.create(['box-shadow', 'width'], {
12 | easing: theme.transitions.easing.easeInOut,
13 | duration: theme.transitions.duration.shorter,
14 | }),
15 | '&.Mui-focused': {
16 | boxShadow: theme.customShadows.z12,
17 | },
18 | ...(stretchStart && {
19 | width: stretchStart,
20 | '&.Mui-focused': {
21 | boxShadow: theme.customShadows.z12,
22 | [theme.breakpoints.up('sm')]: {
23 | width: stretchStart + 60,
24 | },
25 | },
26 | }),
27 | },
28 | '& fieldset': {
29 | borderWidth: `1px !important`,
30 | borderColor: `${theme.palette.grey[500_32]} !important`,
31 | },
32 | }));
33 |
34 | export default InputStyle;
35 |
--------------------------------------------------------------------------------
/frontend/src/components/Logo.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types'
2 | import { Link as RouterLink } from 'react-router-dom'
3 | // @mui
4 | // import { useTheme } from '@mui/material/styles'
5 | import { Box } from '@mui/material'
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | Logo.propTypes = {
10 | disabledLink: PropTypes.bool,
11 | sx: PropTypes.object
12 | }
13 |
14 | export default function Logo({ disabledLink = false, sx }) {
15 | // const theme = useTheme()
16 |
17 | // const PRIMARY_LIGHT = theme.palette.primary.light
18 |
19 | // const PRIMARY_MAIN = theme.palette.primary.main
20 |
21 | // const PRIMARY_DARK = theme.palette.primary.dark
22 |
23 | // OR
24 | // -------------------------------------------------------
25 | // const logo = (
26 | // your path
29 | // sx={{ width: 40, height: 40, cursor: 'pointer', ...sx }}
30 | // />
31 | // );
32 |
33 | const logo =
34 |
35 | if (disabledLink) {
36 | return <>{logo}>
37 | }
38 |
39 | return {logo}
40 | }
41 |
--------------------------------------------------------------------------------
/frontend/src/components/MyAvatar.js:
--------------------------------------------------------------------------------
1 | // hooks
2 | import { useSelector } from 'react-redux'
3 | // utils
4 | import createAvatar from '../utils/createAvatar'
5 | //
6 | import Avatar from './Avatar'
7 |
8 | // ----------------------------------------------------------------------
9 |
10 | export default function MyAvatar({ ...other }) {
11 | // get user
12 | const { user } = useSelector((state) => state?.user)
13 |
14 | return (
15 |
16 | {createAvatar(user?.name).name}
17 |
18 | )
19 | }
20 |
--------------------------------------------------------------------------------
/frontend/src/components/Page.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { Helmet } from 'react-helmet-async';
3 | import { forwardRef } from 'react';
4 | // @mui
5 | import { Box } from '@mui/material';
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | const Page = forwardRef(({ children, title = '', meta, ...other }, ref) => (
10 | <>
11 |
12 | {`${title}`}
13 | {meta}
14 |
15 |
16 |
17 | {children}
18 |
19 | >
20 | ));
21 |
22 | Page.propTypes = {
23 | children: PropTypes.node.isRequired,
24 | title: PropTypes.string,
25 | meta: PropTypes.node,
26 | };
27 |
28 | export default Page;
29 |
--------------------------------------------------------------------------------
/frontend/src/components/ProgressBar.js:
--------------------------------------------------------------------------------
1 | import NProgress from 'nprogress';
2 | import { useEffect, useMemo } from 'react';
3 | // @mui
4 | import { useTheme } from '@mui/material/styles';
5 | import { GlobalStyles } from '@mui/material';
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | export function ProgressBarStyle() {
10 | const theme = useTheme();
11 |
12 | return (
13 |
40 | );
41 | }
42 |
43 | export default function ProgressBar() {
44 | NProgress.configure({
45 | showSpinner: false,
46 | });
47 |
48 | useMemo(() => {
49 | NProgress.start();
50 | }, []);
51 |
52 | useEffect(() => {
53 | NProgress.done();
54 | }, []);
55 |
56 | return null;
57 | }
58 |
--------------------------------------------------------------------------------
/frontend/src/components/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/src/components/SearchNotFound.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { Paper, Typography } from '@mui/material';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | SearchNotFound.propTypes = {
7 | searchQuery: PropTypes.string,
8 | };
9 |
10 | export default function SearchNotFound({ searchQuery = '', ...other }) {
11 | return searchQuery ? (
12 |
13 |
14 | Not found
15 |
16 |
17 | No results found for
18 | "{searchQuery}". Try checking for typos or using complete words.
19 |
20 |
21 | ) : (
22 | Please enter keywords
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/frontend/src/components/SvgIconStyle.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { Box } from '@mui/material';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | SvgIconStyle.propTypes = {
7 | src: PropTypes.string.isRequired,
8 | sx: PropTypes.object,
9 | };
10 |
11 | export default function SvgIconStyle({ src, sx }) {
12 | return (
13 |
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/frontend/src/components/TextIconLabel.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // @mui
3 | import { Stack } from '@mui/material';
4 |
5 | // ----------------------------------------------------------------------
6 |
7 | TextIconLabel.propTypes = {
8 | endIcon: PropTypes.bool,
9 | icon: PropTypes.element,
10 | sx: PropTypes.object,
11 | value: PropTypes.node,
12 | };
13 |
14 | export default function TextIconLabel({ icon, value, endIcon = false, sx, ...other }) {
15 | return (
16 |
25 | {!endIcon && icon}
26 | {value}
27 | {endIcon && icon}
28 |
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/frontend/src/components/TextMaxLine.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { forwardRef } from 'react';
3 | // @mui
4 | import { Typography, Link } from '@mui/material';
5 | // utils
6 | import GetFontValue from '../utils/getFontValue';
7 |
8 | // ----------------------------------------------------------------------
9 |
10 | const TextMaxLine = forwardRef(
11 | ({ asLink, variant = 'body1', line = 2, persistent = false, children, sx, ...other }, ref) => {
12 | const { lineHeight } = GetFontValue(variant);
13 |
14 | const style = {
15 | overflow: 'hidden',
16 | textOverflow: 'ellipsis',
17 | display: '-webkit-box',
18 | WebkitLineClamp: line,
19 | WebkitBoxOrient: 'vertical',
20 | ...(persistent && {
21 | height: lineHeight * line,
22 | }),
23 | ...sx,
24 | };
25 |
26 | if (asLink) {
27 | return (
28 |
29 | {children}
30 |
31 | );
32 | }
33 |
34 | return (
35 |
36 | {children}
37 |
38 | );
39 | }
40 | );
41 |
42 | TextMaxLine.propTypes = {
43 | asLink: PropTypes.bool,
44 | children: PropTypes.node.isRequired,
45 | line: PropTypes.number,
46 | persistent: PropTypes.bool,
47 | sx: PropTypes.object,
48 | variant: PropTypes.oneOf([
49 | 'body1',
50 | 'body2',
51 | 'button',
52 | 'caption',
53 | 'h1',
54 | 'h2',
55 | 'h3',
56 | 'h4',
57 | 'h5',
58 | 'h6',
59 | 'inherit',
60 | 'overline',
61 | 'subtitle1',
62 | 'subtitle2',
63 | ]),
64 | };
65 |
66 | export default TextMaxLine;
67 |
--------------------------------------------------------------------------------
/frontend/src/components/animate/MotionContainer.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { m } from 'framer-motion';
3 | // @mui
4 | import { Box } from '@mui/material';
5 | //
6 | import { varContainer } from './variants';
7 |
8 | // ----------------------------------------------------------------------
9 |
10 | MotionContainer.propTypes = {
11 | action: PropTypes.bool,
12 | animate: PropTypes.bool,
13 | children: PropTypes.node.isRequired
14 | };
15 |
16 | export default function MotionContainer({ animate, action = false, children, ...other }) {
17 | if (action) {
18 | return (
19 |
26 | {children}
27 |
28 | );
29 | }
30 |
31 | return (
32 |
33 | {children}
34 |
35 | );
36 | }
37 |
--------------------------------------------------------------------------------
/frontend/src/components/animate/MotionLazyContainer.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { LazyMotion } from 'framer-motion';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | // eslint-disable-next-line import/extensions
7 | const loadFeatures = () => import('./features.js').then((res) => res.default);
8 |
9 | MotionLazyContainer.propTypes = {
10 | children: PropTypes.node
11 | };
12 |
13 | export default function MotionLazyContainer({ children }) {
14 | return (
15 |
16 | {children}
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/frontend/src/components/animate/MotionViewport.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types'
2 | import { m } from 'framer-motion'
3 | // @mui
4 | import { Box } from '@mui/material'
5 | // hooks
6 | import useResponsive from '../../hooks/useResponsive'
7 | //
8 | import { varContainer } from '.'
9 |
10 | // ----------------------------------------------------------------------
11 |
12 | MotionViewport.propTypes = {
13 | children: PropTypes.node.isRequired,
14 | disableAnimatedMobile: PropTypes.bool
15 | }
16 |
17 | export default function MotionViewport({ children, disableAnimatedMobile = false, ...other }) {
18 | const isMobile = useResponsive('down', 'sm')
19 |
20 | if (isMobile && disableAnimatedMobile) {
21 | return {children}
22 | }
23 |
24 | return (
25 |
33 | {children}
34 |
35 | )
36 | }
37 |
--------------------------------------------------------------------------------
/frontend/src/components/animate/TextAnimate.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { m } from 'framer-motion';
3 | // @mui
4 | import { Box } from '@mui/material';
5 | //
6 | import { varFade } from './variants';
7 |
8 | // ----------------------------------------------------------------------
9 |
10 | TextAnimate.propTypes = {
11 | text: PropTypes.string.isRequired,
12 | variants: PropTypes.object,
13 | sx: PropTypes.object
14 | };
15 |
16 | export default function TextAnimate({ text, variants, sx, ...other }) {
17 | return (
18 |
28 | {text.split('').map((letter, index) => (
29 |
30 | {letter}
31 |
32 | ))}
33 |
34 | );
35 | }
36 |
--------------------------------------------------------------------------------
/frontend/src/components/animate/features.js:
--------------------------------------------------------------------------------
1 | import { domMax } from 'framer-motion';
2 |
3 | export default domMax;
4 |
--------------------------------------------------------------------------------
/frontend/src/components/animate/index.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export * from './variants';
4 |
5 | export { default as DialogAnimate } from './DialogAnimate';
6 | export { default as TextAnimate } from './TextAnimate';
7 |
8 | export { default as FabButtonAnimate } from './FabButtonAnimate';
9 | export { default as IconButtonAnimate } from './IconButtonAnimate';
10 |
11 | export { default as MotionViewport } from './MotionViewport';
12 | export { default as MotionContainer } from './MotionContainer';
13 | export { default as MotionLazyContainer } from './MotionLazyContainer';
14 |
--------------------------------------------------------------------------------
/frontend/src/components/animate/variants/actions.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export const varHover = (scale) => ({
4 | hover: {
5 | scale: scale || 1.1
6 | }
7 | });
8 |
--------------------------------------------------------------------------------
/frontend/src/components/animate/variants/container.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export const varContainer = (props) => {
4 | const staggerIn = props?.staggerIn || 0.05;
5 | const delayIn = props?.staggerIn || 0.05;
6 | const staggerOut = props?.staggerIn || 0.05;
7 |
8 | return {
9 | animate: {
10 | transition: {
11 | staggerChildren: staggerIn,
12 | delayChildren: delayIn
13 | }
14 | },
15 | exit: {
16 | transition: {
17 | staggerChildren: staggerOut,
18 | staggerDirection: -1
19 | }
20 | }
21 | };
22 | };
23 |
--------------------------------------------------------------------------------
/frontend/src/components/animate/variants/flip.js:
--------------------------------------------------------------------------------
1 | import { varTranEnter, varTranExit } from './transition';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export const varFlip = (props) => {
6 | const durationIn = props?.durationIn;
7 | const durationOut = props?.durationOut;
8 | const easeIn = props?.easeIn;
9 | const easeOut = props?.easeOut;
10 |
11 | return {
12 | // IN
13 | inX: {
14 | initial: { rotateX: -180, opacity: 0 },
15 | animate: { rotateX: 0, opacity: 1, transition: varTranEnter({ durationIn, easeIn }) },
16 | exit: { rotateX: -180, opacity: 0, transition: varTranExit({ durationOut, easeOut }) }
17 | },
18 | inY: {
19 | initial: { rotateY: -180, opacity: 0 },
20 | animate: { rotateY: 0, opacity: 1, transition: varTranEnter({ durationIn, easeIn }) },
21 | exit: { rotateY: -180, opacity: 0, transition: varTranExit({ durationOut, easeOut }) }
22 | },
23 |
24 | // OUT
25 | outX: {
26 | initial: { rotateX: 0, opacity: 1 },
27 | animate: { rotateX: 70, opacity: 0, transition: varTranExit({ durationOut, easeOut }) }
28 | },
29 | outY: {
30 | initial: { rotateY: 0, opacity: 1 },
31 | animate: { rotateY: 70, opacity: 0, transition: varTranExit({ durationOut, easeOut }) }
32 | }
33 | };
34 | };
35 |
--------------------------------------------------------------------------------
/frontend/src/components/animate/variants/index.js:
--------------------------------------------------------------------------------
1 | export * from './path';
2 | export * from './fade';
3 | export * from './zoom';
4 | export * from './flip';
5 | export * from './slide';
6 | export * from './scale';
7 | export * from './bounce';
8 | export * from './rotate';
9 | export * from './actions';
10 | export * from './container';
11 | export * from './transition';
12 | export * from './background';
13 |
--------------------------------------------------------------------------------
/frontend/src/components/animate/variants/path.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export const TRANSITION = {
4 | duration: 2,
5 | ease: [0.43, 0.13, 0.23, 0.96]
6 | };
7 |
8 | export const varPath = {
9 | animate: {
10 | fillOpacity: [0, 0, 1],
11 | pathLength: [1, 0.4, 0],
12 | transition: TRANSITION
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/frontend/src/components/animate/variants/rotate.js:
--------------------------------------------------------------------------------
1 | //
2 | import { varTranEnter, varTranExit } from './transition';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | export const varRotate = (props) => {
7 | const durationIn = props?.durationIn;
8 | const durationOut = props?.durationOut;
9 | const easeIn = props?.easeIn;
10 | const easeOut = props?.easeOut;
11 |
12 | return {
13 | // IN
14 | in: {
15 | initial: { opacity: 0, rotate: -360 },
16 | animate: { opacity: 1, rotate: 0, transition: varTranEnter({ durationIn, easeIn }) },
17 | exit: { opacity: 0, rotate: -360, transition: varTranExit({ durationOut, easeOut }) }
18 | },
19 |
20 | // OUT
21 | out: {
22 | initial: { opacity: 1, rotate: 0 },
23 | animate: { opacity: 0, rotate: -360, transition: varTranExit({ durationOut, easeOut }) }
24 | }
25 | };
26 | };
27 |
--------------------------------------------------------------------------------
/frontend/src/components/animate/variants/scale.js:
--------------------------------------------------------------------------------
1 | //
2 | import { varTranEnter, varTranExit } from './transition';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | export const varScale = (props) => {
7 | const durationIn = props?.durationIn;
8 | const durationOut = props?.durationOut;
9 | const easeIn = props?.easeIn;
10 | const easeOut = props?.easeOut;
11 |
12 | return {
13 | // IN
14 | inX: {
15 | initial: { scaleX: 0, opacity: 0 },
16 | animate: { scaleX: 1, opacity: 1, transition: varTranEnter({ durationIn, easeIn }) },
17 | exit: { scaleX: 0, opacity: 0, transition: varTranExit({ durationOut, easeOut }) }
18 | },
19 | inY: {
20 | initial: { scaleY: 0, opacity: 0 },
21 | animate: { scaleY: 1, opacity: 1, transition: varTranEnter({ durationIn, easeIn }) },
22 | exit: { scaleY: 0, opacity: 0, transition: varTranExit({ durationOut, easeOut }) }
23 | },
24 |
25 | // OUT
26 | outX: {
27 | initial: { scaleX: 1, opacity: 1 },
28 | animate: { scaleX: 0, opacity: 0, transition: varTranEnter({ durationIn, easeIn }) }
29 | },
30 | outY: {
31 | initial: { scaleY: 1, opacity: 1 },
32 | animate: { scaleY: 0, opacity: 0, transition: varTranEnter({ durationIn, easeIn }) }
33 | }
34 | };
35 | };
36 |
--------------------------------------------------------------------------------
/frontend/src/components/animate/variants/transition.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export const varTranHover = (props) => {
4 | const duration = props?.duration || 0.32;
5 | const ease = props?.ease || [0.43, 0.13, 0.23, 0.96];
6 |
7 | return { duration, ease };
8 | };
9 |
10 | export const varTranEnter = (props) => {
11 | const duration = props?.durationIn || 0.64;
12 | const ease = props?.easeIn || [0.43, 0.13, 0.23, 0.96];
13 |
14 | return { duration, ease };
15 | };
16 |
17 | export const varTranExit = (props) => {
18 | const duration = props?.durationOut || 0.48;
19 | const ease = props?.easeOut || [0.43, 0.13, 0.23, 0.96];
20 |
21 | return { duration, ease };
22 | };
23 |
--------------------------------------------------------------------------------
/frontend/src/components/carousel/index.js:
--------------------------------------------------------------------------------
1 | export { default as CarouselDots } from './CarouselDots';
2 | export { default as CarouselArrows } from './CarouselArrows';
3 | export { default as CarouselArrowIndex } from './CarouselArrowIndex';
4 |
--------------------------------------------------------------------------------
/frontend/src/components/chart/index.js:
--------------------------------------------------------------------------------
1 | export { default as ChartStyle } from './ChartStyle';
2 | export { default as BaseOptionChart } from './BaseOptionChart';
3 |
--------------------------------------------------------------------------------
/frontend/src/components/color-utils/ColorPreview.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // @mui
3 | import { alpha, styled } from '@mui/material/styles';
4 | import { Box, Typography } from '@mui/material';
5 |
6 | // ----------------------------------------------------------------------
7 |
8 | const RootStyle = styled(Box)(() => ({
9 | display: 'flex',
10 | alignItems: 'center',
11 | justifyContent: 'flex-end',
12 | }));
13 |
14 | const IconStyle = styled('div')(({ theme }) => ({
15 | marginLeft: -4,
16 | borderRadius: '50%',
17 | width: theme.spacing(2),
18 | height: theme.spacing(2),
19 | border: `solid 2px ${theme.palette.background.paper}`,
20 | boxShadow: `inset -1px 1px 2px ${alpha(theme.palette.common.black, 0.24)}`,
21 | }));
22 |
23 | // ----------------------------------------------------------------------
24 |
25 | ColorPreview.propTypes = {
26 | colors: PropTypes.arrayOf(PropTypes.string),
27 | limit: PropTypes.number,
28 | sx: PropTypes.object,
29 | };
30 |
31 | export default function ColorPreview({ colors, limit = 3, sx }) {
32 | const showColor = colors.slice(0, limit);
33 | const moreColor = colors.length - limit;
34 |
35 | return (
36 |
37 | {showColor.map((color, index) => (
38 |
39 | ))}
40 |
41 | {colors.length > limit && {`+${moreColor}`}}
42 |
43 | );
44 | }
45 |
--------------------------------------------------------------------------------
/frontend/src/components/color-utils/index.js:
--------------------------------------------------------------------------------
1 | export { default as ColorPreview } from './ColorPreview';
2 | export { default as ColorManyPicker } from './ColorManyPicker';
3 | export { default as ColorSinglePicker } from './ColorSinglePicker';
4 |
--------------------------------------------------------------------------------
/frontend/src/components/emoji-picker/index.js:
--------------------------------------------------------------------------------
1 | export { default as EmojiPicker } from './EmojiPicker';
2 |
--------------------------------------------------------------------------------
/frontend/src/components/hook-form/FormProvider.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // form
3 | import { FormProvider as Form } from 'react-hook-form';
4 |
5 | // ----------------------------------------------------------------------
6 |
7 | FormProvider.propTypes = {
8 | children: PropTypes.node.isRequired,
9 | methods: PropTypes.object.isRequired,
10 | onSubmit: PropTypes.func,
11 | };
12 |
13 | export default function FormProvider({ children, onSubmit, methods }) {
14 | return (
15 |
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/frontend/src/components/hook-form/RHFEditor.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // form
3 | import { useFormContext, Controller } from 'react-hook-form';
4 | // @mui
5 | import { FormHelperText } from '@mui/material';
6 | //
7 | import Editor from '../editor';
8 |
9 | // ----------------------------------------------------------------------
10 |
11 | RHFEditor.propTypes = {
12 | name: PropTypes.string,
13 | };
14 |
15 | export default function RHFEditor({ name, ...other }) {
16 | const { control } = useFormContext();
17 |
18 | return (
19 | (
23 |
30 | {error?.message}
31 |
32 | }
33 | {...other}
34 | />
35 | )}
36 | />
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/frontend/src/components/hook-form/RHFNumberField.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types'
2 | // form
3 | import { useFormContext, Controller } from 'react-hook-form'
4 | // @mui
5 | import { TextField } from '@mui/material'
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | RHFNumberField.propTypes = {
10 | name: PropTypes.string
11 | }
12 |
13 | export default function RHFNumberField({ name, ...other }) {
14 | const { control } = useFormContext()
15 |
16 | return (
17 | (
21 |
30 | )}
31 | />
32 | )
33 | }
34 |
--------------------------------------------------------------------------------
/frontend/src/components/hook-form/RHFRadioGroup.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types'
2 | // form
3 | import { useFormContext, Controller } from 'react-hook-form'
4 | // @mui
5 | import { Radio, RadioGroup, FormHelperText, FormControlLabel } from '@mui/material'
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | RHFRadioGroup.propTypes = {
10 | name: PropTypes.string,
11 | options: PropTypes.array
12 | }
13 |
14 | export default function RHFRadioGroup({ name, options, ...other }) {
15 | const { control } = useFormContext()
16 |
17 | return (
18 | (
22 |
23 |
24 | {options.map((option) => (
25 | } label={option.label} />
26 | ))}
27 |
28 |
29 | {!!error && (
30 |
31 | {error.message}
32 |
33 | )}
34 |
35 | )}
36 | />
37 | )
38 | }
39 |
--------------------------------------------------------------------------------
/frontend/src/components/hook-form/RHFSelect.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // form
3 | import { useFormContext, Controller } from 'react-hook-form';
4 | // @mui
5 | import { TextField } from '@mui/material';
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | RHFSelect.propTypes = {
10 | children: PropTypes.node,
11 | name: PropTypes.string,
12 | };
13 |
14 | export default function RHFSelect({ name, children, ...other }) {
15 | const { control } = useFormContext();
16 |
17 | return (
18 | (
22 |
31 | {children}
32 |
33 | )}
34 | />
35 | );
36 | }
37 |
--------------------------------------------------------------------------------
/frontend/src/components/hook-form/RHFSlider.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types'
2 | // form
3 | import { useFormContext, Controller } from 'react-hook-form'
4 | // @mui
5 | import { Slider } from '@mui/material'
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | RHFSlider.propTypes = {
10 | name: PropTypes.string
11 | }
12 |
13 | export default function RHFSlider({ name, ...other }) {
14 | const { control } = useFormContext()
15 |
16 | return } />
17 | }
18 |
--------------------------------------------------------------------------------
/frontend/src/components/hook-form/RHFSwitch.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // form
3 | import { useFormContext, Controller } from 'react-hook-form';
4 | // @mui
5 | import { Switch, FormControlLabel } from '@mui/material';
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | RHFSwitch.propTypes = {
10 | name: PropTypes.string,
11 | };
12 |
13 | export default function RHFSwitch({ name, ...other }) {
14 | const { control } = useFormContext();
15 |
16 | return (
17 | } />
20 | }
21 | {...other}
22 | />
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/frontend/src/components/hook-form/RHFTextField.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types'
2 | // form
3 | import { useFormContext, Controller } from 'react-hook-form'
4 | // @mui
5 | import { TextField } from '@mui/material'
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | RHFTextField.propTypes = {
10 | name: PropTypes.string
11 | }
12 |
13 | export default function RHFTextField({ name, ...other }) {
14 | const { control } = useFormContext()
15 |
16 | return (
17 | (
21 |
29 | )}
30 | />
31 | )
32 | }
33 |
--------------------------------------------------------------------------------
/frontend/src/components/hook-form/index.js:
--------------------------------------------------------------------------------
1 | export * from './RHFUpload'
2 | export * from './RHFCheckbox'
3 |
4 | export { default as RHFSwitch } from './RHFSwitch'
5 | export { default as RHFSelect } from './RHFSelect'
6 | export { default as RHFEditor } from './RHFEditor'
7 | export { default as RHFSlider } from './RHFSlider'
8 | export { default as RHFTextField } from './RHFTextField'
9 | export { default as RHFNumberField } from './RHFNumberField'
10 | export { default as RHFRadioGroup } from './RHFRadioGroup'
11 |
12 | export { default as FormProvider } from './FormProvider'
13 |
--------------------------------------------------------------------------------
/frontend/src/components/map/MapControl.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { NavigationControl, FullscreenControl, ScaleControl, GeolocateControl } from 'react-map-gl';
3 | //
4 | import { ControlStyle } from './style';
5 |
6 | // ----------------------------------------------------------------------
7 |
8 | MapControl.propTypes = {
9 | hideFullscreenControl: PropTypes.bool,
10 | hideGeolocateControl: PropTypes.bool,
11 | hideNavigationnControl: PropTypes.bool,
12 | hideScaleControl: PropTypes.bool,
13 | };
14 |
15 | export default function MapControl({
16 | hideScaleControl,
17 | hideGeolocateControl,
18 | hideFullscreenControl,
19 | hideNavigationnControl,
20 | }) {
21 | return (
22 | <>
23 |
24 |
25 | {!hideGeolocateControl && }
26 |
27 | {!hideFullscreenControl && }
28 |
29 | {!hideScaleControl && }
30 |
31 | {!hideNavigationnControl && }
32 | >
33 | );
34 | }
35 |
--------------------------------------------------------------------------------
/frontend/src/components/map/MapMarker.js:
--------------------------------------------------------------------------------
1 | import { Marker } from 'react-map-gl';
2 | // @mui
3 | import { Box } from '@mui/material';
4 |
5 | // ----------------------------------------------------------------------
6 |
7 | const SIZE = 20;
8 |
9 | const ICON = `M20.2,15.7L20.2,15.7c1.1-1.6,1.8-3.6,1.8-5.7c0-5.6-4.5-10-10-10S2,4.5,2,10c0,2,0.6,3.9,1.6,5.4c0,0.1,0.1,0.2,0.2,0.3
10 | c0,0,0.1,0.1,0.1,0.2c0.2,0.3,0.4,0.6,0.7,0.9c2.6,3.1,7.4,7.6,7.4,7.6s4.8-4.5,7.4-7.5c0.2-0.3,0.5-0.6,0.7-0.9
11 | C20.1,15.8,20.2,15.8,20.2,15.7z`;
12 |
13 | // ----------------------------------------------------------------------
14 |
15 | export default function MapMarker({ ...other }) {
16 | return (
17 |
18 | theme.palette.error.main,
26 | transform: `translate(${-SIZE / 2}px,${-SIZE}px)`,
27 | }}
28 | >
29 |
30 |
31 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/frontend/src/components/map/MapPopup.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | //
3 | import { PopupStyle } from './style';
4 |
5 | // ----------------------------------------------------------------------
6 |
7 | MapPopup.propTypes = {
8 | children: PropTypes.node,
9 | sx: PropTypes.object,
10 | };
11 |
12 | export default function MapPopup({ sx, children, ...other }) {
13 | return (
14 |
15 | {children}
16 |
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/frontend/src/components/map/index.js:
--------------------------------------------------------------------------------
1 | export * from './style';
2 |
3 | export { default as MapPopup } from './MapPopup';
4 | export { default as MapMarker } from './MapMarker';
5 | export { default as MapControl } from './MapControl';
6 |
--------------------------------------------------------------------------------
/frontend/src/components/mega-menu/MenuHotProducts.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { Link as RouterLink } from 'react-router-dom';
3 | // @mui
4 | import { Link, Typography, Box } from '@mui/material';
5 |
6 | // ----------------------------------------------------------------------
7 |
8 | MenuHotProducts.propTypes = {
9 | tags: PropTypes.array.isRequired,
10 | };
11 |
12 | export default function MenuHotProducts({ tags, ...other }) {
13 | return (
14 |
15 |
16 | Hot Products:
17 |
18 |
19 | {tags.map((tag, index) => (
20 | theme.transitions.create('all'),
29 | '&:hover': { color: 'primary.main' },
30 | }}
31 | >
32 | {index === 0 ? tag.name : `, ${tag.name} `}
33 |
34 | ))}
35 |
36 | );
37 | }
38 |
--------------------------------------------------------------------------------
/frontend/src/components/mega-menu/index.js:
--------------------------------------------------------------------------------
1 | export { default as MegaMenuDesktopVertical } from './MegaMenuDesktopVertical';
2 | export { default as MegaMenuDesktopHorizon } from './MegaMenuDesktopHorizon';
3 | export { default as MegaMenuMobile } from './MegaMenuMobile';
4 | export { default as MenuConfig } from './MenuConfig';
5 |
--------------------------------------------------------------------------------
/frontend/src/components/nav-section/horizontal/index.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types'
2 | import { memo } from 'react'
3 | // @mui
4 | import { Stack } from '@mui/material'
5 | //
6 | import NavList from './NavList'
7 |
8 | // ----------------------------------------------------------------------
9 |
10 | const hideScrollbar = {
11 | msOverflowStyle: 'none',
12 | scrollbarWidth: 'none',
13 | overflowY: 'scroll',
14 | '&::-webkit-scrollbar': {
15 | display: 'none'
16 | }
17 | }
18 |
19 | NavSectionHorizontal.propTypes = {
20 | navConfig: PropTypes.array
21 | }
22 |
23 | function NavSectionHorizontal({ navConfig }) {
24 | return (
25 |
26 |
27 | {navConfig.map((group) => (
28 |
29 | {group.items.map((list) => (
30 |
31 | ))}
32 |
33 | ))}
34 |
35 |
36 | )
37 | }
38 |
39 | export default memo(NavSectionHorizontal)
40 |
--------------------------------------------------------------------------------
/frontend/src/components/nav-section/index.js:
--------------------------------------------------------------------------------
1 | import { matchPath } from 'react-router-dom';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export { default as NavSectionVertical } from './vertical';
6 | export { default as NavSectionHorizontal } from './horizontal';
7 |
8 | export function isExternalLink(path) {
9 | return path.includes('http');
10 | }
11 |
12 | export function getActive(path, pathname) {
13 | return path ? !!matchPath({ path, end: false }, pathname) : false;
14 | }
15 |
--------------------------------------------------------------------------------
/frontend/src/components/nav-section/vertical/index.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // @mui
3 | import { List, Box } from '@mui/material';
4 | // hooks
5 | import useLocales from '../../../hooks/useLocales';
6 | //
7 | import { ListSubheaderStyle } from './style';
8 | import NavList from './NavList';
9 |
10 | // ----------------------------------------------------------------------
11 |
12 | NavSectionVertical.propTypes = {
13 | isCollapse: PropTypes.bool,
14 | navConfig: PropTypes.array,
15 | };
16 |
17 | export default function NavSectionVertical({ navConfig, isCollapse, ...other }) {
18 | const { translate } = useLocales();
19 |
20 | return (
21 |
22 | {navConfig.map((group) => (
23 |
24 |
31 | {translate(group.subheader)}
32 |
33 |
34 | {group.items.map((list) => (
35 |
42 | ))}
43 |
44 | ))}
45 |
46 | );
47 | }
48 |
--------------------------------------------------------------------------------
/frontend/src/components/organizational-chart/node/SimpleNode.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // @mui
3 | import { alpha } from '@mui/material/styles';
4 | import { Typography, Card } from '@mui/material';
5 |
6 | // ----------------------------------------------------------------------
7 |
8 | SimpleNode.propTypes = {
9 | node: PropTypes.shape({
10 | name: PropTypes.string,
11 | }),
12 | sx: PropTypes.object,
13 | };
14 |
15 | export default function SimpleNode({ node, sx }) {
16 | return (
17 | alpha(theme.palette.primary.main, 0.08),
26 | border: (theme) => `1px solid ${alpha(theme.palette.primary.main, 0.24)}`,
27 | ...sx,
28 | }}
29 | >
30 | {node.name}
31 |
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/frontend/src/components/organizational-chart/node/index.js:
--------------------------------------------------------------------------------
1 | export { default as GroupNode } from './GroupNode';
2 | export { default as SimpleNode } from './SimpleNode';
3 | export { default as StandardNode } from './StandardNode';
4 |
--------------------------------------------------------------------------------
/frontend/src/components/settings/ThemeColorPresets.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { useMemo } from 'react';
3 | // @mui
4 | import { alpha, ThemeProvider, createTheme, useTheme } from '@mui/material/styles';
5 | // hooks
6 | import useSettings from '../../hooks/useSettings';
7 | //
8 | import componentsOverride from '../../theme/overrides';
9 |
10 | // ----------------------------------------------------------------------
11 |
12 | ThemeColorPresets.propTypes = {
13 | children: PropTypes.node,
14 | };
15 |
16 | export default function ThemeColorPresets({ children }) {
17 | const defaultTheme = useTheme();
18 |
19 | const { setColor } = useSettings();
20 |
21 | const themeOptions = useMemo(
22 | () => ({
23 | ...defaultTheme,
24 | palette: {
25 | ...defaultTheme.palette,
26 | primary: setColor,
27 | },
28 | customShadows: {
29 | ...defaultTheme.customShadows,
30 | primary: `0 8px 16px 0 ${alpha(setColor.main, 0.24)}`,
31 | },
32 | }),
33 | [setColor, defaultTheme]
34 | );
35 |
36 | const theme = createTheme(themeOptions);
37 |
38 | theme.components = componentsOverride(theme);
39 |
40 | return {children};
41 | }
42 |
--------------------------------------------------------------------------------
/frontend/src/components/settings/ThemeLocalization.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // @mui
3 | import { ThemeProvider, createTheme, useTheme } from '@mui/material/styles';
4 | // hooks
5 | import useLocales from '../../hooks/useLocales';
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | ThemeLocalization.propTypes = {
10 | children: PropTypes.node.isRequired,
11 | };
12 |
13 | export default function ThemeLocalization({ children }) {
14 | const defaultTheme = useTheme();
15 |
16 | const { currentLang } = useLocales();
17 |
18 | const theme = createTheme(defaultTheme, currentLang.systemValue);
19 |
20 | return {children};
21 | }
22 |
--------------------------------------------------------------------------------
/frontend/src/components/settings/ThemeRtlLayout.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { useEffect } from 'react';
3 | // rtl
4 | import rtlPlugin from 'stylis-plugin-rtl';
5 | // emotion
6 | import createCache from '@emotion/cache';
7 | import { CacheProvider } from '@emotion/react';
8 | // @mui
9 | import { useTheme } from '@mui/material/styles';
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | ThemeRtlLayout.propTypes = {
14 | children: PropTypes.node,
15 | };
16 |
17 | export default function ThemeRtlLayout({ children }) {
18 | const theme = useTheme();
19 |
20 | useEffect(() => {
21 | document.dir = theme.direction;
22 | }, [theme.direction]);
23 |
24 | const cacheRtl = createCache({
25 | key: theme.direction === 'rtl' ? 'rtl' : 'css',
26 | stylisPlugins: theme.direction === 'rtl' ? [rtlPlugin] : [],
27 | });
28 |
29 | return {children};
30 | }
31 |
--------------------------------------------------------------------------------
/frontend/src/components/settings/drawer/BoxMask.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // @mui
3 | import { Radio, FormControlLabel } from '@mui/material';
4 |
5 | // ----------------------------------------------------------------------
6 |
7 | BoxMask.propTypes = {
8 | value: PropTypes.string,
9 | };
10 |
11 | export default function BoxMask({ value }) {
12 | return (
13 | }
17 | sx={{
18 | m: 0,
19 | top: 0,
20 | right: 0,
21 | bottom: 0,
22 | left: 0,
23 | position: 'absolute',
24 | }}
25 | />
26 | );
27 | }
28 |
--------------------------------------------------------------------------------
/frontend/src/components/settings/drawer/SettingFullscreen.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | // @mui
3 | import { alpha } from '@mui/material/styles';
4 | import { Button } from '@mui/material';
5 | //
6 | import Iconify from '../../Iconify';
7 |
8 | // ----------------------------------------------------------------------
9 |
10 | export default function SettingFullscreen() {
11 | const [fullscreen, setFullscreen] = useState(false);
12 |
13 | const toggleFullScreen = () => {
14 | if (!document.fullscreenElement) {
15 | document.documentElement.requestFullscreen();
16 | setFullscreen(true);
17 | } else if (document.exitFullscreen) {
18 | document.exitFullscreen();
19 | setFullscreen(false);
20 | }
21 | };
22 |
23 | return (
24 | }
30 | onClick={toggleFullScreen}
31 | sx={{
32 | fontSize: 14,
33 | ...(fullscreen && {
34 | bgcolor: (theme) => alpha(theme.palette.primary.main, theme.palette.action.selectedOpacity),
35 | }),
36 | }}
37 | >
38 | {fullscreen ? 'Exit Fullscreen' : 'Fullscreen'}
39 |
40 | );
41 | }
42 |
--------------------------------------------------------------------------------
/frontend/src/components/settings/index.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | //
3 | import SettingsDrawer from './drawer';
4 | //
5 | import ThemeContrast from './ThemeContrast';
6 | import ThemeRtlLayout from './ThemeRtlLayout';
7 | import ThemeColorPresets from './ThemeColorPresets';
8 | import ThemeLocalization from './ThemeLocalization';
9 |
10 | // ----------------------------------------------------------------------
11 |
12 | ThemeSettings.propTypes = {
13 | children: PropTypes.node.isRequired,
14 | };
15 |
16 | export default function ThemeSettings({ children }) {
17 | return (
18 |
19 |
20 |
21 |
22 | {children}
23 |
24 |
25 |
26 |
27 |
28 | );
29 | }
30 |
--------------------------------------------------------------------------------
/frontend/src/components/skeleton/SkeletonConversationItem.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { Stack, Skeleton } from '@mui/material';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | export default function SkeletonConversationItem() {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/frontend/src/components/skeleton/SkeletonKanbanColumn.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { Stack, Skeleton, Box, Paper } from '@mui/material';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | export default function SkeletonKanbanColumn() {
7 | return (
8 |
15 | {[...Array(3)].map((_, index) => (
16 |
17 |
18 |
19 | {index === 0 && (
20 |
21 | )}
22 | {index !== 2 && (
23 |
24 | )}
25 |
26 |
27 | ))}
28 |
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/frontend/src/components/skeleton/SkeletonMailSidebarItem.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { Stack, Skeleton } from '@mui/material';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | export default function SkeletonMailSidebarItem() {
7 | return (
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/src/components/skeleton/SkeletonMap.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { Stack, Skeleton } from '@mui/material';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | export default function SkeletonMap() {
7 | return (
8 |
9 | {[...Array(5)].map((_, index) => (
10 |
15 | ))}
16 |
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/frontend/src/components/skeleton/SkeletonPost.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { Box, Skeleton } from '@mui/material';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | export default function SkeletonPost() {
7 | return (
8 | <>
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | >
19 | );
20 | }
21 |
--------------------------------------------------------------------------------
/frontend/src/components/skeleton/SkeletonPostItem.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { Box, Skeleton, Grid } from '@mui/material';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | export default function SkeletonPostItem() {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/frontend/src/components/skeleton/SkeletonProduct.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { Grid, Skeleton } from '@mui/material';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | export default function SkeletonProduct() {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | );
21 | }
22 |
--------------------------------------------------------------------------------
/frontend/src/components/skeleton/SkeletonProductItem.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { Card, Skeleton, Stack } from '@mui/material';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | export default function SkeletonProductItem() {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | );
23 | }
24 |
--------------------------------------------------------------------------------
/frontend/src/components/skeleton/index.js:
--------------------------------------------------------------------------------
1 | export { default as SkeletonMap } from './SkeletonMap';
2 | export { default as SkeletonPost } from './SkeletonPost';
3 | export { default as SkeletonProduct } from './SkeletonProduct';
4 | export { default as SkeletonPostItem } from './SkeletonPostItem';
5 | export { default as SkeletonProductItem } from './SkeletonProductItem';
6 | export { default as SkeletonKanbanColumn } from './SkeletonKanbanColumn';
7 | export { default as SkeletonMailSidebarItem } from './SkeletonMailSidebarItem';
8 | export { default as SkeletonConversationItem } from './SkeletonConversationItem';
9 |
--------------------------------------------------------------------------------
/frontend/src/components/table/TableEmptyRows.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types'
2 | // @mui
3 | import { TableRow, TableCell } from '@mui/material'
4 |
5 | // ----------------------------------------------------------------------
6 |
7 | TableEmptyRows.propTypes = {
8 | emptyRows: PropTypes.number,
9 | height: PropTypes.number
10 | }
11 |
12 | export default function TableEmptyRows({ emptyRows, height }) {
13 | if (!emptyRows) {
14 | return null
15 | }
16 |
17 | return (
18 |
25 |
26 |
27 | )
28 | }
29 |
--------------------------------------------------------------------------------
/frontend/src/components/table/TableMoreMenu.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types'
2 | // @mui
3 | import { IconButton } from '@mui/material'
4 | //
5 | import Iconify from '../Iconify'
6 | import MenuPopover from '../MenuPopover'
7 |
8 | // ----------------------------------------------------------------------
9 |
10 | TableMoreMenu.propTypes = {
11 | actions: PropTypes.node,
12 | open: PropTypes.object,
13 | onClose: PropTypes.func,
14 | onOpen: PropTypes.func
15 | }
16 |
17 | export default function TableMoreMenu({ actions, open, onClose, onOpen }) {
18 | return (
19 | <>
20 |
21 |
22 |
23 |
24 |
42 | {actions}
43 |
44 | >
45 | )
46 | }
47 |
--------------------------------------------------------------------------------
/frontend/src/components/table/TableNoData.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types'
2 | // @mui
3 | import { TableRow, TableCell } from '@mui/material'
4 | //
5 | import EmptyContent from '../EmptyContent'
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | TableNoData.propTypes = {
10 | isNotFound: PropTypes.bool
11 | }
12 |
13 | export default function TableNoData({ isNotFound }) {
14 | return (
15 |
16 | {isNotFound ? (
17 |
18 |
24 |
25 | ) : (
26 |
27 | )}
28 |
29 | )
30 | }
31 |
--------------------------------------------------------------------------------
/frontend/src/components/table/TableSelectedActions.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types'
2 | // @mui
3 | import { Checkbox, Typography, Stack } from '@mui/material'
4 |
5 | // ----------------------------------------------------------------------
6 |
7 | TableSelectedActions.propTypes = {
8 | dense: PropTypes.bool,
9 | actions: PropTypes.node,
10 | rowCount: PropTypes.number,
11 | numSelected: PropTypes.number,
12 | onSelectAllRows: PropTypes.func,
13 | sx: PropTypes.object
14 | }
15 |
16 | export default function TableSelectedActions({ dense, actions, rowCount, numSelected, onSelectAllRows, sx, ...other }) {
17 | return (
18 |
39 | 0 && numSelected < rowCount}
41 | checked={rowCount > 0 && numSelected === rowCount}
42 | onChange={(event) => onSelectAllRows(event.target.checked)}
43 | />
44 |
45 |
56 | {numSelected} selected
57 |
58 |
59 | {actions && actions}
60 |
61 | )
62 | }
63 |
--------------------------------------------------------------------------------
/frontend/src/components/table/TableSkeleton.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { TableRow, TableCell, Skeleton, Stack } from '@mui/material'
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | export default function TableSkeleton({ ...other }) {
7 | return (
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | )
21 | }
22 |
--------------------------------------------------------------------------------
/frontend/src/components/table/index.js:
--------------------------------------------------------------------------------
1 | export { default as TableNoData } from './TableNoData';
2 | export { default as TableMoreMenu } from './TableMoreMenu';
3 | export { default as TableSkeleton } from './TableSkeleton';
4 | export { default as TableEmptyRows } from './TableEmptyRows';
5 | export { default as TableHeadCustom } from './TableHeadCustom';
6 | export { default as TableSelectedActions } from './TableSelectedActions';
7 |
--------------------------------------------------------------------------------
/frontend/src/components/upload/BlockContent.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { Box, Typography, Stack } from '@mui/material';
3 | // assets
4 | import { UploadIllustration } from '../../assets';
5 |
6 | // ----------------------------------------------------------------------
7 |
8 | export default function BlockContent() {
9 | return (
10 |
17 |
18 |
19 |
20 |
21 | Drop or Select file
22 |
23 |
24 |
25 | Drop files here or click
26 |
31 | browse
32 |
33 | thorough your machine
34 |
35 |
36 |
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/frontend/src/components/upload/RejectionFiles.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | // @mui
3 | import { alpha } from '@mui/material/styles';
4 | import { Box, Paper, Typography } from '@mui/material';
5 | // utils
6 | import { fData } from '../../utils/formatNumber';
7 | import getFileData from '../../utils/getFileData';
8 |
9 | // ----------------------------------------------------------------------
10 |
11 | RejectionFiles.propTypes = {
12 | fileRejections: PropTypes.array.isRequired,
13 | };
14 |
15 | export default function RejectionFiles({ fileRejections }) {
16 | return (
17 | alpha(theme.palette.error.main, 0.08),
25 | }}
26 | >
27 | {fileRejections.map(({ file, errors }) => {
28 | const { path, size } = getFileData(file);
29 |
30 | return (
31 |
32 |
33 | {path} - {size ? fData(size) : ''}
34 |
35 |
36 | {errors.map((error) => (
37 |
38 | {error.message}
39 |
40 | ))}
41 |
42 | );
43 | })}
44 |
45 | );
46 | }
47 |
--------------------------------------------------------------------------------
/frontend/src/components/upload/index.js:
--------------------------------------------------------------------------------
1 | export { default as BlockContent } from './BlockContent';
2 | export { default as RejectionFiles } from './RejectionFiles';
3 | export { default as MultiFilePreview } from './MultiFilePreview';
4 |
5 | export { default as UploadAvatar } from './UploadAvatar';
6 | export { default as UploadMultiFile } from './UploadMultiFile';
7 | export { default as UploadSingleFile } from './UploadSingleFile';
8 |
--------------------------------------------------------------------------------
/frontend/src/guards/AuthGuard.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { useState } from 'react';
3 | import { Navigate, useLocation } from 'react-router-dom';
4 | // hooks
5 | import useAuth from '../hooks/useAuth';
6 | // pages
7 | import Login from '../pages/auth/Login';
8 | // components
9 | import LoadingScreen from '../components/LoadingScreen';
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | AuthGuard.propTypes = {
14 | children: PropTypes.node,
15 | };
16 |
17 | export default function AuthGuard({ children }) {
18 | const { isAuthenticated, isInitialized } = useAuth();
19 |
20 | const { pathname } = useLocation();
21 |
22 | const [requestedLocation, setRequestedLocation] = useState(null);
23 |
24 | if (!isInitialized) {
25 | return ;
26 | }
27 |
28 | if (!isAuthenticated) {
29 | if (pathname !== requestedLocation) {
30 | setRequestedLocation(pathname);
31 | }
32 | return ;
33 | }
34 |
35 | if (requestedLocation && pathname !== requestedLocation) {
36 | setRequestedLocation(null);
37 | return ;
38 | }
39 |
40 | return <>{children}>;
41 | }
42 |
--------------------------------------------------------------------------------
/frontend/src/guards/GuestGuard.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { Navigate } from 'react-router-dom';
3 | // hooks
4 | import useAuth from '../hooks/useAuth';
5 | // routes
6 | import { PATH_DASHBOARD } from '../routes/paths';
7 | // components
8 | import LoadingScreen from '../components/LoadingScreen';
9 |
10 | // ----------------------------------------------------------------------
11 |
12 | GuestGuard.propTypes = {
13 | children: PropTypes.node,
14 | };
15 |
16 | export default function GuestGuard({ children }) {
17 | const { isAuthenticated, isInitialized } = useAuth();
18 |
19 | if (isAuthenticated) {
20 | return ;
21 | }
22 |
23 | if (!isInitialized) {
24 | return ;
25 | }
26 |
27 | return <>{children}>;
28 | }
29 |
--------------------------------------------------------------------------------
/frontend/src/guards/RoleBasedGuard.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { m } from 'framer-motion';
3 | // @mui
4 | import { Container, Typography } from '@mui/material';
5 | // hooks
6 | import useAuth from '../hooks/useAuth';
7 | // components
8 | import { MotionContainer, varBounce } from '../components/animate';
9 | // assets
10 | import { ForbiddenIllustration } from '../assets';
11 |
12 | // ----------------------------------------------------------------------
13 |
14 | RoleBasedGuard.propTypes = {
15 | hasContent: PropTypes.bool,
16 | roles: PropTypes.arrayOf(PropTypes.string), // Example ['admin', 'leader']
17 | children: PropTypes.node.isRequired,
18 | };
19 |
20 | export default function RoleBasedGuard({ hasContent, roles, children }) {
21 | // Logic here to get current user role
22 | const { user } = useAuth();
23 |
24 | // const currentRole = 'user';
25 | const currentRole = user?.role; // admin;
26 |
27 | if (typeof roles !== 'undefined' && !roles.includes(currentRole)) {
28 | return hasContent ? (
29 |
30 |
31 |
32 | Permission Denied
33 |
34 |
35 |
36 |
37 | You do not have permission to access this page
38 |
39 |
40 |
41 |
42 |
43 |
44 | ) : null;
45 | }
46 |
47 | return <>{children}>;
48 | }
49 |
--------------------------------------------------------------------------------
/frontend/src/hooks/useAuth.js:
--------------------------------------------------------------------------------
1 | import { useContext } from 'react';
2 | //
3 | import { AuthContext } from '../contexts/JWTContext';
4 | // import { AuthContext } from '../contexts/Auth0Context';
5 | // import { AuthContext } from '../contexts/FirebaseContext';
6 | // import { AuthContext } from '../contexts/AwsCognitoContext';
7 |
8 | // ----------------------------------------------------------------------
9 |
10 | const useAuth = () => {
11 | const context = useContext(AuthContext);
12 |
13 | if (!context) throw new Error('Auth context must be use inside AuthProvider');
14 |
15 | return context;
16 | };
17 |
18 | export default useAuth;
19 |
--------------------------------------------------------------------------------
/frontend/src/hooks/useCollapseDrawer.js:
--------------------------------------------------------------------------------
1 | import { useContext } from 'react';
2 | import { CollapseDrawerContext } from '../contexts/CollapseDrawerContext';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | const useCollapseDrawer = () => useContext(CollapseDrawerContext);
7 |
8 | export default useCollapseDrawer;
9 |
--------------------------------------------------------------------------------
/frontend/src/hooks/useCountdown.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export default function useCountdown(date) {
6 | const [countdown, setCountdown] = useState({
7 | days: '00',
8 | hours: '00',
9 | minutes: '00',
10 | seconds: '00'
11 | });
12 |
13 | useEffect(() => {
14 | const interval = setInterval(() => setNewTime(), 1000);
15 | return () => clearInterval(interval);
16 | // eslint-disable-next-line react-hooks/exhaustive-deps
17 | }, []);
18 |
19 | const setNewTime = () => {
20 | const startTime = date;
21 | const endTime = new Date();
22 | const distanceToNow = startTime - endTime;
23 |
24 | const getDays = Math.floor(distanceToNow / (1000 * 60 * 60 * 24));
25 | const getHours = `0${Math.floor((distanceToNow % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))}`.slice(-2);
26 | const getMinutes = `0${Math.floor((distanceToNow % (1000 * 60 * 60)) / (1000 * 60))}`.slice(-2);
27 | const getSeconds = `0${Math.floor((distanceToNow % (1000 * 60)) / 1000)}`.slice(-2);
28 |
29 | setCountdown({
30 | days: getDays || '000',
31 | hours: getHours || '000',
32 | minutes: getMinutes || '000',
33 | seconds: getSeconds || '000'
34 | });
35 | };
36 |
37 | return countdown;
38 | }
39 |
40 | // Usage
41 | // const countdown = useCountdown(new Date('07/07/2022 21:30'));
42 |
--------------------------------------------------------------------------------
/frontend/src/hooks/useDateRangePicker.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import { isSameDay, isSameMonth } from 'date-fns';
3 | //
4 | import useToggle from './useToggle';
5 |
6 | // ----------------------------------------------------------------------
7 |
8 | export default function useDateRangePicker(date) {
9 | const { toggle: openPicker, onOpen: onOpenPicker, onClose: onClosePicker } = useToggle();
10 |
11 | const [startTime, setStartTime] = useState(date[0]);
12 |
13 | const [endTime, setEndTime] = useState(date[1]);
14 |
15 | const isSameDays = startTime && endTime ? isSameDay(new Date(startTime), new Date(endTime)) : false;
16 |
17 | const isSameMonths = startTime && endTime ? isSameMonth(new Date(startTime), new Date(endTime)) : false;
18 |
19 | const handleChangeStartTime = (newValue) => {
20 | setStartTime(newValue);
21 | };
22 |
23 | const handleChangeEndTime = (newValue) => {
24 | setEndTime(newValue);
25 | };
26 |
27 | return {
28 | startTime,
29 | endTime,
30 | onChangeStartTime: handleChangeStartTime,
31 | onChangeEndTime: handleChangeEndTime,
32 | //
33 | openPicker,
34 | onOpenPicker,
35 | onClosePicker,
36 | //
37 | isSameDays,
38 | isSameMonths,
39 | };
40 | }
41 |
--------------------------------------------------------------------------------
/frontend/src/hooks/useIsMountedRef.js:
--------------------------------------------------------------------------------
1 | import { useRef, useEffect } from 'react';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export default function useIsMountedRef() {
6 | const isMounted = useRef(true);
7 |
8 | useEffect(
9 | () => () => {
10 | isMounted.current = false;
11 | },
12 | []
13 | );
14 |
15 | return isMounted;
16 | }
17 |
--------------------------------------------------------------------------------
/frontend/src/hooks/useLocalStorage.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export default function useLocalStorage(key, defaultValue) {
6 | const [value, setValue] = useState(() => {
7 | const storedValue = localStorage.getItem(key);
8 |
9 | return storedValue === null ? defaultValue : JSON.parse(storedValue);
10 | });
11 |
12 | useEffect(() => {
13 | const listener = (e) => {
14 | if (e.storageArea === localStorage && e.key === key) {
15 | setValue(JSON.parse(e.newValue));
16 | }
17 | };
18 | window.addEventListener('storage', listener);
19 |
20 | return () => {
21 | window.removeEventListener('storage', listener);
22 | };
23 | }, [key, defaultValue]);
24 |
25 | const setValueInLocalStorage = (newValue) => {
26 | setValue((currentValue) => {
27 | const result = typeof newValue === 'function' ? newValue(currentValue) : newValue;
28 |
29 | localStorage.setItem(key, JSON.stringify(result));
30 |
31 | return result;
32 | });
33 | };
34 |
35 | return [value, setValueInLocalStorage];
36 | }
37 |
--------------------------------------------------------------------------------
/frontend/src/hooks/useLocales.js:
--------------------------------------------------------------------------------
1 | import { useTranslation } from 'react-i18next';
2 | import useSettings from './useSettings';
3 | // config
4 | import { allLangs, defaultLang } from '../config';
5 |
6 | // ----------------------------------------------------------------------
7 |
8 | export default function useLocales() {
9 | const { i18n, t: translate } = useTranslation();
10 |
11 | const { onChangeDirectionByLang } = useSettings();
12 |
13 | const langStorage = localStorage.getItem('i18nextLng');
14 |
15 | const currentLang = allLangs.find((_lang) => _lang.value === langStorage) || defaultLang;
16 |
17 | const handleChangeLanguage = (newlang) => {
18 | i18n.changeLanguage(newlang);
19 | onChangeDirectionByLang(newlang);
20 | };
21 |
22 | return {
23 | onChangeLang: handleChangeLanguage,
24 | translate: (text, options) => translate(text, options),
25 | currentLang,
26 | allLangs,
27 | };
28 | }
29 |
--------------------------------------------------------------------------------
/frontend/src/hooks/useOffSetTop.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export default function useOffSetTop(top) {
6 | const [offsetTop, setOffSetTop] = useState(false);
7 | const isTop = top || 100;
8 |
9 | useEffect(() => {
10 | window.onscroll = () => {
11 | if (window.pageYOffset > isTop) {
12 | setOffSetTop(true);
13 | } else {
14 | setOffSetTop(false);
15 | }
16 | };
17 | return () => {
18 | window.onscroll = null;
19 | };
20 | }, [isTop]);
21 |
22 | return offsetTop;
23 | }
24 |
25 | // Usage
26 | // const offset = useOffSetTop(100);
27 |
--------------------------------------------------------------------------------
/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, key, start, end) {
8 | const theme = useTheme()
9 |
10 | const mediaUp = useMediaQuery(theme.breakpoints.up(key))
11 |
12 | const mediaDown = useMediaQuery(theme.breakpoints.down(key))
13 |
14 | const mediaBetween = useMediaQuery(theme.breakpoints.between(start, end))
15 |
16 | const mediaOnly = useMediaQuery(theme.breakpoints.only(key))
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 | if (query === 'only') {
31 | return mediaOnly
32 | }
33 | return null
34 | }
35 |
--------------------------------------------------------------------------------
/frontend/src/hooks/useSettings.js:
--------------------------------------------------------------------------------
1 | import { useContext } from 'react';
2 | import { SettingsContext } from '../contexts/SettingsContext';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | const useSettings = () => useContext(SettingsContext);
7 |
8 | export default useSettings;
9 |
--------------------------------------------------------------------------------
/frontend/src/hooks/useTabs.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export default function useTabs(defaultValues) {
6 | const [currentTab, setCurrentTab] = useState(defaultValues || '');
7 |
8 | return {
9 | currentTab,
10 | onChangeTab: (event, newValue) => {
11 | setCurrentTab(newValue);
12 | },
13 | setCurrentTab,
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/frontend/src/hooks/useToggle.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export default function useToggle(defaultChecked) {
6 | const [toggle, setToggle] = useState(defaultChecked || false);
7 |
8 | return {
9 | toggle,
10 | onToggle: () => setToggle(!toggle),
11 | onOpen: () => setToggle(true),
12 | onClose: () => setToggle(false),
13 | setToggle,
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/frontend/src/layouts/LogoOnlyLayout.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 HeaderStyle = 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 LogoOnlyLayout() {
24 | return (
25 | <>
26 |
27 |
28 |
29 |
30 | >
31 | )
32 | }
33 |
--------------------------------------------------------------------------------
/frontend/src/layouts/dashboard/navbar/NavConfig.js:
--------------------------------------------------------------------------------
1 | // routes
2 | import { PATH_DASHBOARD, PATH_PAGE } from '../../../routes/paths'
3 | // components
4 | import Label from '../../../components/Label'
5 | import Iconify from '../../../components/Iconify'
6 | import SvgIconStyle from '../../../components/SvgIconStyle'
7 |
8 | // ----------------------------------------------------------------------
9 |
10 | const getIcon = (name) =>
11 |
12 | const ICONS = {
13 | blog: getIcon('ic_blog'),
14 | cart: getIcon('ic_cart'),
15 | chat: getIcon('ic_chat'),
16 | mail: getIcon('ic_mail'),
17 | user: getIcon('ic_user'),
18 | kanban: getIcon('ic_kanban'),
19 | banking: getIcon('ic_banking'),
20 | booking: getIcon('ic_booking'),
21 | invoice: getIcon('ic_invoice'),
22 | calendar: getIcon('ic_calendar'),
23 | ecommerce: getIcon('ic_ecommerce'),
24 | analytics: getIcon('ic_analytics'),
25 | dashboard: getIcon('ic_dashboard'),
26 | menuItem: getIcon('ic_menu_item')
27 | }
28 |
29 | const navConfig = [
30 | // GENERAL
31 | // ----------------------------------------------------------------------
32 | {
33 | subheader: '',
34 | items: [
35 | { title: 'home', path: PATH_DASHBOARD.general.app, icon: ICONS.dashboard },
36 | ]
37 | }
38 |
39 | ]
40 |
41 | export default navConfig
42 |
--------------------------------------------------------------------------------
/frontend/src/layouts/dashboard/navbar/NavbarDocs.js:
--------------------------------------------------------------------------------
1 | // @mui
2 | import { Stack, Button, Typography } from '@mui/material';
3 | // hooks
4 | import useAuth from '../../../hooks/useAuth';
5 | import useLocales from '../../../hooks/useLocales';
6 | // routes
7 | import { PATH_DOCS } from '../../../routes/paths';
8 | // assets
9 | import { DocIllustration } from '../../../assets';
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | export default function NavbarDocs() {
14 | const { user } = useAuth();
15 |
16 | const { translate } = useLocales();
17 |
18 | return (
19 |
20 | {/* */}
21 | {/*
22 |
23 |
24 | {translate('docs.hi')}, {user?.displayName}
25 |
26 |
27 | {translate('docs.description')}
28 |
29 |
*/}
30 |
31 | {/* */}
34 |
35 | );
36 | }
37 |
--------------------------------------------------------------------------------
/frontend/src/layouts/dashboard/navbar/NavbarHorizontal.js:
--------------------------------------------------------------------------------
1 | import { memo } from 'react';
2 | // @mui
3 | import { styled } from '@mui/material/styles';
4 | import { Container, AppBar } from '@mui/material';
5 | // config
6 | import { HEADER } from '../../../config';
7 | // components
8 | import { NavSectionHorizontal } from '../../../components/nav-section';
9 | //
10 | import navConfig from './NavConfig';
11 |
12 | // ----------------------------------------------------------------------
13 |
14 | const RootStyle = styled(AppBar)(({ theme }) => ({
15 | transition: theme.transitions.create('top', {
16 | easing: theme.transitions.easing.easeInOut,
17 | duration: theme.transitions.duration.shorter,
18 | }),
19 | width: '100%',
20 | position: 'fixed',
21 | zIndex: theme.zIndex.appBar,
22 | padding: theme.spacing(1, 0),
23 | boxShadow: theme.customShadows.z8,
24 | top: HEADER.DASHBOARD_DESKTOP_OFFSET_HEIGHT,
25 | backgroundColor: theme.palette.background.default,
26 | }));
27 |
28 | // ----------------------------------------------------------------------
29 |
30 | function NavbarHorizontal() {
31 | return (
32 |
33 |
34 |
35 |
36 |
37 | );
38 | }
39 |
40 | export default memo(NavbarHorizontal);
41 |
--------------------------------------------------------------------------------
/frontend/src/layouts/main/index.js:
--------------------------------------------------------------------------------
1 | import { Outlet } from 'react-router-dom'
2 | // @mui
3 | import { Box, Stack } from '@mui/material'
4 | // components
5 | // import Logo from '../../components/Logo';
6 | //
7 | import MainFooter from './MainFooter'
8 | import MainHeader from './MainHeader'
9 |
10 | // ----------------------------------------------------------------------
11 |
12 | export default function MainLayout() {
13 | // const { pathname } = useLocation();
14 |
15 | // const isHome = pathname === '/';
16 |
17 | return (
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | )
29 | }
30 |
--------------------------------------------------------------------------------
/frontend/src/locales/i18n.js:
--------------------------------------------------------------------------------
1 | import i18n from 'i18next';
2 | import LanguageDetector from 'i18next-browser-languagedetector';
3 | import { initReactI18next } from 'react-i18next';
4 | // config
5 | import { defaultLang } from '../config';
6 | //
7 | import enLocales from './en';
8 | import frLocales from './fr';
9 | import vnLocales from './vn';
10 | import cnLocales from './cn';
11 | import arLocales from './ar';
12 |
13 | // ----------------------------------------------------------------------
14 |
15 | i18n
16 | .use(LanguageDetector)
17 | .use(initReactI18next)
18 | .init({
19 | resources: {
20 | en: { translations: enLocales },
21 | fr: { translations: frLocales },
22 | vn: { translations: vnLocales },
23 | cn: { translations: cnLocales },
24 | ar: { translations: arLocales },
25 | },
26 | lng: localStorage.getItem('i18nextLng') || defaultLang.value,
27 | fallbackLng: defaultLang.value,
28 | debug: false,
29 | ns: ['translations'],
30 | defaultNS: 'translations',
31 | interpolation: {
32 | escapeValue: false,
33 | },
34 | });
35 |
36 | export default i18n;
37 |
--------------------------------------------------------------------------------
/frontend/src/pages/dashboard/GeneralApp.js:
--------------------------------------------------------------------------------
1 | import { Container } from '@mui/material'
2 |
3 | import useSettings from '../../hooks/useSettings'
4 | // routes
5 | import { PATH_DASHBOARD } from '../../routes/paths'
6 |
7 | // components
8 | import Page from '../../components/Page'
9 | import HeaderBreadcrumbs from '../../components/HeaderBreadcrumbs'
10 |
11 | export default function GeneralApp() {
12 | const { themeStretch } = useSettings()
13 |
14 | return (
15 |
16 |
17 |
18 |
19 |
20 | )
21 | }
22 |
--------------------------------------------------------------------------------
/frontend/src/pages/dashboard/UserProfile.js:
--------------------------------------------------------------------------------
1 | import { Container } from '@mui/material'
2 | import useSettings from '../../hooks/useSettings'
3 | // routes
4 | import { PATH_DASHBOARD } from '../../routes/paths'
5 | // hooks
6 | import useAuth from '../../hooks/useAuth'
7 | // components
8 | import Page from '../../components/Page'
9 | import HeaderBreadcrumbs from '../../components/HeaderBreadcrumbs'
10 | // sections
11 |
12 | // ----------------------------------------------------------------------
13 |
14 | export default function UserProfile() {
15 | const { themeStretch } = useSettings()
16 | const { user } = useAuth()
17 |
18 | return (
19 |
20 |
21 |
29 |
30 |
31 | )
32 | }
33 |
--------------------------------------------------------------------------------
/frontend/src/redux/rootReducer.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux'
2 | import storage from 'redux-persist/lib/storage'
3 | // slices
4 |
5 | import userReducer from './slices/user'
6 |
7 | // ----------------------------------------------------------------------
8 |
9 | const rootPersistConfig = {
10 | key: 'root',
11 | storage,
12 | keyPrefix: 'redux-',
13 | whitelist: []
14 | }
15 |
16 | const rootReducer = combineReducers({
17 | user: userReducer
18 | })
19 |
20 | export { rootPersistConfig, rootReducer }
21 |
--------------------------------------------------------------------------------
/frontend/src/redux/store.js:
--------------------------------------------------------------------------------
1 | import { configureStore } from '@reduxjs/toolkit';
2 | import { useDispatch as useAppDispatch, useSelector as useAppSelector } from 'react-redux';
3 | import { persistStore, persistReducer } from 'redux-persist';
4 | import { rootPersistConfig, rootReducer } from './rootReducer';
5 |
6 | // ----------------------------------------------------------------------
7 |
8 | const store = configureStore({
9 | reducer: persistReducer(rootPersistConfig, rootReducer),
10 | middleware: (getDefaultMiddleware) =>
11 | getDefaultMiddleware({
12 | serializableCheck: false,
13 | immutableCheck: false,
14 | }),
15 | });
16 |
17 | const persistor = persistStore(store);
18 |
19 | const { dispatch } = store;
20 |
21 | const useSelector = useAppSelector;
22 |
23 | const useDispatch = () => useAppDispatch();
24 |
25 | export { store, persistor, dispatch, useSelector, useDispatch };
26 |
--------------------------------------------------------------------------------
/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/routes/paths.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | function path(root, sublink) {
4 | return `${root}${sublink}`
5 | }
6 |
7 | const ROOTS_AUTH = '/auth'
8 | const ROOTS_DASHBOARD = '/dashboard'
9 |
10 | // ----------------------------------------------------------------------
11 |
12 | export const PATH_AUTH = {
13 | root: ROOTS_AUTH,
14 | login: path(ROOTS_AUTH, '/login'),
15 | register: path(ROOTS_AUTH, '/register'),
16 | loginUnprotected: path(ROOTS_AUTH, '/login-unprotected'),
17 | registerUnprotected: path(ROOTS_AUTH, '/register-unprotected'),
18 | verify: path(ROOTS_AUTH, '/verify'),
19 | resetPassword: path(ROOTS_AUTH, '/reset-password'),
20 | newPassword: path(ROOTS_AUTH, '/new-password')
21 | }
22 |
23 | export const PATH_PAGE = {
24 | page403: '/403',
25 | page404: '/404',
26 | page500: '/500'
27 | }
28 |
29 | export const PATH_DASHBOARD = {
30 | root: ROOTS_DASHBOARD,
31 | general: {
32 | app: path(ROOTS_DASHBOARD, '/app')
33 | },
34 |
35 | permissionDenied: path(ROOTS_DASHBOARD, '/permission-denied'),
36 | user: {
37 | root: path(ROOTS_DASHBOARD, '/user'),
38 |
39 | profile: path(ROOTS_DASHBOARD, '/user/profile'),
40 | account: path(ROOTS_DASHBOARD, '/user/account')
41 | }
42 | }
43 |
44 | export const PATH_DOCS = ''
45 | export const API_DOCS = ''
46 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/user/account/AccountBillingInvoiceHistory.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import { Link as RouterLink } from 'react-router-dom';
3 | // @mui
4 | import { Stack, Link, Button, Typography } from '@mui/material';
5 | // utils
6 | import { fDate } from '../../../../utils/formatTime';
7 | import { fCurrency } from '../../../../utils/formatNumber';
8 | // components
9 | import Iconify from '../../../../components/Iconify';
10 |
11 | // ----------------------------------------------------------------------
12 |
13 | AccountBillingInvoiceHistory.propTypes = {
14 | invoices: PropTypes.array,
15 | };
16 |
17 | export default function AccountBillingInvoiceHistory({ invoices }) {
18 | return (
19 |
20 |
21 | Invoice History
22 |
23 |
24 |
25 | {invoices.map((invoice) => (
26 |
27 |
28 | {fDate(invoice.createdAt)}
29 |
30 | {fCurrency(invoice.price)}
31 |
32 | PDF
33 |
34 |
35 | ))}
36 |
37 |
38 | }>
39 | All invoices
40 |
41 |
42 | );
43 | }
44 |
--------------------------------------------------------------------------------
/frontend/src/sections/@dashboard/user/account/index.js:
--------------------------------------------------------------------------------
1 | export { default as AccountBilling } from './AccountBilling';
2 | export { default as AccountBillingAddressBook } from './AccountBillingAddressBook';
3 | export { default as AccountBillingInvoiceHistory } from './AccountBillingInvoiceHistory';
4 | export { default as AccountBillingPaymentMethod } from './AccountBillingPaymentMethod';
5 | export { default as AccountChangePassword } from './AccountChangePassword';
6 | export { default as AccountGeneral } from './AccountGeneral';
7 | export { default as AccountNotifications } from './AccountNotifications';
8 | export { default as AccountSocialLinks } from './AccountSocialLinks';
9 |
--------------------------------------------------------------------------------
/frontend/src/sections/auth/login/index.js:
--------------------------------------------------------------------------------
1 | export { default as LoginForm } from './LoginForm';
2 |
--------------------------------------------------------------------------------
/frontend/src/sections/auth/new-password/index.js:
--------------------------------------------------------------------------------
1 | export { default as NewPasswordForm } from './NewPasswordForm';
2 |
--------------------------------------------------------------------------------
/frontend/src/sections/auth/register/index.js:
--------------------------------------------------------------------------------
1 | export { default as RegisterForm } from './RegisterForm';
2 |
--------------------------------------------------------------------------------
/frontend/src/sections/auth/reset-password/index.js:
--------------------------------------------------------------------------------
1 | export { default as ResetPasswordForm } from './ResetPasswordForm';
2 |
--------------------------------------------------------------------------------
/frontend/src/sections/auth/verify-code/index.js:
--------------------------------------------------------------------------------
1 | export { default as VerifyCodeForm } from './VerifyCodeForm';
2 |
--------------------------------------------------------------------------------
/frontend/src/theme/breakpoints.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | const breakpoints = {
4 | values: {
5 | xs: 0,
6 | sm: 600,
7 | md: 900,
8 | lg: 1200,
9 | xl: 1536
10 | }
11 | };
12 |
13 | export default breakpoints;
14 |
--------------------------------------------------------------------------------
/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 { createTheme, ThemeProvider as MUIThemeProvider, StyledEngineProvider } from '@mui/material/styles';
6 | // hooks
7 | import useSettings from '../hooks/useSettings';
8 | //
9 | import palette from './palette';
10 | import typography from './typography';
11 | import breakpoints from './breakpoints';
12 | import componentsOverride from './overrides';
13 | import shadows, { customShadows } from './shadows';
14 |
15 | // ----------------------------------------------------------------------
16 |
17 | ThemeProvider.propTypes = {
18 | children: PropTypes.node,
19 | };
20 |
21 | export default function ThemeProvider({ children }) {
22 | const { themeMode, themeDirection } = useSettings();
23 |
24 | const isLight = themeMode === 'light';
25 |
26 | const themeOptions = useMemo(
27 | () => ({
28 | palette: isLight ? palette.light : palette.dark,
29 | typography,
30 | breakpoints,
31 | shape: { borderRadius: 8 },
32 | direction: themeDirection,
33 | shadows: isLight ? shadows.light : shadows.dark,
34 | customShadows: isLight ? customShadows.light : customShadows.dark,
35 | }),
36 | [isLight, themeDirection]
37 | );
38 |
39 | const theme = createTheme(themeOptions);
40 |
41 | theme.components = componentsOverride(theme);
42 |
43 | return (
44 |
45 |
46 |
47 | {children}
48 |
49 |
50 | );
51 | }
52 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Accordion.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Accordion(theme) {
4 | return {
5 | MuiAccordion: {
6 | styleOverrides: {
7 | root: {
8 | '&.Mui-expanded': {
9 | boxShadow: theme.customShadows.z8,
10 | borderRadius: theme.shape.borderRadius,
11 | },
12 | '&.Mui-disabled': {
13 | backgroundColor: 'transparent',
14 | },
15 | },
16 | },
17 | },
18 | MuiAccordionSummary: {
19 | styleOverrides: {
20 | root: {
21 | paddingLeft: theme.spacing(2),
22 | paddingRight: theme.spacing(1),
23 | '&.Mui-disabled': {
24 | opacity: 1,
25 | color: theme.palette.action.disabled,
26 | '& .MuiTypography-root': {
27 | color: 'inherit',
28 | },
29 | },
30 | },
31 | expandIconWrapper: {
32 | color: 'inherit',
33 | },
34 | },
35 | },
36 | };
37 | }
38 |
--------------------------------------------------------------------------------
/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.dropdown,
9 | },
10 | listbox: {
11 | padding: theme.spacing(0, 1),
12 | '& .MuiAutocomplete-option': {
13 | padding: theme.spacing(1),
14 | margin: theme.spacing(1, 0),
15 | borderRadius: theme.shape.borderRadius,
16 | },
17 | },
18 | },
19 | },
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Avatar.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Avatar(theme) {
4 | return {
5 | MuiAvatar: {
6 | styleOverrides: {
7 | colorDefault: {
8 | color: theme.palette.text.secondary,
9 | backgroundColor: theme.palette.grey[400],
10 | },
11 | },
12 | },
13 | MuiAvatarGroup: {
14 | styleOverrides: {
15 | avatar: {
16 | fontSize: 16,
17 | fontWeight: theme.typography.fontWeightMedium,
18 | '&:first-of-type': {
19 | fontSize: 14,
20 | color: theme.palette.primary.main,
21 | backgroundColor: theme.palette.primary.lighter,
22 | },
23 | },
24 | },
25 | },
26 | };
27 | }
28 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Backdrop.js:
--------------------------------------------------------------------------------
1 | import { alpha } from '@mui/material/styles';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export default function Backdrop(theme) {
6 | const varLow = alpha(theme.palette.grey[900], 0.48);
7 | const varHigh = alpha(theme.palette.grey[900], 1);
8 |
9 | return {
10 | MuiBackdrop: {
11 | styleOverrides: {
12 | root: {
13 | background: [
14 | `rgb(22,28,36)`,
15 | `-moz-linear-gradient(75deg, ${varLow} 0%, ${varHigh} 100%)`,
16 | `-webkit-linear-gradient(75deg, ${varLow} 0%, ${varHigh} 100%)`,
17 | `linear-gradient(75deg, ${varLow} 0%, ${varHigh} 100%)`,
18 | ],
19 | '&.MuiBackdrop-invisible': {
20 | background: 'transparent',
21 | },
22 | },
23 | },
24 | },
25 | };
26 | }
27 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Badge.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Badge() {
4 | return {
5 | MuiBadge: {
6 | styleOverrides: {
7 | dot: {
8 | width: 10,
9 | height: 10,
10 | borderRadius: '50%',
11 | },
12 | },
13 | },
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Breadcrumbs.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Breadcrumbs(theme) {
4 | return {
5 | MuiBreadcrumbs: {
6 | styleOverrides: {
7 | separator: {
8 | marginLeft: theme.spacing(2),
9 | marginRight: theme.spacing(2),
10 | },
11 | },
12 | },
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Button.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Button(theme) {
4 | return {
5 | MuiButton: {
6 | styleOverrides: {
7 | root: {
8 | '&:hover': {
9 | boxShadow: 'none',
10 | },
11 | },
12 | sizeLarge: {
13 | height: 48,
14 | },
15 | // contained
16 | containedInherit: {
17 | color: theme.palette.grey[800],
18 | boxShadow: theme.customShadows.z8,
19 | '&:hover': {
20 | backgroundColor: theme.palette.grey[400],
21 | },
22 | },
23 | containedPrimary: {
24 | boxShadow: theme.customShadows.primary,
25 | },
26 | containedSecondary: {
27 | boxShadow: theme.customShadows.secondary,
28 | },
29 | containedInfo: {
30 | boxShadow: theme.customShadows.info,
31 | },
32 | containedSuccess: {
33 | boxShadow: theme.customShadows.success,
34 | },
35 | containedWarning: {
36 | boxShadow: theme.customShadows.warning,
37 | },
38 | containedError: {
39 | boxShadow: theme.customShadows.error,
40 | },
41 | // outlined
42 | outlinedInherit: {
43 | border: `1px solid ${theme.palette.grey[500_32]}`,
44 | '&:hover': {
45 | backgroundColor: theme.palette.action.hover,
46 | },
47 | },
48 | textInherit: {
49 | '&:hover': {
50 | backgroundColor: theme.palette.action.hover,
51 | },
52 | },
53 | },
54 | },
55 | };
56 | }
57 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/ButtonGroup.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function ButtonGroup(theme) {
4 | const styleContained = (color) => ({
5 | props: { variant: 'contained', color },
6 | style: { boxShadow: theme.customShadows[color] },
7 | });
8 |
9 | return {
10 | MuiButtonGroup: {
11 | variants: [
12 | {
13 | props: { variant: 'contained', color: 'inherit' },
14 | style: { boxShadow: theme.customShadows.z8 },
15 | },
16 | styleContained('primary'),
17 | styleContained('secondary'),
18 | styleContained('info'),
19 | styleContained('success'),
20 | styleContained('warning'),
21 | styleContained('error'),
22 |
23 | {
24 | props: { disabled: true },
25 | style: {
26 | boxShadow: 'none',
27 | '& .MuiButtonGroup-grouped.Mui-disabled': {
28 | color: theme.palette.action.disabled,
29 | borderColor: `${theme.palette.action.disabledBackground} !important`,
30 | '&.MuiButton-contained': {
31 | backgroundColor: theme.palette.action.disabledBackground,
32 | },
33 | },
34 | },
35 | },
36 | ],
37 |
38 | styleOverrides: {
39 | root: {
40 | '&:hover': {
41 | boxShadow: 'none',
42 | },
43 | },
44 | },
45 | },
46 | };
47 | }
48 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Card.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Card(theme) {
4 | return {
5 | MuiCard: {
6 | styleOverrides: {
7 | root: {
8 | position: 'relative',
9 | boxShadow: theme.customShadows.card,
10 | borderRadius: Number(theme.shape.borderRadius) * 2,
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', marginTop: theme.spacing(0.5) },
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/theme/overrides/Checkbox.js:
--------------------------------------------------------------------------------
1 | import { CheckboxIcon, CheckboxCheckedIcon, CheckboxIndeterminateIcon } from './CustomIcons';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export default function Checkbox(theme) {
6 | return {
7 | MuiCheckbox: {
8 | defaultProps: {
9 | icon: ,
10 | checkedIcon: ,
11 | indeterminateIcon: ,
12 | },
13 |
14 | styleOverrides: {
15 | root: {
16 | padding: theme.spacing(1),
17 | '&.Mui-checked.Mui-disabled, &.Mui-disabled': {
18 | color: theme.palette.action.disabled,
19 | },
20 | '& .MuiSvgIcon-fontSizeMedium': {
21 | width: 24,
22 | height: 24,
23 | },
24 | '& .MuiSvgIcon-fontSizeSmall': {
25 | width: 20,
26 | height: 20,
27 | },
28 | svg: {
29 | fontSize: 24,
30 | '&[font-size=small]': {
31 | fontSize: 20,
32 | },
33 | },
34 | },
35 | },
36 | },
37 | };
38 | }
39 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Chip.js:
--------------------------------------------------------------------------------
1 | import { CloseIcon } from './CustomIcons';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export default function Chip(theme) {
6 | return {
7 | MuiChip: {
8 | defaultProps: {
9 | deleteIcon: ,
10 | },
11 |
12 | styleOverrides: {
13 | colorDefault: {
14 | '& .MuiChip-avatarMedium, .MuiChip-avatarSmall': {
15 | color: theme.palette.text.secondary,
16 | },
17 | },
18 | outlined: {
19 | borderColor: theme.palette.grey[500_32],
20 | '&.MuiChip-colorPrimary': {
21 | borderColor: theme.palette.primary.main,
22 | },
23 | '&.MuiChip-colorSecondary': {
24 | borderColor: theme.palette.secondary.main,
25 | },
26 | },
27 | //
28 | avatarColorInfo: {
29 | color: theme.palette.info.contrastText,
30 | backgroundColor: theme.palette.info.dark,
31 | },
32 | avatarColorSuccess: {
33 | color: theme.palette.success.contrastText,
34 | backgroundColor: theme.palette.success.dark,
35 | },
36 | avatarColorWarning: {
37 | color: theme.palette.warning.contrastText,
38 | backgroundColor: theme.palette.warning.dark,
39 | },
40 | avatarColorError: {
41 | color: theme.palette.error.contrastText,
42 | backgroundColor: theme.palette.error.dark,
43 | },
44 | },
45 | },
46 | };
47 | }
48 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/ControlLabel.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function ControlLabel(theme) {
4 | return {
5 | MuiFormControlLabel: {
6 | styleOverrides: {
7 | label: {
8 | ...theme.typography.body2,
9 | },
10 | },
11 | },
12 | MuiFormHelperText: {
13 | styleOverrides: {
14 | root: {
15 | marginTop: theme.spacing(1),
16 | },
17 | },
18 | },
19 | MuiFormLabel: {
20 | styleOverrides: {
21 | root: {
22 | color: theme.palette.text.disabled,
23 | },
24 | },
25 | },
26 | };
27 | }
28 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/CssBaseline.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function CssBaseline() {
4 | return {
5 | MuiCssBaseline: {
6 | styleOverrides: {
7 | '*': {
8 | margin: 0,
9 | padding: 0,
10 | boxSizing: 'border-box',
11 | },
12 | html: {
13 | width: '100%',
14 | height: '100%',
15 | WebkitOverflowScrolling: 'touch',
16 | },
17 | body: {
18 | width: '100%',
19 | height: '100%',
20 | },
21 | '#root': {
22 | width: '100%',
23 | height: '100%',
24 | },
25 | input: {
26 | '&[type=number]': {
27 | MozAppearance: 'textfield',
28 | '&::-webkit-outer-spin-button': {
29 | margin: 0,
30 | WebkitAppearance: 'none',
31 | },
32 | '&::-webkit-inner-spin-button': {
33 | margin: 0,
34 | WebkitAppearance: 'none',
35 | },
36 | },
37 | },
38 | img: {
39 | display: 'block',
40 | maxWidth: '100%',
41 | },
42 | },
43 | },
44 | };
45 | }
46 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Dialog.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Dialog(theme) {
4 | return {
5 | MuiDialog: {
6 | styleOverrides: {
7 | paper: {
8 | boxShadow: theme.customShadows.dialog,
9 | '&.MuiPaper-rounded': {
10 | borderRadius: Number(theme.shape.borderRadius) * 2,
11 | },
12 | '&.MuiDialog-paperFullScreen': {
13 | borderRadius: 0,
14 | },
15 | '&.MuiDialog-paper .MuiDialogActions-root': {
16 | padding: theme.spacing(3),
17 | },
18 | '@media (max-width: 600px)': {
19 | margin: theme.spacing(2),
20 | },
21 | '@media (max-width: 663.95px)': {
22 | '&.MuiDialog-paperWidthSm.MuiDialog-paperScrollBody': {
23 | maxWidth: '100%',
24 | },
25 | },
26 | },
27 | paperFullWidth: {
28 | width: '100%',
29 | },
30 | },
31 | },
32 | MuiDialogTitle: {
33 | styleOverrides: {
34 | root: {
35 | padding: theme.spacing(3, 3, 0),
36 | },
37 | },
38 | },
39 | MuiDialogContent: {
40 | styleOverrides: {
41 | root: {
42 | borderTop: 0,
43 | borderBottom: 0,
44 | padding: theme.spacing(3),
45 | },
46 | },
47 | },
48 | MuiDialogActions: {
49 | styleOverrides: {
50 | root: {
51 | '& > :not(:first-of-type)': {
52 | marginLeft: theme.spacing(1.5),
53 | },
54 | },
55 | },
56 | },
57 | };
58 | }
59 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Drawer.js:
--------------------------------------------------------------------------------
1 | import { alpha } from '@mui/material';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export default function Drawer(theme) {
6 | const isLight = theme.palette.mode === 'light';
7 |
8 | return {
9 | MuiDrawer: {
10 | styleOverrides: {
11 | modal: {
12 | '&[role="presentation"]': {
13 | '& .MuiDrawer-paperAnchorLeft': {
14 | boxShadow: `8px 24px 24px 12px ${alpha(theme.palette.grey[900], isLight ? 0.16 : 0.48)}`,
15 | },
16 | '& .MuiDrawer-paperAnchorRight': {
17 | boxShadow: `-8px 24px 24px 12px ${alpha(theme.palette.grey[900], isLight ? 0.16 : 0.48)}`,
18 | },
19 | },
20 | },
21 | },
22 | },
23 | };
24 | }
25 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Fab.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Fab(theme) {
4 | return {
5 | MuiFab: {
6 | defaultProps: {
7 | color: 'primary',
8 | },
9 |
10 | styleOverrides: {
11 | root: {
12 | boxShadow: theme.customShadows.z8,
13 | '&:hover': {
14 | boxShadow: 'none',
15 | backgroundColor: theme.palette.grey[400],
16 | },
17 | },
18 | primary: {
19 | boxShadow: theme.customShadows.primary,
20 | '&:hover': {
21 | backgroundColor: theme.palette.primary.dark,
22 | },
23 | },
24 | secondary: {
25 | boxShadow: theme.customShadows.secondary,
26 | '&:hover': {
27 | backgroundColor: theme.palette.secondary.dark,
28 | },
29 | },
30 | extended: {
31 | '& svg': {
32 | marginRight: theme.spacing(1),
33 | },
34 | },
35 | },
36 | },
37 | };
38 | }
39 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Link.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Link() {
4 | return {
5 | MuiLink: {
6 | defaultProps: {
7 | underline: 'hover',
8 | },
9 | },
10 | };
11 | }
12 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/List.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function List(theme) {
4 | return {
5 | MuiListItemIcon: {
6 | styleOverrides: {
7 | root: {
8 | color: 'inherit',
9 | minWidth: 'auto',
10 | marginRight: theme.spacing(2),
11 | },
12 | },
13 | },
14 | MuiListItemAvatar: {
15 | styleOverrides: {
16 | root: {
17 | minWidth: 'auto',
18 | marginRight: theme.spacing(2),
19 | },
20 | },
21 | },
22 | MuiListItemText: {
23 | styleOverrides: {
24 | root: {
25 | marginTop: 0,
26 | marginBottom: 0,
27 | },
28 | multiline: {
29 | marginTop: 0,
30 | marginBottom: 0,
31 | },
32 | },
33 | },
34 | };
35 | }
36 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/LoadingButton.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function LoadingButton() {
4 | return {
5 | MuiLoadingButton: {
6 | styleOverrides: {
7 | root: {
8 | '&.MuiButton-text': {
9 | '& .MuiLoadingButton-startIconPendingStart': {
10 | marginLeft: 0,
11 | },
12 | '& .MuiLoadingButton-endIconPendingEnd': {
13 | marginRight: 0,
14 | },
15 | },
16 | },
17 | },
18 | },
19 | };
20 | }
21 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Menu.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Menu(theme) {
4 | return {
5 | MuiMenuItem: {
6 | styleOverrides: {
7 | root: {
8 | '&.Mui-selected': {
9 | backgroundColor: theme.palette.action.selected,
10 | '&:hover': {
11 | backgroundColor: theme.palette.action.hover,
12 | },
13 | },
14 | },
15 | },
16 | },
17 | };
18 | }
19 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Pagination.js:
--------------------------------------------------------------------------------
1 | import { alpha } from '@mui/material/styles';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export default function Pagination(theme) {
6 | return {
7 | MuiPaginationItem: {
8 | styleOverrides: {
9 | root: {
10 | '&.Mui-selected': {
11 | fontWeight: theme.typography.fontWeightBold,
12 | },
13 | },
14 | textPrimary: {
15 | '&.Mui-selected': {
16 | color: theme.palette.primary.main,
17 | backgroundColor: alpha(theme.palette.primary.main, 0.08),
18 | '&:hover, &.Mui-focusVisible': {
19 | backgroundColor: `${alpha(theme.palette.primary.main, 0.24)} !important`,
20 | },
21 | },
22 | },
23 | outlined: {
24 | border: `1px solid ${theme.palette.grey[500_32]}`,
25 | },
26 | outlinedPrimary: {
27 | '&.Mui-selected': {
28 | backgroundColor: alpha(theme.palette.primary.main, 0.08),
29 | border: `1px solid ${alpha(theme.palette.primary.main, 0.24)}`,
30 | },
31 | },
32 | },
33 | },
34 | };
35 | }
36 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Paper.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Paper(theme) {
4 | return {
5 | MuiPaper: {
6 | defaultProps: {
7 | elevation: 0,
8 | },
9 |
10 | variants: [
11 | {
12 | props: { variant: 'outlined' },
13 | style: { borderColor: theme.palette.grey[500_12] },
14 | },
15 | ],
16 |
17 | styleOverrides: {
18 | root: {
19 | backgroundImage: 'none',
20 | },
21 | },
22 | },
23 | };
24 | }
25 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Popover.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Popover(theme) {
4 | return {
5 | MuiPopover: {
6 | styleOverrides: {
7 | paper: {
8 | boxShadow: theme.customShadows.dropdown,
9 | borderRadius: Number(theme.shape.borderRadius) * 1.5,
10 | },
11 | },
12 | },
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Progress.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Progress(theme) {
4 | const isLight = theme.palette.mode === 'light';
5 |
6 | return {
7 | MuiLinearProgress: {
8 | styleOverrides: {
9 | root: {
10 | borderRadius: 4,
11 | overflow: 'hidden',
12 | },
13 | bar: {
14 | borderRadius: 4,
15 | },
16 | colorPrimary: {
17 | backgroundColor: theme.palette.primary[isLight ? 'lighter' : 'darker'],
18 | },
19 | buffer: {
20 | backgroundColor: 'transparent',
21 | },
22 | },
23 | },
24 | };
25 | }
26 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Radio.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Radio(theme) {
4 | return {
5 | MuiRadio: {
6 | styleOverrides: {
7 | root: {
8 | padding: theme.spacing(1),
9 | svg: {
10 | fontSize: 24,
11 | '&[font-size=small]': {
12 | fontSize: 20,
13 | },
14 | },
15 | },
16 | },
17 | },
18 | };
19 | }
20 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Rating.js:
--------------------------------------------------------------------------------
1 | import { StarIcon } from './CustomIcons';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | const ICON_SMALL = { width: 20, height: 20 };
6 | const ICON_LARGE = { width: 28, height: 28 };
7 |
8 | export default function Rating(theme) {
9 | return {
10 | MuiRating: {
11 | defaultProps: {
12 | emptyIcon: ,
13 | icon: ,
14 | },
15 |
16 | styleOverrides: {
17 | root: {
18 | '&.Mui-disabled': {
19 | opacity: 0.48,
20 | },
21 | },
22 | iconEmpty: { color: theme.palette.grey[500_48] },
23 | sizeSmall: { '& svg': { ...ICON_SMALL } },
24 | sizeLarge: { '& svg': { ...ICON_LARGE } },
25 | },
26 | },
27 | };
28 | }
29 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Select.js:
--------------------------------------------------------------------------------
1 | import { InputSelectIcon } from './CustomIcons';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export default function Select() {
6 | return {
7 | MuiSelect: {
8 | defaultProps: {
9 | IconComponent: InputSelectIcon,
10 | },
11 | },
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Skeleton.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Skeleton(theme) {
4 | return {
5 | MuiSkeleton: {
6 | defaultProps: {
7 | animation: 'wave',
8 | },
9 |
10 | styleOverrides: {
11 | root: {
12 | backgroundColor: theme.palette.background.neutral,
13 | },
14 | },
15 | },
16 | };
17 | }
18 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Slider.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Slider(theme) {
4 | const isLight = theme.palette.mode === 'light';
5 |
6 | return {
7 | MuiSlider: {
8 | defaultProps: {
9 | size: 'small',
10 | },
11 |
12 | styleOverrides: {
13 | root: {
14 | '&.Mui-disabled': {
15 | color: theme.palette.action.disabled,
16 | },
17 | },
18 | markLabel: {
19 | fontSize: 13,
20 | color: theme.palette.text.disabled,
21 | },
22 | valueLabel: {
23 | borderRadius: 8,
24 | backgroundColor: theme.palette.grey[isLight ? 800 : 700],
25 | },
26 | },
27 | },
28 | };
29 | }
30 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Stepper.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Stepper(theme) {
4 | return {
5 | MuiStepConnector: {
6 | styleOverrides: {
7 | line: {
8 | borderColor: theme.palette.divider,
9 | },
10 | },
11 | },
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/SvgIcon.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function SvgIcon() {
4 | return {
5 | MuiSvgIcon: {
6 | styleOverrides: {
7 | fontSizeSmall: {
8 | width: 20,
9 | height: 20,
10 | fontSize: 'inherit',
11 | },
12 | fontSizeLarge: {
13 | width: 32,
14 | height: 32,
15 | fontSize: 'inherit',
16 | },
17 | },
18 | },
19 | };
20 | }
21 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Switch.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Switch(theme) {
4 | const isLight = theme.palette.mode === 'light';
5 |
6 | return {
7 | MuiSwitch: {
8 | styleOverrides: {
9 | thumb: {
10 | boxShadow: theme.customShadows.z1,
11 | },
12 | track: {
13 | opacity: 1,
14 | backgroundColor: theme.palette.grey[500],
15 | },
16 | switchBase: {
17 | left: 0,
18 | right: 'auto',
19 | '&:not(:.Mui-checked)': {
20 | color: theme.palette.grey[isLight ? 100 : 300],
21 | },
22 | '&.Mui-checked.Mui-disabled, &.Mui-disabled': {
23 | color: theme.palette.grey[isLight ? 400 : 600],
24 | },
25 | '&.Mui-disabled+.MuiSwitch-track': {
26 | opacity: 1,
27 | backgroundColor: `${theme.palette.action.disabledBackground} !important`,
28 | },
29 | },
30 | },
31 | },
32 | };
33 | }
34 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Tabs.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Tabs(theme) {
4 | return {
5 | MuiTabs: {
6 | styleOverrides: {
7 | scrollButtons: {
8 | width: 48,
9 | borderRadius: '50%',
10 | },
11 | },
12 | },
13 | MuiTab: {
14 | styleOverrides: {
15 | root: {
16 | padding: 0,
17 | fontWeight: theme.typography.fontWeightMedium,
18 | borderTopLeftRadius: theme.shape.borderRadius,
19 | borderTopRightRadius: theme.shape.borderRadius,
20 | '&.Mui-selected': {
21 | color: theme.palette.text.primary,
22 | },
23 | '&:not(:last-of-type)': {
24 | marginRight: theme.spacing(5),
25 | },
26 | '@media (min-width: 600px)': {
27 | minWidth: 48,
28 | },
29 | },
30 | labelIcon: {
31 | minHeight: 48,
32 | flexDirection: 'row',
33 | '& > *:first-of-type': {
34 | marginBottom: 0,
35 | marginRight: theme.spacing(1),
36 | },
37 | },
38 | wrapped: {
39 | flexDirection: 'row',
40 | whiteSpace: 'nowrap',
41 | },
42 | textColorInherit: {
43 | opacity: 1,
44 | color: theme.palette.text.secondary,
45 | },
46 | },
47 | },
48 | MuiTabPanel: {
49 | styleOverrides: {
50 | root: {
51 | padding: 0,
52 | },
53 | },
54 | },
55 | };
56 | }
57 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Timeline.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Timeline(theme) {
4 | return {
5 | MuiTimelineDot: {
6 | styleOverrides: {
7 | root: {
8 | boxShadow: 'none',
9 | },
10 | },
11 | },
12 |
13 | MuiTimelineConnector: {
14 | styleOverrides: {
15 | root: {
16 | backgroundColor: theme.palette.divider,
17 | },
18 | },
19 | },
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/ToggleButton.js:
--------------------------------------------------------------------------------
1 | import { alpha } from '@mui/material/styles';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export default function ToggleButton(theme) {
6 | const style = (color) => ({
7 | props: { color },
8 | style: {
9 | '&:hover': {
10 | borderColor: alpha(theme.palette[color].main, 0.48),
11 | backgroundColor: alpha(theme.palette[color].main, theme.palette.action.hoverOpacity),
12 | },
13 | '&.Mui-selected': {
14 | borderColor: alpha(theme.palette[color].main, 0.48),
15 | },
16 | },
17 | });
18 |
19 | return {
20 | MuiToggleButton: {
21 | variants: [
22 | {
23 | props: { color: 'standard' },
24 | style: {
25 | '&.Mui-selected': {
26 | backgroundColor: theme.palette.action.selected,
27 | },
28 | },
29 | },
30 | style('primary'),
31 | style('secondary'),
32 | style('info'),
33 | style('success'),
34 | style('warning'),
35 | style('error'),
36 | ],
37 | },
38 | MuiToggleButtonGroup: {
39 | styleOverrides: {
40 | root: {
41 | borderRadius: theme.shape.borderRadius,
42 | backgroundColor: theme.palette.background.paper,
43 | border: `solid 1px ${theme.palette.grey[500_12]}`,
44 | '& .MuiToggleButton-root': {
45 | margin: 4,
46 | borderColor: 'transparent !important',
47 | borderRadius: `${theme.shape.borderRadius}px !important`,
48 | },
49 | },
50 | },
51 | },
52 | };
53 | }
54 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/Tooltip.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function Tooltip(theme) {
4 | const isLight = theme.palette.mode === 'light';
5 |
6 | return {
7 | MuiTooltip: {
8 | styleOverrides: {
9 | tooltip: {
10 | backgroundColor: theme.palette.grey[isLight ? 800 : 700],
11 | },
12 | arrow: {
13 | color: theme.palette.grey[isLight ? 800 : 700],
14 | },
15 | },
16 | },
17 | };
18 | }
19 |
--------------------------------------------------------------------------------
/frontend/src/theme/overrides/TreeView.js:
--------------------------------------------------------------------------------
1 | import { TreeViewCollapseIcon, TreeViewExpandIcon, TreeViewEndIcon } from './CustomIcons';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export default function TreeView(theme) {
6 | return {
7 | MuiTreeView: {
8 | defaultProps: {
9 | defaultCollapseIcon: ,
10 | defaultExpandIcon: ,
11 | defaultEndIcon: ,
12 | },
13 | },
14 | MuiTreeItem: {
15 | styleOverrides: {
16 | label: { ...theme.typography.body2 },
17 | iconContainer: { width: 'auto' },
18 | },
19 | },
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/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/utils/axios.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | // config
3 | import { HOST_API } from '../config'
4 |
5 | // ----------------------------------------------------------------------
6 |
7 | const axiosInstance = axios.create({
8 | baseURL: HOST_API
9 | })
10 |
11 | axiosInstance.interceptors.response.use(
12 | (response) => response,
13 | (error) => Promise.reject((error.response && error.response.data) || 'Something went wrong')
14 | )
15 |
16 | export default axiosInstance
17 |
--------------------------------------------------------------------------------
/frontend/src/utils/createAvatar.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | const PRIMARY_NAME = ['A', 'N', 'H', 'L', 'Q', '9', '8'];
4 | const INFO_NAME = ['F', 'G', 'T', 'I', 'J', '1', '2', '3'];
5 | const SUCCESS_NAME = ['K', 'D', 'Y', 'B', 'O', '4', '5'];
6 | const WARNING_NAME = ['P', 'E', 'R', 'S', 'C', 'U', '6', '7'];
7 | const ERROR_NAME = ['V', 'W', 'X', 'M', 'Z'];
8 |
9 | function getFirstCharacter(name) {
10 | return name && name.charAt(0).toUpperCase();
11 | }
12 |
13 | function getAvatarColor(name) {
14 | if (PRIMARY_NAME.includes(getFirstCharacter(name))) return 'primary';
15 | if (INFO_NAME.includes(getFirstCharacter(name))) return 'info';
16 | if (SUCCESS_NAME.includes(getFirstCharacter(name))) return 'success';
17 | if (WARNING_NAME.includes(getFirstCharacter(name))) return 'warning';
18 | if (ERROR_NAME.includes(getFirstCharacter(name))) return 'warning';
19 | return 'default';
20 | }
21 |
22 | export default function createAvatar(name) {
23 | return {
24 | name: getFirstCharacter(name),
25 | color: getAvatarColor(name),
26 | };
27 | }
28 |
--------------------------------------------------------------------------------
/frontend/src/utils/flattenArray.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function flattenArray(list, key = 'children') {
4 | let children = [];
5 |
6 | const flatten = list?.map((item) => {
7 | if (item[key] && item[key].length) {
8 | children = [...children, ...item[key]];
9 | }
10 | return item;
11 | });
12 |
13 | return flatten?.concat(children.length ? flattenArray(children, key) : children);
14 | }
15 |
--------------------------------------------------------------------------------
/frontend/src/utils/formatNumber.js:
--------------------------------------------------------------------------------
1 | import numeral from 'numeral';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export function fCurrency(number) {
6 | return numeral(number).format(Number.isInteger(number) ? '$0,0' : '$0,0.00');
7 | }
8 |
9 | export function fPercent(number) {
10 | return numeral(number / 100).format('0.0%');
11 | }
12 |
13 | export function fNumber(number) {
14 | return numeral(number).format();
15 | }
16 |
17 | export function fShortenNumber(number) {
18 | return numeral(number).format('0.00a').replace('.00', '');
19 | }
20 |
21 | export function fData(number) {
22 | return numeral(number).format('0.0 b');
23 | }
24 |
--------------------------------------------------------------------------------
/frontend/src/utils/formatTime.js:
--------------------------------------------------------------------------------
1 | import { format, getTime, formatDistanceToNow } from 'date-fns';
2 |
3 | // ----------------------------------------------------------------------
4 |
5 | export function fDate(date) {
6 | return format(new Date(date), 'dd MMMM yyyy');
7 | }
8 |
9 | export function fDateTime(date) {
10 | return format(new Date(date), 'dd MMM yyyy HH:mm');
11 | }
12 |
13 | export function fTimestamp(date) {
14 | return getTime(new Date(date));
15 | }
16 |
17 | export function fDateTimeSuffix(date) {
18 | return format(new Date(date), 'dd/MM/yyyy hh:mm p');
19 | }
20 |
21 | export function fToNow(date) {
22 | return formatDistanceToNow(new Date(date), {
23 | addSuffix: true,
24 | });
25 | }
26 |
--------------------------------------------------------------------------------
/frontend/src/utils/getColorName.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function getColorName(hex) {
4 | let color;
5 |
6 | switch (hex) {
7 | case '#00AB55':
8 | color = 'Green';
9 | break;
10 | case '#000000':
11 | color = 'Black';
12 | break;
13 | case '#FFFFFF':
14 | color = 'White';
15 | break;
16 | case '#FFC0CB':
17 | color = 'Pink';
18 | break;
19 | case '#FF4842':
20 | color = 'Red';
21 | break;
22 | case '#1890FF':
23 | color = 'Blue';
24 | break;
25 | case '#94D82D':
26 | color = 'Greenyellow';
27 | break;
28 | case '#FFC107':
29 | color = 'Orange';
30 | break;
31 | default:
32 | color = hex;
33 | }
34 |
35 | return color;
36 | }
37 |
--------------------------------------------------------------------------------
/frontend/src/utils/getFileData.js:
--------------------------------------------------------------------------------
1 | // ----------------------------------------------------------------------
2 |
3 | export default function getFileData(file, index) {
4 | if (typeof file === 'string') {
5 | return {
6 | key: index ? `${file}-${index}` : file,
7 | preview: file,
8 | };
9 | }
10 |
11 | return {
12 | key: index ? `${file.name}-${index}` : file.name,
13 | name: file.name,
14 | size: file.size,
15 | path: file.path,
16 | type: file.type,
17 | preview: file.preview,
18 | lastModified: file.lastModified,
19 | lastModifiedDate: file.lastModifiedDate,
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/frontend/src/utils/highlight.js:
--------------------------------------------------------------------------------
1 | import hljs from 'highlight.js';
2 | import 'highlight.js/styles/atom-one-dark-reasonable.css';
3 |
4 | // ----------------------------------------------------------------------
5 |
6 | hljs.configure({
7 | languages: ['javascript', 'jsx', 'sh', 'bash', 'html', 'scss', 'css', 'json'],
8 | });
9 |
10 | if (typeof window !== 'undefined') {
11 | window.hljs = hljs;
12 | }
13 |
--------------------------------------------------------------------------------
/frontend/src/utils/loadColorOptions.js:
--------------------------------------------------------------------------------
1 | export const loadTypesAndColorsArray = [
2 | { key: 'Pending', value: '#ffe208' }, //yellow
3 | { key: 'Open', value: '#ed3c4f' },
4 | { key: 'Covered', value: '#3726ad' },
5 | { key: 'Dispatched', value: '#2e0000' },
6 | { key: 'Loading', value: '#6c98e0' },
7 | { key: 'On Route', value: '#5ccd57' },
8 | { key: 'Un Loading', value: '#96aeab' },
9 | { key: 'In Yard', value: '#e064be' },
10 | { key: 'Delivered', value: '#20ad00' },
11 | { key: 'Completed', value: '#002400' },
12 | { key: 'Deleted', value: '#a4bb8a' }
13 | ]
14 |
--------------------------------------------------------------------------------
/frontend/src/utils/roleOptions.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/frontend/src/utils/roleOptions.js
--------------------------------------------------------------------------------
/frontend/src/utils/uuidv4.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | // ----------------------------------------------------------------------
3 |
4 | export default function uuidv4() {
5 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
6 | const r = (Math.random() * 16) | 0,
7 | v = c === 'x' ? r : (r & 0x3) | 0x8;
8 | return v.toString(16);
9 | });
10 | }
11 |
--------------------------------------------------------------------------------
/image/README/1671452013971.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/image/README/1671452013971.png
--------------------------------------------------------------------------------
/image/README/1671452027931.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faisalnazik/Django-React-Redux-Boilerplate/5101f11ff5efbc54e901d33e504936f3f745b15a/image/README/1671452027931.png
--------------------------------------------------------------------------------