rd init
Some checks are pending
NPM Installation / build (16.x, ubuntu-latest) (push) Waiting to run
NPM Installation / build (16.x, windows-latest) (push) Waiting to run
NPM Installation / build (17.x, ubuntu-latest) (push) Waiting to run
NPM Installation / build (17.x, windows-latest) (push) Waiting to run
NPM Installation / build (18.x, ubuntu-latest) (push) Waiting to run
NPM Installation / build (18.x, windows-latest) (push) Waiting to run

This commit is contained in:
ROSHAN GARG 2024-09-13 10:19:04 +05:30
parent 3ed8eeff31
commit b050c15cec
99 changed files with 8886 additions and 0 deletions

11
.browserslistrc Normal file
View File

@ -0,0 +1,11 @@
# https://github.com/browserslist/browserslist#readme
[production]
>0.2%
not dead
not op_mini all
[development]
last 1 chrome version
last 1 firefox version
last 1 safari version

14
.editorconfig Normal file
View File

@ -0,0 +1,14 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

27
.eslintrc.js Normal file
View File

@ -0,0 +1,27 @@
module.exports = {
// parser: '@typescript-eslint/parser', // Specifies the ESLint parser
parserOptions: {
ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features
sourceType: 'module', // Allows for the use of imports
ecmaFeatures: {
jsx: true, // Allows for the parsing of JSX
},
},
settings: {
react: {
version: 'detect', // Tells eslint-plugin-react to automatically detect the version of React to use
},
},
extends: [
'plugin:react/recommended', // Uses the recommended rules from @eslint-plugin-react
'plugin:prettier/recommended', // Enables eslint-plugin-prettier and eslint-config-prettier. This will display prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.
],
plugins: ['react', 'react-hooks'],
rules: {
rules: {
'react/react-in-jsx-scope': 'off',
},
// Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs
// e.g. "@typescript-eslint/explicit-function-return-type": "off",
},
}

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Enforce Unix newlines
* text=auto eol=lf

46
.github/CODE_OF_CONDUCT.md vendored Normal file
View File

@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at . The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

83
.github/COMMIT_CONVENTION.md vendored Normal file
View File

@ -0,0 +1,83 @@
## Git Commit Message Convention
> This is adapted from [Angular's commit convention](https://github.com/conventional-changelog/conventional-changelog/blob/master/packages/conventional-changelog-angular/convention.md).
#### Examples
Appears under "Features" header, `compiler` subheader:
```
feat(compiler): add 'comments' option
```
Appears under "Bug Fixes" header, `sidebar` subheader, with a link to issue #28:
```
fix(sidebar): handle events on blur
close #28
```
Appears under "Performance Improvements" header, and under "Breaking Changes" with the breaking change explanation:
```
perf(core): improve vdom diffing by removing 'foo' option
BREAKING CHANGE: The 'foo' option has been removed.
```
The following commit and commit `667ecc1` do not appear in the changelog if they are under the same release. If not, the revert commit appears under the "Reverts" header.
```
revert: feat(compiler): add 'comments' option
This reverts commit 667ecc1654a317a13331b17617d973392f415f02.
```
### Full Message Format
A commit message consists of a **header**, **body** and **footer**. The header has a **type**, **scope** and **subject**:
```
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
The **header** is mandatory and the **scope** of the header is optional.
### Revert
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
### Type
If the prefix is `feat`, `fix` or `perf`, it will appear in the changelog. However if there is any [BREAKING CHANGE](#footer), the commit will always appear in the changelog.
Other prefixes are up to your discretion. Suggested prefixes are `docs`, `chore`, `style`, `refactor`, and `test` for non-changelog related tasks.
### Scope
The scope could be anything specifying place of the commit change. For example `core`, `compiler`, `ssr`, `v-model`, `transition` etc...
### Subject
The subject contains succinct description of the change:
* use the imperative, present tense: "change" not "changed" nor "changes"
* don't capitalize first letter
* no dot (.) at the end
### Body
Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes".
The body should include the motivation for the change and contrast this with previous behavior.
### Footer
The footer should contain any information about **Breaking Changes** and is also the place to
reference GitHub issues that this commit **Closes**.
**Breaking Changes** should start with the word `BREAKING CHANGE:` with a space or two newlines. The rest of the commit message is then used for this.

178
.github/CONTRIBUTING.md vendored Normal file
View File

@ -0,0 +1,178 @@
# Contributing to CoreUI
Looking to contribute something to CoreUI? **Here's how you can help.**
Please take a moment to review this document in order to make the contribution process easy and effective for everyone involved.
Following these guidelines helps to communicate that you respect the time of the developers managing and developing this open source project. In return, they should reciprocate that respect in addressing your issue or assessing
patches and features.
## Using the issue tracker
The [issue tracker](https://github.com/coreui/coreui-free-react-admin-template/issues) is
the preferred channel for [bug reports](#bug-reports), [features requests](#feature-requests)
and [submitting pull requests](#pull-requests), but please respect the following
restrictions:
* Please **do not** use the issue tracker for personal support requests.
* Please **do not** post comments consisting solely of "+1" or ":thumbsup:".
Use [GitHub's "reactions" feature](https://github.com/blog/2119-add-reactions-to-pull-requests-issues-and-comments)
instead.
## Bug reports
A bug is a _demonstrable problem_ that is caused by the code in the repository.
Good bug reports are extremely helpful, so thanks!
Guidelines for bug reports:
0. **Validate and lint your code** &mdash; to ensure your problem isn't caused by a simple error in your own code.
1. **Use the GitHub issue search** &mdash; check if the issue has already been reported.
2. **Check if the issue has been fixed** &mdash; try to reproduce it using the latest `master` or development branch in the repository.
3. **Isolate the problem** &mdash; ideally create a [reduced test case](https://css-tricks.com/reduced-test-cases/) and a live example. [This JS Bin](http://jsbin.com/lefey/1/edit?html,output) is a helpful template.
A good bug report shouldn't leave others needing to chase you up for more
information. Please try to be as detailed as possible in your report. What is
your environment? What steps will reproduce the issue? What browser(s) and OS
experience the problem? Do other browsers show the bug differently? What
would you expect to be the outcome? All these details will help people to fix
any potential bugs.
Example:
> Short and descriptive example bug report title
>
> A summary of the issue and the browser/OS environment in which it occurs. If
> suitable, include the steps required to reproduce the bug.
>
> 1. This is the first step
> 2. This is the second step
> 3. Further steps, etc.
>
> `<url>` - a link to the reduced test case
>
> Any other information you want to share that is relevant to the issue being
> reported. This might include the lines of code that you have identified as
> causing the bug, and potential solutions (and your opinions on their
> merits).
## Feature requests
Feature requests are welcome. Before opening a feature request, please take a
moment to find out whether your idea fits with the scope and aims of the
project. It's up to *you* to make a strong case to convince the project's
developers of the merits of this feature. Please provide as much detail
and context as possible.
## Pull requests
Good pull requests—patches, improvements, new features—are a fantastic
help. They should remain focused in scope and avoid containing unrelated
commits.
**Please ask first** before embarking on any significant pull request (e.g.
implementing features, refactoring code, porting to a different language),
otherwise you risk spending a lot of time working on something that the
project's developers might not want to merge into the project.
Adhering to the following process is the best way to get your work
included in the project:
1. [Fork](https://help.github.com/fork-a-repo/) the project, clone your fork,
and configure the remotes:
```bash
# Clone your fork of the repo into the current directory
git clone https://github.com/<your-username>/coreui-react.git
# Navigate to the newly cloned directory
cd coreui
# Assign the original repo to a remote called "upstream"
git remote add upstream https://github.com/coreui/coreui-react.git
```
2. If you cloned a while ago, get the latest changes from upstream:
```bash
git checkout master
git pull upstream master
```
3. Create a new topic branch (off the main project development branch) to
contain your feature, change, or fix:
```bash
git checkout -b <topic-branch-name>
```
4. Commit your changes in logical chunks. Please adhere to these [git commit
message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
or your code is unlikely to be merged into the main project. Use Git's
[interactive rebase](https://help.github.com/articles/interactive-rebase)
feature to tidy up your commits before making them public.
5. Locally merge (or rebase) the upstream development branch into your topic branch:
```bash
git pull [--rebase] upstream master
```
6. Push your topic branch up to your fork:
```bash
git push origin <topic-branch-name>
```
7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/)
with a clear title and description against the `master` branch.
**IMPORTANT**: By submitting a patch, you agree to allow the project owners to
license your work under the terms of the [MIT License](LICENSE).
### Semantic Git commit messages
Inspired by Sparkbox's awesome article on
[semantic commit messages](http://seesparkbox.com/foundry/semantic_commit_messages).
Please use following commit message format.
* chore (updating npm tasks etc; no production code change) -> ```git test -m 'chore: commit-message-here'```
* docs (changes to documentation) -> ```git commit -m 'docs: commit-message-here'```
* feat (new feature) -> ```git commit -m 'feat: commit-message-here'```
* fix (bug fix) -> ```git commit -m 'fix: commit-message-here'```
* refactor (refactoring production code) -> ```git commit -m 'refactor: commit-message-here'```
* style (formatting, missing semi colons, etc; no code change) -> ```git commit -m 'style: commit-message-here'```
* test (adding missing tests, refactoring tests; no production code change) -> ```git test -m 'refactor: commit-message-here'```
## Code guidelines
### HTML
[Adhere to the Code Guide.](http://codeguide.co/#html)
- Use tags and elements appropriate for an HTML5 doctype (e.g., self-closing tags).
- Use CDNs and HTTPS for third-party JS when possible. We don't use protocol-relative URLs in this case because they break when viewing the page locally via `file://`.
- Use [WAI-ARIA](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA) attributes in documentation examples to promote accessibility.
### CSS
[Adhere to the Code Guide.](http://codeguide.co/#css)
- When feasible, default color palettes should comply with [WCAG color contrast guidelines](http://www.w3.org/TR/WCAG20/#visual-audio-contrast).
- Except in rare cases, don't remove default `:focus` styles (via e.g. `outline: none;`) without providing alternative styles. See [this A11Y Project post](http://a11yproject.com/posts/never-remove-css-outlines) for more details.
### JS
- No semicolons (in client-side JS)
- 2 spaces (no tabs)
- strict mode
- "Attractive"
- Don't use [jQuery event alias convenience methods](https://github.com/jquery/jquery/blob/master/src/event/alias.js) (such as `$().focus()`). Instead, use [`$().trigger(eventType, ...)`](http://api.jquery.com/trigger/) or [`$().on(eventType, ...)`](http://api.jquery.com/on/), depending on whether you're firing an event or listening for an event. (For example, `$().trigger('focus')` or `$().on('focus', function (event) { /* handle focus event */ })`) We do this to be compatible with custom builds of jQuery where the event aliases module has been excluded.
## License
By contributing your code, you agree to license your contribution under the [MIT License](LICENSE).

4
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,4 @@
# These are supported funding model platforms
custom: "https://coreui.io/pricing?support=react"
open_collective: coreui

20
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,20 @@
---
name: Bug report
about: Tell us about a bug you may have identified in CoreUI Free React Admin Template.
title: ''
labels: ''
assignees: ''
---
Before opening:
- [Search for duplicate or closed issues](https://github.com/coreui/coreui-free-react-admin-template/issues?utf8=%E2%9C%93&q=is%3Aissue)
- [Validate](https://html5.validator.nu/) any HTML to avoid common problems
- Read the [contributing guidelines](https://github.com/coreui/coreui-free-react-admin-template/blob/v4-dev/.github/CONTRIBUTING.md)
Bug reports must include:
- Operating system and version (Windows, macOS, Android, iOS)
- Browser and version (Chrome, Firefox, Safari, Microsoft Edge, Opera, Android Browser)
- A [reduced test case](https://css-tricks.com/reduced-test-cases/) or suggested fix using [CodePen](https://codepen.io/) or [JS Bin](https://jsbin.com/)

View File

@ -0,0 +1,18 @@
---
name: Feature request
about: Suggest an idea for a new feature in CoreUI Free React Admin Template.
title: ''
labels: feature
assignees: ''
---
Before opening:
- [Search for duplicate or closed issues](https://github.com/coreui/coreui-free-react-admin-template/issues?utf8=%E2%9C%93&q=is%3Aissue)
- Read the [contributing guidelines](https://github.com/coreui/coreui-free-react-admin-template/blob/main/.github/CONTRIBUTING.md)
Feature requests must include:
- As much detail as possible for what we should add and why it's important to Bootstrap
- Relevant links to prior art, screenshots, or live demos whenever possible

9
.github/SUPPORT.md vendored Normal file
View File

@ -0,0 +1,9 @@
### Bug reports
See the [contributing guidelines](CONTRIBUTING.md) for sharing bug reports.
### How-to
For general troubleshooting or help getting started:
- Search or start a new discussion on [GitHub Discussions](https://github.com/coreui/coreui-free-react-admin-template/discussions).

34
.github/workflows/npm.yml vendored Normal file
View File

@ -0,0 +1,34 @@
name: NPM Installation
on:
push:
branches-ignore:
- "dependabot/**"
schedule:
- cron: '0 0 * * *'
env:
FORCE_COLOR: 2
NODE: 16
jobs:
build:
strategy:
matrix:
platform: [ubuntu-latest, windows-latest]
node-version: [16.x, 17.x, 18.x]
runs-on: ${{ matrix.platform }}
steps:
- name: Clone repository
uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ env.node-version }}
- name: Install npm dependencies
run: npm install
- name: Run build
run: npm run build

27
.github/workflows/stale.yml vendored Normal file
View File

@ -0,0 +1,27 @@
# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
#
# You can adjust the behavior by modifying this file.
# For more information, see:
# https://github.com/actions/stale
name: Mark stale issues and pull requests
on:
schedule:
- cron: '15 14 * * *'
jobs:
stale:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions'
stale-pr-message: 'This PR has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions'
stale-issue-label: 'no-issue-activity'
stale-pr-label: 'no-pr-activity'

25
.gitignore vendored Normal file
View File

@ -0,0 +1,25 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
/node_modules
package-lock.json
yarn.lock
# testing
/coverage
# production
/build
# misc
.eslintcache
.DS_Store
.idea
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

1
.prettierignore Normal file
View File

@ -0,0 +1 @@
build/

7
.prettierrc.js Normal file
View File

@ -0,0 +1,7 @@
module.exports = {
semi: false,
trailingComma: 'all',
singleQuote: true,
printWidth: 100,
tabWidth: 2,
}

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2024 creativeLabs Łukasz Holeczek.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

30
index.html Normal file
View File

@ -0,0 +1,30 @@
<!doctype html>
<!--
* CoreUI Free React.js Admin Template
* @version v5.1.0
* @link https://coreui.io/product/free-react-admin-template/
* Copyright (c) 2024 creativeLabs Łukasz Holeczek
* Licensed under MIT (https://github.com/coreui/coreui-free-react-admin-template/blob/main/LICENSE)
-->
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="CoreUI for React - Open Source Bootstrap Admin Template" />
<meta name="author" content="Łukasz Holeczek" />
<meta
name="keyword"
content="Bootstrap,Admin,Template,Open,Source,CSS,SCSS,HTML,RWD,Dashboard,React"
/>
<title>Retail distributer</title>
<link rel="manifest" href="/manifest.json" />
<link rel="shortcut icon" href="/favicon.ico" />
</head>
<body>
<noscript> You need to enable JavaScript to run this app </noscript>
<div id="root"></div>
<script type="module" src="/src/index.js"></script>
<!-- built files will be auto injected -->
</body>
</html>

67
package.json Normal file
View File

@ -0,0 +1,67 @@
{
"name": "@coreui/coreui-free-react-admin-template",
"version": "5.1.0",
"description": "CoreUI Free React Admin Template",
"homepage": ".",
"bugs": {
"url": "https://github.com/coreui/coreui-free-react-admin-template/issues"
},
"repository": {
"type": "git",
"url": "git@github.com:coreui/coreui-free-react-admin-template.git"
},
"license": "MIT",
"author": "The CoreUI Team (https://github.com/orgs/coreui/people)",
"scripts": {
"build": "vite build",
"lint": "eslint \"src/**/*.js\"",
"serve": "vite preview",
"start": "vite"
},
"dependencies": {
"@coreui/chartjs": "^4.0.0",
"@coreui/coreui": "^5.0.2",
"@coreui/icons": "^3.0.1",
"@coreui/icons-react": "^2.2.1",
"@coreui/react": "^5.1.0",
"@coreui/react-chartjs": "^3.0.0",
"@coreui/utils": "^2.0.2",
"@emotion/react": "^11.13.0",
"@emotion/styled": "^11.13.0",
"@fortawesome/fontawesome-svg-core": "^6.6.0",
"@fortawesome/free-solid-svg-icons": "^6.6.0",
"@fortawesome/react-fontawesome": "^0.2.2",
"@mui/icons-material": "^5.16.4",
"@mui/material": "^5.16.4",
"@popperjs/core": "^2.11.8",
"@themesberg/react-bootstrap": "^1.4.1",
"axios": "^1.7.2",
"chart.js": "^4.4.3",
"classnames": "^2.5.1",
"core-js": "^3.37.1",
"date-fns": "^3.6.0",
"jwt-decode": "^4.0.0",
"prop-types": "^15.8.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-redux": "^9.1.2",
"react-router-dom": "^6.23.1",
"redux": "^5.0.1",
"redux-thunk": "^3.1.0",
"simplebar-react": "^3.2.5",
"sweetalert2": "^11.12.3"
},
"devDependencies": {
"@vitejs/plugin-react": "^4.3.1",
"autoprefixer": "^10.4.19",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react": "^7.34.2",
"eslint-plugin-react-hooks": "^4.6.2",
"postcss": "^8.4.38",
"prettier": "3.3.2",
"sass": "^1.77.5",
"vite": "^5.2.13"
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

15
public/manifest.json Normal file
View File

@ -0,0 +1,15 @@
{
"short_name": "CoreUI-React",
"name": "CoreUI-React sample",
"icons": [
{
"src": "./assets/img/favicon.png",
"sizes": "100x100",
"type": "image/png"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

68
src/App.js Normal file
View File

@ -0,0 +1,68 @@
import React, { Suspense, useEffect } from 'react'
import { HashRouter, Route, Routes } from 'react-router-dom'
import { useSelector } from 'react-redux'
import { CSpinner, useColorModes } from '@coreui/react'
import './scss/style.scss'
import ProtectedRoute from './protectedRoute'
// Containers
const DefaultLayout = React.lazy(() => import('./layout/DefaultLayout'))
// Pages
const Login = React.lazy(() => import('./views/pages/login/Login'))
const Register = React.lazy(() => import('./views/pages/register/Register'))
const Page404 = React.lazy(() => import('./views/pages/page404/Page404'))
const Page500 = React.lazy(() => import('./views/pages/page500/Page500'))
const ForgetPassword = React.lazy(() => import('./views/pages/forgetPassword'))
const App = () => {
const { isColorModeSet, setColorMode } = useColorModes('coreui-free-react-admin-template-theme')
const storedTheme = 'light'
console.log('theme1', storedTheme)
useEffect(() => {
// const urlParams = new URLSearchParams(window.location.href.split('?')[1])
// const theme = urlParams.get('theme') && urlParams.get('theme').match(/^[A-Za-z0-9\s]+/)[0]
// console.log('theme', theme)
// if () {
// setColorMode(theme)
// }
// if (isColorModeSet()) {
// return
// }
setColorMode(storedTheme)
}, []) // eslint-disable-line react-hooks/exhaustive-deps
return (
<HashRouter>
<Suspense
fallback={
<div className="pt-3 text-center">
<CSpinner color="primary" variant="grow" />
</div>
}
>
<Routes>
{/* <Route exact path="/change-password" name="My profile" element={<ChangePassword />} /> */}
<Route exact path="/login" name="Login Page" element={<Login />} />
<Route exact path="/register" name="Register Page" element={<Register />} />
<Route exact path="/404" name="Page 404" element={<Page404 />} />
<Route exact path="/500" name="Page 500" element={<Page500 />} />
<Route
exact
path="/forget-password"
name="Forget password "
element={<ForgetPassword />}
/>
<Route path="/*" element={<ProtectedRoute element={DefaultLayout} />} />
<Route path="*" name="Home" element={<DefaultLayout />} />
</Routes>
</Suspense>
</HashRouter>
)
}
export default App

348
src/_nav.js Normal file
View File

@ -0,0 +1,348 @@
import React from 'react'
import CIcon from '@coreui/icons-react'
import {
cilBell,
cilBorderAll,
cilCalculator,
cilChartPie,
cilCursor,
cilDescription,
cilDrop,
cilFile,
cilNotes,
cilPaperPlane,
cilPencil,
cilPuzzle,
cilShare,
cilSpeedometer,
cilStar,
} from '@coreui/icons'
import { CNavGroup, CNavItem, CNavTitle } from '@coreui/react'
const _nav = [
{
component: CNavItem,
name: 'Dashboard',
to: '/dashboard',
icon: <CIcon icon={cilSpeedometer} customClassName="nav-icon" />,
},
{
component: CNavItem,
name: 'Shop',
to: '/shop',
icon: <CIcon icon={cilShare} customClassName="nav-icon" />,
},
// {
// component: CNavItem,
// name: 'Cart',
// to: '/cart',
// icon: <CIcon icon={cilShare} customClassName="nav-icon" />,
// },
// {
// component: CNavItem,
// name: 'Orders Placed',
// to: '/orders-placed',
// icon: <CIcon icon={cilPaperPlane} customClassName="nav-icon" />,
// },
// {
// component: CNavItem,
// name: 'Product manual',
// to: '/product-manual',
// icon: <CIcon icon={cilFile} customClassName="nav-icon" />,
// },
// {
// component: CNavItem,
// name: 'Orders',
// to: '/order',
// icon: <CIcon icon={cilBorderAll} customClassName="nav-icon" />,
// },
{
component: CNavItem,
name: 'KYC',
to: '/kyc',
icon: <CIcon icon={cilDescription} customClassName="nav-icon" />,
},
// {
// component: CNavTitle,
// name: 'Theme',
// },
// {
// component: CNavItem,
// name: 'Colors',
// to: '/theme/colors',
// icon: <CIcon icon={cilDrop} customClassName="nav-icon" />,
// },
// {
// component: CNavItem,
// name: 'Typography',
// to: '/theme/typography',
// icon: <CIcon icon={cilPencil} customClassName="nav-icon" />,
// },
// {
// component: CNavTitle,
// name: 'Components',
// },
// {
// component: CNavGroup,
// name: 'Base',
// to: '/base',
// icon: <CIcon icon={cilPuzzle} customClassName="nav-icon" />,
// items: [
// {
// component: CNavItem,
// name: 'Accordion',
// to: '/base/accordion',
// },
// {
// component: CNavItem,
// name: 'Breadcrumb',
// to: '/base/breadcrumbs',
// },
// {
// component: CNavItem,
// name: 'Cards',
// to: '/base/cards',
// },
// {
// component: CNavItem,
// name: 'Carousel',
// to: '/base/carousels',
// },
// {
// component: CNavItem,
// name: 'Collapse',
// to: '/base/collapses',
// },
// {
// component: CNavItem,
// name: 'List group',
// to: '/base/list-groups',
// },
// {
// component: CNavItem,
// name: 'Navs & Tabs',
// to: '/base/navs',
// },
// {
// component: CNavItem,
// name: 'Pagination',
// to: '/base/paginations',
// },
// {
// component: CNavItem,
// name: 'Placeholders',
// to: '/base/placeholders',
// },
// {
// component: CNavItem,
// name: 'Popovers',
// to: '/base/popovers',
// },
// {
// component: CNavItem,
// name: 'Progress',
// to: '/base/progress',
// },
// {
// component: CNavItem,
// name: 'Spinners',
// to: '/base/spinners',
// },
// {
// component: CNavItem,
// name: 'Tables',
// to: '/base/tables',
// },
// {
// component: CNavItem,
// name: 'Tabs',
// to: '/base/tabs',
// },
// {
// component: CNavItem,
// name: 'Tooltips',
// to: '/base/tooltips',
// },
// ],
// },
// {
// component: CNavGroup,
// name: 'Buttons',
// to: '/buttons',
// icon: <CIcon icon={cilCursor} customClassName="nav-icon" />,
// items: [
// {
// component: CNavItem,
// name: 'Buttons',
// to: '/buttons/buttons',
// },
// {
// component: CNavItem,
// name: 'Buttons groups',
// to: '/buttons/button-groups',
// },
// {
// component: CNavItem,
// name: 'Dropdowns',
// to: '/buttons/dropdowns',
// },
// ],
// },
// {
// component: CNavGroup,
// name: 'Forms',
// icon: <CIcon icon={cilNotes} customClassName="nav-icon" />,
// items: [
// {
// component: CNavItem,
// name: 'Form Control',
// to: '/forms/form-control',
// },
// {
// component: CNavItem,
// name: 'Select',
// to: '/forms/select',
// },
// {
// component: CNavItem,
// name: 'Checks & Radios',
// to: '/forms/checks-radios',
// },
// {
// component: CNavItem,
// name: 'Range',
// to: '/forms/range',
// },
// {
// component: CNavItem,
// name: 'Input Group',
// to: '/forms/input-group',
// },
// {
// component: CNavItem,
// name: 'Floating Labels',
// to: '/forms/floating-labels',
// },
// {
// component: CNavItem,
// name: 'Layout',
// to: '/forms/layout',
// },
// {
// component: CNavItem,
// name: 'Validation',
// to: '/forms/validation',
// },
// ],
// },
// {
// component: CNavItem,
// name: 'Charts',
// to: '/charts',
// icon: <CIcon icon={cilChartPie} customClassName="nav-icon" />,
// },
// {
// component: CNavGroup,
// name: 'Icons',
// icon: <CIcon icon={cilStar} customClassName="nav-icon" />,
// items: [
// {
// component: CNavItem,
// name: 'CoreUI Free',
// to: '/icons/coreui-icons',
// badge: {
// color: 'success',
// text: 'NEW',
// },
// },
// {
// component: CNavItem,
// name: 'CoreUI Flags',
// to: '/icons/flags',
// },
// {
// component: CNavItem,
// name: 'CoreUI Brands',
// to: '/icons/brands',
// },
// ],
// },
// {
// component: CNavGroup,
// name: 'Notifications',
// icon: <CIcon icon={cilBell} customClassName="nav-icon" />,
// items: [
// {
// component: CNavItem,
// name: 'Alerts',
// to: '/notifications/alerts',
// },
// {
// component: CNavItem,
// name: 'Badges',
// to: '/notifications/badges',
// },
// {
// component: CNavItem,
// name: 'Modal',
// to: '/notifications/modals',
// },
// {
// component: CNavItem,
// name: 'Toasts',
// to: '/notifications/toasts',
// },
// ],
// },
// {
// component: CNavItem,
// name: 'Widgets',
// to: '/widgets',
// icon: <CIcon icon={cilCalculator} customClassName="nav-icon" />,
// badge: {
// color: 'info',
// text: 'NEW',
// },
// },
// {
// component: CNavTitle,
// name: 'Extras',
// },
// {
// component: CNavGroup,
// name: 'Pages',
// icon: <CIcon icon={cilStar} customClassName="nav-icon" />,
// items: [
// {
// component: CNavItem,
// name: 'Login',
// to: '/login',
// },
// {
// component: CNavItem,
// name: 'Register',
// to: '/register',
// },
// {
// component: CNavItem,
// name: 'Error 404',
// to: '/404',
// },
// {
// component: CNavItem,
// name: 'Error 500',
// to: '/500',
// },
// ],
// },
// {
// component: CNavItem,
// name: 'Docs',
// href: 'https://coreui.io/react/docs/templates/installation/',
// icon: <CIcon icon={cilDescription} customClassName="nav-icon" />,
// },
]
export default _nav

18
src/assets/brand/logo.js Normal file
View File

@ -0,0 +1,18 @@
export const logo = [
'599 116',
`<g>
<g fill="none" fill-rule="nonzero">
<g style="fill:#80d0ff;">
<path d="m358.773 79.151-8.768-20.736a.25.25 0 0 0-.255-.191h-9.985a.226.226 0 0 0-.256.255v20.543a.566.566 0 0 1-.64.641h-1.216a.565.565 0 0 1-.64-.64v-43.52a.566.566 0 0 1 .64-.64h12.544a9.979 9.979 0 0 1 7.744 3.23 12.204 12.204 0 0 1 2.944 8.546 12.439 12.439 0 0 1-2.24 7.584 9.37 9.37 0 0 1-6.08 3.744c-.17.086-.214.191-.127.32l8.704 20.608.064.255c0 .342-.192.512-.576.512h-1.152a.703.703 0 0 1-.705-.51Zm-19.264-41.793v18.496a.226.226 0 0 0 .256.257h10.304a7.669 7.669 0 0 0 6.017-2.592 9.878 9.878 0 0 0 2.303-6.816 10.286 10.286 0 0 0-2.272-6.976 7.601 7.601 0 0 0-6.048-2.624h-10.304a.226.226 0 0 0-.256.255ZM398.082 37.102H378.05a.226.226 0 0 0-.256.256v18.496a.226.226 0 0 0 .256.257h13.824a.566.566 0 0 1 .64.64v.96a.566.566 0 0 1-.64.64H378.05a.226.226 0 0 0-.256.256v18.56a.226.226 0 0 0 .256.256h20.032a.567.567 0 0 1 .64.64v.96a.566.566 0 0 1-.64.64h-22.144a.566.566 0 0 1-.64-.64v-43.52a.566.566 0 0 1 .64-.64h22.144a.566.566 0 0 1 .64.64v.96a.566.566 0 0 1-.64.64ZM435.802 79.151l-2.431-8.832a.296.296 0 0 0-.32-.192h-16.768a.295.295 0 0 0-.32.192l-2.368 8.768a.658.658 0 0 1-.704.576h-1.216a.588.588 0 0 1-.48-.191.582.582 0 0 1-.096-.513l12.031-43.584a.644.644 0 0 1 .704-.512h1.6a.644.644 0 0 1 .704.512l12.16 43.584.065.192c0 .342-.214.512-.64.512h-1.217a.643.643 0 0 1-.704-.512ZM416.7 67.92a.303.303 0 0 0 .223.096h15.489a.304.304 0 0 0 .223-.096c.065-.065.075-.117.033-.16l-7.873-28.928c-.043-.085-.085-.128-.127-.128-.042 0-.086.043-.128.128l-7.872 28.928c-.043.043-.033.095.032.16ZM453.357 76.911a11.637 11.637 0 0 1-3.328-8.704V46.19a11.414 11.414 0 0 1 3.36-8.575 12.09 12.09 0 0 1 8.8-3.265 12.253 12.253 0 0 1 8.865 3.233 11.39 11.39 0 0 1 3.36 8.607v.64a.566.566 0 0 1-.641.641l-1.28.064c-.427 0-.64-.192-.64-.576v-.833a9.287 9.287 0 0 0-2.656-6.912 10.67 10.67 0 0 0-14.016 0 9.284 9.284 0 0 0-2.656 6.913v22.272a9.282 9.282 0 0 0 2.656 6.912 10.673 10.673 0 0 0 14.016 0 9.286 9.286 0 0 0 2.656-6.912v-.768c0-.384.213-.576.64-.575l1.28.063a.566.566 0 0 1 .64.64v.511a11.498 11.498 0 0 1-3.36 8.64 13.626 13.626 0 0 1-17.696 0v.001ZM511.193 35.503v.96a.565.565 0 0 1-.64.64H499.8a.226.226 0 0 0-.256.256v41.663a.566.566 0 0 1-.64.641h-1.216a.565.565 0 0 1-.64-.64V37.357a.227.227 0 0 0-.256-.255h-10.176a.565.565 0 0 1-.64-.64v-.96a.566.566 0 0 1 .64-.64h23.936a.566.566 0 0 1 .64.64ZM518.822 78.51a2.835 2.835 0 0 1-.8-2.047 2.923 2.923 0 0 1 .8-2.112c.544-.56 1.3-.862 2.08-.832a2.847 2.847 0 0 1 2.944 2.944c.03.78-.273 1.536-.832 2.08a2.921 2.921 0 0 1-2.112.8 2.754 2.754 0 0 1-2.08-.832ZM539.16 77.007a11.31 11.31 0 0 1-3.2-8.416v-5.44a.566.566 0 0 1 .64-.64h1.217a.567.567 0 0 1 .64.64v5.504a9.144 9.144 0 0 0 2.528 6.72 8.974 8.974 0 0 0 6.687 2.56 8.79 8.79 0 0 0 9.28-9.28V35.504a.565.565 0 0 1 .64-.64h1.217a.566.566 0 0 1 .64.64V68.59a11.252 11.252 0 0 1-3.233 8.416 13.062 13.062 0 0 1-17.055 0ZM577.106 77.102a10.482 10.482 0 0 1-3.36-8.127v-1.792a.565.565 0 0 1 .64-.64h1.088a.566.566 0 0 1 .64.64v1.6a8.544 8.544 0 0 0 2.752 6.655 10.536 10.536 0 0 0 7.36 2.496 9.876 9.876 0 0 0 6.976-2.367 8.215 8.215 0 0 0 2.56-6.336 8.397 8.397 0 0 0-1.12-4.416 11.383 11.383 0 0 0-3.328-3.392 71.626 71.626 0 0 0-6.176-3.712 71.302 71.302 0 0 1-6.24-3.84 12.174 12.174 0 0 1-3.424-3.68 10.257 10.257 0 0 1-1.28-5.345 9.86 9.86 0 0 1 3.072-7.744 12.012 12.012 0 0 1 8.32-2.752c3.796 0 6.783 1.035 8.96 3.105a10.823 10.823 0 0 1 3.264 8.224v1.6a.566.566 0 0 1-.64.64h-1.152a.565.565 0 0 1-.64-.64v-1.471a8.865 8.865 0 0 0-2.624-6.689 9.994 9.994 0 0 0-7.232-2.528 9.365 9.365 0 0 0-6.528 2.144 7.822 7.822 0 0 0-2.368 6.112 7.8 7.8 0 0 0 1.024 4.16 10.376 10.376 0 0 0 3.008 3.04 62.829 62.829 0 0 0 5.952 3.488 71.058 71.058 0 0 1 6.72 4.256 13.454 13.454 0 0 1 3.648 3.936 10.049 10.049 0 0 1 1.28 5.184 10.714 10.714 0 0 1-3.264 8.191c-2.175 2.05-5.12 3.073-8.832 3.073-3.798 0-6.817-1.024-9.057-3.073Z"/>
</g>
<g style="fill:currentColor;">
<path d="m96.59 25.058-39-22.517a12 12 0 0 0-12 0l-39 22.517a12.034 12.034 0 0 0-6 10.392v45.033a12.033 12.033 0 0 0 6 10.393l39 22.516a12 12 0 0 0 12 0l39-22.516a12.033 12.033 0 0 0 6-10.393V35.45a12.034 12.034 0 0 0-6-10.392Zm-2 55.425a4 4 0 0 1-2 3.464l-39 22.517a4 4 0 0 1-4 0l-39-22.517a4 4 0 0 1-2-3.464V35.45a4 4 0 0 1 2-3.464l39-22.517a4 4 0 0 1 4 0l39 22.517a4 4 0 0 1 2 3.464v45.033Z"/>
<path d="M74.612 71.005h-2.866c-.673 0-1.335.17-1.925.493l-17.28 9.485L32.59 69.465V46.487L52.54 34.97l17.29 9.455a4 4 0 0 0 1.919.49h2.863a2 2 0 0 0 2-2v-2.712a2 2 0 0 0-1.04-1.754L56.383 27.952a8.039 8.039 0 0 0-7.842.09L28.59 39.56a8.025 8.025 0 0 0-4 6.929v22.976a8 8 0 0 0 4 6.928l19.95 11.519a8.043 8.043 0 0 0 7.843.087l19.19-10.53a2 2 0 0 0 1.038-1.754v-2.71a2 2 0 0 0-1.999-2Z"/>
<g transform="translate(118 34)">
<path d="M51.335.362c-8.28.009-14.99 6.719-15 15v17.277c0 8.284 6.716 15 15 15 8.284 0 15-6.716 15-15V15.36c-.01-8.28-6.72-14.99-15-15Zm7 32.277a7 7 0 0 1-14 0V15.36a7 7 0 0 1 14 0V32.64ZM14.67 8.421a7.01 7.01 0 0 1 7.867 6.075.99.99 0 0 0 .985.865h6.03a1.01 1.01 0 0 0 .998-1.097C29.945 6.14 22.971-.02 14.834.381 6.751.932.504 7.696.59 15.796v16.407C.503 40.305 6.752 47.068 14.835 47.62c8.137.401 15.11-5.76 15.716-13.884a1.01 1.01 0 0 0-.999-1.097h-6.03a.99.99 0 0 0-.984.865 7.01 7.01 0 0 1-7.868 6.075 7.164 7.164 0 0 1-6.08-7.184v-16.79a7.164 7.164 0 0 1 6.08-7.184ZM97.513 27.928a12.158 12.158 0 0 0 7.184-11.077v-3.702C104.697 6.44 99.257 1 92.547 1H75.59a1 1 0 0 0-1 1v44a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V29h6.621l7.916 17.414a1 1 0 0 0 .91.586h6.591a1 1 0 0 0 .91-1.414l-8.025-17.658Zm-.816-11.077A4.154 4.154 0 0 1 92.547 21h-9.85V9h9.85a4.154 4.154 0 0 1 4.15 4.15v3.7ZM139.59 1h-26a1 1 0 0 0-1 1v44a1 1 0 0 0 1 1h26a1 1 0 0 0 1-1v-6a1 1 0 0 0-1-1h-19V27h13a1 1 0 0 0 1-1v-6a1 1 0 0 0-1-1h-13V9h19a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1ZM177.59 1h-6a1 1 0 0 0-1 1v22.648a7.007 7.007 0 1 1-14 0V2a1 1 0 0 0-1-1h-6a1 1 0 0 0-1 1v22.648a15.003 15.003 0 1 0 30 0V2a1 1 0 0 0-1-1Z"/>
<rect width="8" height="38" x="186.59" y="1" rx="1"/>
</g>
</g>
</g>
</g>`,
]

View File

@ -0,0 +1,7 @@
export const sygnet = [
'102 115',
`<g style="fill: currentColor">
<path d="M96 24.124 57 1.608a12 12 0 0 0-12 0L6 24.124a12.034 12.034 0 0 0-6 10.393V79.55a12.033 12.033 0 0 0 6 10.392l39 22.517a12 12 0 0 0 12 0l39-22.517a12.033 12.033 0 0 0 6-10.392V34.517a12.034 12.034 0 0 0-6-10.393ZM94 79.55a4 4 0 0 1-2 3.464l-39 22.517a4 4 0 0 1-4 0L10 83.014a4 4 0 0 1-2-3.464V34.517a4 4 0 0 1 2-3.464L49 8.536a4 4 0 0 1 4 0l39 22.517a4 4 0 0 1 2 3.464V79.55Z"/>
<path d="M74.022 70.071h-2.866a4 4 0 0 0-1.925.494L51.95 80.05 32 68.531V45.554l19.95-11.519 17.29 9.455a4 4 0 0 0 1.919.49h2.863a2 2 0 0 0 2-2v-2.71a2 2 0 0 0-1.04-1.756L55.793 27.02a8.04 8.04 0 0 0-7.843.09L28 38.626a8.025 8.025 0 0 0-4 6.929V68.53a8 8 0 0 0 4 6.928l19.95 11.519a8.043 8.043 0 0 0 7.843.088l19.19-10.532a2 2 0 0 0 1.038-1.753v-2.71a2 2 0 0 0-2-2Z"/>
</g>`,
]

View File

@ -0,0 +1,26 @@
[
{
"name": "Item 1",
"image": "https://images.pexels.com/photos/341523/pexels-photo-341523.jpeg?auto=compress&cs=tinysrgb&w=600",
"price": 10.99,
"categoryName": "phone"
},
{
"name": "Item 2",
"image": "https://images.pexels.com/photos/90946/pexels-photo-90946.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
"price": 20.99,
"categoryName": "phone"
},
{
"name": "Item 3",
"image": "https://images.pexels.com/photos/341523/pexels-photo-341523.jpeg?auto=compress&cs=tinysrgb&w=600",
"price": 30.99,
"categoryName": "camera"
},
{
"name": "Item 4",
"image": "https://images.pexels.com/photos/90946/pexels-photo-90946.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
"price": 40.99,
"categoryName": "camera"
}
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
src/assets/images/react.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

BIN
src/assets/images/vue.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

BIN
src/assets/logo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

10
src/auth.js Normal file
View File

@ -0,0 +1,10 @@
export const isAutheticated = () => {
if (typeof window == 'undefined') {
return true
}
if (localStorage.getItem('authToken')) {
return localStorage.getItem('authToken')
} else {
return false
}
}

11
src/axios.js Normal file
View File

@ -0,0 +1,11 @@
import axios from 'axios'
const Axios = axios.create({
// baseURL: 'http://localhost:5000/',
// baseURL: 'https://leadesh-whatsapp.onrender.com',
// baseURL: "https://api.leadesh.com/",
// baseURL: 'https://cheminova-api-2.onrender.com', // latest is this one
baseURL: 'https://api.cnapp.co.in', // latest is this one
})
export default Axios

View File

@ -0,0 +1,51 @@
import React from 'react'
import { useLocation } from 'react-router-dom'
import routes from '../routes'
import { CBreadcrumb, CBreadcrumbItem } from '@coreui/react'
const AppBreadcrumb = () => {
const currentLocation = useLocation().pathname
const getRouteName = (pathname, routes) => {
const currentRoute = routes.find((route) => route.path === pathname)
return currentRoute ? currentRoute.name : false
}
const getBreadcrumbs = (location) => {
const breadcrumbs = []
location.split('/').reduce((prev, curr, index, array) => {
const currentPathname = `${prev}/${curr}`
const routeName = getRouteName(currentPathname, routes)
routeName &&
breadcrumbs.push({
pathname: currentPathname,
name: routeName,
active: index + 1 === array.length ? true : false,
})
return currentPathname
})
return breadcrumbs
}
const breadcrumbs = getBreadcrumbs(currentLocation)
return (
<CBreadcrumb className="my-0">
<CBreadcrumbItem href="/">Home</CBreadcrumbItem>
{breadcrumbs.map((breadcrumb, index) => {
return (
<CBreadcrumbItem
{...(breadcrumb.active ? { active: true } : { href: breadcrumb.pathname })}
key={index}
>
{breadcrumb.name}
</CBreadcrumbItem>
)
})}
</CBreadcrumb>
)
}
export default React.memo(AppBreadcrumb)

View File

@ -0,0 +1,33 @@
import React, { Suspense } from 'react'
import { Navigate, Route, Routes } from 'react-router-dom'
import { CContainer, CSpinner } from '@coreui/react'
// routes config
import routes from '../routes'
const AppContent = () => {
return (
<CContainer className="px-4" lg>
<Suspense fallback={<CSpinner color="primary" />}>
<Routes>
{routes.map((route, idx) => {
return (
route.element && (
<Route
key={idx}
path={route.path}
exact={route.exact}
name={route.name}
element={<route.element />}
/>
)
)
})}
<Route path="/" element={<Navigate to="dashboard" replace />} />
</Routes>
</Suspense>
</CContainer>
)
}
export default React.memo(AppContent)

View File

@ -0,0 +1,23 @@
import React from 'react'
import { CFooter } from '@coreui/react'
const AppFooter = () => {
return (
<CFooter className="px-4">
{/* <div>
<a href="https://coreui.io" target="_blank" rel="noopener noreferrer">
CoreUI
</a>
<span className="ms-1">&copy; 2024 creativeLabs.</span>
</div>
<div className="ms-auto">
<span className="me-1">Powered by</span>
<a href="https://coreui.io/react" target="_blank" rel="noopener noreferrer">
CoreUI React Admin &amp; Dashboard Template
</a>
</div> */}
</CFooter>
)
}
export default React.memo(AppFooter)

151
src/components/AppHeader.js Normal file
View File

@ -0,0 +1,151 @@
import React, { useEffect, useRef } from 'react'
import { NavLink } from 'react-router-dom'
import { useSelector, useDispatch } from 'react-redux'
import {
CContainer,
CDropdown,
CDropdownItem,
CDropdownMenu,
CDropdownToggle,
CHeader,
CHeaderNav,
CHeaderToggler,
CNavLink,
CNavItem,
useColorModes,
} from '@coreui/react'
import CIcon from '@coreui/icons-react'
import {
cilBell,
cilContrast,
cilEnvelopeOpen,
cilList,
cilMenu,
cilMoon,
cilSun,
} from '@coreui/icons'
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart'
import { AppBreadcrumb } from './index'
import { AppHeaderDropdown } from './header/index'
import { IconButton } from '@mui/material'
const AppHeader = () => {
const headerRef = useRef()
const { colorMode, setColorMode } = useColorModes('coreui-free-react-admin-template-theme')
const dispatch = useDispatch()
const sidebarShow = useSelector((state) => state.sidebarShow)
useEffect(() => {
document.addEventListener('scroll', () => {
headerRef.current &&
headerRef.current.classList.toggle('shadow-sm', document.documentElement.scrollTop > 0)
})
}, [])
return (
<CHeader position="sticky" className="mb-4 p-0" ref={headerRef}>
<CContainer className="border-bottom px-4" fluid>
<CHeaderToggler
onClick={() => dispatch({ type: 'set', sidebarShow: !sidebarShow })}
style={{ marginInlineStart: '-14px' }}
>
<CIcon icon={cilMenu} size="lg" />
</CHeaderToggler>
{/* <CHeaderNav className="d-none d-md-flex">
<CNavItem>
<CNavLink to="/dashboard" as={NavLink}>
Dashboard
</CNavLink>
</CNavItem>
<CNavItem>
<CNavLink href="#">Users</CNavLink>
</CNavItem>
<CNavItem>
<CNavLink href="#">Settings</CNavLink>
</CNavItem>
</CHeaderNav>
<CHeaderNav className="ms-auto">
<CNavItem>
<CNavLink href="#">
<CIcon icon={cilBell} size="lg" />
</CNavLink>
</CNavItem>
<CNavItem>
<CNavLink href="#">
<CIcon icon={cilList} size="lg" />
</CNavLink>
</CNavItem>
<CNavItem>
<CNavLink href="#">
<CIcon icon={cilEnvelopeOpen} size="lg" />
</CNavLink>
</CNavItem>
</CHeaderNav> */}
<CHeaderNav>
{/* <li className="nav-item py-1">
<div className="vr h-100 mx-2 text-body text-opacity-75"></div>
</li>
<CDropdown variant="nav-item" placement="bottom-end">
<CDropdownToggle caret={false}>
{colorMode === 'dark' ? (
<CIcon icon={cilMoon} size="lg" />
) : colorMode === 'auto' ? (
<CIcon icon={cilContrast} size="lg" />
) : (
<CIcon icon={cilSun} size="lg" />
)}
</CDropdownToggle>
<CDropdownMenu>
<CDropdownItem
active={colorMode === 'light'}
className="d-flex align-items-center"
as="button"
type="button"
onClick={() => setColorMode('light')}
>
<CIcon className="me-2" icon={cilSun} size="lg" /> Light
</CDropdownItem>
<CDropdownItem
active={colorMode === 'dark'}
className="d-flex align-items-center"
as="button"
type="button"
onClick={() => setColorMode('dark')}
>
<CIcon className="me-2" icon={cilMoon} size="lg" /> Dark
</CDropdownItem>
<CDropdownItem
active={colorMode === 'auto'}
className="d-flex align-items-center"
as="button"
type="button"
onClick={() => setColorMode('auto')}
>
<CIcon className="me-2" icon={cilContrast} size="lg" /> Auto
</CDropdownItem>
</CDropdownMenu>
</CDropdown>
<li className="nav-item py-1">
<div className="vr h-100 mx-2 text-body text-opacity-75"></div>
</li> */}
<AppHeaderDropdown />
{/* <CNavLink to="/cart" as={NavLink}>
<IconButton>
<ShoppingCartIcon style={{ color: 'black' }} />
</IconButton>
</CNavLink> */}
</CHeaderNav>
</CContainer>
<CContainer className="px-4" fluid>
<AppBreadcrumb />
</CContainer>
</CHeader>
)
}
export default AppHeader

View File

@ -0,0 +1,65 @@
import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import {
CCloseButton,
CSidebar,
CSidebarBrand,
CSidebarFooter,
CSidebarHeader,
CSidebarToggler,
} from '@coreui/react'
import CIcon from '@coreui/icons-react'
import { AppSidebarNav } from './AppSidebarNav'
import logo from 'src/assets/logo.jpg'
import { sygnet } from 'src/assets/brand/sygnet'
// sidebar nav config
import navigation from '../_nav'
const AppSidebar = () => {
const dispatch = useDispatch()
const unfoldable = useSelector((state) => state.sidebarUnfoldable)
const sidebarShow = useSelector((state) => state.sidebarShow)
return (
<CSidebar
className="border-end"
colorScheme="dark"
position="fixed"
unfoldable={unfoldable}
visible={sidebarShow}
onVisibleChange={(visible) => {
dispatch({ type: 'set', sidebarShow: visible })
}}
>
<CSidebarHeader className="border-bottom">
<CSidebarBrand to="/">
{/* <CIcon customClassName="sidebar-brand-full" icon={logo} height={32} /> */}
<img
className="sidebar-brand-full"
src={logo}
height={32}
style={{ marginLeft: '-0.8rem' }}
/>
<CIcon customClassName="sidebar-brand-narrow" icon={sygnet} height={32} />
</CSidebarBrand>
<CCloseButton
className="d-lg-none"
dark
onClick={() => dispatch({ type: 'set', sidebarShow: false })}
/>
</CSidebarHeader>
<AppSidebarNav items={navigation} />
<CSidebarFooter className="border-top d-none d-lg-flex">
<CSidebarToggler
onClick={() => dispatch({ type: 'set', sidebarUnfoldable: !unfoldable })}
/>
</CSidebarFooter>
</CSidebar>
)
}
export default React.memo(AppSidebar)

View File

@ -0,0 +1,69 @@
import React from 'react'
import { NavLink } from 'react-router-dom'
import PropTypes from 'prop-types'
import SimpleBar from 'simplebar-react'
import 'simplebar-react/dist/simplebar.min.css'
import { CBadge, CNavLink, CSidebarNav } from '@coreui/react'
export const AppSidebarNav = ({ items }) => {
const navLink = (name, icon, badge, indent = false) => {
return (
<>
{icon
? icon
: indent && (
<span className="nav-icon">
<span className="nav-icon-bullet"></span>
</span>
)}
{name && name}
{badge && (
<CBadge color={badge.color} className="ms-auto">
{badge.text}
</CBadge>
)}
</>
)
}
const navItem = (item, index, indent = false) => {
const { component, name, badge, icon, ...rest } = item
const Component = component
return (
<Component as="div" key={index}>
{rest.to || rest.href ? (
<CNavLink {...(rest.to && { as: NavLink })} {...rest}>
{navLink(name, icon, badge, indent)}
</CNavLink>
) : (
navLink(name, icon, badge, indent)
)}
</Component>
)
}
const navGroup = (item, index) => {
const { component, name, icon, items, to, ...rest } = item
const Component = component
return (
<Component compact as="div" key={index} toggler={navLink(name, icon)} {...rest}>
{item.items?.map((item, index) =>
item.items ? navGroup(item, index) : navItem(item, index, true),
)}
</Component>
)
}
return (
<CSidebarNav as={SimpleBar}>
{items &&
items.map((item, index) => (item.items ? navGroup(item, index) : navItem(item, index)))}
</CSidebarNav>
)
}
AppSidebarNav.propTypes = {
items: PropTypes.arrayOf(PropTypes.any).isRequired,
}

View File

@ -0,0 +1,38 @@
import PropTypes from 'prop-types'
import React from 'react'
import { CCallout, CLink } from '@coreui/react'
const DocsCallout = (props) => {
const { content, href, name } = props
const plural = name.slice(-1) === 's' ? true : false
const _href = `https://coreui.io/react/docs/${href}`
return (
<CCallout color="info" className="bg-white">
{content
? content
: `A React ${name} component ${
plural ? 'have' : 'has'
} been created as a native React.js version
of Bootstrap ${name}. ${name} ${plural ? 'are' : 'is'} delivered with some new features,
variants, and unique design that matches CoreUI Design System requirements.`}
<br />
<br />
For more information please visit our official{' '}
<CLink href={_href} target="_blank">
documentation of CoreUI Components Library for React.js
</CLink>
.
</CCallout>
)
}
DocsCallout.propTypes = {
content: PropTypes.string,
href: PropTypes.string,
name: PropTypes.string,
}
export default React.memo(DocsCallout)

View File

@ -0,0 +1,43 @@
import PropTypes from 'prop-types'
import React from 'react'
import { CNav, CNavItem, CNavLink, CTabContent, CTabPane } from '@coreui/react'
import CIcon from '@coreui/icons-react'
import { cilCode, cilMediaPlay } from '@coreui/icons'
const DocsExample = (props) => {
const { children, href, tabContentClassName } = props
const _href = `https://coreui.io/react/docs/${href}`
return (
<div className="example">
<CNav variant="underline-border">
<CNavItem>
<CNavLink href="#" active>
<CIcon icon={cilMediaPlay} className="me-2" />
Preview
</CNavLink>
</CNavItem>
<CNavItem>
<CNavLink href={_href} target="_blank">
<CIcon icon={cilCode} className="me-2" />
Code
</CNavLink>
</CNavItem>
</CNav>
<CTabContent className={`rounded-bottom ${tabContentClassName ? tabContentClassName : ''}`}>
<CTabPane className="p-3 preview" visible>
{children}
</CTabPane>
</CTabContent>
</div>
)
}
DocsExample.propTypes = {
children: PropTypes.node,
href: PropTypes.string,
tabContentClassName: PropTypes.string,
}
export default React.memo(DocsExample)

View File

@ -0,0 +1,31 @@
import PropTypes from 'prop-types'
import React from 'react'
import { CLink } from '@coreui/react'
const DocsLink = (props) => {
const { href, name, text, ...rest } = props
const _href = name ? `https://coreui.io/react/docs/components/${name}` : href
return (
<div className="float-end">
<CLink
{...rest}
href={_href}
rel="noreferrer noopener"
target="_blank"
className="card-header-action"
>
<small className="text-body-secondary">{text || 'docs'}</small>
</CLink>
</div>
)
}
DocsLink.propTypes = {
href: PropTypes.string,
name: PropTypes.string,
text: PropTypes.string,
}
export default React.memo(DocsLink)

View File

@ -0,0 +1,92 @@
import React, { useEffect, useState } from 'react'
import {
CAvatar,
CBadge,
CDropdown,
CDropdownDivider,
CDropdownHeader,
CDropdownItem,
CDropdownMenu,
CDropdownToggle,
} from '@coreui/react'
import {
cilBell,
cilCreditCard,
cilCommentSquare,
cilEnvelopeOpen,
cilFile,
cilLockLocked,
cilSettings,
cilTask,
cilUser,
} from '@coreui/icons'
import CIcon from '@coreui/icons-react'
import avatar8 from './../../assets/images/avatars/8.jpg'
import { useNavigate } from 'react-router-dom'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faUserCircle } from '@fortawesome/free-solid-svg-icons'
import Swal from 'sweetalert2'
import Axios from '../../axios'
import { isAutheticated } from '../../auth'
const AppHeaderDropdown = () => {
const navigate = useNavigate()
const signout = async () => {
localStorage.removeItem('authToken')
Swal.fire('success!', 'Logged Out', 'success')
navigate('/login')
}
const [user, setUser] = useState(null)
const token = isAutheticated()
const getData = async () => {
let res = await Axios.get(`/api/rd-get-me`, {
headers: {
Authorization: `Bearer ${token}`,
},
})
if (res.status === 200) {
setUser({ ...res.data.myData })
}
}
useEffect(() => {
getData()
}, [])
return (
<CDropdown variant="nav-item">
<CDropdownToggle placement="bottom-end" className="py-0 pe-0" caret={false}>
<div className="media d-flex align-items-center " style={{ marginTop: '0.5rem' }}>
<FontAwesomeIcon
style={{ fontSize: '2rem' }}
className="user-avatar md-avatar rounded-circle "
icon={faUserCircle}
/>
<div className="media-body ms-2 text-dark align-items-center d-none d-lg-block">
<span className="mb-0 font-small fw-bold"> {user?.name}</span>
</div>
</div>
</CDropdownToggle>
<CDropdownMenu className="pt-0" placement="bottom-end">
<CDropdownHeader className="bg-body-secondary fw-semibold mb-2">Account</CDropdownHeader>
<CDropdownItem onClick={() => navigate('/my-profile')}>
<CIcon icon={cilUser} className="me-2" />
Profile
</CDropdownItem>
<CDropdownItem onClick={() => navigate('/change-password')}>
<CIcon icon={cilSettings} className="me-2" />
Change Password
</CDropdownItem>
<CDropdownDivider />
<CDropdownItem onClick={signout}>
<CIcon icon={cilLockLocked} className="me-2" />
Logout
</CDropdownItem>
</CDropdownMenu>
</CDropdown>
)
}
export default AppHeaderDropdown

View File

@ -0,0 +1,3 @@
import AppHeaderDropdown from './AppHeaderDropdown'
export { AppHeaderDropdown }

21
src/components/index.js Normal file
View File

@ -0,0 +1,21 @@
import AppBreadcrumb from './AppBreadcrumb'
import AppContent from './AppContent'
import AppFooter from './AppFooter'
import AppHeader from './AppHeader'
import AppHeaderDropdown from './header/AppHeaderDropdown'
import AppSidebar from './AppSidebar'
import DocsCallout from './DocsCallout'
import DocsLink from './DocsLink'
import DocsExample from './DocsExample'
export {
AppBreadcrumb,
AppContent,
AppFooter,
AppHeader,
AppHeaderDropdown,
AppSidebar,
DocsCallout,
DocsLink,
DocsExample,
}

16
src/index.css Normal file
View File

@ -0,0 +1,16 @@
/* Poppins */
@import url('https://fonts.googleapis.com/css2?family=Poppins&display=swap');
/* Space Grotesk */
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk&display=swap');
/* Inter */
@import url('https://fonts.googleapis.com/css2?family=Inter&display=swap');
@tailwind base;
@tailwind components;
@tailwind utilities;
body {
margin: 0;
padding: 0;
min-height: 100vh;
}

14
src/index.js Normal file
View File

@ -0,0 +1,14 @@
import React from 'react'
import { createRoot } from 'react-dom/client'
import { Provider } from 'react-redux'
import 'core-js'
import './index.css'
import App from './App'
import store from './store'
createRoot(document.getElementById('root')).render(
<Provider store={store}>
<App />
</Provider>,
)

View File

@ -0,0 +1,19 @@
import React from 'react'
import { AppContent, AppSidebar, AppFooter, AppHeader } from '../components/index'
const DefaultLayout = () => {
return (
<div>
<AppSidebar />
<div className="wrapper d-flex flex-column min-vh-100">
<AppHeader />
<div className="body flex-grow-1">
<AppContent />
</div>
<AppFooter />
</div>
</div>
)
}
export default DefaultLayout

42
src/protectedRoute.js Normal file
View File

@ -0,0 +1,42 @@
/* eslint-disable react/react-in-jsx-scope */
/* eslint-disable react/prop-types */
import { useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import { jwtDecode } from 'jwt-decode'
const isTokenExpired = (token) => {
try {
const decodedToken = jwtDecode(token)
console.log('Decoded Token:', decodedToken) // Debugging
const currentTime = Date.now() / 1000
console.log('Current Time:', currentTime) // Debugging
console.log('Token Expiration Time:', decodedToken.exp) // Debugging
return decodedToken.exp < currentTime
} catch (error) {
console.error('Error decoding token:', error) // Debugging
return true // If there's an error decoding the token, consider it expired
}
}
const ProtectedRoute = ({ element: Element }) => {
const navigate = useNavigate()
useEffect(() => {
const checkToken = () => {
const token = localStorage.getItem('authToken')
console.log('Token:', token) // Debugging
if (!token || isTokenExpired(token)) {
console.log('Token is expired or not present, redirecting to login')
navigate('/login')
} else {
console.log('Token is valid')
}
}
checkToken()
}, [navigate])
return <Element />
}
export default ProtectedRoute

View File

@ -0,0 +1,126 @@
const initialState = {
items: [],
}
const cartactionTypes = {
ADD_TO_CART: 'ADD_TO_CART',
REMOVE_FROM_CART: 'REMOVE_FROM_CART',
INCREASE_COUNT: 'INCREASE_COUNT',
DECREASE_COUNT: 'DECREASE_COUNT',
LOAD_CART: 'LOAD_CART',
CLEAR_CART: 'CLEAR_CART',
}
export const addToCart = (product) => (dispatch, getState) => {
dispatch({
type: cartactionTypes.ADD_TO_CART,
payload: product,
})
localStorage.setItem('cart', JSON.stringify(getState().cart.items))
}
export const removeFromCart = (productId) => (dispatch, getState) => {
dispatch({
type: cartactionTypes.REMOVE_FROM_CART,
payload: productId,
})
localStorage.setItem('cart', JSON.stringify(getState().cart.items))
}
export const increaseCount = (productId) => (dispatch, getState) => {
dispatch({
type: cartactionTypes.INCREASE_COUNT,
payload: productId,
})
localStorage.setItem('cart', JSON.stringify(getState().cart.items))
}
export const decreaseCount = (productId) => (dispatch, getState) => {
dispatch({
type: cartactionTypes.DECREASE_COUNT,
payload: productId,
})
localStorage.setItem('cart', JSON.stringify(getState().cart.items))
}
export const loadCart = () => (dispatch) => {
const cartItems = JSON.parse(localStorage.getItem('cart')) || []
dispatch({
type: cartactionTypes.LOAD_CART,
payload: cartItems,
})
}
export const clearCart = () => (dispatch) => {
dispatch({
type: cartactionTypes.CLEAR_CART,
})
localStorage.removeItem('cart')
}
export const cartReducer = (state = initialState, action) => {
switch (action.type) {
case cartactionTypes.LOAD_CART:
return {
...state,
items: action.payload,
}
case cartactionTypes.ADD_TO_CART:
const existingItem = state.items.find((item) => item._id === action.payload._id)
if (existingItem) {
return {
...state,
items: state.items.map((item) =>
item._id === action.payload._id ? { ...item, count: item.count + 1 } : item,
),
}
} else {
return {
...state,
items: [...state.items, { ...action.payload, count: 1 }],
}
}
case cartactionTypes.REMOVE_FROM_CART:
return {
...state,
items: state.items.filter((item) => item._id !== action.payload),
}
case cartactionTypes.INCREASE_COUNT:
return {
...state,
items: state.items.map((item) =>
item._id === action.payload ? { ...item, count: item.count + 1 } : item,
),
}
case cartactionTypes.DECREASE_COUNT:
return {
...state,
items: state.items.map((item) =>
item._id === action.payload && item.count > 1 ? { ...item, count: item.count - 1 } : item,
),
}
case cartactionTypes.CLEAR_CART:
return {
...state,
items: [],
}
default:
return state
}
}
// src/store/cart/selectors.js
// Selector to get all cart items
export const selectCartItems = (state) => state.cart.items
// Selector to get the total count of items in the cart
export const selectCartItemCount = (state) =>
state.cart.items.reduce((total, item) => total + item.count, 0)
// Selector to get the subtotal (sum of price * count) of items in the cart
export const selectCartSubtotal = (state) =>
state.cart.items.reduce((total, item) => total + item.price * item.count, 0)
// Selector to check if a specific product is already in the cart
export const selectIsProductInCart = (productId) => (state) =>
state.cart.items.some((item) => item._id === productId)

37
src/routes.js Normal file
View File

@ -0,0 +1,37 @@
import { element } from 'prop-types'
import React from 'react'
import Cart from './views/pages/cart/cart'
import OrderDetails from './views/orders/OrderDetails'
import ProductManual from './views/pages/productManual/productManual'
import ViewProductManual from './views/pages/productManual/viewProductManual'
const Dashboard = React.lazy(() => import('./views/dashboard/Dashboard'))
const Shop = React.lazy(() => import('./views/shops/Shop'))
const Order = React.lazy(() => import('./views/orders/Order'))
const MyProfile = React.lazy(() => import('./views/pages/profile/MyProfile'))
const ChangePassword = React.lazy(() => import('./views/pages/profile/ChangePassword'))
const Kyc = React.lazy(() => import('./views/pages/Kyc/kyc'))
const KycDetails = React.lazy(() => import('./views/pages/Kyc/kycDetails'))
const routes = [
{ path: '/', exact: true, name: 'Home' },
{ path: '/dashboard', name: 'Dashboard', element: Dashboard },
{ path: '/shop', name: 'Shop', element: Shop },
{ path: '/orders-placed', name: 'Order', element: Order },
{ path: '/orders-placed/:id', name: 'Order', element: OrderDetails },
// KYC
{ path: '/kyc', name: 'KYC', element: Kyc },
{ path: '/kyc/details/:id', name: 'Kyc details', element: KycDetails },
// Product manual
{ path: '/product-manual', name: 'Product Manual ', element: ProductManual },
{ path: '/product-manual/:id', name: 'Product Manual ', element: ViewProductManual },
{ path: '/my-profile', name: 'Profile', element: MyProfile },
{ path: '/change-password', name: 'Change password', element: ChangePassword },
{ path: '/cart', name: 'Cart', element: Cart },
]
export default routes

1
src/scss/_custom.scss Normal file
View File

@ -0,0 +1 @@
// Here you can add other styles

64
src/scss/_theme.scss Normal file
View File

@ -0,0 +1,64 @@
body {
background-color: var(--cui-tertiary-bg);
}
.wrapper {
width: 100%;
@include ltr-rtl("padding-left", var(--cui-sidebar-occupy-start, 0));
@include ltr-rtl("padding-right", var(--cui-sidebar-occupy-end, 0));
will-change: auto;
@include transition(padding .15s);
}
.header > .container-fluid,
.sidebar-header {
min-height: calc(4rem + 1px); // stylelint-disable-line function-disallowed-list
}
.sidebar-brand-full {
margin-left: 3px;
}
.sidebar-header {
.nav-underline-border {
--cui-nav-underline-border-link-padding-x: 1rem;
--cui-nav-underline-border-gap: 0;
}
.nav-link {
display: flex;
align-items: center;
min-height: calc(4rem + 1px); // stylelint-disable-line function-disallowed-list
}
}
.sidebar-toggler {
@include ltr-rtl("margin-left", auto);
}
.sidebar-narrow,
.sidebar-narrow-unfoldable:not(:hover) {
.sidebar-toggler {
@include ltr-rtl("margin-right", auto);
}
}
.header > .container-fluid + .container-fluid {
min-height: 3rem;
}
.footer {
min-height: calc(3rem + 1px); // stylelint-disable-line function-disallowed-list
}
@if $enable-dark-mode {
@include color-mode(dark) {
body {
background-color: var(--cui-dark-bg-subtle);
}
.footer {
--cui-footer-bg: var(--cui-body-bg);
}
}
}

5
src/scss/_variables.scss Normal file
View File

@ -0,0 +1,5 @@
// Variable overrides
//
// If you want to customize your project please add your variables below.
$enable-deprecation-messages: false !default;

116
src/scss/examples.scss Normal file
View File

@ -0,0 +1,116 @@
/* stylelint-disable declaration-no-important, scss/selector-no-redundant-nesting-selector */
$enable-deprecation-messages: false; /* stylelint-disable-line scss/dollar-variable-default */
@import "@coreui/coreui/scss/functions";
@import "@coreui/coreui/scss/variables";
@import "@coreui/coreui/scss/mixins";
.example {
&:not(:first-child) {
margin-top: 1.5rem;
}
.tab-content {
background-color: var(--#{$prefix}tertiary-bg);
}
& + p {
margin-top: 1.5rem;
}
// Components examples
.preview {
+ p {
margin-top: 2rem;
}
> .form-control {
+ .form-control {
margin-top: .5rem;
}
}
> .nav + .nav,
> .alert + .alert,
> .navbar + .navbar,
> .progress + .progress {
margin-top: 1rem;
}
> .dropdown-menu {
position: static;
display: block;
}
> :last-child {
margin-bottom: 0;
}
// Images
> svg + svg,
> img + img {
margin-left: .5rem;
}
// Buttons
> .btn,
> .btn-group {
margin: .25rem .125rem;
}
> .btn-toolbar + .btn-toolbar {
margin-top: .5rem;
}
// List groups
> .list-group {
max-width: 400px;
}
> [class*="list-group-horizontal"] {
max-width: 100%;
}
// Navbars
.fixed-top,
.sticky-top {
position: static;
margin: -1rem -1rem 1rem;
}
.fixed-bottom {
position: static;
margin: 1rem -1rem -1rem;
}
@include media-breakpoint-up(sm) {
.fixed-top,
.sticky-top {
margin: -1.5rem -1.5rem 1rem;
}
.fixed-bottom {
margin: 1rem -1.5rem -1.5rem;
}
}
// Pagination
.pagination {
margin-top: .5rem;
margin-bottom: .5rem;
}
.docs-example-modal {
.modal {
position: static;
display: block;
}
}
}
}
@if $enable-dark-mode {
@include color-mode(dark) {
.example .tab-content {
background-color: var(--#{$prefix}secondary-bg) !important;
}
}
}

15
src/scss/style.scss Normal file
View File

@ -0,0 +1,15 @@
// If you want to override variables do it here
@import "variables";
// Import styles
@import "@coreui/coreui/scss/coreui";
@import "@coreui/chartjs/scss/coreui-chartjs";
// Vendors
@import "vendors/simplebar";
// Custom styles for this theme
@import "theme";
// If you want to add custom CSS you can put it here
@import "custom";

5
src/scss/vendors/simplebar.scss vendored Normal file
View File

@ -0,0 +1,5 @@
.simplebar-content {
display: flex;
flex-direction: column;
min-height: 100%;
}

24
src/store.js Normal file
View File

@ -0,0 +1,24 @@
import { applyMiddleware, combineReducers, legacy_createStore as createStore } from 'redux'
import { cartReducer } from './redux-store/CartStore/ducs'
import { thunk } from 'redux-thunk'
// import { composeWithDevTools } from 'redux-devtools-extension'
const initialState = {
sidebarShow: true,
theme: 'light',
}
const changeState = (state = initialState, { type, ...rest }) => {
switch (type) {
case 'set':
return { ...state, ...rest }
default:
return state
}
}
const rootReducer = combineReducers({
cart: cartReducer,
changeState: changeState,
})
const store = createStore(rootReducer, applyMiddleware(thunk))
export default store

View File

@ -0,0 +1,439 @@
import React from 'react'
import {
CButton,
CDropdown,
CDropdownDivider,
CDropdownItem,
CDropdownMenu,
CDropdownToggle,
CButtonGroup,
CButtonToolbar,
CCard,
CCardBody,
CCardHeader,
CCol,
CFormCheck,
CFormInput,
CInputGroup,
CInputGroupText,
CRow,
} from '@coreui/react'
import { DocsExample } from 'src/components'
const ButtonGroups = () => {
return (
<CRow>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Button Group</strong> <span>Basic example</span>
</CCardHeader>
<CCardBody>
<p>
Wrap a series of <code>&lt;CButton&gt;</code> components in{' '}
<code>&lt;CButtonGroup&gt;</code>.{' '}
</p>
<DocsExample href="components/button-group">
<CButtonGroup role="group" aria-label="Basic example">
<CButton color="primary">Left</CButton>
<CButton color="primary">Middle</CButton>
<CButton color="primary">Right</CButton>
</CButtonGroup>
</DocsExample>
<p>
These classes can also be added to groups of links, as an alternative to the{' '}
<code>&lt;CNav&gt;</code> components.
</p>
<DocsExample href="components/button-group">
<CButtonGroup>
<CButton href="#" color="primary" active>
Active link
</CButton>
<CButton href="#" color="primary">
Link
</CButton>
<CButton href="#" color="primary">
Link
</CButton>
</CButtonGroup>
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Button Group</strong> <span>Mixed styles</span>
</CCardHeader>
<CCardBody>
<DocsExample href="components/button-group#mixed-styles">
<CButtonGroup role="group" aria-label="Basic mixed styles example">
<CButton color="danger">Left</CButton>
<CButton color="warning">Middle</CButton>
<CButton color="success">Right</CButton>
</CButtonGroup>
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Button Group</strong> <span>Outlined styles</span>
</CCardHeader>
<CCardBody>
<DocsExample href="components/button-group#outlined-styles">
<CButtonGroup role="group" aria-label="Basic outlined example">
<CButton color="primary" variant="outline">
Left
</CButton>
<CButton color="primary" variant="outline">
Middle
</CButton>
<CButton color="primary" variant="outline">
Right
</CButton>
</CButtonGroup>
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Button Group</strong> <span>Checkbox and radio button groups</span>
</CCardHeader>
<CCardBody>
<p>
Combine button-like checkbox and radio toggle buttons into a seamless looking button
group.
</p>
<DocsExample href="components/button-group#checkbox-and-radio-button-groups">
<CButtonGroup role="group" aria-label="Basic checkbox toggle button group">
<CFormCheck
button={{ variant: 'outline' }}
id="btncheck1"
autoComplete="off"
label="Checkbox 1"
/>
<CFormCheck
button={{ variant: 'outline' }}
id="btncheck2"
autoComplete="off"
label="Checkbox 2"
/>
<CFormCheck
button={{ variant: 'outline' }}
id="btncheck3"
autoComplete="off"
label="Checkbox 3"
/>
</CButtonGroup>
</DocsExample>
<DocsExample href="components/button-group#checkbox-and-radio-button-groups">
<CButtonGroup role="group" aria-label="Basic checkbox toggle button group">
<CFormCheck
type="radio"
button={{ variant: 'outline' }}
name="btnradio"
id="btnradio1"
autoComplete="off"
label="Radio 1"
/>
<CFormCheck
type="radio"
button={{ variant: 'outline' }}
name="btnradio"
id="btnradio2"
autoComplete="off"
label="Radio 2"
/>
<CFormCheck
type="radio"
button={{ variant: 'outline' }}
name="btnradio"
id="btnradio3"
autoComplete="off"
label="Radio 3"
/>
</CButtonGroup>
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Button Group</strong> <span>Button toolbar</span>
</CCardHeader>
<CCardBody>
<p>
Join sets of button groups into button toolbars for more complicated components. Use
utility classes as needed to space out groups, buttons, and more.
</p>
<DocsExample href="components/button-group#button-toolbar">
<CButtonToolbar role="group" aria-label="Toolbar with button groups">
<CButtonGroup className="me-2" role="group" aria-label="First group">
<CButton color="primary">1</CButton>
<CButton color="primary">2</CButton>
<CButton color="primary">3</CButton>
<CButton color="primary">4</CButton>
</CButtonGroup>
<CButtonGroup className="me-2" role="group" aria-label="Second group">
<CButton color="secondary">5</CButton>
<CButton color="secondary">6</CButton>
<CButton color="secondary">7</CButton>
</CButtonGroup>
<CButtonGroup className="me-2" role="group" aria-label="Third group">
<CButton color="info">8</CButton>
</CButtonGroup>
</CButtonToolbar>
</DocsExample>
<p>
Feel free to combine input groups with button groups in your toolbars. Similar to the
example above, youll likely need some utilities through to space items correctly.
</p>
<DocsExample href="components/button-group#button-toolbar">
<CButtonToolbar className="mb-3" role="group" aria-label="Toolbar with button groups">
<CButtonGroup className="me-2" role="group" aria-label="First group">
<CButton color="secondary" variant="outline">
1
</CButton>
<CButton color="secondary" variant="outline">
2
</CButton>
<CButton color="secondary" variant="outline">
3
</CButton>
<CButton color="secondary" variant="outline">
4
</CButton>
</CButtonGroup>
<CInputGroup>
<CInputGroupText>@</CInputGroupText>
<CFormInput
placeholder="Input group example"
aria-label="Input group example"
aria-describedby="btnGroupAddon"
/>
</CInputGroup>
</CButtonToolbar>
<CButtonToolbar
className="justify-content-between"
role="group"
aria-label="Toolbar with button groups"
>
<CButtonGroup className="me-2" role="group" aria-label="First group">
<CButton color="secondary" variant="outline">
1
</CButton>
<CButton color="secondary" variant="outline">
2
</CButton>
<CButton color="secondary" variant="outline">
3
</CButton>
<CButton color="secondary" variant="outline">
4
</CButton>
</CButtonGroup>
<CInputGroup>
<CInputGroupText>@</CInputGroupText>
<CFormInput
placeholder="Input group example"
aria-label="Input group example"
aria-describedby="btnGroupAddon"
/>
</CInputGroup>
</CButtonToolbar>
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Button Group</strong> <span>Sizing</span>
</CCardHeader>
<CCardBody>
<p>
Alternatively, of implementing button sizing classes to each button in a group, set{' '}
<code>size</code> property to all <code>&lt;CButtonGroup&gt;</code>&#39;s, including
each one when nesting multiple groups.
</p>
<DocsExample href="components/button-group#sizing">
<CButtonGroup size="lg" role="group" aria-label="Large button group">
<CButton color="dark" variant="outline">
Left
</CButton>
<CButton color="dark" variant="outline">
Middle
</CButton>
<CButton color="dark" variant="outline">
Right
</CButton>
</CButtonGroup>
<br />
<CButtonGroup role="group" aria-label="Default button group">
<CButton color="dark" variant="outline">
Left
</CButton>
<CButton color="dark" variant="outline">
Middle
</CButton>
<CButton color="dark" variant="outline">
Right
</CButton>
</CButtonGroup>
<br />
<CButtonGroup size="sm" role="group" aria-label="Small button group">
<CButton color="dark" variant="outline">
Left
</CButton>
<CButton color="dark" variant="outline">
Middle
</CButton>
<CButton color="dark" variant="outline">
Right
</CButton>
</CButtonGroup>
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Button Group</strong> <span>Nesting</span>
</CCardHeader>
<CCardBody>
<p className="text-body-secondary small">
Put a <code>&lt;CButtonGroup&gt;</code> inside another{' '}
<code>&lt;CButtonGroup&gt;</code> when you need dropdown menus combined with a series
of buttons.
</p>
<DocsExample href="components/button-group#nesting">
<CButtonGroup role="group" aria-label="Button group with nested dropdown">
<CButton color="primary">1</CButton>
<CButton color="primary">2</CButton>
<CDropdown variant="btn-group">
<CDropdownToggle color="primary">Dropdown</CDropdownToggle>
<CDropdownMenu>
<CDropdownItem href="#">Action</CDropdownItem>
<CDropdownItem href="#">Another action</CDropdownItem>
<CDropdownItem href="#">Something else here</CDropdownItem>
<CDropdownDivider />
<CDropdownItem href="#">Separated link</CDropdownItem>
</CDropdownMenu>
</CDropdown>
</CButtonGroup>
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Button Group</strong> <span>Vertical variation</span>
</CCardHeader>
<CCardBody>
<p className="text-body-secondary small">
Create a set of buttons that appear vertically stacked rather than horizontally.{' '}
<strong>Split button dropdowns are not supported here.</strong>
</p>
<DocsExample href="components/button-group/#vertical-variation">
<CButtonGroup vertical role="group" aria-label="Vertical button group">
<CButton color="dark">Button</CButton>
<CButton color="dark">Button</CButton>
<CButton color="dark">Button</CButton>
<CButton color="dark">Button</CButton>
<CButton color="dark">Button</CButton>
<CButton color="dark">Button</CButton>
<CButton color="dark">Button</CButton>
</CButtonGroup>
</DocsExample>
<DocsExample href="components/button-group/#vertical-variation">
<CButtonGroup vertical role="group" aria-label="Vertical button group">
<CButton color="primary">Button</CButton>
<CButton color="primary">Button</CButton>
<CDropdown variant="btn-group">
<CDropdownToggle color="primary">Dropdown</CDropdownToggle>
<CDropdownMenu>
<CDropdownItem href="#">Action</CDropdownItem>
<CDropdownItem href="#">Another action</CDropdownItem>
<CDropdownItem href="#">Something else here</CDropdownItem>
<CDropdownDivider />
<CDropdownItem href="#">Separated link</CDropdownItem>
</CDropdownMenu>
</CDropdown>
<CButton color="primary">Button</CButton>
<CButton color="primary">Button</CButton>
<CDropdown variant="btn-group">
<CDropdownToggle color="primary">Dropdown</CDropdownToggle>
<CDropdownMenu>
<CDropdownItem href="#">Action</CDropdownItem>
<CDropdownItem href="#">Another action</CDropdownItem>
<CDropdownItem href="#">Something else here</CDropdownItem>
<CDropdownDivider />
<CDropdownItem href="#">Separated link</CDropdownItem>
</CDropdownMenu>
</CDropdown>
<CDropdown variant="btn-group">
<CDropdownToggle color="primary">Dropdown</CDropdownToggle>
<CDropdownMenu>
<CDropdownItem href="#">Action</CDropdownItem>
<CDropdownItem href="#">Another action</CDropdownItem>
<CDropdownItem href="#">Something else here</CDropdownItem>
<CDropdownDivider />
<CDropdownItem href="#">Separated link</CDropdownItem>
</CDropdownMenu>
</CDropdown>
<CDropdown variant="btn-group">
<CDropdownToggle color="primary">Dropdown</CDropdownToggle>
<CDropdownMenu>
<CDropdownItem href="#">Action</CDropdownItem>
<CDropdownItem href="#">Another action</CDropdownItem>
<CDropdownItem href="#">Something else here</CDropdownItem>
<CDropdownDivider />
<CDropdownItem href="#">Separated link</CDropdownItem>
</CDropdownMenu>
</CDropdown>
</CButtonGroup>
</DocsExample>
<DocsExample href="components/button-group/#vertical-variation">
<CButtonGroup vertical role="group" aria-label="Vertical button group">
<CFormCheck
type="radio"
button={{ color: 'danger', variant: 'outline' }}
name="vbtnradio"
id="vbtnradio1"
autoComplete="off"
label="Radio 1"
defaultChecked
/>
<CFormCheck
type="radio"
button={{ color: 'danger', variant: 'outline' }}
name="vbtnradio"
id="vbtnradio2"
autoComplete="off"
label="Radio 2"
/>
<CFormCheck
type="radio"
button={{ color: 'danger', variant: 'outline' }}
name="vbtnradio"
id="vbtnradio3"
autoComplete="off"
label="Radio 3"
/>
</CButtonGroup>
</DocsExample>
</CCardBody>
</CCard>
</CCol>
</CRow>
)
}
export default ButtonGroups

View File

@ -0,0 +1,401 @@
import React from 'react'
import { CButton, CCard, CCardBody, CCardHeader, CCol, CRow } from '@coreui/react'
import CIcon from '@coreui/icons-react'
import { cilBell } from '@coreui/icons'
import { DocsExample } from 'src/components'
const Buttons = () => {
return (
<CRow>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Button</strong>
</CCardHeader>
<CCardBody>
<p className="text-body-secondary small">
CoreUI includes a bunch of predefined buttons components, each serving its own
semantic purpose. Buttons show what action will happen when the user clicks or touches
it. CoreUI buttons are used to initialize operations, both in the background or
foreground of an experience.
</p>
<DocsExample href="components/buttons">
{['normal', 'active', 'disabled'].map((state, index) => (
<CRow className="align-items-center mb-3" key={index}>
<CCol xs={12} xl={2} className="mb-3 mb-xl-0">
{state.charAt(0).toUpperCase() + state.slice(1)}
</CCol>
<CCol xs>
{[
'primary',
'secondary',
'success',
'danger',
'warning',
'info',
'light',
'dark',
].map((color, index) => (
<CButton
color={color}
key={index}
active={state === 'active'}
disabled={state === 'disabled'}
>
{color.charAt(0).toUpperCase() + color.slice(1)}
</CButton>
))}
<CButton color="link">Link</CButton>
</CCol>
</CRow>
))}
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Button</strong> <small>with icons</small>
</CCardHeader>
<CCardBody>
<p className="text-body-secondary small">
You can combine button with our <a href="https://coreui.io/icons/">CoreUI Icons</a>.
</p>
<DocsExample href="components/buttons">
{['normal', 'active', 'disabled'].map((state, index) => (
<CRow className="align-items-center mb-3" key={index}>
<CCol xs={12} xl={2} className="mb-3 mb-xl-0">
{state.charAt(0).toUpperCase() + state.slice(1)}
</CCol>
<CCol xs>
{[
'primary',
'secondary',
'success',
'danger',
'warning',
'info',
'light',
'dark',
].map((color, index) => (
<CButton
color={color}
key={index}
active={state === 'active'}
disabled={state === 'disabled'}
>
<CIcon icon={cilBell} className="me-2" />
{color.charAt(0).toUpperCase() + color.slice(1)}
</CButton>
))}
<CButton color="link">
<CIcon icon={cilBell} className="me-2" />
Link
</CButton>
</CCol>
</CRow>
))}
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Button</strong> <small>Button components</small>
</CCardHeader>
<CCardBody>
<p className="text-body-secondary small">
The <code>&lt;CButton&gt;</code> component are designed for{' '}
<code>&lt;button&gt;</code> , <code>&lt;a&gt;</code> or <code>&lt;input&gt;</code>{' '}
elements (though some browsers may apply a slightly different rendering).
</p>
<p className="text-body-secondary small">
If you&#39;re using <code>&lt;CButton&gt;</code> component as <code>&lt;a&gt;</code>{' '}
elements that are used to trigger functionality ex. collapsing content, these links
should be given a <code>role=&#34;button&#34;</code> to adequately communicate their
meaning to assistive technologies such as screen readers.
</p>
<DocsExample href="components/buttons#button-components">
<CButton as="a" color="primary" href="#" role="button">
Link
</CButton>
<CButton type="submit" color="primary">
Button
</CButton>
<CButton as="input" type="button" color="primary" value="Input" />
<CButton as="input" type="submit" color="primary" value="Submit" />
<CButton as="input" type="reset" color="primary" value="Reset" />
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Button</strong> <small>outline</small>
</CCardHeader>
<CCardBody>
<p className="text-body-secondary small">
If you need a button, but without the strong background colors. Set{' '}
<code>variant=&#34;outline&#34;</code> prop to remove all background colors.
</p>
<DocsExample href="components/buttons#outline-buttons">
{['normal', 'active', 'disabled'].map((state, index) => (
<CRow className="align-items-center mb-3" key={index}>
<CCol xs={12} xl={2} className="mb-3 mb-xl-0">
{state.charAt(0).toUpperCase() + state.slice(1)}
</CCol>
<CCol xs>
{[
'primary',
'secondary',
'success',
'danger',
'warning',
'info',
'light',
'dark',
].map((color, index) => (
<CButton
color={color}
variant="outline"
key={index}
active={state === 'active'}
disabled={state === 'disabled'}
>
{color.charAt(0).toUpperCase() + color.slice(1)}
</CButton>
))}
</CCol>
</CRow>
))}
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Button</strong> <small>ghost</small>
</CCardHeader>
<CCardBody>
<p className="text-body-secondary small">
If you need a ghost variant of button, set <code>variant=&#34;ghost&#34;</code> prop
to remove all background colors.
</p>
<DocsExample href="components/buttons#ghost-buttons">
{['normal', 'active', 'disabled'].map((state, index) => (
<CRow className="align-items-center mb-3" key={index}>
<CCol xs={12} xl={2} className="mb-3 mb-xl-0">
{state.charAt(0).toUpperCase() + state.slice(1)}
</CCol>
<CCol xs>
{[
'primary',
'secondary',
'success',
'danger',
'warning',
'info',
'light',
'dark',
].map((color, index) => (
<CButton
color={color}
variant="ghost"
key={index}
active={state === 'active'}
disabled={state === 'disabled'}
>
{color.charAt(0).toUpperCase() + color.slice(1)}
</CButton>
))}
</CCol>
</CRow>
))}
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Button</strong> <small>Sizes</small>
</CCardHeader>
<CCardBody>
<p className="text-body-secondary small">
Larger or smaller buttons? Add <code>size=&#34;lg&#34;</code> or{' '}
<code>size=&#34;sm&#34;</code> for additional sizes.
</p>
<DocsExample href="components/buttons#sizes">
<CButton color="primary" size="lg">
Large button
</CButton>
<CButton color="secondary" size="lg">
Large button
</CButton>
</DocsExample>
<DocsExample href="components/buttons#sizes">
<CButton color="primary" size="sm">
Small button
</CButton>
<CButton color="secondary" size="sm">
Small button
</CButton>
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Button</strong> <small>Pill</small>
</CCardHeader>
<CCardBody>
<DocsExample href="components/buttons#pill-buttons">
{[
'primary',
'secondary',
'success',
'danger',
'warning',
'info',
'light',
'dark',
].map((color, index) => (
<CButton color={color} shape="rounded-pill" key={index}>
{color.charAt(0).toUpperCase() + color.slice(1)}
</CButton>
))}
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Button</strong> <small>Square</small>
</CCardHeader>
<CCardBody>
<DocsExample href="components/buttons#square">
{[
'primary',
'secondary',
'success',
'danger',
'warning',
'info',
'light',
'dark',
].map((color, index) => (
<CButton color={color} shape="rounded-0" key={index}>
{color.charAt(0).toUpperCase() + color.slice(1)}
</CButton>
))}
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Button</strong> <small>Disabled state</small>
</CCardHeader>
<CCardBody>
<p className="text-body-secondary small">
Add the <code>disabled</code> boolean prop to any <code>&lt;CButton&gt;</code>{' '}
component to make buttons look inactive. Disabled button has{' '}
<code>pointer-events: none</code> applied to, disabling hover and active states from
triggering.
</p>
<DocsExample href="components/buttons#disabled-state">
<CButton color="primary" size="lg" disabled>
Primary button
</CButton>
<CButton color="secondary" size="lg" disabled>
Button
</CButton>
</DocsExample>
<p className="text-body-secondary small">
Disabled buttons using the <code>&lt;a&gt;</code> component act a little different:
</p>
<p className="text-body-secondary small">
<code>&lt;a&gt;</code>s don&#39;tsupport the <code>disabled</code> attribute, so
CoreUI has to add <code>.disabled</code> className to make buttons look inactive.
CoreUI also has to add to the disabled button component{' '}
<code>aria-disabled=&#34;true&#34;</code> attribute to show the state of the component
to assistive technologies.
</p>
<DocsExample href="components/buttons#disabled-state">
<CButton as="a" href="#" color="primary" size="lg" disabled>
Primary link
</CButton>
<CButton as="a" href="#" color="secondary" size="lg" disabled>
Link
</CButton>
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Button</strong> <small>Block buttons</small>
</CCardHeader>
<CCardBody>
<p className="text-body-secondary small">
Create buttons that span the full width of a parentby using utilities.
</p>
<DocsExample href="components/buttons#block-buttons">
<div className="d-grid gap-2">
<CButton color="primary">Button</CButton>
<CButton color="primary">Button</CButton>
</div>
</DocsExample>
<p className="text-body-secondary small">
Here we create a responsive variation, starting with vertically stacked buttons until
the <code>md</code> breakpoint, where <code>.d-md-block</code> replaces the{' '}
<code>.d-grid</code> class, thus nullifying the <code>gap-2</code> utility. Resize
your browser to see them change.
</p>
<DocsExample href="components/buttons#block-buttons">
<div className="d-grid gap-2 d-md-block">
<CButton color="primary">Button</CButton>
<CButton color="primary">Button</CButton>
</div>
</DocsExample>
<p className="text-body-secondary small">
You can adjust the width of your block buttons with grid column width classes. For
example, for a half-width &#34;block button&#34;, use <code>.col-6</code>. Center it
horizontally with <code>.mx-auto</code>, too.
</p>
<DocsExample href="components/buttons#block-buttons">
<div className="d-grid gap-2 col-6 mx-auto">
<CButton color="primary">Button</CButton>
<CButton color="primary">Button</CButton>
</div>
</DocsExample>
<p className="text-body-secondary small">
Additional utilities can be used to adjust the alignment of buttons when horizontal.
Here we&#39;ve taken our previous responsive example and added some flex utilities and
a margin utility on the button to right align the buttons when they&#39;re no longer
stacked.
</p>
<DocsExample href="components/buttons#block-buttons">
<div className="d-grid gap-2 d-md-flex justify-content-md-end">
<CButton color="primary" className="me-md-2">
Button
</CButton>
<CButton color="primary">Button</CButton>
</div>
</DocsExample>
</CCardBody>
</CCard>
</CCol>
</CRow>
)
}
export default Buttons

View File

@ -0,0 +1,338 @@
import React from 'react'
import {
CButton,
CButtonGroup,
CCard,
CCardBody,
CCardHeader,
CCol,
CDropdown,
CDropdownDivider,
CDropdownItem,
CDropdownMenu,
CDropdownToggle,
CRow,
} from '@coreui/react'
import { DocsExample } from 'src/components'
const Dropdowns = () => {
return (
<CRow>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Dropdown</strong> <small>Single button</small>
</CCardHeader>
<CCardBody>
<p className="text-body-secondary small">
Here&#39;s how you can put them to work with either <code>&lt;button&gt;</code>{' '}
elements:
</p>
<DocsExample href="components/dropdown#single-button">
<CDropdown>
<CDropdownToggle color="secondary">Dropdown button</CDropdownToggle>
<CDropdownMenu>
<CDropdownItem href="#">Action</CDropdownItem>
<CDropdownItem href="#">Another action</CDropdownItem>
<CDropdownItem href="#">Something else here</CDropdownItem>
</CDropdownMenu>
</CDropdown>
</DocsExample>
<p className="text-body-secondary small">
The best part is you can do this with any button variant, too:
</p>
<DocsExample href="components/dropdown#single-button">
<>
{['primary', 'secondary', 'success', 'info', 'warning', 'danger'].map(
(color, index) => (
<CDropdown variant="btn-group" key={index}>
<CDropdownToggle color={color}>{color}</CDropdownToggle>
<CDropdownMenu>
<CDropdownItem href="#">Action</CDropdownItem>
<CDropdownItem href="#">Another action</CDropdownItem>
<CDropdownItem href="#">Something else here</CDropdownItem>
<CDropdownDivider />
<CDropdownItem href="#">Separated link</CDropdownItem>
</CDropdownMenu>
</CDropdown>
),
)}
</>
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Dropdown</strong> <small>Split button</small>
</CCardHeader>
<CCardBody>
<p className="text-body-secondary small">
Similarly, create split button dropdowns with virtually the same markup as single
button dropdowns, but with the addition of boolean prop <code>split</code> for proper
spacing around the dropdown caret.
</p>
<p className="text-body-secondary small">
We use this extra class to reduce the horizontal <code>padding</code> on either side
of the caret by 25% and remove the <code>margin-left</code> that&#39;s attached for
normal button dropdowns. Those additional changes hold the caret centered in the split
button and implement a more properly sized hit area next to the main button.
</p>
<DocsExample href="components/dropdown#split-button">
<>
{['primary', 'secondary', 'success', 'info', 'warning', 'danger'].map(
(color, index) => (
<CDropdown variant="btn-group" key={index}>
<CButton color={color}>{color}</CButton>
<CDropdownToggle color={color} split />
<CDropdownMenu>
<CDropdownItem href="#">Action</CDropdownItem>
<CDropdownItem href="#">Another action</CDropdownItem>
<CDropdownItem href="#">Something else here</CDropdownItem>
<CDropdownDivider />
<CDropdownItem href="#">Separated link</CDropdownItem>
</CDropdownMenu>
</CDropdown>
),
)}
</>
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Dropdown</strong> <small>Sizing</small>
</CCardHeader>
<CCardBody>
<p className="text-body-secondary small">
Button dropdowns work with buttons of all sizes, including default and split dropdown
buttons.
</p>
<DocsExample href="components/dropdown#sizing">
<CDropdown variant="btn-group">
<CDropdownToggle color="secondary" size="lg">
Large button
</CDropdownToggle>
<CDropdownMenu>
<CDropdownItem href="#">Action</CDropdownItem>
<CDropdownItem href="#">Another action</CDropdownItem>
<CDropdownItem href="#">Something else here</CDropdownItem>
<CDropdownDivider />
<CDropdownItem href="#">Separated link</CDropdownItem>
</CDropdownMenu>
</CDropdown>
<CDropdown variant="btn-group">
<CButton color="secondary" size="lg">
Large split button
</CButton>
<CDropdownToggle color="secondary" size="lg" split />
<CDropdownMenu>
<CDropdownItem href="#">Action</CDropdownItem>
<CDropdownItem href="#">Another action</CDropdownItem>
<CDropdownItem href="#">Something else here</CDropdownItem>
<CDropdownDivider />
<CDropdownItem href="#">Separated link</CDropdownItem>
</CDropdownMenu>
</CDropdown>
</DocsExample>
<DocsExample href="components/dropdown#sizing">
<CDropdown variant="btn-group">
<CDropdownToggle color="secondary" size="sm">
Small button
</CDropdownToggle>
<CDropdownMenu>
<CDropdownItem href="#">Action</CDropdownItem>
<CDropdownItem href="#">Another action</CDropdownItem>
<CDropdownItem href="#">Something else here</CDropdownItem>
<CDropdownDivider />
<CDropdownItem href="#">Separated link</CDropdownItem>
</CDropdownMenu>
</CDropdown>
<CDropdown variant="btn-group">
<CButton color="secondary" size="sm">
Small split button
</CButton>
<CDropdownToggle color="secondary" size="sm" split />
<CDropdownMenu>
<CDropdownItem href="#">Action</CDropdownItem>
<CDropdownItem href="#">Another action</CDropdownItem>
<CDropdownItem href="#">Something else here</CDropdownItem>
<CDropdownDivider />
<CDropdownItem href="#">Separated link</CDropdownItem>
</CDropdownMenu>
</CDropdown>
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Dropdown</strong> <small>Single button</small>
</CCardHeader>
<CCardBody>
<p className="text-body-secondary small">
Opt into darker dropdowns to match a dark navbar or custom style by set{' '}
<code>dark</code> property. No changes are required to the dropdown items.
</p>
<DocsExample href="components/dropdown#dark-dropdowns">
<CDropdown dark>
<CDropdownToggle color="secondary">Dropdown button</CDropdownToggle>
<CDropdownMenu>
<CDropdownItem href="#">Action</CDropdownItem>
<CDropdownItem href="#">Another action</CDropdownItem>
<CDropdownItem href="#">Something else here</CDropdownItem>
<CDropdownDivider />
<CDropdownItem href="#">Separated link</CDropdownItem>
</CDropdownMenu>
</CDropdown>
</DocsExample>
<p className="text-body-secondary small">And putting it to use in a navbar:</p>
<DocsExample href="components/dropdown#dark-dropdowns">
<nav className="navbar navbar-expand-lg navbar-dark bg-dark">
<div className="container-fluid">
<a className="navbar-brand" href="https://coreui.io/react/">
Navbar
</a>
<button
className="navbar-toggler"
type="button"
data-coreui-toggle="collapse"
data-coreui-target="#navbarNavDarkDropdown"
aria-controls="navbarNavDarkDropdown"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span className="navbar-toggler-icon"></span>
</button>
<div className="collapse navbar-collapse" id="navbarNavDarkDropdown">
<ul className="navbar-nav">
<CDropdown dark as="li" variant="nav-item">
<CDropdownToggle>Dropdown</CDropdownToggle>
<CDropdownMenu>
<CDropdownItem href="#">Action</CDropdownItem>
<CDropdownItem href="#">Another action</CDropdownItem>
<CDropdownItem href="#">Something else here</CDropdownItem>
<CDropdownDivider />
<CDropdownItem href="#">Separated link</CDropdownItem>
</CDropdownMenu>
</CDropdown>
</ul>
</div>
</div>
</nav>
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Dropdown</strong> <small>Dropup</small>
</CCardHeader>
<CCardBody>
<p className="text-body-secondary small">
Trigger dropdown menus above elements by adding{' '}
<code>direction=&#34;dropup&#34;</code> to the <code>&lt;CDropdown&gt;</code>{' '}
component.
</p>
<DocsExample href="components/dropdown#dropup">
<CDropdown variant="btn-group" direction="dropup">
<CDropdownToggle color="secondary">Dropdown</CDropdownToggle>
<CDropdownMenu>
<CDropdownItem href="#">Action</CDropdownItem>
<CDropdownItem href="#">Another action</CDropdownItem>
<CDropdownItem href="#">Something else here</CDropdownItem>
<CDropdownDivider />
<CDropdownItem href="#">Separated link</CDropdownItem>
</CDropdownMenu>
</CDropdown>
<CDropdown variant="btn-group" direction="dropup">
<CButton color="secondary">Small split button</CButton>
<CDropdownToggle color="secondary" split />
<CDropdownMenu>
<CDropdownItem href="#">Action</CDropdownItem>
<CDropdownItem href="#">Another action</CDropdownItem>
<CDropdownItem href="#">Something else here</CDropdownItem>
<CDropdownDivider />
<CDropdownItem href="#">Separated link</CDropdownItem>
</CDropdownMenu>
</CDropdown>
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Dropdown</strong> <small>Dropright</small>
</CCardHeader>
<CCardBody>
<p className="text-body-secondary small">
Trigger dropdown menus at the right of the elements by adding{' '}
<code>direction=&#34;dropend&#34;</code> to the <code>&lt;CDropdown&gt;</code>{' '}
component.
</p>
<DocsExample href="components/dropdown#dropright">
<CDropdown variant="btn-group" direction="dropend">
<CDropdownToggle color="secondary">Dropdown</CDropdownToggle>
<CDropdownMenu>
<CDropdownItem href="#">Action</CDropdownItem>
<CDropdownItem href="#">Another action</CDropdownItem>
<CDropdownItem href="#">Something else here</CDropdownItem>
<CDropdownDivider />
<CDropdownItem href="#">Separated link</CDropdownItem>
</CDropdownMenu>
</CDropdown>
<CDropdown variant="btn-group" direction="dropend">
<CButton color="secondary">Small split button</CButton>
<CDropdownToggle color="secondary" split />
<CDropdownMenu>
<CDropdownItem href="#">Action</CDropdownItem>
<CDropdownItem href="#">Another action</CDropdownItem>
<CDropdownItem href="#">Something else here</CDropdownItem>
<CDropdownDivider />
<CDropdownItem href="#">Separated link</CDropdownItem>
</CDropdownMenu>
</CDropdown>
</DocsExample>
</CCardBody>
</CCard>
</CCol>
<CCol xs={12}>
<CCard className="mb-4">
<CCardHeader>
<strong>React Dropdown</strong> <small>Dropleft</small>
</CCardHeader>
<CCardBody>
<p className="text-body-secondary small">
Trigger dropdown menus at the left of the elements by adding{' '}
<code>direction=&#34;dropstart&#34;</code> to the <code>&lt;CDropdown&gt;</code>{' '}
component.
</p>
<DocsExample href="components/dropdown#dropleft">
<CButtonGroup>
<CDropdown variant="btn-group" direction="dropstart">
<CDropdownToggle color="secondary" split />
<CDropdownMenu>
<CDropdownItem href="#">Action</CDropdownItem>
<CDropdownItem href="#">Another action</CDropdownItem>
<CDropdownItem href="#">Something else here</CDropdownItem>
<CDropdownDivider />
<CDropdownItem href="#">Separated link</CDropdownItem>
</CDropdownMenu>
</CDropdown>
<CButton color="secondary">Small split button</CButton>
</CButtonGroup>
</DocsExample>
</CCardBody>
</CCard>
</CCol>
</CRow>
)
}
export default Dropdowns

View File

@ -0,0 +1,5 @@
import ButtonDropdowns from './ButtonDropdowns'
import ButtonGroups from './ButtonGroups'
import Buttons from './Buttons'
export { ButtonDropdowns, ButtonGroups, Buttons }

View File

@ -0,0 +1,86 @@
import { Box, Typography, Card, CardContent, Grid } from '@mui/material'
import React, { useState, useEffect } from 'react'
import Axios from '../../axios'
import AddShoppingCartIcon from '@mui/icons-material/AddShoppingCart'
import LocalShippingIcon from '@mui/icons-material/LocalShipping'
import CancelIcon from '@mui/icons-material/Cancel'
import HourglassEmptyIcon from '@mui/icons-material/HourglassEmpty'
import CheckCircleIcon from '@mui/icons-material/CheckCircle'
import { isAutheticated } from '../../auth'
const Dashboard = () => {
const [counts, setCounts] = useState({
new: 0,
dispatched: 0,
cancelled: 0,
processing: 0,
delivered: 0,
})
const token = isAutheticated()
// Fetch counts on component mount
// useEffect(() => {
// const getCounts = async () => {
// try {
// const res = await Axios.get('/api/get-counts-pdOrders', {
// headers: {
// Authorization: `Bearer ${token}`,
// },
// }) // Updated API endpoint
// if (res.status === 200) {
// console.log('res', res)
// setCounts(res.data.counts) // Assuming the response is in the format { new, dispatched, cancelled, processing, delivered }
// }
// } catch (error) {
// console.error('Failed to fetch status counts:', error)
// }
// }
// getCounts()
// }, [])
// Define colors for different statuses
const statusColors = {
new: '#4caf50', // Green
dispatched: '#2196f3', // Blue
cancelled: '#f44336', // Red
processing: '#ff9800', // Orange
delivered: '#9c27b0', // Purple
}
const statusIcons = {
new: <AddShoppingCartIcon sx={{ fontSize: 50, color: '#fff' }} />,
dispatched: <LocalShippingIcon sx={{ fontSize: 50, color: '#fff' }} />,
cancelled: <CancelIcon sx={{ fontSize: 50, color: '#fff' }} />,
processing: <HourglassEmptyIcon sx={{ fontSize: 50, color: '#fff' }} />,
delivered: <CheckCircleIcon sx={{ fontSize: 50, color: '#fff' }} />,
}
return (
<Box sx={{ flexGrow: 1, padding: 2 }}>
<Typography textAlign="center" variant="h3" gutterBottom>
Orders Status Summary
</Typography>
<Grid container spacing={3}>
{Object.keys(counts).map((status) => (
<Grid item xs={12} sm={6} md={3} key={status}>
<Card sx={{ backgroundColor: statusColors[status], color: '#fff' }}>
<CardContent
sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}
>
<Box>
<Typography variant="h6" component="div">
{status.charAt(0).toUpperCase() + status.slice(1)}
</Typography>
<Typography variant="h4" component="div">
{counts[status]}
</Typography>
</Box>
{statusIcons[status]} {/* Display the corresponding icon */}
</CardContent>
</Card>
</Grid>
))}
</Grid>
</Box>
)
}
export default Dashboard

158
src/views/orders/Order.js Normal file
View File

@ -0,0 +1,158 @@
import React, { useEffect, useState } from 'react'
import {
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Paper,
Typography,
Skeleton,
Box,
Button,
TablePagination,
} from '@mui/material'
import Axios from '../../axios'
import { isAutheticated } from '../../auth'
import { useNavigate } from 'react-router-dom'
const Order = () => {
const [orders, setOrders] = useState([])
const [loading, setLoading] = useState(true)
const [page, setPage] = useState(0)
const [rowsPerPage, setRowsPerPage] = useState(5)
const [totalOrders, setTotalOrders] = useState(0)
const token = isAutheticated()
const navigate = useNavigate()
const formatAMPM = (date) => {
var hours = new Date(date).getHours()
var minutes = new Date(date).getMinutes()
var ampm = hours >= 12 ? 'PM' : 'AM'
hours = hours % 12
hours = hours ? hours : 12 // the hour '0' should be '12'
minutes = minutes < 10 ? '0' + minutes : minutes
var strTime = hours + ':' + minutes + ' ' + ampm
return strTime
}
// Helper function to capitalize the first letter of a string
const capitalizeFirstLetter = (string) => {
return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase()
}
useEffect(() => {
// Fetch orders from the API with pagination
const fetchOrders = async () => {
try {
const response = await Axios.get('/api/get-placed-order-pd', {
headers: {
'Access-Control-Allow-Origin': '*',
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
params: {
page: page + 1, // page number for API (usually starts from 1)
limit: rowsPerPage, // number of rows per page
},
})
setOrders(response.data.plcaedOrders)
setTotalOrders(response.data.totalOrders) // Ensure the API returns the total count of orders
} catch (error) {
console.error('Error fetching orders:', error)
} finally {
setLoading(false)
}
}
fetchOrders()
}, [page, rowsPerPage])
const handleChangePage = (event, newPage) => {
setPage(newPage)
}
const handleChangeRowsPerPage = (event) => {
setRowsPerPage(parseInt(event.target.value, 10))
setPage(0) // Reset page to 0 when rows per page changes
}
return (
<Box>
<Typography variant="h4" mb={2} textAlign={'center'}>
Order placed list
</Typography>
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow sx={{ fontWeight: 'bold' }}>
<TableCell sx={{ fontWeight: 'bold' }}>Order ID</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Order Date</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Items</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Order Value</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Status</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Action</TableCell>
</TableRow>
</TableHead>
<TableBody>
{loading ? (
Array.from(new Array(rowsPerPage)).map((_, index) => (
<TableRow key={index}>
<TableCell colSpan={6}>
<Skeleton height={40} />
</TableCell>
</TableRow>
))
) : orders.length > 0 ? (
orders.map((order) => (
<TableRow key={order._id}>
<TableCell>{order.uniqueId}</TableCell>
<TableCell>
{new Date(order?.createdAt)
.toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
})
.replace(',', '')}{' '}
, {`${formatAMPM(order?.createdAt)}`}
</TableCell>
<TableCell>{order.orderItem.length}</TableCell>
<TableCell>{order.grandTotal.toFixed(2)}</TableCell>
<TableCell>{capitalizeFirstLetter(order.status)}</TableCell>
<TableCell>
<Button
variant="contained"
color="primary"
onClick={() => navigate(`/orders-placed/${order._id}`)}
>
View
</Button>
</TableCell>
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={6} align="center">
<Typography variant="body1">Data not found</Typography>
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
component="div"
count={totalOrders} // Total number of orders
rowsPerPage={rowsPerPage}
page={page}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</TableContainer>
</Box>
)
}
export default Order

View File

@ -0,0 +1,233 @@
import React, { useEffect, useState } from 'react'
import {
Box,
Button,
Grid,
Paper,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Typography,
} from '@mui/material'
import axios from 'axios' // Make sure you have axios installed
import { useNavigate, useParams } from 'react-router-dom'
import Axios from '../../axios'
import { isAutheticated } from '../../auth'
const OrderDetails = () => {
const [order, setOrder] = useState(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState(null)
const token = isAutheticated()
const navigate = useNavigate()
const { id } = useParams() // Assuming order ID is passed as a route parameter
const [ownerDetails, setOwnerDetails] = useState()
const getData = async () => {
let res = await Axios.get(`/api/v1/user/details`, {
headers: {
Authorization: `Bearer ${token}`,
},
})
if (res.data.success) {
setOwnerDetails({ ...res.data.user })
}
}
console.log('order', order)
useEffect(() => {
const fetchOrderDetails = async () => {
try {
const response = await Axios.get(`/api/get-single-placed-order-pd/${id}`, {
headers: {
Authorization: `Bearer ${token}`,
},
}) // Adjust API endpoint as needed
setOrder(response.data.singleOrder)
console.log(response)
setLoading(false)
} catch (err) {
setError(err.return_msg)
setLoading(false)
}
}
getData()
fetchOrderDetails()
}, [id])
if (loading) {
return <Typography>Loading...</Typography>
}
if (error) {
return <Typography>Error: {error}</Typography>
}
if (!order) {
return <Typography>No data found</Typography>
}
const {
uniqueId,
billTo,
shipTo,
paymentMode,
orderItem,
subtotal,
gstTotal,
grandTotal,
statusHistory, // Assume this is an array of status objects
} = order
console.log(statusHistory)
return (
<Box>
{/* Order Details Section */}
<Box sx={{ my: '2rem', background: '#fff', padding: '1rem', borderRadius: '0.8rem' }}>
<Box display="flex" justifyContent="space-between" alignItems="center" mb={2}>
<Typography variant="h4" sx={{ flexGrow: 1, textAlign: 'center' }}>
Order ID: {uniqueId}
</Typography>
<Button color="primary" onClick={() => navigate('/orders-placed')} variant="contained">
Back
</Button>
</Box>
<Grid container spacing={2}>
<Grid item sm={6} md={6} lg={6}>
<Typography variant="h5" sx={{ mb: '0.5rem' }}>
Bill Address
</Typography>
<Typography sx={{ mb: '0.5rem' }}>{billTo}</Typography>
</Grid>
<Grid item sm={6} md={6} lg={6}>
<Typography variant="h5" sx={{ mb: '0.5rem' }}>
Ship Address
</Typography>
<Typography sx={{ mb: '0.5rem' }}>{shipTo}</Typography>
</Grid>
<Grid item sm={6} md={6} lg={6}>
<Typography variant="h5" sx={{ mb: '0.5rem' }}>
Payment Mode: <strong>{paymentMode}</strong>
</Typography>
</Grid>
<Grid item sm={12} md={12} lg={12}>
<Typography variant="h5" sx={{ mb: '0.5rem' }}>
SBU: <strong>{ownerDetails?.SBU}</strong>
</Typography>
</Grid>
</Grid>
</Box>
{/* Order Items Table */}
<Box my={8}>
<Grid container spacing={5}>
<Grid item xs={12}>
<Box>
<TableContainer
component={Paper}
elevation={0}
sx={{ borderBottom: '1.5px solid #CFCFD5', borderRadius: 0 }}
>
<Table sx={{ minWidth: 650 }} size="large">
<TableHead>
<TableRow>
<TableCell sx={{ fontWeight: 'bold' }}>Product</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Category</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Brand</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>SKU</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Quantity</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Price</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>GST</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Subtotal</TableCell>
</TableRow>
</TableHead>
<TableBody>
{order.orderItem.map((row, index) => {
const gstAmount = (row.price * row.GST) / 100
return (
<TableRow
key={index}
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
>
<TableCell>
<Box sx={{ display: 'flex' }}>
<Box>
<Typography fontWeight={600}>{row.name}</Typography>
</Box>
</Box>
</TableCell>
<TableCell>{row.categoryName}</TableCell>
<TableCell>{row.brandName}</TableCell>
<TableCell>{row.SKU}</TableCell>
<TableCell>{row.quantity}</TableCell>
<TableCell>{row.price}</TableCell>
<TableCell>{gstAmount}</TableCell>
<TableCell>{row.price * row.quantity}</TableCell>
</TableRow>
)
})}
<TableRow>
<TableCell colSpan={7} />
<TableCell>
Subtotal:<strong> {subtotal}</strong>
</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={7} />
<TableCell>
Total GST:<strong> {gstTotal} </strong>
</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={7} />
<TableCell>
Grand Total: <strong> {grandTotal}</strong>
</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
</Box>
</Grid>
</Grid>
</Box>
{/* Status History Table */}
{statusHistory.length > 0 && (
<Box mt={8}>
<Typography variant="h5" sx={{ mb: '1rem' }}>
Status History
</Typography>
<TableContainer
component={Paper}
elevation={0}
sx={{ borderBottom: '1.5px solid #CFCFD5', borderRadius: '0.8rem' }}
>
<Table sx={{ minWidth: 650 }} size="large">
<TableHead>
<TableRow>
<TableCell>Status</TableCell>
<TableCell>Timestamp</TableCell>
</TableRow>
</TableHead>
<TableBody>
{statusHistory.map((status, index) => (
<TableRow key={index}>
<TableCell>{status.status}</TableCell>
<TableCell>{new Date(status.timestamp).toLocaleString()}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</Box>
)}
</Box>
)
}
export default OrderDetails

View File

@ -0,0 +1,46 @@
/* eslint-disable react/prop-types */
import React from 'react'
const MessageList = ({ messages }) => {
const formatAMPM = (date) => {
var hours = new Date(date).getHours()
var minutes = new Date(date).getMinutes()
var ampm = hours >= 12 ? 'PM' : 'AM'
hours = hours % 12
hours = hours ? hours : 12 // the hour '0' should be '12'
minutes = minutes < 10 ? '0' + minutes : minutes
var strTime = hours + ':' + minutes + ' ' + ampm
return strTime
}
const formatDateWithoutComma = (date) => {
const dateObj = new Date(date)
const dateStr = dateObj.toDateString().split(' ')
return `${dateStr[1]} ${dateStr[2]} ${dateStr[3]}`
}
return (
<>
{messages.map((msg, index) => (
<div
key={index}
style={{
marginBottom: '10px',
padding: '10px',
borderRadius: '5px',
backgroundColor: msg.user === 'Principal Distributer' ? '#212631' : 'blue',
boxShadow: '0px 3px 6px rgba(0,0,0,0.1)',
}}
>
<div style={{ fontWeight: 'bold', marginBottom: '5px', color: 'white' }}>{msg.user}</div>
<div style={{ fontWeight: 'bold', marginBottom: '5px', color: 'white' }}>
{/* {new Date(`${msg.replyDate}`).toDateString()} */}
{`${formatDateWithoutComma(msg?.replyDate)}`}
<span> , {`${formatAMPM(msg?.replyDate)}`}</span>
</div>
<div style={{ color: 'white' }}>{msg.message}</div>
</div>
))}
</>
)
}
export default MessageList

View File

@ -0,0 +1,55 @@
/* eslint-disable react/prop-types */
import React from 'react'
import { Box, Modal, Typography, IconButton, Button } from '@mui/material'
import CloseIcon from '@mui/icons-material/Close'
const ImgModal = ({ open, handleClose, imageUrl }) => {
const handleDownload = () => {
const link = document.createElement('a')
link.href = imageUrl
link.download = imageUrl.split('/').pop()
link.click()
}
return (
<Modal
open={open}
onClose={handleClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={{ ...modalStyle, width: '90%', height: '90%' }}>
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 }}>
<Typography id="modal-modal-title" variant="h6" component="h2">
Document Image
</Typography>
<IconButton onClick={handleClose}>
<CloseIcon />
</IconButton>
</Box>
<Box sx={{ display: 'flex', justifyContent: 'center', mb: 2 }}>
<img
src={imageUrl}
alt="Document"
style={{ maxWidth: '100%', maxHeight: '600px', objectFit: 'contain' }}
/>
</Box>
<Button variant="contained" onClick={handleDownload} sx={{ textTransform: 'unset' }}>
Download
</Button>
</Box>
</Modal>
)
}
const modalStyle = {
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
bgcolor: 'background.paper',
boxShadow: 24,
p: 4,
}
export default ImgModal

351
src/views/pages/Kyc/kyc.js Normal file
View File

@ -0,0 +1,351 @@
import React, { useState, useEffect } from 'react'
import {
Box,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Paper,
TablePagination,
Button,
Tooltip,
Tabs,
Tab,
Modal,
TextField,
DialogActions,
Typography,
} from '@mui/material'
import { useNavigate } from 'react-router-dom'
import Axios from '../../../axios'
import { isAutheticated } from '../../../auth'
import Swal from 'sweetalert2'
const Kyc = () => {
const [rows, setRows] = useState([])
const [page, setPage] = useState(0)
const [rowsPerPage, setRowsPerPage] = useState(10)
const [tabIndex, setTabIndex] = useState(0)
const [loading, setLoading] = useState(false)
const [openModal, setOpenModal] = useState(false)
const [openModal2, setOpenModal2] = useState(false)
const [rejectionReason, setRejectionReason] = useState('')
const [selectedRowId, setSelectedRowId] = useState(null)
const [selectedRowId2, setSelectedRowId2] = useState(null)
const navigate = useNavigate()
const token = isAutheticated()
// useEffect(() => {
// const fetchData = async () => {
// try {
// const response = await Axios.get('/api/kyc/getAll/', {
// headers: {
// Authorization: `Bearer ${token}`,
// 'Content-Type': 'application/json',
// },
// })
// console.log(response)
// setRows(response.data)
// } catch (error) {
// console.error('Error fetching data: ', error)
// }
// }
// fetchData()
// }, [])
const handleChangePage = (event, newPage) => {
setPage(newPage)
}
const handleChangeRowsPerPage = (event) => {
setRowsPerPage(parseInt(event.target.value, 10))
setPage(0)
}
const handleViewClick = (id) => {
navigate(`/kyc/details/${id}`)
}
const handleTabChange = (event, newValue) => {
setTabIndex(newValue)
}
const filterRowsByStatus = (status) => {
return rows.filter((row) => row.status === status)
}
const filteredRows = filterRowsByStatus(
tabIndex === 0 ? 'new' : tabIndex === 1 ? 'approved' : 'reject',
)
const handleRejectClick = async (id) => {
setSelectedRowId(id)
setOpenModal(true)
}
const handleApproveClick = async (id) => {
setSelectedRowId2(id)
setOpenModal2(true)
}
const handleApproveConfirm = async () => {
try {
setLoading(true)
console.log(selectedRowId2)
await Axios.patch(
`/api/kyc/update/${selectedRowId2}`,
{
status: 'approved',
},
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
},
)
setRows((prevRows) =>
prevRows.map((row) => (row._id === selectedRowId2 ? { ...row, status: 'approved' } : row)),
)
setLoading(true)
Swal.fire('Success', 'Approved', 'success')
handleModalClose2()
} catch (error) {
setLoading(false)
console.error('Error approving KYC: ', error)
Swal.fire('Error!', error.message, 'error')
handleModalClose2()
}
}
const handleModalClose = () => {
setOpenModal(false)
setRejectionReason('')
}
const handleModalClose2 = () => {
setOpenModal2(false)
}
const handleRejectionReasonChange = (event) => {
setRejectionReason(event.target.value)
}
const handleRejectConfirm = async () => {
try {
setLoading(true)
await Axios.patch(
`/api/kyc/update/${selectedRowId}`,
{
status: 'reject',
rejectionReason,
user: 'Principal Distributer',
},
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
},
)
setRows((prevRows) =>
prevRows.map((row) => (row._id === selectedRowId ? { ...row, status: 'reject' } : row)),
)
setLoading(true)
Swal.fire('Success', 'Rejected', 'success')
handleModalClose()
} catch (error) {
setLoading(false)
console.error('Error rejecting KYC: ', error)
Swal.fire('Error!', error.message, 'error')
handleModalClose()
}
}
const formatAMPM = (date) => {
var hours = new Date(date).getHours()
var minutes = new Date(date).getMinutes()
var ampm = hours >= 12 ? 'PM' : 'AM'
hours = hours % 12
hours = hours ? hours : 12 // the hour '0' should be '12'
minutes = minutes < 10 ? '0' + minutes : minutes
var strTime = hours + ':' + minutes + ' ' + ampm
return strTime
}
const capitalizeStatus = (status) => {
return status.charAt(0).toUpperCase() + status.slice(1)
}
// Helper function to format the date
const formatDateWithoutComma = (date) => {
const dateObj = new Date(date)
const dateStr = dateObj.toDateString().split(' ')
return `${dateStr[1]} ${dateStr[2]} ${dateStr[3]}`
}
return (
<Box sx={{ width: '100%' }}>
<Paper sx={{ width: '100%', mb: 2 }}>
<Tabs value={tabIndex} onChange={handleTabChange}>
<Tab label="New" sx={{ textTransform: 'unset' }} />
<Tab label="Approved" sx={{ textTransform: 'unset' }} />
<Tab label="Rejected" sx={{ textTransform: 'unset' }} />
</Tabs>
<TableContainer>
<Table>
<TableHead>
<TableRow>
<TableCell sx={{ fontWeight: 'bold' }}>ID</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Trade Name</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Created On</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Status</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Action</TableCell>
</TableRow>
</TableHead>
<TableBody>
{filteredRows.length !== 0 &&
filteredRows
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
.map((row) => (
<TableRow key={row._id}>
<TableCell>{row._id}</TableCell>
<TableCell>{row.trade_name}</TableCell>
<TableCell>
{`${formatDateWithoutComma(row?.createdAt)}`}
<span>, {`${formatAMPM(row?.createdAt)}`}</span>
</TableCell>
<TableCell>{capitalizeStatus(row.status)}</TableCell>
<TableCell>
<Tooltip title="View">
<Button
sx={{ mr: '1rem', textTransform: 'unset' }}
color="primary"
variant="contained"
onClick={() => handleViewClick(row._id)}
>
View
</Button>
</Tooltip>
{tabIndex === 0 && (
<>
<Tooltip title="Approve">
<Button
sx={{ mr: '1rem', textTransform: 'unset' }}
color="success"
variant="contained"
onClick={() => handleApproveClick(row._id)}
>
Approve
</Button>
</Tooltip>
<Tooltip title="Reject">
<Button
sx={{ mr: '1rem', textTransform: 'unset' }}
color="error"
variant="contained"
onClick={() => handleRejectClick(row._id)}
>
Reject
</Button>
</Tooltip>
</>
)}
</TableCell>
</TableRow>
))}
{filteredRows.length === 0 && (
<h5 style={{ textAlign: 'center' }}>No kyc available</h5>
)}
</TableBody>
</Table>
</TableContainer>
<TablePagination
rowsPerPageOptions={[10, 15, 25]}
component="div"
count={filteredRows.length}
rowsPerPage={rowsPerPage}
page={page}
onPageChange={handleChangePage}
onRowsPerPageChange={handleChangeRowsPerPage}
/>
</Paper>
<Modal
open={openModal}
onClose={handleModalClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={{ ...modalStyle, width: 400 }}>
<h2 id="modal-modal-title">Rejection Reason</h2>
<TextField
fullWidth
multiline
rows={4}
value={rejectionReason}
onChange={handleRejectionReasonChange}
variant="outlined"
label="Enter rejection reason"
/>
<DialogActions>
<Button onClick={handleModalClose} sx={{ textTransform: 'unset' }} color="primary">
Cancel
</Button>
<Button
onClick={handleRejectConfirm}
sx={{ textTransform: 'unset' }}
color="error"
variant="contained"
>
Confirm
</Button>
</DialogActions>
</Box>
</Modal>
<Modal
open={openModal2}
onClose={handleModalClose2}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={{ ...modalStyle, width: 400 }}>
<h2 id="modal-modal-title">Approval Confirmation</h2>
<Typography id="modal-modal-description" sx={{ mt: 2 }}>
Are you sure you want to approve this KYC?
</Typography>
<DialogActions>
<Button
onClick={handleModalClose2}
sx={{ textTransform: 'unset' }}
color="primary"
// variant="contained"
>
Cancel
</Button>
<Button
onClick={handleApproveConfirm}
sx={{ textTransform: 'unset' }}
color="success"
variant="contained"
>
Confirm
</Button>
</DialogActions>
</Box>
</Modal>
</Box>
)
}
const modalStyle = {
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
bgcolor: 'background.paper',
boxShadow: 24,
p: 4,
}
export default Kyc

View File

@ -0,0 +1,466 @@
import React, { useState, useEffect } from 'react'
import axios from 'axios'
import {
Box,
Typography,
Grid,
Paper,
Avatar,
Button,
TextField,
Modal,
DialogActions,
} from '@mui/material'
import { useNavigate, useParams } from 'react-router-dom'
import { format } from 'date-fns'
import Axios from '../../../axios'
import { isAutheticated } from '../../../auth'
import MessageList from './MessageList'
import Swal from 'sweetalert2'
import ImgModal from './imgModal'
const KycDetails = () => {
const { id } = useParams()
const [openRejectModal, setOpenRejectModal] = useState(false)
const [openApproveModal, setOpenApproveModal] = useState(false)
const [rejectionReason, setRejectionReason] = useState('')
const [selectedRowId, setSelectedRowId] = useState(null)
const [retailerDetails, setRetailerDetails] = useState(null)
const [openImageModal, setOpenImageModal] = useState(false)
const [selectedImageUrl, setSelectedImageUrl] = useState('')
const token = isAutheticated()
const navigate = useNavigate()
useEffect(() => {
const fetchData = async () => {
try {
const response = await Axios.get(`/api/kyc/get-single-kyc/${id}`, {
headers: {
'Access-Control-Allow-Origin': '*',
Authorization: `Bearer ${token}`,
'Content-Type': 'multipart/formdata',
},
})
console.log(response.data)
setRetailerDetails(response.data)
} catch (error) {
console.error('Error fetching data: ', error)
}
}
fetchData()
}, [id])
const [msg, setMsg] = useState('')
const handelSend = async () => {
try {
const resp = await Axios.patch(
`/api/kyc/update/${id}`,
{
rejectionReason: msg,
user: 'Principal Distributer', // Replace with actual user type
},
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
},
)
setRetailerDetails(resp.data.kyc)
setMsg('')
Swal.fire('Success', 'Message sent', 'success')
} catch (error) {
console.error('Error sending message: ', error)
Swal.fire('Error!', error.message, 'error')
}
}
const handleModalClose = () => {
setOpenRejectModal(false)
setOpenApproveModal(false)
setRejectionReason('')
}
const handleRejectionReasonChange = (event) => {
setRejectionReason(event.target.value)
}
const formatDateWithoutComma = (date) => {
const dateObj = new Date(date)
const dateStr = dateObj.toDateString().split(' ')
return `${dateStr[1]} ${dateStr[2]} ${dateStr[3]}`
}
const handleRejectConfirm = async () => {
try {
const res = await Axios.patch(
`/api/kyc/update/${id}`,
{
status: 'reject',
rejectionReason,
user: 'Principal Distributer', // Replace with actual user type
},
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
},
)
setRetailerDetails(res.data.kyc)
Swal.fire('Success', 'Rejected', 'success')
handleModalClose()
} catch (error) {
console.error('Error rejecting KYC: ', error)
Swal.fire('Error!', error.message, 'error')
handleModalClose()
}
}
const handleApproveConfirm = async () => {
try {
const res = await Axios.patch(
`/api/kyc/update/${id}`,
{
status: 'approved',
// user: 'Principal Distributer', // Replace with actual user type
},
{
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
},
)
setRetailerDetails(res.data.kyc)
Swal.fire('Success', 'Approved', 'success')
handleModalClose()
} catch (error) {
console.error('Error approving KYC: ', error)
Swal.fire('Error!', error.message, 'error')
handleModalClose()
}
}
const formatAMPM = (date) => {
var hours = new Date(date).getHours()
var minutes = new Date(date).getMinutes()
var ampm = hours >= 12 ? 'PM' : 'AM'
hours = hours % 12
hours = hours ? hours : 12 // the hour '0' should be '12'
minutes = minutes < 10 ? '0' + minutes : minutes
var strTime = hours + ':' + minutes + ' ' + ampm
return strTime
}
const handleRejectClick = () => {
setOpenRejectModal(true)
}
const handleApproveClick = () => {
setOpenApproveModal(true)
}
const handleImageClick = (url) => {
setSelectedImageUrl(url)
console.log(selectedImageUrl)
setOpenImageModal(true)
}
if (!retailerDetails) {
return <Typography>Loading...</Typography>
}
return (
<Box sx={{ p: 3 }}>
<Box sx={{ display: 'flex', mb: '1rem' }}>
<Typography variant="h4" flex={1} gutterBottom>
Retailer Details
</Typography>
<Button
onClick={() => navigate('/kyc')}
color="primary"
sx={{ padding: '0.5rem 1rem' }}
variant="contained"
>
Back
</Button>
</Box>
<Paper sx={{ p: 2, mb: 3 }}>
<Typography variant="h5" gutterBottom>
Retailer Details
</Typography>
<Grid container spacing={2}>
<Grid item xs={6}>
<Typography>
<strong>Trade Name:</strong> {retailerDetails.trade_name}
</Typography>
<Typography>
<strong>Name:</strong> {retailerDetails.name}
</Typography>
<Typography>
<strong>Address:</strong> {retailerDetails.address}
</Typography>
<Typography>
<strong>Town/City:</strong> {retailerDetails.city}
</Typography>
</Grid>
<Grid item xs={6}>
<Typography>
<strong>District:</strong> {retailerDetails.district}
</Typography>
<Typography>
<strong>State:</strong> {retailerDetails.state}
</Typography>
<Typography>
<strong>Pincode:</strong> {retailerDetails.pincode}
</Typography>
<Typography>
<strong>Mobile Number:</strong> {retailerDetails.mobile_number}
</Typography>
<Typography>
<strong>Mapped Principal Distributor:</strong>{' '}
{retailerDetails.principal_distributer.name}
</Typography>
</Grid>
</Grid>
</Paper>
<Paper sx={{ p: 2, mb: 3 }}>
<Typography variant="h6" gutterBottom>
Documents
</Typography>
<Grid container spacing={2}>
<Grid item xs={6}>
<Typography>
<strong>PAN Number:</strong> {retailerDetails.pan_number}
</Typography>
<Avatar
variant="square"
src={retailerDetails.pan_img.url}
sx={{ width: 100, height: 100, mb: 2 }}
onClick={() => handleImageClick(retailerDetails.pan_img.url)}
/>
<Typography>
<strong>Aadhar Number:</strong> {retailerDetails.aadhar_number}
</Typography>
<Avatar
variant="square"
src={retailerDetails.aadhar_img.url}
sx={{ width: 100, height: 100, mb: 2 }}
onClick={() => handleImageClick(retailerDetails.aadhar_img.url)}
/>
<Typography>
<strong>GST Number:</strong> {retailerDetails.gst_number}
</Typography>
<Avatar
variant="square"
src={retailerDetails.gst_img.url}
sx={{ width: 100, height: 100, mb: 2 }}
onClick={() => handleImageClick(retailerDetails.gst_img.url)}
/>
</Grid>
<Grid item xs={6}>
<Typography>
<strong>Pesticide License:</strong>
</Typography>
<Avatar
variant="square"
src={retailerDetails.pesticide_license_img.url}
sx={{ width: 100, height: 100, mb: 2 }}
onClick={() => handleImageClick(retailerDetails.pesticide_license_img.url)}
/>
<Typography>
<strong>Fertilizer License (optional):</strong>
</Typography>
{retailerDetails.fertilizer_license_img ? (
<Avatar
variant="square"
src={retailerDetails.fertilizer_license_img.url}
sx={{ width: 100, height: 100, mb: 2 }}
onClick={() => handleImageClick(retailerDetails.fertilizer_license_img.url)}
/>
) : (
<Typography>Img not available</Typography>
)}
<Typography>
<strong>Selfie of Entrance Board:</strong>
</Typography>
<Avatar
variant="square"
src={retailerDetails.selfie_entrance_img.url}
sx={{ width: 100, height: 100, mb: 2 }}
onClick={() => handleImageClick(retailerDetails.selfie_entrance_img.url)}
/>
</Grid>
</Grid>
</Paper>
<Paper sx={{ p: 2, mb: 3 }}>
<Typography variant="h6" gutterBottom>
Sales Coordinators/Territory Manager Details
</Typography>
<Grid container spacing={2}>
<Grid item xs={6}>
<Typography>
<strong>Designation:</strong>{' '}
{retailerDetails.userType === 'SalesCoOrdinator'
? 'Sales Coordinator'
: 'Territory Manager'}
</Typography>
<Typography>
<strong>Name:</strong> {retailerDetails.addedBy.name}
</Typography>
<Typography>
<strong>Employee ID:</strong> {retailerDetails.addedBy.uniqueId}
</Typography>
</Grid>
<Grid item xs={6}>
<Typography>
<strong>Uploaded on:</strong>{' '}
{/* {new Date(`${retailerDetails?.createdAt}`).toDateString()} */}
{`${formatDateWithoutComma(retailerDetails?.createdAt)}`}
<span> , {`${formatAMPM(retailerDetails?.createdAt)}`}</span>
</Typography>
<Typography>
<strong>Resubmitted on:</strong>{' '}
{/* {new Date(`${retailerDetails?.updatedAt}`).toDateString()} */}
{`${formatDateWithoutComma(retailerDetails?.updatedAt)}`}
<span> , {`${formatAMPM(retailerDetails?.createdAt)}`}</span>
</Typography>
</Grid>
</Grid>
</Paper>
{retailerDetails.notes.length > 0 && retailerDetails.status === 'reject' && (
<Paper sx={{ p: 2, mb: 3 }}>
<Typography variant="h6" gutterBottom>
Notes:
</Typography>
<MessageList messages={retailerDetails.notes} />
<TextField
fullWidth
multiline
rows={4}
value={msg}
onChange={(e) => setMsg(e.target.value)}
variant="outlined"
label="send message"
/>
<Button
variant="contained"
sx={{ textTransform: 'unset', mt: '2rem' }}
onClick={() => handelSend()}
>
Send
</Button>
</Paper>
)}
{retailerDetails.status === 'new' && (
<>
<Modal
open={openRejectModal}
onClose={handleModalClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={{ ...modalStyle, width: 400 }}>
<h2 id="modal-modal-title">Rejection Reason</h2>
<TextField
fullWidth
multiline
rows={4}
value={rejectionReason}
onChange={handleRejectionReasonChange}
variant="outlined"
label="Enter rejection reason"
/>
<DialogActions>
<Button onClick={handleModalClose} sx={{ textTransform: 'unset' }} color="primary">
Cancel
</Button>
<Button
onClick={handleRejectConfirm}
sx={{ textTransform: 'unset' }}
color="error"
variant="contained"
>
Confirm
</Button>
</DialogActions>
</Box>
</Modal>
<Modal
open={openApproveModal}
onClose={handleModalClose}
aria-labelledby="modal-modal-title"
aria-describedby="modal-modal-description"
>
<Box sx={{ ...modalStyle, width: 400 }}>
<h2 id="modal-modal-title">Approval Confirmation</h2>
<Typography id="modal-modal-description" sx={{ mt: 2 }}>
Are you sure you want to approve this KYC?
</Typography>
<DialogActions>
<Button onClick={handleModalClose} sx={{ textTransform: 'unset' }} color="primary">
Cancel
</Button>
<Button
onClick={handleApproveConfirm}
sx={{ textTransform: 'unset' }}
color="success"
variant="contained"
>
Confirm
</Button>
</DialogActions>
</Box>
</Modal>
<Paper sx={{ p: 2, mb: 3 }}>
<Button
sx={{ mr: '1rem', textTransform: 'unset' }}
color="success"
variant="contained"
onClick={handleApproveClick}
>
Approve
</Button>
<Button
sx={{ mr: '1rem', textTransform: 'unset' }}
color="error"
variant="contained"
onClick={handleRejectClick}
>
Reject
</Button>
</Paper>
</>
)}
<ImgModal
open={openImageModal}
handleClose={() => setOpenImageModal(false)}
imageUrl={selectedImageUrl}
/>
</Box>
)
}
const modalStyle = {
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
bgcolor: 'background.paper',
boxShadow: 24,
p: 4,
}
export default KycDetails

View File

@ -0,0 +1,167 @@
import {
Box,
Button,
FormControl,
FormControlLabel,
Grid,
InputLabel,
MenuItem,
Radio,
RadioGroup,
Select,
Typography,
FormHelperText,
} from '@mui/material'
import React, { useState } from 'react'
const AddressAndPayment = ({
billTo,
setBillTo,
shipTo,
setShipTo,
paymentMode,
setPaymentMode,
handleTabChange,
}) => {
const [billToError, setBillToError] = useState(false)
const [shipToError, setShipToError] = useState(false)
const [paymentModeError, setPaymentModeError] = useState(false)
const handleReviewOrderClick = (e) => {
let isValid = true
// Check if Bill Address is filled
if (billTo === '') {
setBillToError(true)
isValid = false
} else {
setBillToError(false)
}
// Check if Ship Address is filled
if (shipTo === '') {
setShipToError(true)
isValid = false
} else {
setShipToError(false)
}
// Check if Payment Mode is selected
if (paymentMode === '') {
setPaymentModeError(true)
isValid = false
} else {
setPaymentModeError(false)
}
// If all fields are valid, move to the next tab
if (isValid) {
handleTabChange(e, 2)
}
}
return (
<div>
<Box sx={{ my: '2rem', background: '#fff', padding: '1rem', borderRadius: '0.8rem' }}>
<Typography variant="h4" textAlign={'center'} marginBottom={2}>
Select Address and Payment Mode
</Typography>
<Grid container spacing={3}>
<Grid item sm={6} md={6} lg={6}>
<Typography sx={{ mb: '0.5rem' }}>Bill Address</Typography>
<FormControl required fullWidth error={billToError}>
<InputLabel id="bill-address-label">Bill Address</InputLabel>
<Select
labelId="bill-address-label"
id="bill-address-select"
required
value={billTo}
label="Bill Address"
onChange={(e) => setBillTo(e.target.value)}
>
<MenuItem value={'123, MG Road, Bengaluru, Karnataka - 560001'}>
123, MG Road, Bengaluru, Karnataka - 560001
</MenuItem>
<MenuItem value={'456, Park Street, Kolkata, West Bengal - 700016'}>
456, Park Street, Kolkata, West Bengal - 700016
</MenuItem>
<MenuItem value={'789, Connaught Place, New Delhi - 110001'}>
789, Connaught Place, New Delhi - 110001
</MenuItem>
</Select>
{billToError && <FormHelperText>Bill Address is required</FormHelperText>}
</FormControl>
</Grid>
<Grid item sm={6} md={6} lg={6}>
<Typography sx={{ mb: '0.5rem' }}>Ship Address</Typography>
<FormControl required fullWidth error={shipToError}>
<InputLabel id="ship-address-label">Ship Address</InputLabel>
<Select
labelId="ship-address-label"
id="ship-address-select"
value={shipTo}
label="Ship Address"
onChange={(e) => setShipTo(e.target.value)}
>
<MenuItem value={'123, MG Road, Bengaluru, Karnataka - 560001'}>
123, MG Road, Bengaluru, Karnataka - 560001
</MenuItem>
<MenuItem value={'456, Park Street, Kolkata, West Bengal - 700016'}>
456, Park Street, Kolkata, West Bengal - 700016
</MenuItem>
<MenuItem value={'789, Connaught Place, New Delhi - 110001'}>
789, Connaught Place, New Delhi - 110001
</MenuItem>
</Select>
{shipToError && <FormHelperText>Ship Address is required</FormHelperText>}
</FormControl>
</Grid>
{billTo !== '' && (
<Grid item sm={6} md={6} lg={6}>
<Typography variant="h5" sx={{ mb: '0.5rem' }}>
Selected Bill Address
</Typography>
<Typography sx={{ mb: '0.5rem' }}>{billTo}</Typography>
</Grid>
)}
{shipTo !== '' && (
<Grid item sm={6} md={6} lg={6}>
<Typography variant="h5" sx={{ mb: '0.5rem' }}>
Selected Ship to Address
</Typography>
<Typography sx={{ mb: '0.5rem' }}>{shipTo}</Typography>
</Grid>
)}
<Grid item sm={12} md={12} lg={12}>
<Typography>Payment Mode</Typography>
<FormControl component="fieldset" error={paymentModeError}>
<RadioGroup value={paymentMode} onChange={(e) => setPaymentMode(e.target.value)}>
<FormControlLabel
value="online-transfer"
control={<Radio />}
label="Online Transfer"
/>
<FormControlLabel value="cheque" control={<Radio />} label="Cheque" />
<FormControlLabel value="credit" control={<Radio />} label="Credit" />
</RadioGroup>
{paymentModeError && <FormHelperText>Payment Mode is required</FormHelperText>}
</FormControl>
</Grid>
</Grid>
<Box sx={{ display: 'flex', justifyContent: 'center', my: 4 }}>
<Button
variant="contained"
size="large"
color="primary"
onClick={handleReviewOrderClick}
sx={{ width: '200px' }}
>
View Order
</Button>
</Box>
</Box>
</div>
)
}
export default AddressAndPayment

View File

@ -0,0 +1,251 @@
import React, { useEffect, useState } from 'react'
import { Box, Button, colors, Container, IconButton, Tab, Tabs, Typography } from '@mui/material'
import CheckIcon from '@mui/icons-material/Check'
// import ShoppingCart from '../../Components/ShoppingCart'
// import CheckoutDetails from '../../Components/CheckoutDetails'
// import OrderComplete from '../../Components/OrderComplete'
import PropTypes from 'prop-types'
import Checkout from './addressAndPayment'
import ShopingCart from './shopingCart'
import OrderComplete from './orderConfirmation'
import AddressAndPayment from './addressAndPayment'
import Swal from 'sweetalert2'
import ReviewOrder from './reviewOrder'
import OrderConfirmation from './orderConfirmation'
import { useDispatch, useSelector } from 'react-redux'
import {
clearCart,
loadCart,
selectCartItemCount,
selectCartItems,
selectCartSubtotal,
} from '../../../redux-store/CartStore/ducs'
const TabItem = ({ label, active, complete, onClick, reference, stepNumber }) => (
<Box
ref={reference}
onClick={onClick}
sx={{
minWidth: '256px',
display: 'flex',
alignItems: 'center',
pb: '1rem',
cursor: 'pointer',
borderBottom: complete ? '2px solid #45B26B' : active ? '2px solid black' : '',
}}
>
<IconButton
sx={{
background: complete ? '#45B26B' : active ? '#000' : '#B1B5C3',
marginRight: '1rem',
}}
>
{complete ? (
<CheckIcon sx={{ color: 'white' }} />
) : (
<Typography
color={active ? 'white' : complete ? '#45B26B' : '#FCFCFD'}
width={30}
height={30}
borderRadius={'50%'}
>
{stepNumber}
</Typography>
)}
</IconButton>
<Typography
sx={{
fontFamily: 'inter',
fontSize: '1rem',
fontWeight: 'bold',
color: complete ? '#45B26B' : active ? 'black' : '#B1B5C3',
}}
>
{label}
</Typography>
</Box>
)
TabItem.propTypes = {
label: PropTypes.string.isRequired,
active: PropTypes.bool.isRequired,
complete: PropTypes.bool.isRequired,
onClick: PropTypes.func.isRequired,
reference: PropTypes.object.isRequired,
stepNumber: PropTypes.number.isRequired,
}
const styles = {
tab: {
backgroundColor: '#FFFFFF',
color: 'black',
padding: '0px 25px',
textAlign: 'center',
textTransform: 'none',
textDecoration: 'none',
minWidth: 50,
'&.Mui-selected': {
backgroundColor: '#007FFF',
border: 'none',
color: 'white',
textAlign: 'center',
textDecoration: 'none',
},
},
tabs: {
// maxWidth: 355,
borderRadius: 20,
maxHeight: 50,
'&.MuiTabs-root': {
minHeight: 0,
},
},
}
const Cart = () => {
const [shipTo, setShipTo] = useState('')
const [billTo, setBillTo] = useState('')
const dispatch = useDispatch()
const [paymentMode, setPaymentMode] = useState('')
const cartItems = useSelector(selectCartItems)
const totalItemCount = useSelector(selectCartItemCount)
const cartSubtotal = useSelector(selectCartSubtotal)
const [value, setValue] = useState(0)
const handleTabChange = (event, newValue) => {
console.log(newValue)
if (value === 3 && newValue !== 3) {
setPaymentMode('')
setBillTo('')
setShipTo('')
dispatch(clearCart())
}
if (newValue === 1 && cartItems.length === 0) {
Swal.fire('Cart is emplty ,can not move to next screen pls add items to cart ')
return
}
if (newValue === 2 && (shipTo === '' || billTo === '' || paymentMode === '')) {
Swal.fire('Fill all the details ,can not move to next screen ')
return
}
if (newValue === 3 && (shipTo === '' || billTo === '' || paymentMode === '')) {
Swal.fire('Fill all the details ,can not move to next screen ')
return
}
setValue(newValue)
}
// const handleAddressAndOrderClick = () => {
// if (cartItems.length === 0) {
// Swal.fire('Cart is emplty can not move to next screen pls add items to cart ')
// return
// }
// setValue(1)
// }
const [orderId, setOrderId] = useState(null)
// const [cartItem, setCartItem] = useState([
// {
// product: {
// _id: '1',
// name: 'Product 1',
// image: [
// {
// url: 'https://images.pexels.com/photos/341523/pexels-photo-341523.jpeg?auto=compress&cs=tinysrgb&w=600',
// },
// ],
// variant: { price: 100, gst_Id: { tax: 5 } },
// hsn: '1234',
// },
// quantity: 2,
// subtotal: 200,
// },
// {
// product: {
// _id: '2',
// name: 'Product 2',
// image: [
// {
// url: 'https://images.pexels.com/photos/341523/pexels-photo-341523.jpeg?auto=compress&cs=tinysrgb&w=600',
// },
// ],
// variant: { price: 150, gst_Id: { tax: 5 } },
// hsn: '5678',
// },
// quantity: 1,
// subtotal: 150,
// },
// ])
return (
<Container>
<Tabs
value={value}
indicatorColor="primary"
textColor="primary"
onChange={handleTabChange}
TabIndicatorProps={{
style: {
backgroundColor: 'white',
display: 'none',
},
}}
sx={styles.tabs}
>
<Tab label="Cart " value={0} sx={styles.tab} />
<Tab label="Address and Payment Mode" value={1} sx={styles.tab} />
<Tab label="Review Order" value={2} sx={styles.tab} />
<Tab label="Order Confirmation" value={3} sx={styles.tab} />
</Tabs>
{value === 0 &&
(cartItems.length === 0 ? (
<Typography sx={{ m: '2rem ', background: '#FFF', padding: '1rem' }}>
No items available. Please add items to the cart.
</Typography>
) : (
<Box>
<ShopingCart cartItems={cartItems} handleTabChange={handleTabChange} />
</Box>
))}
{value === 1 && (
<Box>
<AddressAndPayment
billTo={billTo}
setBillTo={setBillTo}
shipTo={shipTo}
setShipTo={setShipTo}
paymentMode={paymentMode}
setPaymentMode={setPaymentMode}
handleTabChange={handleTabChange}
/>
</Box>
)}
{value === 2 && (
<Box>
<ReviewOrder
billTo={billTo}
shipTo={shipTo}
paymentMode={paymentMode}
orderId={orderId}
setOrderId={setOrderId}
cartItem={cartItems}
handleTabChange={handleTabChange}
/>
</Box>
)}
{value === 3 && (
<Box>
<OrderConfirmation
billTo={billTo}
shipTo={shipTo}
paymentMode={paymentMode}
orderId={orderId}
cartItem={cartItems}
/>
</Box>
)}
</Container>
)
}
export default Cart

View File

@ -0,0 +1,159 @@
import {
Box,
Container,
Grid,
Paper,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Typography,
} from '@mui/material'
import React, { useEffect, useState } from 'react'
import { useSelector } from 'react-redux'
import { selectCartSubtotal } from '../../../redux-store/CartStore/ducs'
import { isAutheticated } from '../../../auth'
import Axios from '../../../axios'
const OrderConfirmation = ({ orderId, billTo, shipTo, paymentMode, cartItem }) => {
const subtotal = useSelector(selectCartSubtotal)
const [ownerDetails, setOwnerDetails] = useState()
const token = isAutheticated()
const getData = async () => {
let res = await Axios.get(`/api/v1/user/details`, {
headers: {
Authorization: `Bearer ${token}`,
},
})
if (res.data.success) {
setOwnerDetails({ ...res.data.user })
}
}
useEffect(() => {
getData()
}, [])
// Calculate total GST for the entire cart
const totalGST = cartItem.reduce((acc, item) => {
// console.log(item)
const gstAmount = (item.price * item.GST) / 100
return acc + gstAmount * item.count
}, 0)
return (
<Box>
<Box sx={{ my: '2rem', background: '#fff', padding: '1rem', borderRadius: '0.8rem' }}>
<Typography variant="h4" textAlign={'center'} marginBottom={2}>
OrderId : {orderId}
</Typography>
<Grid container spacing={2}>
<Grid item sm={6} md={6} lg={6}>
<Typography variant="h5" sx={{ mb: '0.5rem' }}>
Bill Address
</Typography>
<Typography sx={{ mb: '0.5rem' }}>{billTo}</Typography>
</Grid>
<Grid item sm={6} md={6} lg={6}>
<Typography variant="h5" sx={{ mb: '0.5rem' }}>
Ship Address
</Typography>
<Typography sx={{ mb: '0.5rem' }}>{shipTo}</Typography>
</Grid>
<Grid item sm={6} md={6} lg={6}>
<Typography variant="h5" sx={{ mb: '0.5rem' }}>
Payment mode : <strong>{paymentMode}</strong>
</Typography>
</Grid>
<Grid item sm={12} md={12} lg={12}>
<Typography variant="h5" sx={{ mb: '0.5rem' }}>
SBU: <strong>{ownerDetails?.SBU}</strong>
</Typography>
</Grid>
</Grid>
</Box>
<Box my={8}>
<Grid container spacing={5}>
<Grid item xs={12}>
<Box>
<TableContainer
component={Paper}
elevation={0}
sx={{ borderBottom: '1.5px solid #CFCFD5', borderRadius: 0 }}
>
<Table sx={{ minWidth: 650 }} size="large">
<TableHead>
<TableRow>
<TableCell sx={{ fontWeight: 'bold' }}>Product</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Category</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Brand</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>SKU</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Quantity</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Price</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>GST</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Subtotal</TableCell>
</TableRow>
</TableHead>
<TableBody>
{cartItem.map((row, index) => {
const gstAmount = (row.price * row.GST) / 100
return (
<TableRow
key={index}
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
>
<TableCell>
<Box sx={{ display: 'flex' }}>
{/* <img
src={row.product.image[0].url}
alt={row.product.name}
style={{ width: '100px', height: '70px', marginRight: '1rem' }}
/> */}
<Box>
<Typography fontWeight={600}>{row.name}</Typography>
</Box>
</Box>
</TableCell>
<TableCell>{row.category.categoryName}</TableCell>
<TableCell>{row.brand.brandName}</TableCell>
<TableCell>{row.SKU}</TableCell>
<TableCell>{row.count}</TableCell>
<TableCell>{row.price}</TableCell>
<TableCell>{gstAmount}</TableCell>
<TableCell>{row.price * row.count}</TableCell>
</TableRow>
)
})}
<TableRow>
<TableCell colSpan={7} />
<TableCell>
Subtotal:<strong> {subtotal}</strong>
</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={7} />
<TableCell>
Total GST:<strong> {totalGST} </strong>
</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={7} />
<TableCell>
Grand Total: <strong> {subtotal + totalGST}</strong>
</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
</Box>
</Grid>
</Grid>
</Box>
</Box>
)
}
export default OrderConfirmation

View File

@ -0,0 +1,196 @@
import {
Box,
Button,
Container,
Grid,
Paper,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Typography,
} from '@mui/material'
import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { clearCart, selectCartSubtotal } from '../../../redux-store/CartStore/ducs'
import Axios from '../../../axios'
import { isAutheticated } from '../../../auth'
import Swal from 'sweetalert2'
const ReviewOrder = ({
orderId,
billTo,
shipTo,
paymentMode,
cartItem,
handleTabChange,
setOrderId,
}) => {
const subtotal = useSelector(selectCartSubtotal)
const token = isAutheticated()
const dispatch = useDispatch()
// Calculate total GST for the entire cart
const totalGST = cartItem.reduce((acc, item) => {
// console.log(item)
const gstAmount = (item.price * item.GST) / 100
return acc + gstAmount * item.count
}, 0)
const handleConfirmOrder = async (e) => {
e.preventDefault()
if (!billTo || !shipTo || !paymentMode || !cartItem || !subtotal || !totalGST) {
Swal.fire('All fields are required ')
}
try {
const res = await Axios.post(
'/api/order-place',
{
billTo,
shipTo,
paymentMode,
grandTotal: subtotal + totalGST,
gstTotal: totalGST,
subtotal: subtotal,
orderItems: cartItem,
},
{
headers: {
'Access-Control-Allow-Origin': '*',
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
},
)
console.log(res)
if (res.status === 201) {
setOrderId(res?.data?.placedOrder?.uniqueId)
console.log(res)
Swal.fire('Success!', 'Your order has been placed successfully.', 'success')
handleTabChange(e, 3)
}
} catch (error) {
Swal.fire('Something went wrong', error.message, 'error')
}
}
console.log('cartitems', cartItem)
return (
<Box>
<Box sx={{ my: '2rem', background: '#fff', padding: '1rem', borderRadius: '0.8rem' }}>
<Grid container spacing={2}>
<Grid item sm={6} md={6} lg={6}>
<Typography variant="h5" sx={{ mb: '0.5rem' }}>
Bill Address
</Typography>
<Typography sx={{ mb: '0.5rem' }}>{billTo}</Typography>
</Grid>
<Grid item sm={6} md={6} lg={6}>
<Typography variant="h5" sx={{ mb: '0.5rem' }}>
Ship Address
</Typography>
<Typography sx={{ mb: '0.5rem' }}>{shipTo}</Typography>
</Grid>
<Grid item sm={6} md={6} lg={6}>
<Typography variant="h5" sx={{ mb: '0.5rem' }}>
Payment mode : <strong>{paymentMode}</strong>
</Typography>
</Grid>
</Grid>
</Box>
<Box my={4}>
<Grid container spacing={5}>
<Grid item xs={12}>
<Box>
<TableContainer
component={Paper}
elevation={0}
sx={{ borderBottom: '1.5px solid #CFCFD5', borderRadius: 0 }}
>
<Table sx={{ minWidth: 650 }} size="large">
<TableHead>
<TableRow>
<TableCell sx={{ fontWeight: 'bold' }}>Product</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Category</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Brand</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>SKU</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Quantity</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Price</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>GST</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Subtotal</TableCell>
</TableRow>
</TableHead>
<TableBody>
{cartItem.map((row, index) => {
const gstAmount = (row.price * row.GST) / 100
return (
<TableRow
key={index}
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
>
<TableCell>
<Box sx={{ display: 'flex' }}>
{/* <img
src={row.product.image[0].url}
alt={row.product.name}
style={{ width: '100px', height: '70px', marginRight: '1rem' }}
/> */}
<Box>
<Typography fontWeight={600}>{row.name}</Typography>
</Box>
</Box>
</TableCell>
<TableCell>{row.category.categoryName}</TableCell>
<TableCell>{row.brand.brandName}</TableCell>
<TableCell>{row.SKU}</TableCell>
<TableCell>{row.count}</TableCell>
<TableCell>{row.price}</TableCell>
<TableCell>{gstAmount}</TableCell>
<TableCell>{row.price * row.count}</TableCell>
</TableRow>
)
})}
<TableRow>
<TableCell colSpan={7} />
<TableCell>
Subtotal:<strong> {subtotal}</strong>
</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={7} />
<TableCell>
Total GST:<strong> {totalGST} </strong>
</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={7} />
<TableCell>
Grand Total: <strong> {subtotal + totalGST}</strong>
</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
</Box>
</Grid>
</Grid>
<Box display={'flex'} justifyContent={'center'} mt={4} gap={10}>
<Button variant="contained" color="primary" onClick={(e) => handleTabChange(e, 0)}>
Update Order
</Button>
<Button variant="contained" color="success" onClick={handleConfirmOrder}>
Confirm Order
</Button>
</Box>
</Box>
</Box>
)
}
export default ReviewOrder

View File

@ -0,0 +1,191 @@
import React from 'react'
import {
Box,
Container,
Grid,
Paper,
Typography,
Button,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
useMediaQuery,
} from '@mui/material'
import ClearIcon from '@mui/icons-material/Clear'
import { useDispatch, useSelector } from 'react-redux'
import {
selectCartItems,
selectCartSubtotal,
increaseCount,
decreaseCount,
removeFromCart,
selectCartItemCount,
} from '../../../redux-store/CartStore/ducs' // Adjust this path as per your project structure
const ShoppingCart = ({ handleTabChange }) => {
const matches = useMediaQuery('(min-width:1200px)')
const dispatch = useDispatch()
// Fetching cart items and subtotal from the Redux store
const cartItems = useSelector(selectCartItems)
const subtotal = useSelector(selectCartSubtotal)
console.log(cartItems)
// Calculate total GST for the entire cart
const totalGST = cartItems.reduce((acc, item) => {
// console.log(item)
const gstAmount = (item.price * item.GST) / 100
return acc + gstAmount * item.count
}, 0)
const handleDecrease = (productId) => {
dispatch(decreaseCount(productId))
}
const handleIncrease = (productId) => {
dispatch(increaseCount(productId))
}
const removeCartItemHandler = (productId) => {
dispatch(removeFromCart(productId))
}
return (
<Box>
<Container>
<Box my={8}>
<Grid container spacing={5}>
<Grid item xs={12}>
<Box>
<TableContainer
component={Paper}
elevation={0}
sx={{ borderBottom: '1.5px solid #CFCFD5', borderRadius: 0 }}
>
<Table sx={{ minWidth: 650 }} size="large">
<TableHead>
<TableRow>
<TableCell sx={{ fontWeight: 'bold' }}>Product</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>SKU</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Quantity</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Price</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>GST</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Subtotal</TableCell>
</TableRow>
</TableHead>
<TableBody>
{cartItems.map((row, index) => {
const gstAmount = (row.price * row.GST) / 100
return (
<TableRow
key={index}
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
>
<TableCell>
<Box sx={{ display: 'flex' }}>
{/* <img
src={row.product.image[0].url}
alt={row.product.name}
style={{ width: '100px', height: '70px', marginRight: '1rem' }}
/> */}
<Box>
<Typography fontWeight={600}>{row.name}</Typography>
<Box
onClick={() => removeCartItemHandler(row._id)}
sx={{
display: 'flex',
alignItems: 'center',
cursor: 'pointer',
color: '#6C7275',
marginTop: '0.5rem',
}}
>
<ClearIcon fontSize="small" />
<Typography>Remove</Typography>
</Box>
</Box>
</Box>
</TableCell>
<TableCell>{row.SKU}</TableCell>
<TableCell>
<Box
sx={{
display: 'flex',
alignItems: 'center',
border: '1px solid #6C7275',
borderRadius: '4px',
width: '80px',
justifyContent: 'space-between',
}}
>
<Typography
onClick={() => handleDecrease(row._id)}
sx={{ cursor: 'pointer', padding: '0.5rem' }}
>
-
</Typography>
<Typography>{row.count}</Typography>
<Typography
onClick={() => handleIncrease(row._id)}
sx={{ cursor: 'pointer', padding: '0.5rem' }}
>
+
</Typography>
</Box>
</TableCell>
<TableCell>{row.price}</TableCell>
<TableCell>{gstAmount}</TableCell>
<TableCell>{row.price * row.count}</TableCell>
</TableRow>
)
})}
<TableRow>
<TableCell colSpan={5} />
<TableCell>
Subtotal:<strong> {subtotal}</strong>
</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={5} />
<TableCell>
Total GST:<strong> {totalGST} </strong>
</TableCell>
</TableRow>
<TableRow>
<TableCell colSpan={5} />
<TableCell>
Grand total: <strong> {subtotal + totalGST}</strong>
</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
</Box>
</Grid>
</Grid>
</Box>
</Container>
<Box sx={{ display: 'flex', justifyContent: 'center', my: 4 }}>
<Button
variant="contained"
size="large"
color="primary"
onClick={(e) => handleTabChange(e, 1)}
sx={{
width: '200px',
}}
>
Address and payment mode
</Button>
</Box>
</Box>
)
}
export default ShoppingCart

View File

@ -0,0 +1,106 @@
import { cilUser } from '@coreui/icons'
import CIcon from '@coreui/icons-react'
import {
CButton,
CCard,
CCardBody,
CCardGroup,
CCol,
CContainer,
CForm,
CFormInput,
CInputGroup,
CInputGroupText,
CRow,
CSpinner,
} from '@coreui/react'
import React, { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import Swal from 'sweetalert2'
import Axios from '../../axios'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faEnvelope } from '@fortawesome/free-solid-svg-icons'
const ForgetPassword = () => {
const [email, setEmail] = useState('')
const [loading, setLoading] = useState(false)
const navigate = useNavigate()
const handleSubmit = async (e) => {
e.preventDefault()
try {
const res = await Axios.post('/api/forgot-password', { email })
console.log(res)
if (res?.status === 200) {
Swal.fire('success', res?.data?.message, 'success')
navigate('/login')
} else if (res?.status === 305) {
Swal.fire('error', res?.data?.message, 'error')
}
} catch (err) {
Swal.fire('error', 'User Not found with this email ', 'error')
}
}
return (
<>
<div className="bg-body-tertiary min-vh-100 d-flex flex-row align-items-center">
<CContainer>
<CRow className="justify-content-center">
<CCol md={8}>
<CCardGroup>
<CCard className="p-4">
<CCardBody>
<CForm onSubmit={handleSubmit}>
<h1>Forget Password</h1>
<p className="text-body-secondary">
Enter your email we will send you the password
</p>
<CInputGroup className="mb-3">
<CInputGroupText>
<FontAwesomeIcon icon={faEnvelope} />
</CInputGroupText>
<CFormInput
type="email"
required
placeholder="abc@gmail.com"
onChange={(e) => setEmail(e.target.value)}
value={email}
name="email"
autoComplete="email"
/>
</CInputGroup>
<CRow>
<CCol xs={12}>
<CButton
color="primary"
type="submit"
style={{ width: '100%' }}
className="px-4"
disabled={loading}
>
{loading ? <CSpinner variant="grow" /> : 'Generate password '}
</CButton>
</CCol>
<CCol xs={6} className="text-right">
<span className="text-body-secondary">
If you know you password? Continue to
</span>
<CButton onClick={() => navigate('/login')} color="link" className="px-2">
Sign in?
</CButton>
</CCol>
</CRow>
</CForm>
</CCardBody>
</CCard>
</CCardGroup>
</CCol>
</CRow>
</CContainer>
</div>
</>
)
}
export default ForgetPassword

View File

@ -0,0 +1,195 @@
import React, { useEffect, useState } from 'react'
import { Link, useNavigate } from 'react-router-dom'
import {
CButton,
CCard,
CCardBody,
CCardGroup,
CCol,
CContainer,
CForm,
CFormInput,
CInputGroup,
CInputGroupText,
CRow,
CSpinner,
} from '@coreui/react'
import CIcon from '@coreui/icons-react'
import { cilLockLocked, cilUser } from '@coreui/icons'
// import axios from 'axios'
import Axios from '../../../axios'
import Swal from 'sweetalert2'
import { clearCart } from '../../../redux-store/CartStore/ducs'
import { useDispatch } from 'react-redux'
const Login = () => {
const [loading, setLoading] = useState(false)
const [validForm, setValidForm] = useState(false)
const dispatch = useDispatch()
const navigate = useNavigate()
const [auth, setAuth] = useState({
email: '',
password: '',
})
const [errors, setErrors] = useState({
emailError: '',
passwordError: '',
})
const validEmailRegex = RegExp(
/^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i,
)
const validPasswordRegex = RegExp(/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\w\s]).{7,}$/)
// const history = useNavigate()
// const handleChange = (e) => (event) => {
// setAuth({ ...auth, [e]: event.target.value });
// };
const validateForm = () => {
let valid = true
Object.values(errors).forEach((val) => {
if (val.length > 0) {
valid = false
return false
}
})
Object.values(auth).forEach((val) => {
if (val.length <= 0) {
valid = false
return false
}
})
return valid
}
//cheking email and password
useEffect(() => {
if (validateForm()) {
setValidForm(true)
} else {
setValidForm(false)
}
}, [errors])
const handleChange = (e) => {
const { name, value } = e.target
switch (name) {
case 'email':
setErrors({
...errors,
emailError: validEmailRegex.test(value) ? '' : 'Email is not valid!',
})
break
case 'password':
setErrors((errors) => ({
...errors,
passwordError: validPasswordRegex.test(value)
? ''
: 'Password Shoud Be 8 Characters Long, Atleast One Uppercase, Atleast One Lowercase,Atleast One Digit, Atleast One Special Character',
}))
break
default:
break
}
setAuth({ ...auth, [name]: value })
}
const handleSubmit = async (e) => {
if (!(auth.email && auth.password)) {
return Swal.fire('Error!', 'All fields are required', 'error')
}
setLoading(true)
try {
const res = await Axios.post('/api/rd-login', auth)
console.log(res)
if (res.data.success === true) {
localStorage.setItem('authToken', res.data.token)
dispatch(clearCart())
navigate('/dashboard')
setLoading(false)
Swal.fire('success', 'logged in successfully ', 'success')
}
} catch (error) {
setLoading(false)
Swal.fire('Error!', 'Invalid Credentials', error.message)
}
}
return (
<div className="bg-body-tertiary min-vh-100 d-flex flex-row align-items-center">
<CContainer>
<CRow className="justify-content-center">
<CCol md={8}>
<CCardGroup>
<CCard className="p-4">
<CCardBody>
<CForm>
<h1>Login</h1>
<p className="text-body-secondary">Sign In to your account</p>
<CInputGroup className="mb-3">
<CInputGroupText>
<CIcon icon={cilUser} />
</CInputGroupText>
<CFormInput
type="email"
placeholder="Email"
onChange={handleChange}
value={auth.email}
name="email"
autoComplete="email"
/>
</CInputGroup>
{errors.emailError && (
<p className="text-center py-2 text-danger">{errors.emailError}</p>
)}
<CInputGroup className="mb-4">
<CInputGroupText>
<CIcon icon={cilLockLocked} />
</CInputGroupText>
<CFormInput
type="password"
name="password"
value={auth.password}
onChange={handleChange}
placeholder="Password"
autoComplete="current-password"
/>
</CInputGroup>
{errors.passwordError && (
<p className="text-center py-2 text-danger">{errors.passwordError}</p>
)}
<CRow>
<CCol xs={6}>
<CButton
color="primary"
type="submit"
className="px-4"
onClick={handleSubmit}
disabled={loading}
>
{loading ? <CSpinner variant="grow" /> : 'Login'}
</CButton>
</CCol>
<CCol xs={6} className="text-right">
<CButton
onClick={() => navigate('/forget-password')}
color="link"
className="px-0"
>
Forgot password?
</CButton>
</CCol>
</CRow>
</CForm>
</CCardBody>
</CCard>
</CCardGroup>
</CCol>
</CRow>
</CContainer>
</div>
)
}
export default Login

View File

@ -0,0 +1,41 @@
import React from 'react'
import {
CButton,
CCol,
CContainer,
CFormInput,
CInputGroup,
CInputGroupText,
CRow,
} from '@coreui/react'
import CIcon from '@coreui/icons-react'
import { cilMagnifyingGlass } from '@coreui/icons'
const Page404 = () => {
return (
<div className="bg-body-tertiary min-vh-100 d-flex flex-row align-items-center">
<CContainer>
<CRow className="justify-content-center">
<CCol md={6}>
<div className="clearfix">
<h1 className="float-start display-3 me-4">404</h1>
<h4 className="pt-3">Oops! You{"'"}re lost.</h4>
<p className="text-body-secondary float-start">
The page you are looking for was not found.
</p>
</div>
<CInputGroup className="input-prepend">
<CInputGroupText>
<CIcon icon={cilMagnifyingGlass} />
</CInputGroupText>
<CFormInput type="text" placeholder="What are you looking for?" />
<CButton color="info">Search</CButton>
</CInputGroup>
</CCol>
</CRow>
</CContainer>
</div>
)
}
export default Page404

View File

@ -0,0 +1,41 @@
import React from 'react'
import {
CButton,
CCol,
CContainer,
CFormInput,
CInputGroup,
CInputGroupText,
CRow,
} from '@coreui/react'
import CIcon from '@coreui/icons-react'
import { cilMagnifyingGlass } from '@coreui/icons'
const Page500 = () => {
return (
<div className="bg-body-tertiary min-vh-100 d-flex flex-row align-items-center">
<CContainer>
<CRow className="justify-content-center">
<CCol md={6}>
<span className="clearfix">
<h1 className="float-start display-3 me-4">500</h1>
<h4 className="pt-3">Houston, we have a problem!</h4>
<p className="text-body-secondary float-start">
The page you are looking for is temporarily unavailable.
</p>
</span>
<CInputGroup className="input-prepend">
<CInputGroupText>
<CIcon icon={cilMagnifyingGlass} />
</CInputGroupText>
<CFormInput type="text" placeholder="What are you looking for?" />
<CButton color="info">Search</CButton>
</CInputGroup>
</CCol>
</CRow>
</CContainer>
</div>
)
}
export default Page500

View File

@ -0,0 +1,117 @@
import React, { useEffect, useState, useRef } from 'react'
import Axios from '../../../axios'
import { isAutheticated } from '../../../auth'
import {
Box,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Paper,
Button,
TextField,
CircularProgress,
Pagination,
} from '@mui/material'
import { Link } from 'react-router-dom'
const ProductManual = () => {
const [loading, setLoading] = useState(true)
const token = isAutheticated()
const [productManuals, setProductManuals] = useState([])
const [currentPage, setCurrentPage] = useState(1)
const [itemsPerPage, setItemsPerPage] = useState(10)
const [totalData, setTotalData] = useState(0)
const titleRef = useRef('')
const getProductManuals = async () => {
try {
setLoading(true)
const response = await Axios.get(`/api/productmanual/getall`, {
headers: { Authorization: `Bearer ${token}` },
params: {
page: currentPage,
show: itemsPerPage,
title: titleRef.current.value || '',
},
})
if (response.status === 200) {
const { productManuals, total } = response.data
setProductManuals(productManuals)
setTotalData(total)
}
} catch (error) {
console.error('Failed to fetch product manuals:', error)
} finally {
setLoading(false)
}
}
useEffect(() => {
getProductManuals()
}, [currentPage, itemsPerPage])
const handleFilterChange = () => {
setCurrentPage(1)
getProductManuals()
}
const handlePageChange = (event, page) => {
setCurrentPage(page)
}
return (
<Box sx={{ padding: 2 }}>
{/* Filter Text Field */}
{/* Table and Pagination */}
{loading ? (
<CircularProgress />
) : (
<>
<TableContainer component={Paper}>
<Table>
<TableHead>
<TableRow>
<TableCell sx={{ fontWeight: 'bold' }}>Name</TableCell>
<TableCell sx={{ fontWeight: 'bold' }}>Action</TableCell>
</TableRow>
</TableHead>
<TableBody>
{productManuals.map((manual) => (
<TableRow key={manual._id}>
<TableCell>{manual.title}</TableCell>
<TableCell>
<Button
variant="contained"
color="primary"
component={Link}
to={`/product-manual/${manual._id}`}
>
View
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
{/* Pagination */}
<Box sx={{ display: 'flex', justifyContent: 'center', mt: 2 }}>
<Pagination
count={Math.ceil(totalData / itemsPerPage)}
page={currentPage}
onChange={handlePageChange}
color="primary"
/>
</Box>
</>
)}
</Box>
)
}
export default ProductManual

View File

@ -0,0 +1,107 @@
import React, { useEffect, useState } from 'react'
import Button from '@mui/material/Button' // Updated import for MUI v5
import { Link, useParams } from 'react-router-dom'
import Swal from 'sweetalert2' // Import SweetAlert2
import axios from 'axios'
import Axios from '../../../axios'
import { isAutheticated } from '../../../auth'
const ViewProductManual = () => {
const [title, setTitle] = useState('')
const [image, setImage] = useState('')
const token = isAutheticated()
const { id } = useParams()
const getproductmanual = async () => {
try {
const res = await Axios.get(`/api/productmanual/getone/${id}`, {
headers: { Authorization: `Bearer ${token}` },
})
setTitle(res?.data?.productManual?.title)
setImage(res?.data?.productManual?.product_manual)
} catch (err) {
console.error(err)
// SweetAlert2 configuration
Swal.fire({
title: 'Error',
text: 'Unable to fetch the product manual',
icon: 'error',
confirmButtonText: 'Retry',
showCancelButton: true,
confirmButtonColor: '#d33',
cancelButtonColor: '#3085d6',
cancelButtonText: 'Cancel',
})
}
}
useEffect(() => {
getproductmanual()
}, [])
return (
<div className="container">
<div className="row">
<div className="col-12">
<div className="page-title-box d-flex align-items-center justify-content-between">
<div style={{ fontSize: '22px' }} className="fw-bold">
View Product Manual
</div>
<div style={{ display: 'flex', gap: '1rem' }}>
<h4 className="mb-0"></h4>
</div>
<div className="page-title-right">
<Link to="/product-manual">
<Button
variant="contained"
color="secondary"
sx={{
fontWeight: 'bold',
mb: 1,
textTransform: 'capitalize',
}}
>
Back
</Button>
</Link>
</div>
</div>
</div>
</div>
<div className="row">
<div className="col-lg-12 col-md-12 col-sm-12 my-1">
<div className="card h-100">
<div className="card-body px-5">
<h4
className="card-title"
style={{
fontWeight: 'bold',
fontSize: '3rem',
marginBottom: '1rem',
textTransform: 'capitalize',
}}
>
{title}
</h4>
<div className="mb-3">
{image &&
(image.url.endsWith('.pdf') ? (
<iframe
src={image.url}
title="Product Manual"
style={{ width: '100%', height: '80vh', border: 'none' }}
/>
) : (
<img src={image.url} alt="blog" style={{ width: '100%', height: '50vh' }} />
))}
</div>
</div>
</div>
</div>
</div>
</div>
)
}
export default ViewProductManual

View File

@ -0,0 +1,212 @@
import React, { useState } from 'react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faAngleLeft, faEnvelope, faLockOpen, faUnlockAlt } from '@fortawesome/free-solid-svg-icons'
import { Col, Row, Form, Card, Button, Container, InputGroup } from '@themesberg/react-bootstrap'
import { Link, useNavigate } from 'react-router-dom'
// import axios from 'axios'
// import { Routes } from '../../routes'
import Swal from 'sweetalert2'
import { isAutheticated } from '../../../auth'
import Axios from '../../../axios'
// import Axios from '../../axios'
const ChangePassword = () => {
const [loading, setLoading] = useState(false)
const navigate = useNavigate()
const token = isAutheticated()
const [user, setUser] = useState({
oldPassword: '',
newPassword: '',
confirmPassword: '',
})
const [errors, setErrors] = useState({
confirmPasswordError: '',
newPasswordError: '',
oldPasswordError: '',
passwordMismatchError: '',
})
const validEmailRegex = RegExp(
/^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i,
)
const validPasswordRegex = RegExp(/^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[^\w\s]).{7,}$/)
const handleChange = (e) => {
const { name, value } = e.target
switch (name) {
case 'oldPassword':
setErrors({
...errors,
oldPasswordError: validPasswordRegex.test(value)
? ''
: 'Password Shoud Be 8 Characters Long, Atleast One Uppercase, Atleast One Lowercase,Atleast One Digit, Atleast One Special Character',
})
break
case 'newPassword':
setErrors({
...errors,
newPasswordError: validPasswordRegex.test(value)
? ''
: 'Password Shoud Be 8 Characters Long, Atleast One Uppercase, Atleast One Lowercase,Atleast One Digit, Atleast One Special Character',
})
break
case 'confirmPassword':
setErrors({
...errors,
confirmPasswordError: validPasswordRegex.test(value)
? ''
: 'Password should be 8 characters long, contain at least one uppercase letter, one lowercase letter, one digit, and one special character',
passwordMismatchError: value !== user.newPassword ? 'Passwords do not match' : '',
})
break
default:
break
}
setUser({ ...user, [name]: value })
}
const handleSubmit = async (e) => {
e.preventDefault()
if (!(user.oldPassword && user.newPassword && user.confirmPassword)) {
return Swal.fire('Error!', 'All fields are required', 'error')
}
if (!(user.newPassword.length >= 8)) {
return Swal.fire('Error!', 'New password must be 8 characters long', 'error')
}
if (user.newPassword !== user.confirmPassword) {
return Swal.fire('Error!', 'New Password and Confirm Password do not match!', 'error')
}
setLoading(true)
try {
const res = await Axios.put(
'/api/rd-password/update',
{ ...user },
{
headers: {
Authorization: `Bearer ${token}`,
},
},
)
console.log(res)
if (res?.data.success) {
Swal.fire({
title: 'Done',
text: 'Password Changed',
icon: 'success',
confirmButtonText: 'ok',
confirmButtonColor: '#303c54',
iconColor: '#303c54',
}).then(() => {
navigate('/dashboard')
})
}
} catch (error) {
Swal.fire('Error!', error.response?.data.message || 'Something went wrong', 'error')
} finally {
setLoading(false)
}
}
return (
<main>
<section className="bg-soft d-flex align-items-center my-5 mt-lg-6 mb-lg-5">
<Container>
<Row className="justify-content-center">
<p className="text-center">
<Card.Link as={Link} to={'/dashboard'} className="text-gray-700">
<FontAwesomeIcon icon={faAngleLeft} className="me-2" /> Back to Dashboard
</Card.Link>
</p>
<Col
xs={12}
style={{ maxWidth: '600px' }}
className="d-flex align-items-center justify-content-center"
>
<div className="bg-white shadow-soft border rounded border-light p-4 p-lg-5 w-100 fmxw-500">
<h3 className="mb-4">Change Password</h3>
<Form onSubmit={handleSubmit}>
<Form.Group id="password" className="mb-4">
<Form.Label>Old Password</Form.Label>
<InputGroup>
<InputGroup.Text>
<FontAwesomeIcon icon={faLockOpen} />
</InputGroup.Text>
<Form.Control
required
type="password"
placeholder="old password"
name="oldPassword"
value={user.oldPassword}
onChange={handleChange}
pattern="^(?=.*[a-z](){}[])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"
title="The password should have 1 upper-case letter, 1 lower-case letter, 1 number, 1 special character and at least 8 characters."
/>
</InputGroup>
</Form.Group>
{errors.oldPasswordError && (
<p className="text-center py-2 text-danger">{errors.oldPasswordError}</p>
)}
<Form.Group id="password" className="mb-4">
<Form.Label>New Password</Form.Label>
<InputGroup>
<InputGroup.Text>
<FontAwesomeIcon icon={faLockOpen} />
</InputGroup.Text>
<Form.Control
required
type="password"
placeholder="new password"
name="newPassword"
value={user.newPassword}
onChange={handleChange}
pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"
title="The password should have 1 upper-case letter, 1 lower-case letter, 1 number, 1 special character and at least 8 characters."
/>
</InputGroup>
</Form.Group>
{errors.newPasswordError && (
<p className="text-center py-2 text-danger">{errors.newPasswordError}</p>
)}
<Form.Group id="password" className="mb-4">
<Form.Label>Confirm Password</Form.Label>
<InputGroup>
<InputGroup.Text>
<FontAwesomeIcon icon={faLockOpen} />
</InputGroup.Text>
<Form.Control
required
type="password"
placeholder="Confirm password"
name="confirmPassword"
value={user.confirmPassword}
onChange={handleChange}
pattern="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$"
title="The password should have 1 upper-case letter, 1 lower-case letter, 1 number, 1 special character and at least 8 characters."
/>
</InputGroup>
</Form.Group>
{errors.confirmPasswordError && (
<p className="text-center py-2 text-danger">{errors.confirmPasswordError}</p>
)}
<Button variant="primary" type="submit" className="w-100">
{loading ? <>Loading...</> : <> Change Password </>}
</Button>
</Form>
</div>
</Col>
</Row>
</Container>
</section>
</main>
)
}
export default ChangePassword

View File

@ -0,0 +1,193 @@
import React, { useEffect, useState } from 'react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import {
faAngleLeft,
faEnvelope,
faLockOpen,
faMobile,
faUnlockAlt,
faUser,
} from '@fortawesome/free-solid-svg-icons'
import { Col, Row, Form, Card, Button, Container, InputGroup } from '@themesberg/react-bootstrap'
import { Link, useNavigate } from 'react-router-dom'
import { isAutheticated } from '../../../auth'
import Axios from '../../../axios'
import Swal from 'sweetalert2'
// import { Axios } from 'axios'
// import Axios from '../../axios'
// import { Routes } from '../../routes'
// import Swal from 'sweetalert2'
const MyProfile = () => {
const [loading, setLoading] = useState(false)
const token = isAutheticated()
const [ownerDetails, setOwnerDetails] = useState({
name: '',
email: '',
mobile_number: '',
})
const history = useNavigate()
const getData = async () => {
let res = await Axios.get(`/api/rd-get-me`, {
headers: {
Authorization: `Bearer ${token}`,
},
})
if (res.data.success) {
console.log(res)
setOwnerDetails({ ...res.data.myData })
}
}
const handleChange = (event) => {
const { name, value } = event.target
setOwnerDetails({ ...ownerDetails, [name]: value })
}
async function handleSubmit(e) {
e.preventDefault()
if (
ownerDetails.name === '' ||
ownerDetails.email === '' ||
ownerDetails.mobile_number === ''
) {
Swal.fire({
title: 'Warning',
text: 'Fill all mandatory fields',
icon: 'error',
button: 'Close',
dangerMode: true,
})
return
}
const formData = new FormData()
formData.append('name', ownerDetails.name)
formData.append('mobile_number', ownerDetails.mobile_number)
setLoading(true)
try {
const res = await Axios.patch(`api/rd-profile/update`, formData, {
headers: {
'Access-Control-Allow-Origin': '*',
Authorization: `Bearer ${token}`,
'Content-Type': 'multipart/formdata',
},
})
if (res.status === 200) {
setLoading(false)
Swal.fire({
title: 'Edited',
text: 'Profile Edited Successfully!',
icon: 'success',
button: 'Return',
})
}
} catch (error) {
const message = error?.response?.data?.message || 'Something went wrong!'
setLoading(false)
Swal.fire({
title: 'Warning',
text: message,
icon: 'error',
button: 'Retry',
dangerMode: true,
})
}
}
console.log(ownerDetails)
const handleCancle = () => {
Navigate('/dashboard')
}
useEffect(() => {
getData()
}, [])
return (
<main>
<section className="bg-soft d-flex align-items-center my-5 mt-lg-6 mb-lg-5">
<Container>
<Row className="justify-content-center">
<p className="text-center">
<Card.Link as={Link} to={'/dashboard'} className="text-gray-700">
<FontAwesomeIcon icon={faAngleLeft} className="me-2" /> Back to Dashboard
</Card.Link>
</p>
<Col xs={12} className="d-flex align-items-center justify-content-center">
<div className="bg-white shadow-soft border rounded border-light p-4 p-lg-5 w-100 fmxw-500">
<h3 className="mb-4">Profile</h3>
<Form onSubmit={handleSubmit}>
<Form.Group id="name" className="mb-4">
<Form.Label>Name</Form.Label>
<InputGroup>
<InputGroup.Text>
<FontAwesomeIcon icon={faUser} />
</InputGroup.Text>
<Form.Control
required
type="text"
placeholder="Your Name"
name="name"
value={ownerDetails.name}
onChange={handleChange}
/>
</InputGroup>
</Form.Group>
<Form.Group id="email" className="mb-4">
<Form.Label>Email</Form.Label>
<InputGroup>
<InputGroup.Text>
<FontAwesomeIcon icon={faEnvelope} />
</InputGroup.Text>
<Form.Control
autoFocus
required
readOnly={true}
type="email"
placeholder="example@gmail.com"
name="email"
value={ownerDetails.email}
onChange={handleChange}
// pattern="[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}"
title="Please enter a valid email address"
/>
</InputGroup>
</Form.Group>
<Form.Group id="mobile" className="mb-4">
<Form.Label>Mobile Number</Form.Label>
<InputGroup>
<InputGroup.Text>
<FontAwesomeIcon icon={faMobile} />
</InputGroup.Text>
<Form.Control
required
type="tel"
placeholder="Your Mobile Number"
name="mobile_number"
value={ownerDetails.mobile_number}
onChange={handleChange}
// pattern="[0-9]{10}" // Assuming a 10-digit mobile number, adjust as needed
title="Please enter a valid 10-digit mobile number"
/>
</InputGroup>
</Form.Group>
<Button variant="primary" type="submit" className="w-100">
{loading ? <>Loading...</> : <>Update</>}
</Button>
</Form>
</div>
</Col>
</Row>
</Container>
</section>
</main>
)
}
export default MyProfile

View File

@ -0,0 +1,71 @@
import React from 'react'
import {
CButton,
CCard,
CCardBody,
CCol,
CContainer,
CForm,
CFormInput,
CInputGroup,
CInputGroupText,
CRow,
} from '@coreui/react'
import CIcon from '@coreui/icons-react'
import { cilLockLocked, cilUser } from '@coreui/icons'
const Register = () => {
return (
<div className="bg-body-tertiary min-vh-100 d-flex flex-row align-items-center">
<CContainer>
<CRow className="justify-content-center">
<CCol md={9} lg={7} xl={6}>
<CCard className="mx-4">
<CCardBody className="p-4">
<CForm>
<h1>Register</h1>
<p className="text-body-secondary">Create your account</p>
<CInputGroup className="mb-3">
<CInputGroupText>
<CIcon icon={cilUser} />
</CInputGroupText>
<CFormInput placeholder="Username" autoComplete="username" />
</CInputGroup>
<CInputGroup className="mb-3">
<CInputGroupText>@</CInputGroupText>
<CFormInput placeholder="Email" autoComplete="email" />
</CInputGroup>
<CInputGroup className="mb-3">
<CInputGroupText>
<CIcon icon={cilLockLocked} />
</CInputGroupText>
<CFormInput
type="password"
placeholder="Password"
autoComplete="new-password"
/>
</CInputGroup>
<CInputGroup className="mb-4">
<CInputGroupText>
<CIcon icon={cilLockLocked} />
</CInputGroupText>
<CFormInput
type="password"
placeholder="Repeat password"
autoComplete="new-password"
/>
</CInputGroup>
<div className="d-grid">
<CButton color="success">Create Account</CButton>
</div>
</CForm>
</CCardBody>
</CCard>
</CCol>
</CRow>
</CContainer>
</div>
)
}
export default Register

139
src/views/shops/Shop.js Normal file
View File

@ -0,0 +1,139 @@
import { useEffect, useRef, useState } from 'react'
import { useDispatch } from 'react-redux'
import Swal from 'sweetalert2'
import Axios from '../../axios'
import {
Box,
CircularProgress,
Container,
FormControl,
Grid,
MenuItem,
Pagination,
Select,
Typography,
} from '@mui/material'
import ShopCard from './shopCard'
const Shop = () => {
const [option, setOption] = useState('all')
const [products, setProducts] = useState([])
const [categories, setCategories] = useState([])
const [loading, setLoading] = useState(true)
const [currentPage, setCurrentPage] = useState(1)
const [totalData, setTotalData] = useState(0)
const itemsPerPage = 10 // Adjust this according to your requirements
const nameRef = useRef('')
const categoryRef = useRef('')
const dispatch = useDispatch()
const handleChange = (event) => {
const selectedValue = event.target.value
setOption(selectedValue)
categoryRef.current = selectedValue === 'all' ? '' : selectedValue // Set to an empty string if "All" is selected
setCurrentPage(1) // Reset to first page when filter changes
}
const getCategories = async () => {
try {
const response = await Axios.get('/api/category/getCategories')
setCategories(response.data?.categories || []) // Assuming the response has a categories property
} catch (err) {
Swal.fire({
title: 'Error',
text: 'Failed to fetch categories',
icon: 'error',
button: 'Retry',
dangerMode: true,
})
}
}
const getProductsData = async () => {
setLoading(true)
try {
const response = await Axios.get('/api/product/getAll/user/', {
params: {
page: currentPage,
show: itemsPerPage,
name: nameRef.current || '',
category: categoryRef.current || '', // Send category only if it's not empty
},
})
setProducts(response.data?.products || [])
setTotalData(response.data?.total_data || 0)
} catch (err) {
const msg = err?.response?.data?.msg || 'Something went wrong!'
Swal.fire({
title: 'Error',
text: msg,
icon: 'error',
button: 'Retry',
dangerMode: true,
})
} finally {
setLoading(false)
}
}
useEffect(() => {
getCategories() // Fetch categories on component mount
getProductsData()
}, [currentPage, option])
const handlePageChange = (event, value) => {
setCurrentPage(value)
}
return (
<Container>
<Typography sx={{ fontWeight: 'bold' }} variant="h4">
Categories
</Typography>
<FormControl sx={{ width: '400px', mt: '1rem' }}>
<Select
labelId="category-select-label"
id="category-select"
value={option}
onChange={handleChange}
>
<MenuItem value="all">All</MenuItem>
{categories.map((category) => (
<MenuItem key={category._id} value={category.categoryName}>
{category.categoryName}
</MenuItem>
))}
</Select>
</FormControl>
<Box mt={3}>
{loading ? (
<CircularProgress />
) : (
<>
<Grid container spacing={2}>
{products.map((item, i) => (
<Grid key={i} item xs={12} sm={6} md={4} lg={4}>
<ShopCard item={item} />
</Grid>
))}
</Grid>
<Box mt={3} display="flex" justifyContent="center">
<Pagination
count={Math.ceil(totalData / itemsPerPage)}
page={currentPage}
onChange={handlePageChange}
color="primary"
/>
</Box>
</>
)}
</Box>
</Container>
)
}
export default Shop

View File

@ -0,0 +1,46 @@
/* eslint-disable react/prop-types */
import { Button, Card, CardContent, CardMedia, Typography } from '@mui/material'
import React from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { addToCart, selectIsProductInCart } from '../../redux-store/CartStore/ducs'
import Swal from 'sweetalert2'
// eslint-disable-next-line react/prop-types
const ShopCard = ({ item }) => {
const dispatch = useDispatch()
const isProductInCart = useSelector(selectIsProductInCart(item._id))
const handleAddToCart = () => {
if (!isProductInCart) {
dispatch(addToCart(item))
Swal.fire('Product added to cart ')
}
}
return (
<div>
<Card>
<CardMedia component="img" height="150" image={item?.image} alt={item?.name} />
<CardContent>
<Typography gutterBottom variant="h5" component="div">
{item?.name}
</Typography>
<Typography variant="body2" color="text.secondary">
${item?.price}
</Typography>
<Button
variant="contained"
color="primary"
fullWidth
disabled={isProductInCart}
// onClick={handleAddToCart}
sx={{ marginTop: '10px' }}
>
{isProductInCart ? 'Already in Cart' : 'Add to Cart'}
</Button>
</CardContent>
</Card>
</div>
)
}
export default ShopCard

View File

@ -0,0 +1,91 @@
import React, { useEffect, useState, createRef } from 'react'
import PropTypes from 'prop-types'
import classNames from 'classnames'
import { CRow, CCol, CCard, CCardHeader, CCardBody } from '@coreui/react'
import { rgbToHex } from '@coreui/utils'
import { DocsLink } from 'src/components'
const ThemeView = () => {
const [color, setColor] = useState('rgb(255, 255, 255)')
const ref = createRef()
useEffect(() => {
const el = ref.current.parentNode.firstChild
const varColor = window.getComputedStyle(el).getPropertyValue('background-color')
setColor(varColor)
}, [ref])
return (
<table className="table w-100" ref={ref}>
<tbody>
<tr>
<td className="text-body-secondary">HEX:</td>
<td className="font-weight-bold">{rgbToHex(color)}</td>
</tr>
<tr>
<td className="text-body-secondary">RGB:</td>
<td className="font-weight-bold">{color}</td>
</tr>
</tbody>
</table>
)
}
const ThemeColor = ({ className, children }) => {
const classes = classNames(className, 'theme-color w-75 rounded mb-3')
return (
<CCol xs={12} sm={6} md={4} xl={2} className="mb-4">
<div className={classes} style={{ paddingTop: '75%' }}></div>
{children}
<ThemeView />
</CCol>
)
}
ThemeColor.propTypes = {
children: PropTypes.node,
className: PropTypes.string,
}
const Colors = () => {
return (
<>
<CCard className="mb-4">
<CCardHeader>
Theme colors
<DocsLink href="https://coreui.io/docs/utilities/colors/" />
</CCardHeader>
<CCardBody>
<CRow>
<ThemeColor className="bg-primary">
<h6>Brand Primary Color</h6>
</ThemeColor>
<ThemeColor className="bg-secondary">
<h6>Brand Secondary Color</h6>
</ThemeColor>
<ThemeColor className="bg-success">
<h6>Brand Success Color</h6>
</ThemeColor>
<ThemeColor className="bg-danger">
<h6>Brand Danger Color</h6>
</ThemeColor>
<ThemeColor className="bg-warning">
<h6>Brand Warning Color</h6>
</ThemeColor>
<ThemeColor className="bg-info">
<h6>Brand Info Color</h6>
</ThemeColor>
<ThemeColor className="bg-light">
<h6>Brand Light Color</h6>
</ThemeColor>
<ThemeColor className="bg-dark">
<h6>Brand Dark Color</h6>
</ThemeColor>
</CRow>
</CCardBody>
</CCard>
</>
)
}
export default Colors

View File

@ -0,0 +1,229 @@
import React from 'react'
import { CCard, CCardHeader, CCardBody } from '@coreui/react'
import { DocsLink } from 'src/components'
const Typography = () => {
return (
<>
<CCard className="mb-4">
<CCardHeader>
Headings
<DocsLink href="https://coreui.io/docs/content/typography/" />
</CCardHeader>
<CCardBody>
<p>
Documentation and examples for Bootstrap typography, including global settings,
headings, body text, lists, and more.
</p>
<table className="table">
<thead>
<tr>
<th>Heading</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<p>
<code className="highlighter-rouge">&lt;h1&gt;&lt;/h1&gt;</code>
</p>
</td>
<td>
<span className="h1">h1. Bootstrap heading</span>
</td>
</tr>
<tr>
<td>
<p>
<code className="highlighter-rouge">&lt;h2&gt;&lt;/h2&gt;</code>
</p>
</td>
<td>
<span className="h2">h2. Bootstrap heading</span>
</td>
</tr>
<tr>
<td>
<p>
<code className="highlighter-rouge">&lt;h3&gt;&lt;/h3&gt;</code>
</p>
</td>
<td>
<span className="h3">h3. Bootstrap heading</span>
</td>
</tr>
<tr>
<td>
<p>
<code className="highlighter-rouge">&lt;h4&gt;&lt;/h4&gt;</code>
</p>
</td>
<td>
<span className="h4">h4. Bootstrap heading</span>
</td>
</tr>
<tr>
<td>
<p>
<code className="highlighter-rouge">&lt;h5&gt;&lt;/h5&gt;</code>
</p>
</td>
<td>
<span className="h5">h5. Bootstrap heading</span>
</td>
</tr>
<tr>
<td>
<p>
<code className="highlighter-rouge">&lt;h6&gt;&lt;/h6&gt;</code>
</p>
</td>
<td>
<span className="h6">h6. Bootstrap heading</span>
</td>
</tr>
</tbody>
</table>
</CCardBody>
</CCard>
<CCard className="mb-4">
<CCardHeader>Headings</CCardHeader>
<CCardBody>
<p>
<code className="highlighter-rouge">.h1</code> through
<code className="highlighter-rouge">.h6</code>
classes are also available, for when you want to match the font styling of a heading but
cannot use the associated HTML element.
</p>
<div className="bd-example">
<p className="h1">h1. Bootstrap heading</p>
<p className="h2">h2. Bootstrap heading</p>
<p className="h3">h3. Bootstrap heading</p>
<p className="h4">h4. Bootstrap heading</p>
<p className="h5">h5. Bootstrap heading</p>
<p className="h6">h6. Bootstrap heading</p>
</div>
</CCardBody>
</CCard>
<CCard className="mb-4">
<div className="card-header">Display headings</div>
<div className="card-body">
<p>
Traditional heading elements are designed to work best in the meat of your page content.
When you need a heading to stand out, consider using a <strong>display heading</strong>
a larger, slightly more opinionated heading style.
</p>
<div className="bd-example bd-example-type">
<table className="table">
<tbody>
<tr>
<td>
<span className="display-1">Display 1</span>
</td>
</tr>
<tr>
<td>
<span className="display-2">Display 2</span>
</td>
</tr>
<tr>
<td>
<span className="display-3">Display 3</span>
</td>
</tr>
<tr>
<td>
<span className="display-4">Display 4</span>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</CCard>
<CCard className="mb-4">
<CCardHeader>Inline text elements</CCardHeader>
<CCardBody>
<p>
Traditional heading elements are designed to work best in the meat of your page content.
When you need a heading to stand out, consider using a <strong>display heading</strong>
a larger, slightly more opinionated heading style.
</p>
<div className="bd-example">
<p>
You can use the mark tag to <mark>highlight</mark> text.
</p>
<p>
<del>This line of text is meant to be treated as deleted text.</del>
</p>
<p>
<s>This line of text is meant to be treated as no longer accurate.</s>
</p>
<p>
<ins>This line of text is meant to be treated as an addition to the document.</ins>
</p>
<p>
<u>This line of text will render as underlined</u>
</p>
<p>
<small>This line of text is meant to be treated as fine print.</small>
</p>
<p>
<strong>This line rendered as bold text.</strong>
</p>
<p>
<em>This line rendered as italicized text.</em>
</p>
</div>
</CCardBody>
</CCard>
<CCard className="mb-4">
<CCardHeader>Description list alignment</CCardHeader>
<CCardBody>
<p>
Align terms and descriptions horizontally by using our grid systems predefined classes
(or semantic mixins). For longer terms, you can optionally add a{' '}
<code className="highlighter-rouge">.text-truncate</code> class to truncate the text
with an ellipsis.
</p>
<div className="bd-example">
<dl className="row">
<dt className="col-sm-3">Description lists</dt>
<dd className="col-sm-9">A description list is perfect for defining terms.</dd>
<dt className="col-sm-3">Euismod</dt>
<dd className="col-sm-9">
<p>
Vestibulum id ligula porta felis euismod semper eget lacinia odio sem nec elit.
</p>
<p>Donec id elit non mi porta gravida at eget metus.</p>
</dd>
<dt className="col-sm-3">Malesuada porta</dt>
<dd className="col-sm-9">Etiam porta sem malesuada magna mollis euismod.</dd>
<dt className="col-sm-3 text-truncate">Truncated term is truncated</dt>
<dd className="col-sm-9">
Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut
fermentum massa justo sit amet risus.
</dd>
<dt className="col-sm-3">Nesting</dt>
<dd className="col-sm-9">
<dl className="row">
<dt className="col-sm-4">Nested definition list</dt>
<dd className="col-sm-8">
Aenean posuere, tortor sed cursus feugiat, nunc augue blandit nunc.
</dd>
</dl>
</dd>
</dl>
</div>
</CCardBody>
</CCard>
</>
)
}
export default Typography

View File

@ -0,0 +1,898 @@
import React from 'react'
import {
CCard,
CCardBody,
CCardGroup,
CCardHeader,
CCol,
CLink,
CRow,
CWidgetStatsB,
CWidgetStatsC,
CWidgetStatsE,
CWidgetStatsF,
} from '@coreui/react'
import { getStyle } from '@coreui/utils'
import CIcon from '@coreui/icons-react'
import {
cilArrowRight,
cilBasket,
cilBell,
cilChartPie,
cilMoon,
cilLaptop,
cilPeople,
cilSettings,
cilSpeech,
cilSpeedometer,
cilUser,
cilUserFollow,
} from '@coreui/icons'
import { CChartBar, CChartLine } from '@coreui/react-chartjs'
import { DocsExample } from 'src/components'
import WidgetsBrand from './WidgetsBrand'
import WidgetsDropdown from './WidgetsDropdown'
const Widgets = () => {
const random = (min, max) => Math.floor(Math.random() * (max - min + 1) + min)
return (
<CCard className="mb-4">
<CCardHeader>Widgets</CCardHeader>
<CCardBody>
<DocsExample href="components/widgets/#cwidgetstatsa">
<WidgetsDropdown />
</DocsExample>
<DocsExample href="components/widgets/#cwidgetstatsb">
<CRow xs={{ gutter: 4 }}>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsB
progress={{ color: 'success', value: 89.9 }}
text="Lorem ipsum dolor sit amet enim."
title="Widget title"
value="89.9%"
/>
</CCol>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsB
value="12.124"
title="Widget title"
progress={{ color: 'info', value: 89.9 }}
text="Lorem ipsum dolor sit amet enim."
/>
</CCol>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsB
value="$98.111,00"
title="Widget title"
progress={{ color: 'warning', value: 89.9 }}
text="Lorem ipsum dolor sit amet enim."
/>
</CCol>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsB
value="2 TB"
title="Widget title"
progress={{ color: 'primary', value: 89.9 }}
text="Lorem ipsum dolor sit amet enim."
/>
</CCol>
</CRow>
</DocsExample>
<DocsExample href="components/widgets/#cwidgetstatsb">
<CRow xs={{ gutter: 4 }}>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsB
color="success"
inverse
value="89.9%"
title="Widget title"
progress={{ value: 89.9 }}
text="Lorem ipsum dolor sit amet enim."
/>
</CCol>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsB
color="info"
inverse
value="12.124"
title="Widget title"
progress={{ value: 89.9 }}
text="Lorem ipsum dolor sit amet enim."
/>
</CCol>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsB
color="warning"
inverse
value="$98.111,00"
title="Widget title"
progress={{ value: 89.9 }}
text="Lorem ipsum dolor sit amet enim."
/>
</CCol>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsB
color="primary"
inverse
value="2 TB"
title="Widget title"
progress={{ value: 89.9 }}
text="Lorem ipsum dolor sit amet enim."
/>
</CCol>
</CRow>
</DocsExample>
<DocsExample href="components/widgets/#cwidgetstatse">
<CRow xs={{ gutter: 4 }}>
<CCol sm={4} md={3} xl={2}>
<CWidgetStatsE
chart={
<CChartBar
className="mx-auto"
style={{ height: '40px', width: '80px' }}
data={{
labels: [
'M',
'T',
'W',
'T',
'F',
'S',
'S',
'M',
'T',
'W',
'T',
'F',
'S',
'S',
'M',
],
datasets: [
{
backgroundColor: getStyle('--cui-danger'),
borderColor: 'transparent',
borderWidth: 1,
data: [
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
],
},
],
}}
options={{
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
},
scales: {
x: {
display: false,
},
y: {
display: false,
},
},
}}
/>
}
title="title"
value="1,123"
/>
</CCol>
<CCol sm={4} md={3} xl={2}>
<CWidgetStatsE
chart={
<CChartBar
className="mx-auto"
style={{ height: '40px', width: '80px' }}
data={{
labels: [
'M',
'T',
'W',
'T',
'F',
'S',
'S',
'M',
'T',
'W',
'T',
'F',
'S',
'S',
'M',
],
datasets: [
{
backgroundColor: getStyle('--cui-primary'),
borderColor: 'transparent',
borderWidth: 1,
data: [
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
],
},
],
}}
options={{
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
},
scales: {
x: {
display: false,
},
y: {
display: false,
},
},
}}
/>
}
title="title"
value="1,123"
/>
</CCol>
<CCol sm={4} md={3} xl={2}>
<CWidgetStatsE
chart={
<CChartBar
className="mx-auto"
style={{ height: '40px', width: '80px' }}
data={{
labels: [
'M',
'T',
'W',
'T',
'F',
'S',
'S',
'M',
'T',
'W',
'T',
'F',
'S',
'S',
'M',
],
datasets: [
{
backgroundColor: getStyle('--cui-success'),
borderColor: 'transparent',
borderWidth: 1,
data: [
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
],
},
],
}}
options={{
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
},
scales: {
x: {
display: false,
},
y: {
display: false,
},
},
}}
/>
}
title="title"
value="1,123"
/>
</CCol>
<CCol sm={4} md={3} xl={2}>
<CWidgetStatsE
chart={
<CChartLine
className="mx-auto"
style={{ height: '40px', width: '80px' }}
data={{
labels: [
'M',
'T',
'W',
'T',
'F',
'S',
'S',
'M',
'T',
'W',
'T',
'F',
'S',
'S',
'M',
],
datasets: [
{
backgroundColor: 'transparent',
borderColor: getStyle('--cui-danger'),
borderWidth: 2,
data: [
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
],
},
],
}}
options={{
maintainAspectRatio: false,
elements: {
line: {
tension: 0.4,
},
point: {
radius: 0,
},
},
plugins: {
legend: {
display: false,
},
},
scales: {
x: {
display: false,
},
y: {
display: false,
},
},
}}
/>
}
title="title"
value="1,123"
/>
</CCol>
<CCol sm={4} md={3} xl={2}>
<CWidgetStatsE
chart={
<CChartLine
className="mx-auto"
style={{ height: '40px', width: '80px' }}
data={{
labels: [
'M',
'T',
'W',
'T',
'F',
'S',
'S',
'M',
'T',
'W',
'T',
'F',
'S',
'S',
'M',
],
datasets: [
{
backgroundColor: 'transparent',
borderColor: getStyle('--cui-success'),
borderWidth: 2,
data: [
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
],
},
],
}}
options={{
maintainAspectRatio: false,
elements: {
line: {
tension: 0.4,
},
point: {
radius: 0,
},
},
plugins: {
legend: {
display: false,
},
},
scales: {
x: {
display: false,
},
y: {
display: false,
},
},
}}
/>
}
title="title"
value="1,123"
/>
</CCol>
<CCol sm={4} md={3} xl={2}>
<CWidgetStatsE
chart={
<CChartLine
className="mx-auto"
style={{ height: '40px', width: '80px' }}
data={{
labels: [
'M',
'T',
'W',
'T',
'F',
'S',
'S',
'M',
'T',
'W',
'T',
'F',
'S',
'S',
'M',
],
datasets: [
{
backgroundColor: 'transparent',
borderColor: getStyle('--cui-info'),
borderWidth: 2,
data: [
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
random(40, 100),
],
},
],
}}
options={{
maintainAspectRatio: false,
elements: {
line: {
tension: 0.4,
},
point: {
radius: 0,
},
},
plugins: {
legend: {
display: false,
},
},
scales: {
x: {
display: false,
},
y: {
display: false,
},
},
}}
/>
}
title="title"
value="1,123"
/>
</CCol>
</CRow>
</DocsExample>
<DocsExample href="components/widgets/#cwidgetstatsf">
<CRow xs={{ gutter: 4 }}>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsF
icon={<CIcon width={24} icon={cilSettings} size="xl" />}
title="income"
value="$1.999,50"
color="primary"
/>
</CCol>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsF
icon={<CIcon width={24} icon={cilUser} size="xl" />}
title="income"
value="$1.999,50"
color="info"
/>
</CCol>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsF
icon={<CIcon width={24} icon={cilMoon} size="xl" />}
title="income"
value="$1.999,50"
color="warning"
/>
</CCol>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsF
icon={<CIcon width={24} icon={cilBell} size="xl" />}
title="income"
value="$1.999,50"
color="danger"
/>
</CCol>
</CRow>
</DocsExample>
<DocsExample href="components/widgets/#cwidgetstatsf">
<CRow xs={{ gutter: 4 }}>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsF
icon={<CIcon width={24} icon={cilSettings} size="xl" />}
title="income"
value="$1.999,50"
color="primary"
footer={
<CLink
className="font-weight-bold font-xs text-body-secondary"
href="https://coreui.io/"
rel="noopener norefferer"
target="_blank"
>
View more
<CIcon icon={cilArrowRight} className="float-end" width={16} />
</CLink>
}
/>
</CCol>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsF
icon={<CIcon width={24} icon={cilLaptop} size="xl" />}
title="income"
value="$1.999,50"
color="info"
footer={
<CLink
className="font-weight-bold font-xs text-body-secondary"
href="https://coreui.io/"
rel="noopener norefferer"
target="_blank"
>
View more
<CIcon icon={cilArrowRight} className="float-end" width={16} />
</CLink>
}
/>
</CCol>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsF
icon={<CIcon width={24} icon={cilMoon} size="xl" />}
title="income"
value="$1.999,50"
color="warning"
footer={
<CLink
className="font-weight-bold font-xs text-body-secondary"
href="https://coreui.io/"
rel="noopener norefferer"
target="_blank"
>
View more
<CIcon icon={cilArrowRight} className="float-end" width={16} />
</CLink>
}
/>
</CCol>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsF
icon={<CIcon width={24} icon={cilBell} size="xl" />}
title="income"
value="$1.999,50"
color="danger"
footer={
<CLink
className="font-weight-bold font-xs text-body-secondary"
href="https://coreui.io/"
rel="noopener norefferer"
target="_blank"
>
View more
<CIcon icon={cilArrowRight} className="float-end" width={16} />
</CLink>
}
/>
</CCol>
</CRow>
</DocsExample>
<DocsExample href="components/widgets/#cwidgetstatsf">
<CRow xs={{ gutter: 4 }}>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsF
icon={<CIcon width={24} icon={cilSettings} size="xl" />}
padding={false}
title="income"
value="$1.999,50"
color="primary"
/>
</CCol>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsF
icon={<CIcon width={24} icon={cilUser} size="xl" />}
padding={false}
title="income"
value="$1.999,50"
color="info"
/>
</CCol>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsF
icon={<CIcon width={24} icon={cilMoon} size="xl" />}
padding={false}
title="income"
value="$1.999,50"
color="warning"
/>
</CCol>
<CCol xs={12} sm={6} xl={4} xxl={3}>
<CWidgetStatsF
icon={<CIcon width={24} icon={cilBell} size="xl" />}
padding={false}
title="income"
value="$1.999,50"
color="danger"
/>
</CCol>
</CRow>
</DocsExample>
<DocsExample href="components/widgets/#cwidgetstatsd">
<WidgetsBrand />
</DocsExample>
<DocsExample href="components/widgets/#cwidgetstatsd">
<WidgetsBrand withCharts />
</DocsExample>
<DocsExample href="components/widgets/#cwidgetstatsc">
<CCardGroup className="mb-4">
<CWidgetStatsC
icon={<CIcon icon={cilPeople} height={36} />}
value="87.500"
title="Visitors"
progress={{ color: 'info', value: 75 }}
/>
<CWidgetStatsC
icon={<CIcon icon={cilUserFollow} height={36} />}
value="385"
title="New Clients"
progress={{ color: 'success', value: 75 }}
/>
<CWidgetStatsC
icon={<CIcon icon={cilBasket} height={36} />}
value="1238"
title="Products sold"
progress={{ color: 'warning', value: 75 }}
/>
<CWidgetStatsC
icon={<CIcon icon={cilChartPie} height={36} />}
value="28%"
title="Returning Visitors"
progress={{ color: 'primary', value: 75 }}
/>
<CWidgetStatsC
icon={<CIcon icon={cilSpeedometer} height={36} />}
value="5:34:11"
title="Avg. Time"
progress={{ color: 'danger', value: 75 }}
/>
</CCardGroup>
</DocsExample>
<DocsExample href="components/widgets/#cwidgetstatsc">
<CRow xs={{ gutter: 4 }}>
<CCol xs={6} lg={4} xxl={2}>
<CWidgetStatsC
icon={<CIcon icon={cilPeople} height={36} />}
value="87.500"
title="Visitors"
progress={{ color: 'info', value: 75 }}
/>
</CCol>
<CCol xs={6} lg={4} xxl={2}>
<CWidgetStatsC
icon={<CIcon icon={cilUserFollow} height={36} />}
value="385"
title="New Clients"
progress={{ color: 'success', value: 75 }}
/>
</CCol>
<CCol xs={6} lg={4} xxl={2}>
<CWidgetStatsC
icon={<CIcon icon={cilBasket} height={36} />}
value="1238"
title="Products sold"
progress={{ color: 'warning', value: 75 }}
/>
</CCol>
<CCol xs={6} lg={4} xxl={2}>
<CWidgetStatsC
icon={<CIcon icon={cilChartPie} height={36} />}
value="28%"
title="Returning Visitors"
progress={{ color: 'primary', value: 75 }}
/>
</CCol>
<CCol xs={6} lg={4} xxl={2}>
<CWidgetStatsC
icon={<CIcon icon={cilSpeedometer} height={36} />}
value="5:34:11"
title="Avg. Time"
progress={{ color: 'danger', value: 75 }}
/>
</CCol>
<CCol xs={6} lg={4} xxl={2}>
<CWidgetStatsC
icon={<CIcon icon={cilSpeech} height={36} />}
value="972"
title="Comments"
progress={{ color: 'info', value: 75 }}
/>
</CCol>
</CRow>
</DocsExample>
<DocsExample href="components/widgets/#cwidgetstatsc">
<CRow xs={{ gutter: 4 }}>
<CCol xs={6} lg={4} xxl={2}>
<CWidgetStatsC
color="info"
icon={<CIcon icon={cilPeople} height={36} />}
value="87.500"
title="Visitors"
inverse
progress={{ value: 75 }}
/>
</CCol>
<CCol xs={6} lg={4} xxl={2}>
<CWidgetStatsC
color="success"
icon={<CIcon icon={cilUserFollow} height={36} />}
value="385"
title="New Clients"
inverse
progress={{ value: 75 }}
/>
</CCol>
<CCol xs={6} lg={4} xxl={2}>
<CWidgetStatsC
color="warning"
icon={<CIcon icon={cilBasket} height={36} />}
value="1238"
title="Products sold"
inverse
progress={{ value: 75 }}
/>
</CCol>
<CCol xs={6} lg={4} xxl={2}>
<CWidgetStatsC
color="primary"
icon={<CIcon icon={cilChartPie} height={36} />}
value="28%"
title="Returning Visitors"
inverse
progress={{ value: 75 }}
/>
</CCol>
<CCol xs={6} lg={4} xxl={2}>
<CWidgetStatsC
color="danger"
icon={<CIcon icon={cilSpeedometer} height={36} />}
value="5:34:11"
title="Avg. Time"
inverse
progress={{ value: 75 }}
/>
</CCol>
<CCol xs={6} lg={4} xxl={2}>
<CWidgetStatsC
color="info"
icon={<CIcon icon={cilSpeech} height={36} />}
value="972"
title="Comments"
inverse
progress={{ value: 75 }}
/>
</CCol>
</CRow>
</DocsExample>
</CCardBody>
</CCard>
)
}
export default Widgets

View File

@ -0,0 +1,182 @@
import React from 'react'
import PropTypes from 'prop-types'
import { CWidgetStatsD, CRow, CCol } from '@coreui/react'
import CIcon from '@coreui/icons-react'
import { cibFacebook, cibLinkedin, cibTwitter, cilCalendar } from '@coreui/icons'
import { CChart } from '@coreui/react-chartjs'
const WidgetsBrand = (props) => {
const chartOptions = {
elements: {
line: {
tension: 0.4,
},
point: {
radius: 0,
hitRadius: 10,
hoverRadius: 4,
hoverBorderWidth: 3,
},
},
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
},
scales: {
x: {
display: false,
},
y: {
display: false,
},
},
}
return (
<CRow className={props.className} xs={{ gutter: 4 }}>
<CCol sm={6} xl={4} xxl={3}>
<CWidgetStatsD
{...(props.withCharts && {
chart: (
<CChart
className="position-absolute w-100 h-100"
type="line"
data={{
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
backgroundColor: 'rgba(255,255,255,.1)',
borderColor: 'rgba(255,255,255,.55)',
pointHoverBackgroundColor: '#fff',
borderWidth: 2,
data: [65, 59, 84, 84, 51, 55, 40],
fill: true,
},
],
}}
options={chartOptions}
/>
),
})}
icon={<CIcon icon={cibFacebook} height={52} className="my-4 text-white" />}
values={[
{ title: 'friends', value: '89K' },
{ title: 'feeds', value: '459' },
]}
style={{
'--cui-card-cap-bg': '#3b5998',
}}
/>
</CCol>
<CCol sm={6} xl={4} xxl={3}>
<CWidgetStatsD
{...(props.withCharts && {
chart: (
<CChart
className="position-absolute w-100 h-100"
type="line"
data={{
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
backgroundColor: 'rgba(255,255,255,.1)',
borderColor: 'rgba(255,255,255,.55)',
pointHoverBackgroundColor: '#fff',
borderWidth: 2,
data: [1, 13, 9, 17, 34, 41, 38],
fill: true,
},
],
}}
options={chartOptions}
/>
),
})}
icon={<CIcon icon={cibTwitter} height={52} className="my-4 text-white" />}
values={[
{ title: 'followers', value: '973k' },
{ title: 'tweets', value: '1.792' },
]}
style={{
'--cui-card-cap-bg': '#00aced',
}}
/>
</CCol>
<CCol sm={6} xl={4} xxl={3}>
<CWidgetStatsD
{...(props.withCharts && {
chart: (
<CChart
className="position-absolute w-100 h-100"
type="line"
data={{
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
backgroundColor: 'rgba(255,255,255,.1)',
borderColor: 'rgba(255,255,255,.55)',
pointHoverBackgroundColor: '#fff',
borderWidth: 2,
data: [78, 81, 80, 45, 34, 12, 40],
fill: true,
},
],
}}
options={chartOptions}
/>
),
})}
icon={<CIcon icon={cibLinkedin} height={52} className="my-4 text-white" />}
values={[
{ title: 'contacts', value: '500' },
{ title: 'feeds', value: '1.292' },
]}
style={{
'--cui-card-cap-bg': '#4875b4',
}}
/>
</CCol>
<CCol sm={6} xl={4} xxl={3}>
<CWidgetStatsD
color="warning"
{...(props.withCharts && {
chart: (
<CChart
className="position-absolute w-100 h-100"
type="line"
data={{
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
backgroundColor: 'rgba(255,255,255,.1)',
borderColor: 'rgba(255,255,255,.55)',
pointHoverBackgroundColor: '#fff',
borderWidth: 2,
data: [35, 23, 56, 22, 97, 23, 64],
fill: true,
},
],
}}
options={chartOptions}
/>
),
})}
icon={<CIcon icon={cilCalendar} height={52} className="my-4 text-white" />}
values={[
{ title: 'events', value: '12+' },
{ title: 'meetings', value: '4' },
]}
/>
</CCol>
</CRow>
)
}
WidgetsBrand.propTypes = {
className: PropTypes.string,
withCharts: PropTypes.bool,
}
export default WidgetsBrand

View File

@ -0,0 +1,396 @@
import React, { useEffect, useRef } from 'react'
import PropTypes from 'prop-types'
import {
CRow,
CCol,
CDropdown,
CDropdownMenu,
CDropdownItem,
CDropdownToggle,
CWidgetStatsA,
} from '@coreui/react'
import { getStyle } from '@coreui/utils'
import { CChartBar, CChartLine } from '@coreui/react-chartjs'
import CIcon from '@coreui/icons-react'
import { cilArrowBottom, cilArrowTop, cilOptions } from '@coreui/icons'
const WidgetsDropdown = (props) => {
const widgetChartRef1 = useRef(null)
const widgetChartRef2 = useRef(null)
useEffect(() => {
document.documentElement.addEventListener('ColorSchemeChange', () => {
if (widgetChartRef1.current) {
setTimeout(() => {
widgetChartRef1.current.data.datasets[0].pointBackgroundColor = getStyle('--cui-primary')
widgetChartRef1.current.update()
})
}
if (widgetChartRef2.current) {
setTimeout(() => {
widgetChartRef2.current.data.datasets[0].pointBackgroundColor = getStyle('--cui-info')
widgetChartRef2.current.update()
})
}
})
}, [widgetChartRef1, widgetChartRef2])
return (
<CRow className={props.className} xs={{ gutter: 4 }}>
<CCol sm={6} xl={4} xxl={3}>
<CWidgetStatsA
color="primary"
value={
<>
26K{' '}
<span className="fs-6 fw-normal">
(-12.4% <CIcon icon={cilArrowBottom} />)
</span>
</>
}
title="Users"
action={
<CDropdown alignment="end">
<CDropdownToggle color="transparent" caret={false} className="text-white p-0">
<CIcon icon={cilOptions} />
</CDropdownToggle>
<CDropdownMenu>
<CDropdownItem>Action</CDropdownItem>
<CDropdownItem>Another action</CDropdownItem>
<CDropdownItem>Something else here...</CDropdownItem>
<CDropdownItem disabled>Disabled action</CDropdownItem>
</CDropdownMenu>
</CDropdown>
}
chart={
<CChartLine
ref={widgetChartRef1}
className="mt-3 mx-3"
style={{ height: '70px' }}
data={{
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'My First dataset',
backgroundColor: 'transparent',
borderColor: 'rgba(255,255,255,.55)',
pointBackgroundColor: getStyle('--cui-primary'),
data: [65, 59, 84, 84, 51, 55, 40],
},
],
}}
options={{
plugins: {
legend: {
display: false,
},
},
maintainAspectRatio: false,
scales: {
x: {
border: {
display: false,
},
grid: {
display: false,
drawBorder: false,
},
ticks: {
display: false,
},
},
y: {
min: 30,
max: 89,
display: false,
grid: {
display: false,
},
ticks: {
display: false,
},
},
},
elements: {
line: {
borderWidth: 1,
tension: 0.4,
},
point: {
radius: 4,
hitRadius: 10,
hoverRadius: 4,
},
},
}}
/>
}
/>
</CCol>
<CCol sm={6} xl={4} xxl={3}>
<CWidgetStatsA
color="info"
value={
<>
$6.200{' '}
<span className="fs-6 fw-normal">
(40.9% <CIcon icon={cilArrowTop} />)
</span>
</>
}
title="Income"
action={
<CDropdown alignment="end">
<CDropdownToggle color="transparent" caret={false} className="text-white p-0">
<CIcon icon={cilOptions} />
</CDropdownToggle>
<CDropdownMenu>
<CDropdownItem>Action</CDropdownItem>
<CDropdownItem>Another action</CDropdownItem>
<CDropdownItem>Something else here...</CDropdownItem>
<CDropdownItem disabled>Disabled action</CDropdownItem>
</CDropdownMenu>
</CDropdown>
}
chart={
<CChartLine
ref={widgetChartRef2}
className="mt-3 mx-3"
style={{ height: '70px' }}
data={{
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'My First dataset',
backgroundColor: 'transparent',
borderColor: 'rgba(255,255,255,.55)',
pointBackgroundColor: getStyle('--cui-info'),
data: [1, 18, 9, 17, 34, 22, 11],
},
],
}}
options={{
plugins: {
legend: {
display: false,
},
},
maintainAspectRatio: false,
scales: {
x: {
border: {
display: false,
},
grid: {
display: false,
drawBorder: false,
},
ticks: {
display: false,
},
},
y: {
min: -9,
max: 39,
display: false,
grid: {
display: false,
},
ticks: {
display: false,
},
},
},
elements: {
line: {
borderWidth: 1,
},
point: {
radius: 4,
hitRadius: 10,
hoverRadius: 4,
},
},
}}
/>
}
/>
</CCol>
<CCol sm={6} xl={4} xxl={3}>
<CWidgetStatsA
color="warning"
value={
<>
2.49%{' '}
<span className="fs-6 fw-normal">
(84.7% <CIcon icon={cilArrowTop} />)
</span>
</>
}
title="Conversion Rate"
action={
<CDropdown alignment="end">
<CDropdownToggle color="transparent" caret={false} className="text-white p-0">
<CIcon icon={cilOptions} />
</CDropdownToggle>
<CDropdownMenu>
<CDropdownItem>Action</CDropdownItem>
<CDropdownItem>Another action</CDropdownItem>
<CDropdownItem>Something else here...</CDropdownItem>
<CDropdownItem disabled>Disabled action</CDropdownItem>
</CDropdownMenu>
</CDropdown>
}
chart={
<CChartLine
className="mt-3"
style={{ height: '70px' }}
data={{
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'My First dataset',
backgroundColor: 'rgba(255,255,255,.2)',
borderColor: 'rgba(255,255,255,.55)',
data: [78, 81, 80, 45, 34, 12, 40],
fill: true,
},
],
}}
options={{
plugins: {
legend: {
display: false,
},
},
maintainAspectRatio: false,
scales: {
x: {
display: false,
},
y: {
display: false,
},
},
elements: {
line: {
borderWidth: 2,
tension: 0.4,
},
point: {
radius: 0,
hitRadius: 10,
hoverRadius: 4,
},
},
}}
/>
}
/>
</CCol>
<CCol sm={6} xl={4} xxl={3}>
<CWidgetStatsA
color="danger"
value={
<>
44K{' '}
<span className="fs-6 fw-normal">
(-23.6% <CIcon icon={cilArrowBottom} />)
</span>
</>
}
title="Sessions"
action={
<CDropdown alignment="end">
<CDropdownToggle color="transparent" caret={false} className="text-white p-0">
<CIcon icon={cilOptions} />
</CDropdownToggle>
<CDropdownMenu>
<CDropdownItem>Action</CDropdownItem>
<CDropdownItem>Another action</CDropdownItem>
<CDropdownItem>Something else here...</CDropdownItem>
<CDropdownItem disabled>Disabled action</CDropdownItem>
</CDropdownMenu>
</CDropdown>
}
chart={
<CChartBar
className="mt-3 mx-3"
style={{ height: '70px' }}
data={{
labels: [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
'January',
'February',
'March',
'April',
],
datasets: [
{
label: 'My First dataset',
backgroundColor: 'rgba(255,255,255,.2)',
borderColor: 'rgba(255,255,255,.55)',
data: [78, 81, 80, 45, 34, 12, 40, 85, 65, 23, 12, 98, 34, 84, 67, 82],
barPercentage: 0.6,
},
],
}}
options={{
maintainAspectRatio: false,
plugins: {
legend: {
display: false,
},
},
scales: {
x: {
grid: {
display: false,
drawTicks: false,
},
ticks: {
display: false,
},
},
y: {
border: {
display: false,
},
grid: {
display: false,
drawBorder: false,
drawTicks: false,
},
ticks: {
display: false,
},
},
},
}}
/>
}
/>
</CCol>
</CRow>
)
}
WidgetsDropdown.propTypes = {
className: PropTypes.string,
withCharts: PropTypes.bool,
}
export default WidgetsDropdown

49
vite.config.mjs Normal file
View File

@ -0,0 +1,49 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'node:path'
import autoprefixer from 'autoprefixer'
export default defineConfig(() => {
return {
base: './',
build: {
outDir: 'build',
},
css: {
postcss: {
plugins: [
autoprefixer({}), // add options if needed
],
},
},
esbuild: {
loader: 'jsx',
include: /src\/.*\.jsx?$/,
exclude: [],
},
optimizeDeps: {
force: true,
esbuildOptions: {
loader: {
'.js': 'jsx',
},
},
},
plugins: [react()],
resolve: {
alias: [
{
find: 'src/',
replacement: `${path.resolve(__dirname, 'src')}/`,
},
],
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.scss'],
},
server: {
port: 3000,
proxy: {
// https://vitejs.dev/config/server-options.html
},
},
}
})