├── .env ├── .env.template ├── public ├── robots.txt ├── logo.jpg ├── intro.png ├── favicon.ico ├── logo192.png ├── logo512.png ├── favicon-16x16.png ├── favicon-32x32.png ├── apple-touch-icon.png ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── manifest.json └── index.html ├── postcss.config.js ├── src ├── components │ ├── Typography │ │ ├── Title.js │ │ ├── HelperText.js │ │ ├── ErrorText.js │ │ └── Subtitle.js │ ├── CalendarView │ │ ├── util.js │ │ └── index.js │ ├── Input │ │ ├── SearchBar.js │ │ ├── ToogleInput.js │ │ ├── InputText.js │ │ ├── TextAreaInput.js │ │ └── SelectBox.js │ └── Cards │ │ └── TitleCard.js ├── containers │ ├── SuspenseContent.js │ ├── Layout.js │ ├── ModalLayout.js │ ├── SidebarSubmenu.js │ ├── PageContent.js │ ├── LeftSidebar.js │ ├── RightSidebar.js │ └── Header.js ├── setupTests.js ├── App.test.js ├── pages │ ├── Login.js │ ├── Register.js │ ├── DocFeatures.js │ ├── DocComponents.js │ ├── GettingStarted.js │ ├── ForgotPassword.js │ ├── protected │ │ ├── Leads.js │ │ ├── Charts.js │ │ ├── Team.js │ │ ├── Bills.js │ │ ├── Calendar.js │ │ ├── Dashboard.js │ │ ├── Transactions.js │ │ ├── Integration.js │ │ ├── ProfileSettings.js │ │ ├── 404.js │ │ ├── Welcome.js │ │ └── Blank.js │ └── Documentation.js ├── reportWebVitals.js ├── utils │ ├── globalConstantUtil.js │ └── dummyData.js ├── app │ ├── store.js │ ├── init.js │ └── auth.js ├── features │ ├── common │ │ ├── components │ │ │ ├── NotificationBodyRightDrawer.js │ │ │ └── ConfirmationModalBody.js │ │ ├── rightDrawerSlice.js │ │ ├── headerSlice.js │ │ └── modalSlice.js │ ├── calendar │ │ ├── CalendarEventsBodyRightDrawer.js │ │ └── index.js │ ├── user │ │ ├── components │ │ │ └── TemplatePointers.js │ │ ├── LandingIntro.js │ │ ├── Login.js │ │ ├── Register.js │ │ └── ForgotPassword.js │ ├── dashboard │ │ ├── components │ │ │ ├── AmountStats.js │ │ │ ├── PageStats.js │ │ │ ├── DashboardStats.js │ │ │ ├── LineChart.js │ │ │ ├── BarChart.js │ │ │ ├── UserChannels.js │ │ │ ├── DoughnutChart.js │ │ │ └── DashboardTopBar.js │ │ └── index.js │ ├── documentation │ │ ├── DocGettingStarted.js │ │ ├── components │ │ │ ├── DocComponentsNav.js │ │ │ ├── FeaturesNav.js │ │ │ ├── GettingStartedNav.js │ │ │ ├── DocComponentsContent.js │ │ │ ├── FeaturesContent.js │ │ │ └── GettingStartedContent.js │ │ ├── DocFeatures.js │ │ └── DocComponents.js │ ├── leads │ │ ├── leadSlice.js │ │ ├── components │ │ │ └── AddLeadModalBody.js │ │ └── index.js │ ├── charts │ │ ├── components │ │ │ ├── LineChart.js │ │ │ ├── BarChart.js │ │ │ ├── ScatterChart.js │ │ │ ├── StackBarChart.js │ │ │ ├── DoughnutChart.js │ │ │ └── PieChart.js │ │ └── index.js │ ├── settings │ │ ├── profilesettings │ │ │ └── index.js │ │ ├── billing │ │ │ └── index.js │ │ └── team │ │ │ └── index.js │ ├── integration │ │ └── index.js │ └── transactions │ │ └── index.js ├── App.css ├── index.css ├── index.js ├── App.js ├── routes │ ├── index.js │ └── sidebar.js └── logo.svg ├── .gitignore ├── tailwind.config.js ├── LICENSE.md ├── package.json └── README.md /.env: -------------------------------------------------------------------------------- 1 | REACT_APP_BASE_URL=https://reqres.in/ 2 | -------------------------------------------------------------------------------- /.env.template: -------------------------------------------------------------------------------- 1 | REACT_APP_BASE_URL=https://reqres.in/ 2 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /public/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robbins23/daisyui-admin-dashboard-template/HEAD/public/logo.jpg -------------------------------------------------------------------------------- /public/intro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robbins23/daisyui-admin-dashboard-template/HEAD/public/intro.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robbins23/daisyui-admin-dashboard-template/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robbins23/daisyui-admin-dashboard-template/HEAD/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robbins23/daisyui-admin-dashboard-template/HEAD/public/logo512.png -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robbins23/daisyui-admin-dashboard-template/HEAD/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robbins23/daisyui-admin-dashboard-template/HEAD/public/favicon-32x32.png -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | 6 | }, 7 | } 8 | -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robbins23/daisyui-admin-dashboard-template/HEAD/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robbins23/daisyui-admin-dashboard-template/HEAD/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robbins23/daisyui-admin-dashboard-template/HEAD/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /src/components/Typography/Title.js: -------------------------------------------------------------------------------- 1 | function Title({className, children}){ 2 | return( 3 |

{children}

4 | ) 5 | } 6 | 7 | export default Title -------------------------------------------------------------------------------- /src/components/Typography/HelperText.js: -------------------------------------------------------------------------------- 1 | function HelperText({className, children}){ 2 | return( 3 |
{children}
4 | ) 5 | } 6 | 7 | export default HelperText -------------------------------------------------------------------------------- /src/components/Typography/ErrorText.js: -------------------------------------------------------------------------------- 1 | function ErrorText({styleClass, children}){ 2 | return( 3 |

{children}

4 | ) 5 | } 6 | 7 | export default ErrorText -------------------------------------------------------------------------------- /src/components/Typography/Subtitle.js: -------------------------------------------------------------------------------- 1 | function Subtitle({styleClass, children}){ 2 | return( 3 |
{children}
4 | ) 5 | } 6 | 7 | export default Subtitle -------------------------------------------------------------------------------- /src/containers/SuspenseContent.js: -------------------------------------------------------------------------------- 1 | function SuspenseContent(){ 2 | return( 3 |
4 | Loading... 5 |
6 | ) 7 | } 8 | 9 | export default SuspenseContent -------------------------------------------------------------------------------- /src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /src/pages/Login.js: -------------------------------------------------------------------------------- 1 | import {useState, useRef} from 'react' 2 | import {Link} from 'react-router-dom' 3 | import Login from '../features/user/Login' 4 | 5 | function ExternalPage(){ 6 | 7 | 8 | return( 9 |
10 | 11 |
12 | ) 13 | } 14 | 15 | export default ExternalPage -------------------------------------------------------------------------------- /src/pages/Register.js: -------------------------------------------------------------------------------- 1 | import {useState, useRef} from 'react' 2 | import {Link} from 'react-router-dom' 3 | import Register from '../features/user/Register' 4 | 5 | function ExternalPage(){ 6 | 7 | 8 | return( 9 |
10 | 11 |
12 | ) 13 | } 14 | 15 | export default ExternalPage -------------------------------------------------------------------------------- /src/pages/DocFeatures.js: -------------------------------------------------------------------------------- 1 | import {useState, useRef} from 'react' 2 | import {Link} from 'react-router-dom' 3 | import DocFeatures from '../features/documentation/DocFeatures' 4 | 5 | function ExternalPage(){ 6 | 7 | 8 | return( 9 |
10 | 11 |
12 | ) 13 | } 14 | 15 | export default ExternalPage -------------------------------------------------------------------------------- /src/pages/DocComponents.js: -------------------------------------------------------------------------------- 1 | import {useState, useRef} from 'react' 2 | import {Link} from 'react-router-dom' 3 | import DocComponents from '../features/documentation/DocComponents' 4 | 5 | function ExternalPage(){ 6 | 7 | 8 | return( 9 |
10 | 11 |
12 | ) 13 | } 14 | 15 | export default ExternalPage -------------------------------------------------------------------------------- /src/pages/GettingStarted.js: -------------------------------------------------------------------------------- 1 | import {useState, useRef} from 'react' 2 | import {Link} from 'react-router-dom' 3 | import DocGettingStarted from '../features/documentation/DocGettingStarted' 4 | 5 | function ExternalPage(){ 6 | 7 | 8 | return( 9 |
10 | 11 |
12 | ) 13 | } 14 | 15 | export default ExternalPage -------------------------------------------------------------------------------- /src/pages/ForgotPassword.js: -------------------------------------------------------------------------------- 1 | import {useState, useRef} from 'react' 2 | import {Link} from 'react-router-dom' 3 | import ForgotPassword from '../features/user/ForgotPassword' 4 | import Login from '../features/user/Login' 5 | 6 | function ExternalPage(){ 7 | 8 | 9 | return( 10 |
11 | 12 |
13 | ) 14 | } 15 | 16 | export default ExternalPage -------------------------------------------------------------------------------- /src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | .env.development2.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | "./src/**/*.{js,jsx,ts,tsx}", 5 | "./node_modules/react-tailwindcss-datepicker/dist/index.esm.js" 6 | ], 7 | darkMode: ["class", '[data-theme="dark"]'], 8 | theme: { 9 | extend: {}, 10 | }, 11 | plugins: [require("@tailwindcss/typography"), require("daisyui")], 12 | daisyui: { 13 | themes: ["light", "dark"], 14 | }, 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/pages/protected/Leads.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { useDispatch } from 'react-redux' 3 | import { setPageTitle } from '../../features/common/headerSlice' 4 | import Leads from '../../features/leads' 5 | 6 | function InternalPage(){ 7 | const dispatch = useDispatch() 8 | 9 | useEffect(() => { 10 | dispatch(setPageTitle({ title : "Leads"})) 11 | }, []) 12 | 13 | 14 | return( 15 | 16 | ) 17 | } 18 | 19 | export default InternalPage -------------------------------------------------------------------------------- /src/pages/protected/Charts.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { useDispatch } from 'react-redux' 3 | import Charts from '../../features/charts' 4 | import { setPageTitle } from '../../features/common/headerSlice' 5 | 6 | function InternalPage(){ 7 | const dispatch = useDispatch() 8 | 9 | useEffect(() => { 10 | dispatch(setPageTitle({ title : "Analytics"})) 11 | }, []) 12 | 13 | 14 | return( 15 | 16 | ) 17 | } 18 | 19 | export default InternalPage -------------------------------------------------------------------------------- /src/pages/protected/Team.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { useDispatch } from 'react-redux' 3 | import { setPageTitle } from '../../features/common/headerSlice' 4 | import Team from '../../features/settings/team' 5 | 6 | function InternalPage(){ 7 | const dispatch = useDispatch() 8 | 9 | useEffect(() => { 10 | dispatch(setPageTitle({ title : "Team Members"})) 11 | }, []) 12 | 13 | 14 | return( 15 | 16 | ) 17 | } 18 | 19 | export default InternalPage -------------------------------------------------------------------------------- /src/pages/protected/Bills.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { useDispatch } from 'react-redux' 3 | import { setPageTitle } from '../../features/common/headerSlice' 4 | import Billing from '../../features/settings/billing' 5 | 6 | function InternalPage(){ 7 | const dispatch = useDispatch() 8 | 9 | useEffect(() => { 10 | dispatch(setPageTitle({ title : "Bills"})) 11 | }, []) 12 | 13 | 14 | return( 15 | 16 | ) 17 | } 18 | 19 | export default InternalPage -------------------------------------------------------------------------------- /src/pages/protected/Calendar.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { useDispatch } from 'react-redux' 3 | import { setPageTitle } from '../../features/common/headerSlice' 4 | import Calendar from '../../features/calendar' 5 | 6 | function InternalPage(){ 7 | const dispatch = useDispatch() 8 | 9 | useEffect(() => { 10 | dispatch(setPageTitle({ title : "Calendar"})) 11 | }, []) 12 | 13 | 14 | return( 15 | 16 | ) 17 | } 18 | 19 | export default InternalPage -------------------------------------------------------------------------------- /src/utils/globalConstantUtil.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = Object.freeze({ 3 | MODAL_BODY_TYPES : { 4 | USER_DETAIL : "USER_DETAIL", 5 | LEAD_ADD_NEW : "LEAD_ADD_NEW", 6 | CONFIRMATION : "CONFIRMATION", 7 | DEFAULT : "", 8 | }, 9 | 10 | RIGHT_DRAWER_TYPES : { 11 | NOTIFICATION : "NOTIFICATION", 12 | CALENDAR_EVENTS : "CALENDAR_EVENTS", 13 | }, 14 | 15 | CONFIRMATION_MODAL_CLOSE_TYPES : { 16 | LEAD_DELETE : "LEAD_DELETE", 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /src/pages/protected/Dashboard.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { useDispatch } from 'react-redux' 3 | import { setPageTitle } from '../../features/common/headerSlice' 4 | import Dashboard from '../../features/dashboard/index' 5 | 6 | function InternalPage(){ 7 | const dispatch = useDispatch() 8 | 9 | useEffect(() => { 10 | dispatch(setPageTitle({ title : "Dashboard"})) 11 | }, []) 12 | 13 | 14 | return( 15 | 16 | ) 17 | } 18 | 19 | export default InternalPage -------------------------------------------------------------------------------- /src/pages/protected/Transactions.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { useDispatch } from 'react-redux' 3 | import { setPageTitle } from '../../features/common/headerSlice' 4 | import Transactions from '../../features/transactions' 5 | 6 | function InternalPage(){ 7 | const dispatch = useDispatch() 8 | 9 | useEffect(() => { 10 | dispatch(setPageTitle({ title : "Transactions"})) 11 | }, []) 12 | 13 | 14 | return( 15 | 16 | ) 17 | } 18 | 19 | export default InternalPage -------------------------------------------------------------------------------- /src/pages/protected/Integration.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { useDispatch } from 'react-redux' 3 | import { setPageTitle } from '../../features/common/headerSlice' 4 | import Integration from '../../features/integration' 5 | 6 | function InternalPage(){ 7 | 8 | const dispatch = useDispatch() 9 | 10 | useEffect(() => { 11 | dispatch(setPageTitle({ title : "Integrations"})) 12 | }, []) 13 | 14 | return( 15 | 16 | ) 17 | } 18 | 19 | export default InternalPage -------------------------------------------------------------------------------- /src/app/store.js: -------------------------------------------------------------------------------- 1 | import { configureStore } from '@reduxjs/toolkit' 2 | import headerSlice from '../features/common/headerSlice' 3 | import modalSlice from '../features/common/modalSlice' 4 | import rightDrawerSlice from '../features/common/rightDrawerSlice' 5 | import leadsSlice from '../features/leads/leadSlice' 6 | 7 | const combinedReducer = { 8 | header : headerSlice, 9 | rightDrawer : rightDrawerSlice, 10 | modal : modalSlice, 11 | lead : leadsSlice 12 | } 13 | 14 | export default configureStore({ 15 | reducer: combinedReducer 16 | }) -------------------------------------------------------------------------------- /src/pages/protected/ProfileSettings.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { useDispatch } from 'react-redux' 3 | import { setPageTitle } from '../../features/common/headerSlice' 4 | import ProfileSettings from '../../features/settings/profilesettings' 5 | 6 | function InternalPage(){ 7 | const dispatch = useDispatch() 8 | 9 | useEffect(() => { 10 | dispatch(setPageTitle({ title : "Settings"})) 11 | }, []) 12 | 13 | 14 | return( 15 | 16 | ) 17 | } 18 | 19 | export default InternalPage -------------------------------------------------------------------------------- /src/app/init.js: -------------------------------------------------------------------------------- 1 | import axios from "axios" 2 | 3 | const initializeApp = () => { 4 | 5 | // Setting base URL for all API request via axios 6 | axios.defaults.baseURL = process.env.REACT_APP_BASE_URL 7 | 8 | 9 | if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') { 10 | // dev code 11 | 12 | 13 | 14 | } else { 15 | // Prod build code 16 | 17 | 18 | 19 | // Removing console.log from prod 20 | console.log = () => {}; 21 | 22 | 23 | // init analytics here 24 | } 25 | 26 | } 27 | 28 | export default initializeApp -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "DashWind", 3 | "name": "DashWind", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /src/components/CalendarView/util.js: -------------------------------------------------------------------------------- 1 | const moment = require("moment"); 2 | 3 | module.exports = Object.freeze({ 4 | CALENDAR_EVENT_STYLE : { 5 | "BLUE" : "bg-blue-200 dark:bg-blue-600 dark:text-blue-100", 6 | "GREEN" : "bg-green-200 dark:bg-green-600 dark:text-green-100", 7 | "PURPLE" : "bg-purple-200 dark:bg-purple-600 dark:text-purple-100", 8 | "ORANGE" : "bg-orange-200 dark:bg-orange-600 dark:text-orange-100", 9 | "PINK" : "bg-pink-200 dark:bg-pink-600 dark:text-pink-100", 10 | "MORE" : "hover:underline cursor-pointer font-medium " 11 | } 12 | 13 | 14 | }); 15 | -------------------------------------------------------------------------------- /src/features/common/components/NotificationBodyRightDrawer.js: -------------------------------------------------------------------------------- 1 | function NotificationBodyRightDrawer(){ 2 | return( 3 | <> 4 | { 5 | [...Array(15)].map((_, i) => { 6 | return
7 | {i % 2 === 0 ? `Your sales has increased by 30% yesterday` : `Total likes for instagram post - New launch this week, has crossed 100k `} 8 |
9 | }) 10 | } 11 | 12 | ) 13 | } 14 | 15 | export default NotificationBodyRightDrawer -------------------------------------------------------------------------------- /src/features/calendar/CalendarEventsBodyRightDrawer.js: -------------------------------------------------------------------------------- 1 | import { CALENDAR_EVENT_STYLE } from "../../components/CalendarView/util" 2 | 3 | const THEME_BG = CALENDAR_EVENT_STYLE 4 | 5 | function CalendarEventsBodyRightDrawer({filteredEvents}){ 6 | return( 7 | <> 8 | { 9 | filteredEvents.map((e, k) => { 10 | return
11 | {e.title} 12 |
13 | }) 14 | } 15 | 16 | ) 17 | } 18 | 19 | export default CalendarEventsBodyRightDrawer -------------------------------------------------------------------------------- /src/components/Input/SearchBar.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | import React, { useEffect } from 'react' 4 | 5 | function SearchBar({searchText, styleClass, placeholderText, setSearchText}) { 6 | 7 | 8 | 9 | const updateSearchInput = (value) => { 10 | setSearchText(value) 11 | } 12 | 13 | return ( 14 |
15 |
16 | updateSearchInput(e.target.value)} className="input input-sm input-bordered w-full max-w-xs" /> 17 |
18 |
19 | ) 20 | } 21 | 22 | export default SearchBar 23 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | .loading-indicator:before { 6 | content: ''; 7 | background: #00000080; 8 | position: fixed; 9 | width: 100%; 10 | height: 100%; 11 | top: 0; 12 | left: 0; 13 | z-index: 1000; 14 | } 15 | 16 | .loading-indicator:after { 17 | content: ' '; 18 | position: fixed; 19 | top: 40%; 20 | left: 45%; 21 | z-index: 10010; 22 | color:white; 23 | text-align:center; 24 | font-weight:bold; 25 | font-size:1.2rem; 26 | border: 16px solid #f3f3f3; /* Light grey */ 27 | border-top: 16px solid #0474bf; /* Blue */ 28 | border-radius: 50%; 29 | width: 120px; 30 | height: 120px; 31 | animation: spin 2s linear infinite; 32 | } -------------------------------------------------------------------------------- /src/features/user/components/TemplatePointers.js: -------------------------------------------------------------------------------- 1 | function TemplatePointers(){ 2 | return( 3 | <> 4 |

Admin Dashboard Starter Kit

5 |

Light/dark mode toggle

6 |

Redux toolkit and other utility libraries configured

7 |

Calendar, Modal, Sidebar components

8 |

✓ User-friendly documentation

9 |

Daisy UI components, Tailwind CSS support

10 | 11 | ) 12 | } 13 | 14 | export default TemplatePointers -------------------------------------------------------------------------------- /src/pages/protected/404.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { useDispatch } from 'react-redux' 3 | import { setPageTitle } from '../../features/common/headerSlice' 4 | import FaceFrownIcon from '@heroicons/react/24/solid/FaceFrownIcon' 5 | 6 | function InternalPage(){ 7 | 8 | const dispatch = useDispatch() 9 | 10 | useEffect(() => { 11 | dispatch(setPageTitle({ title : ""})) 12 | }, []) 13 | 14 | return( 15 |
16 |
17 |
18 | 19 |

404 - Not Found

20 |
21 |
22 |
23 | ) 24 | } 25 | 26 | export default InternalPage -------------------------------------------------------------------------------- /src/components/Input/ToogleInput.js: -------------------------------------------------------------------------------- 1 | import { useState } from "react" 2 | 3 | 4 | function ToogleInput({labelTitle, labelStyle, type, containerStyle, defaultValue, placeholder, updateFormValue, updateType}){ 5 | 6 | const [value, setValue] = useState(defaultValue) 7 | 8 | const updateToogleValue = () => { 9 | setValue(!value) 10 | updateFormValue({updateType, value : !value}) 11 | } 12 | 13 | return( 14 |
15 | 19 |
20 | ) 21 | } 22 | 23 | 24 | export default ToogleInput 25 | -------------------------------------------------------------------------------- /src/pages/protected/Welcome.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { useDispatch } from 'react-redux' 3 | import { setPageTitle } from '../../features/common/headerSlice' 4 | import {Link} from 'react-router-dom' 5 | import TemplatePointers from '../../features/user/components/TemplatePointers' 6 | 7 | function InternalPage(){ 8 | 9 | const dispatch = useDispatch() 10 | 11 | useEffect(() => { 12 | dispatch(setPageTitle({ title : ""})) 13 | }, []) 14 | 15 | return( 16 |
17 |
18 |
19 | 20 | 21 |
22 |
23 |
24 | ) 25 | } 26 | 27 | export default InternalPage -------------------------------------------------------------------------------- /src/pages/protected/Blank.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { useDispatch } from 'react-redux' 3 | import { setPageTitle } from '../../features/common/headerSlice' 4 | 5 | import DocumentIcon from '@heroicons/react/24/solid/DocumentIcon' 6 | 7 | function InternalPage(){ 8 | 9 | const dispatch = useDispatch() 10 | 11 | useEffect(() => { 12 | dispatch(setPageTitle({ title : "Page Title"})) 13 | }, []) 14 | 15 | return( 16 |
17 |
18 |
19 | 20 |

Blank Page

21 |
22 |
23 |
24 | ) 25 | } 26 | 27 | export default InternalPage -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React, { Suspense } from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | import store from './app/store' 7 | import { Provider } from 'react-redux' 8 | import SuspenseContent from './containers/SuspenseContent'; 9 | 10 | const root = ReactDOM.createRoot(document.getElementById('root')); 11 | root.render( 12 | // 13 | }> 14 | 15 | 16 | 17 | 18 | // 19 | ); 20 | 21 | // If you want to start measuring performance in your app, pass a function 22 | // to log results (for example: reportWebVitals(console.log)) 23 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 24 | reportWebVitals(); 25 | -------------------------------------------------------------------------------- /src/components/Input/InputText.js: -------------------------------------------------------------------------------- 1 | import { useState } from "react" 2 | 3 | 4 | function InputText({labelTitle, labelStyle, type, containerStyle, defaultValue, placeholder, updateFormValue, updateType}){ 5 | 6 | const [value, setValue] = useState(defaultValue) 7 | 8 | const updateInputValue = (val) => { 9 | setValue(val) 10 | updateFormValue({updateType, value : val}) 11 | } 12 | 13 | return( 14 |
15 | 18 | updateInputValue(e.target.value)}className="input input-bordered w-full " /> 19 |
20 | ) 21 | } 22 | 23 | 24 | export default InputText -------------------------------------------------------------------------------- /src/components/Input/TextAreaInput.js: -------------------------------------------------------------------------------- 1 | import { useState } from "react" 2 | 3 | 4 | function TextAreaInput({labelTitle, labelStyle, type, containerStyle, defaultValue, placeholder, updateFormValue, updateType}){ 5 | 6 | const [value, setValue] = useState(defaultValue) 7 | 8 | const updateInputValue = (val) => { 9 | setValue(val) 10 | updateFormValue({updateType, value : val}) 11 | } 12 | 13 | return( 14 |
15 | 18 | 19 |
20 | ) 21 | } 22 | 23 | 24 | export default TextAreaInput -------------------------------------------------------------------------------- /src/features/dashboard/components/AmountStats.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | function AmountStats({}){ 4 | return( 5 |
6 |
7 |
Amount to be Collected
8 |
$25,600
9 |
10 | 11 |
12 |
13 | 14 |
15 |
Cash in hand
16 |
$5,600
17 |
18 | 19 |
20 |
21 |
22 | ) 23 | } 24 | 25 | export default AmountStats -------------------------------------------------------------------------------- /src/features/user/LandingIntro.js: -------------------------------------------------------------------------------- 1 | import TemplatePointers from "./components/TemplatePointers" 2 | 3 | 4 | 5 | function LandingIntro(){ 6 | 7 | return( 8 |
9 |
10 |
11 | 12 |

dashwind-logoDashWind

13 | 14 |
Dashwind Admin Template
15 | 16 | {/* Importing pointers component */} 17 | 18 | 19 |
20 | 21 |
22 |
23 | ) 24 | 25 | } 26 | 27 | export default LandingIntro -------------------------------------------------------------------------------- /src/features/dashboard/components/PageStats.js: -------------------------------------------------------------------------------- 1 | import HeartIcon from '@heroicons/react/24/outline/HeartIcon' 2 | import BoltIcon from '@heroicons/react/24/outline/BoltIcon' 3 | 4 | 5 | function PageStats({}){ 6 | return( 7 |
8 | 9 |
10 |
11 | 12 |
13 |
Total Likes
14 |
25.6K
15 |
21% more than last month
16 |
17 | 18 |
19 |
20 | 21 |
22 |
Page Views
23 |
2.6M
24 |
14% more than last month
25 |
26 |
27 | ) 28 | } 29 | 30 | export default PageStats -------------------------------------------------------------------------------- /src/components/Cards/TitleCard.js: -------------------------------------------------------------------------------- 1 | import Subtitle from "../Typography/Subtitle" 2 | 3 | 4 | function TitleCard({title, children, topMargin, TopSideButtons}){ 5 | return( 6 |
7 | 8 | {/* Title for Card */} 9 | 10 | {title} 11 | 12 | {/* Top side button, show only if present */} 13 | { 14 | TopSideButtons &&
{TopSideButtons}
15 | } 16 |
17 | 18 |
19 | 20 | {/** Card Body */} 21 |
22 | {children} 23 |
24 |
25 | 26 | ) 27 | } 28 | 29 | 30 | export default TitleCard -------------------------------------------------------------------------------- /src/features/dashboard/components/DashboardStats.js: -------------------------------------------------------------------------------- 1 | function DashboardStats({title, icon, value, description, colorIndex}){ 2 | 3 | const COLORS = ["primary", "primary"] 4 | 5 | const getDescStyle = () => { 6 | if(description.includes("↗︎"))return "font-bold text-green-700 dark:text-green-300" 7 | else if(description.includes("↙"))return "font-bold text-rose-500 dark:text-red-400" 8 | else return "" 9 | } 10 | 11 | return( 12 |
13 |
14 |
{icon}
15 |
{title}
16 |
{value}
17 |
{description}
18 |
19 |
20 | ) 21 | } 22 | 23 | export default DashboardStats -------------------------------------------------------------------------------- /src/features/common/rightDrawerSlice.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from '@reduxjs/toolkit' 2 | 3 | export const rightDrawerSlice = createSlice({ 4 | name: 'rightDrawer', 5 | initialState: { 6 | header: "", // current title state management 7 | isOpen : false, // right drawer state management for opening closing 8 | bodyType : "", // right drawer content management 9 | extraObject : {}, 10 | }, 11 | reducers: { 12 | 13 | openRightDrawer: (state, action) => { 14 | const {header, bodyType, extraObject} = action.payload 15 | state.isOpen = true 16 | state.bodyType = bodyType 17 | state.header = header 18 | state.extraObject = extraObject 19 | }, 20 | 21 | closeRightDrawer: (state, action) => { 22 | state.isOpen = false 23 | state.bodyType = "" 24 | state.header = "" 25 | state.extraObject = {} 26 | }, 27 | 28 | } 29 | }) 30 | 31 | export const { openRightDrawer, closeRightDrawer } = rightDrawerSlice.actions 32 | 33 | export default rightDrawerSlice.reducer -------------------------------------------------------------------------------- /src/features/common/headerSlice.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from '@reduxjs/toolkit' 2 | 3 | export const headerSlice = createSlice({ 4 | name: 'header', 5 | initialState: { 6 | pageTitle: "Home", // current page title state management 7 | noOfNotifications : 15, // no of unread notifications 8 | newNotificationMessage : "", // message of notification to be shown 9 | newNotificationStatus : 1, // to check the notification type - success/ error/ info 10 | }, 11 | reducers: { 12 | setPageTitle: (state, action) => { 13 | state.pageTitle = action.payload.title 14 | }, 15 | 16 | 17 | removeNotificationMessage: (state, action) => { 18 | state.newNotificationMessage = "" 19 | }, 20 | 21 | showNotification: (state, action) => { 22 | state.newNotificationMessage = action.payload.message 23 | state.newNotificationStatus = action.payload.status 24 | }, 25 | } 26 | }) 27 | 28 | export const { setPageTitle, removeNotificationMessage, showNotification } = headerSlice.actions 29 | 30 | export default headerSlice.reducer -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Dashwind - Admin Dashboard Template 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/features/common/modalSlice.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from '@reduxjs/toolkit' 2 | 3 | export const modalSlice = createSlice({ 4 | name: 'modal', 5 | initialState: { 6 | title: "", // current title state management 7 | isOpen : false, // modal state management for opening closing 8 | bodyType : "", // modal content management 9 | size : "", // modal content management 10 | extraObject : {}, 11 | }, 12 | reducers: { 13 | 14 | openModal: (state, action) => { 15 | const {title, bodyType, extraObject, size} = action.payload 16 | state.isOpen = true 17 | state.bodyType = bodyType 18 | state.title = title 19 | state.size = size || 'md' 20 | state.extraObject = extraObject 21 | }, 22 | 23 | closeModal: (state, action) => { 24 | state.isOpen = false 25 | state.bodyType = "" 26 | state.title = "" 27 | state.extraObject = {} 28 | }, 29 | 30 | } 31 | }) 32 | 33 | export const { openModal, closeModal } = modalSlice.actions 34 | 35 | export default modalSlice.reducer -------------------------------------------------------------------------------- /src/features/documentation/DocGettingStarted.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react" 2 | import { useDispatch } from "react-redux" 3 | import TitleCard from "../../components/Cards/TitleCard" 4 | import { setPageTitle, showNotification } from "../common/headerSlice" 5 | import GettingStartedNav from "./components/GettingStartedNav" 6 | import ReadMe from "./components/GettingStartedContent" 7 | import GettingStartedContent from "./components/GettingStartedContent" 8 | 9 | 10 | 11 | function GettingStarted(){ 12 | 13 | const dispatch = useDispatch() 14 | 15 | useEffect(() => { 16 | dispatch(setPageTitle({ title : "Documentation"})) 17 | }, []) 18 | 19 | 20 | return( 21 | <> 22 |
23 |
24 | 25 |
26 | 27 |
28 | 29 |
30 | 31 |
32 | 33 | 34 | ) 35 | } 36 | 37 | export default GettingStarted -------------------------------------------------------------------------------- /src/features/documentation/components/DocComponentsNav.js: -------------------------------------------------------------------------------- 1 | import { useState } from "react" 2 | 3 | function DocComponentsNav({activeIndex}){ 4 | 5 | const SECTION_NAVS = [ 6 | {name : "Typography", isActive : activeIndex === 1 ? true : false}, 7 | {name : "Form Input", isActive : false}, 8 | {name : "Cards", isActive : false}, 9 | ] 10 | const [navs, setNavs] = useState(SECTION_NAVS) 11 | 12 | const scrollToSection = (currentIndex) => { 13 | setNavs(navs.map((n, k) => { 14 | if(k === currentIndex)return {...n, isActive : true} 15 | else return {...n, isActive : false} 16 | })) 17 | document.getElementById('component'+(currentIndex+1)).scrollIntoView({behavior: 'smooth' }) 18 | } 19 | 20 | return( 21 |
    22 |
  • Components
  • 23 | 24 | { 25 | navs.map((n, k) => { 26 | return( 27 |
  • scrollToSection(k)} className={n.isActive ? "bordered" : ""}>{n.name}
  • 28 | ) 29 | }) 30 | } 31 |
32 | ) 33 | } 34 | 35 | export default DocComponentsNav -------------------------------------------------------------------------------- /src/features/leads/leadSlice.js: -------------------------------------------------------------------------------- 1 | import { createSlice, createAsyncThunk } from '@reduxjs/toolkit' 2 | import axios from 'axios' 3 | 4 | 5 | 6 | export const getLeadsContent = createAsyncThunk('/leads/content', async () => { 7 | const response = await axios.get('/api/users?page=2', {}) 8 | return response.data; 9 | }) 10 | 11 | export const leadsSlice = createSlice({ 12 | name: 'leads', 13 | initialState: { 14 | isLoading: false, 15 | leads : [] 16 | }, 17 | reducers: { 18 | 19 | 20 | addNewLead: (state, action) => { 21 | let {newLeadObj} = action.payload 22 | state.leads = [...state.leads, newLeadObj] 23 | }, 24 | 25 | deleteLead: (state, action) => { 26 | let {index} = action.payload 27 | state.leads.splice(index, 1) 28 | } 29 | }, 30 | 31 | extraReducers: { 32 | [getLeadsContent.pending]: state => { 33 | state.isLoading = true 34 | }, 35 | [getLeadsContent.fulfilled]: (state, action) => { 36 | state.leads = action.payload.data 37 | state.isLoading = false 38 | }, 39 | [getLeadsContent.rejected]: state => { 40 | state.isLoading = false 41 | }, 42 | } 43 | }) 44 | 45 | export const { addNewLead, deleteLead } = leadsSlice.actions 46 | 47 | export default leadsSlice.reducer -------------------------------------------------------------------------------- /src/features/documentation/DocFeatures.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react" 2 | import { useDispatch } from "react-redux" 3 | import TitleCard from "../../components/Cards/TitleCard" 4 | import { setPageTitle, showNotification } from "../common/headerSlice" 5 | import GettingStartedNav from "./components/GettingStartedNav" 6 | import ReadMe from "./components/GettingStartedContent" 7 | import GettingStartedContent from "./components/GettingStartedContent" 8 | import FeaturesNav from "./components/FeaturesNav" 9 | import FeaturesContent from "./components/FeaturesContent" 10 | 11 | 12 | 13 | function Features(){ 14 | 15 | const dispatch = useDispatch() 16 | 17 | useEffect(() => { 18 | dispatch(setPageTitle({ title : "Documentation"})) 19 | }, []) 20 | 21 | 22 | return( 23 | <> 24 |
25 |
26 | 27 |
28 | 29 |
30 | 31 |
32 | 33 |
34 | 35 | 36 | ) 37 | } 38 | 39 | export default Features -------------------------------------------------------------------------------- /src/features/charts/components/LineChart.js: -------------------------------------------------------------------------------- 1 | import { 2 | Chart as ChartJS, 3 | CategoryScale, 4 | LinearScale, 5 | PointElement, 6 | LineElement, 7 | Title, 8 | Tooltip, 9 | Filler, 10 | Legend, 11 | } from 'chart.js'; 12 | import { Line } from 'react-chartjs-2'; 13 | import TitleCard from '../../../components/Cards/TitleCard'; 14 | 15 | ChartJS.register( 16 | CategoryScale, 17 | LinearScale, 18 | PointElement, 19 | LineElement, 20 | Title, 21 | Tooltip, 22 | Filler, 23 | Legend 24 | ); 25 | 26 | function LineChart(){ 27 | 28 | const options = { 29 | responsive: true, 30 | plugins: { 31 | legend: { 32 | position: 'top', 33 | }, 34 | }, 35 | }; 36 | 37 | 38 | const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; 39 | 40 | const data = { 41 | labels, 42 | datasets: [ 43 | { 44 | fill: true, 45 | label: 'MAU', 46 | data: labels.map(() => { return Math.random() * 100 + 500 }), 47 | borderColor: 'rgb(53, 162, 235)', 48 | backgroundColor: 'rgba(53, 162, 235, 0.5)', 49 | }, 50 | ], 51 | }; 52 | 53 | 54 | return( 55 | 56 | 57 | 58 | ) 59 | } 60 | 61 | 62 | export default LineChart -------------------------------------------------------------------------------- /src/features/dashboard/components/LineChart.js: -------------------------------------------------------------------------------- 1 | import { 2 | Chart as ChartJS, 3 | CategoryScale, 4 | LinearScale, 5 | PointElement, 6 | LineElement, 7 | Title, 8 | Tooltip, 9 | Filler, 10 | Legend, 11 | } from 'chart.js'; 12 | import { Line } from 'react-chartjs-2'; 13 | import TitleCard from '../../../components/Cards/TitleCard'; 14 | 15 | ChartJS.register( 16 | CategoryScale, 17 | LinearScale, 18 | PointElement, 19 | LineElement, 20 | Title, 21 | Tooltip, 22 | Filler, 23 | Legend 24 | ); 25 | 26 | function LineChart(){ 27 | 28 | const options = { 29 | responsive: true, 30 | plugins: { 31 | legend: { 32 | position: 'top', 33 | }, 34 | }, 35 | }; 36 | 37 | 38 | const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; 39 | 40 | const data = { 41 | labels, 42 | datasets: [ 43 | { 44 | fill: true, 45 | label: 'MAU', 46 | data: labels.map(() => { return Math.random() * 100 + 500 }), 47 | borderColor: 'rgb(53, 162, 235)', 48 | backgroundColor: 'rgba(53, 162, 235, 0.5)', 49 | }, 50 | ], 51 | }; 52 | 53 | 54 | return( 55 | 56 | 57 | 58 | ) 59 | } 60 | 61 | 62 | export default LineChart -------------------------------------------------------------------------------- /src/features/documentation/DocComponents.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react" 2 | import { useDispatch } from "react-redux" 3 | import TitleCard from "../../components/Cards/TitleCard" 4 | import { setPageTitle, showNotification } from "../common/headerSlice" 5 | import DocComponentsNav from "./components/DocComponentsNav" 6 | import ReadMe from "./components/GettingStartedContent" 7 | import DocComponentsContent from "./components/DocComponentsContent" 8 | import FeaturesNav from "./components/FeaturesNav" 9 | import FeaturesContent from "./components/FeaturesContent" 10 | 11 | 12 | 13 | function DocComponents(){ 14 | 15 | const dispatch = useDispatch() 16 | 17 | useEffect(() => { 18 | dispatch(setPageTitle({ title : "Documentation"})) 19 | }, []) 20 | 21 | 22 | return( 23 | <> 24 |
25 |
26 | 27 |
28 | 29 |
30 | 31 |
32 | 33 |
34 | 35 | 36 | ) 37 | } 38 | 39 | export default DocComponents -------------------------------------------------------------------------------- /src/features/common/components/ConfirmationModalBody.js: -------------------------------------------------------------------------------- 1 | import {useDispatch, useSelector} from 'react-redux' 2 | import axios from 'axios' 3 | import { CONFIRMATION_MODAL_CLOSE_TYPES, MODAL_CLOSE_TYPES } from '../../../utils/globalConstantUtil' 4 | import { deleteLead } from '../../leads/leadSlice' 5 | import { showNotification } from '../headerSlice' 6 | 7 | function ConfirmationModalBody({ extraObject, closeModal}){ 8 | 9 | const dispatch = useDispatch() 10 | 11 | const { message, type, _id, index} = extraObject 12 | 13 | 14 | const proceedWithYes = async() => { 15 | if(type === CONFIRMATION_MODAL_CLOSE_TYPES.LEAD_DELETE){ 16 | // positive response, call api or dispatch redux function 17 | dispatch(deleteLead({index})) 18 | dispatch(showNotification({message : "Lead Deleted!", status : 1})) 19 | } 20 | closeModal() 21 | } 22 | 23 | return( 24 | <> 25 |

26 | {message} 27 |

28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 |
36 | 37 | ) 38 | } 39 | 40 | export default ConfirmationModalBody -------------------------------------------------------------------------------- /src/features/dashboard/components/BarChart.js: -------------------------------------------------------------------------------- 1 | import { 2 | Chart as ChartJS, 3 | CategoryScale, 4 | LinearScale, 5 | BarElement, 6 | Title, 7 | Tooltip, 8 | Legend, 9 | } from 'chart.js'; 10 | import { Bar } from 'react-chartjs-2'; 11 | import TitleCard from '../../../components/Cards/TitleCard'; 12 | 13 | ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend); 14 | 15 | function BarChart(){ 16 | 17 | const options = { 18 | responsive: true, 19 | plugins: { 20 | legend: { 21 | position: 'top', 22 | } 23 | }, 24 | }; 25 | 26 | const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; 27 | 28 | const data = { 29 | labels, 30 | datasets: [ 31 | { 32 | label: 'Store 1', 33 | data: labels.map(() => { return Math.random() * 1000 + 500 }), 34 | backgroundColor: 'rgba(255, 99, 132, 1)', 35 | }, 36 | { 37 | label: 'Store 2', 38 | data: labels.map(() => { return Math.random() * 1000 + 500 }), 39 | backgroundColor: 'rgba(53, 162, 235, 1)', 40 | }, 41 | ], 42 | }; 43 | 44 | return( 45 | 46 | 47 | 48 | 49 | ) 50 | } 51 | 52 | 53 | export default BarChart -------------------------------------------------------------------------------- /src/features/charts/components/BarChart.js: -------------------------------------------------------------------------------- 1 | import { 2 | Chart as ChartJS, 3 | CategoryScale, 4 | LinearScale, 5 | BarElement, 6 | Title, 7 | Tooltip, 8 | Legend, 9 | } from 'chart.js'; 10 | import { Bar } from 'react-chartjs-2'; 11 | import TitleCard from '../../../components/Cards/TitleCard'; 12 | 13 | ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend); 14 | 15 | function BarChart(){ 16 | 17 | const options = { 18 | responsive: true, 19 | plugins: { 20 | legend: { 21 | position: 'top', 22 | } 23 | }, 24 | }; 25 | 26 | const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; 27 | 28 | const data = { 29 | labels, 30 | datasets: [ 31 | { 32 | label: 'Store 1', 33 | data: labels.map(() => { return Math.random() * 1000 + 500 }), 34 | backgroundColor: 'rgba(255, 99, 132, 1)', 35 | }, 36 | { 37 | label: 'Store 2', 38 | data: labels.map(() => { return Math.random() * 1000 + 500 }), 39 | backgroundColor: 'rgba(53, 162, 235, 1)', 40 | }, 41 | ], 42 | }; 43 | 44 | return( 45 | 46 | 47 | 48 | 49 | ) 50 | } 51 | 52 | 53 | export default BarChart -------------------------------------------------------------------------------- /src/app/auth.js: -------------------------------------------------------------------------------- 1 | import axios from "axios" 2 | 3 | const checkAuth = () => { 4 | /* Getting token value stored in localstorage, if token is not present we will open login page 5 | for all internal dashboard routes */ 6 | const TOKEN = localStorage.getItem("token") 7 | const PUBLIC_ROUTES = ["login", "forgot-password", "register", "documentation"] 8 | 9 | const isPublicPage = PUBLIC_ROUTES.some( r => window.location.href.includes(r)) 10 | 11 | if(!TOKEN && !isPublicPage){ 12 | window.location.href = '/login' 13 | return; 14 | }else{ 15 | axios.defaults.headers.common['Authorization'] = `Bearer ${TOKEN}` 16 | 17 | axios.interceptors.request.use(function (config) { 18 | // UPDATE: Add this code to show global loading indicator 19 | document.body.classList.add('loading-indicator'); 20 | return config 21 | }, function (error) { 22 | return Promise.reject(error); 23 | }); 24 | 25 | axios.interceptors.response.use(function (response) { 26 | // UPDATE: Add this code to hide global loading indicator 27 | document.body.classList.remove('loading-indicator'); 28 | return response; 29 | }, function (error) { 30 | document.body.classList.remove('loading-indicator'); 31 | return Promise.reject(error); 32 | }); 33 | return TOKEN 34 | } 35 | } 36 | 37 | export default checkAuth -------------------------------------------------------------------------------- /src/features/documentation/components/FeaturesNav.js: -------------------------------------------------------------------------------- 1 | import { useState } from "react" 2 | 3 | function FeaturesNav({activeIndex}){ 4 | 5 | const SECTION_NAVS = [ 6 | {name : "Authentication", isActive : activeIndex === 1 ? true : false}, 7 | {name : "Sidebar", isActive : false}, 8 | {name : "Add New Page", isActive : false}, 9 | {name : "Right sidebar", isActive : false}, 10 | {name : "Themes", isActive : false}, 11 | {name : "Modal", isActive : false}, 12 | {name : "Notification", isActive : false}, 13 | ] 14 | const [navs, setNavs] = useState(SECTION_NAVS) 15 | 16 | const scrollToSection = (currentIndex) => { 17 | setNavs(navs.map((n, k) => { 18 | if(k === currentIndex)return {...n, isActive : true} 19 | else return {...n, isActive : false} 20 | })) 21 | document.getElementById('feature'+(currentIndex+1)).scrollIntoView({behavior: 'smooth' }) 22 | } 23 | 24 | return( 25 |
    26 |
  • Features
  • 27 | 28 | { 29 | navs.map((n, k) => { 30 | return( 31 |
  • scrollToSection(k)} className={n.isActive ? "bordered" : ""}>{n.name}
  • 32 | ) 33 | }) 34 | } 35 |
36 | ) 37 | } 38 | 39 | export default FeaturesNav -------------------------------------------------------------------------------- /src/features/documentation/components/GettingStartedNav.js: -------------------------------------------------------------------------------- 1 | import { useState } from "react" 2 | 3 | function GettingStartedNav({activeIndex}){ 4 | 5 | const SECTION_NAVS = [ 6 | {name : "Introduction", isActive : activeIndex === 1 ? true : false}, 7 | {name : "How to Use", isActive : false}, 8 | {name : "Tailwind CSS", isActive : false}, 9 | {name : "Daisy UI", isActive : false}, 10 | {name : "Chart JS", isActive : false}, 11 | {name : "Redux Toolkit", isActive : false}, 12 | {name : "Hero Icons", isActive : false}, 13 | {name : "Project Structure", isActive : false}, 14 | ] 15 | const [navs, setNavs] = useState(SECTION_NAVS) 16 | 17 | const scrollToSection = (currentIndex) => { 18 | setNavs(navs.map((n, k) => { 19 | if(k === currentIndex)return {...n, isActive : true} 20 | else return {...n, isActive : false} 21 | })) 22 | document.getElementById('getstarted'+(currentIndex+1)).scrollIntoView({behavior: 'smooth' }) 23 | } 24 | 25 | return( 26 |
    27 |
  • Getting Started
  • 28 | 29 | { 30 | navs.map((n, k) => { 31 | return( 32 |
  • scrollToSection(k)} className={n.isActive ? "bordered" : ""}>{n.name}
  • 33 | ) 34 | }) 35 | } 36 |
37 | ) 38 | } 39 | 40 | export default GettingStartedNav -------------------------------------------------------------------------------- /src/features/charts/components/ScatterChart.js: -------------------------------------------------------------------------------- 1 | import { 2 | Chart as ChartJS, 3 | Filler, 4 | ArcElement, 5 | Tooltip, 6 | Legend, 7 | } from 'chart.js'; 8 | import { Scatter } from 'react-chartjs-2'; 9 | import TitleCard from '../../../components/Cards/TitleCard'; 10 | 11 | ChartJS.register(ArcElement, Tooltip, Legend, 12 | Tooltip, 13 | Filler, 14 | Legend); 15 | 16 | function ScatterChart(){ 17 | 18 | const options = { 19 | scales: { 20 | y: { 21 | beginAtZero: true, 22 | }, 23 | }, 24 | }; 25 | 26 | const data = { 27 | datasets: [ 28 | { 29 | label: 'Orders > 1k', 30 | data: Array.from({ length: 100 }, () => ({ 31 | x: Math.random() * 11, 32 | y: Math.random() * 31, 33 | })), 34 | backgroundColor: 'rgba(255, 99, 132, 1)', 35 | }, 36 | { 37 | label: 'Orders > 2K', 38 | data: Array.from({ length: 100 }, () => ({ 39 | x: Math.random() * 12, 40 | y: Math.random() * 12, 41 | })), 42 | backgroundColor: 'rgba(0, 0, 255, 1)', 43 | }, 44 | ], 45 | }; 46 | 47 | return( 48 | 49 | 50 | 51 | ) 52 | } 53 | 54 | 55 | export default ScatterChart -------------------------------------------------------------------------------- /src/components/Input/SelectBox.js: -------------------------------------------------------------------------------- 1 | 2 | import axios from 'axios' 3 | import capitalize from 'capitalize-the-first-letter' 4 | import React, { useState, useEffect } from 'react' 5 | import InformationCircleIcon from '@heroicons/react/24/outline/InformationCircleIcon' 6 | 7 | 8 | function SelectBox(props){ 9 | 10 | const {labelTitle, labelDescription, defaultValue, containerStyle, placeholder, labelStyle, options, updateType, updateFormValue} = props 11 | 12 | const [value, setValue] = useState(defaultValue || "") 13 | 14 | 15 | const updateValue = (newValue) =>{ 16 | updateFormValue({updateType, value : newValue}) 17 | setValue(newValue) 18 | } 19 | 20 | 21 | return ( 22 |
23 | 28 | 29 | 37 |
38 | ) 39 | } 40 | 41 | export default SelectBox 42 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { lazy, useEffect } from 'react' 2 | import './App.css'; 3 | import { BrowserRouter as Router, Route, Routes, Navigate } from 'react-router-dom' 4 | import { themeChange } from 'theme-change' 5 | import checkAuth from './app/auth'; 6 | import initializeApp from './app/init'; 7 | 8 | // Importing pages 9 | const Layout = lazy(() => import('./containers/Layout')) 10 | const Login = lazy(() => import('./pages/Login')) 11 | const ForgotPassword = lazy(() => import('./pages/ForgotPassword')) 12 | const Register = lazy(() => import('./pages/Register')) 13 | const Documentation = lazy(() => import('./pages/Documentation')) 14 | 15 | 16 | // Initializing different libraries 17 | initializeApp() 18 | 19 | 20 | // Check for login and initialize axios 21 | const token = checkAuth() 22 | 23 | 24 | function App() { 25 | 26 | useEffect(() => { 27 | // 👆 daisy UI themes initialization 28 | themeChange(false) 29 | }, []) 30 | 31 | 32 | return ( 33 | <> 34 | 35 | 36 | } /> 37 | } /> 38 | } /> 39 | } /> 40 | 41 | {/* Place new routes over this */} 42 | } /> 43 | 44 | }/> 45 | 46 | 47 | 48 | 49 | ) 50 | } 51 | 52 | export default App 53 | -------------------------------------------------------------------------------- /src/containers/Layout.js: -------------------------------------------------------------------------------- 1 | import PageContent from "./PageContent" 2 | import LeftSidebar from "./LeftSidebar" 3 | import { useSelector, useDispatch } from 'react-redux' 4 | import RightSidebar from './RightSidebar' 5 | import { useEffect } from "react" 6 | import { removeNotificationMessage } from "../features/common/headerSlice" 7 | import {NotificationContainer, NotificationManager} from 'react-notifications'; 8 | import 'react-notifications/lib/notifications.css'; 9 | import ModalLayout from "./ModalLayout" 10 | 11 | function Layout(){ 12 | const dispatch = useDispatch() 13 | const {newNotificationMessage, newNotificationStatus} = useSelector(state => state.header) 14 | 15 | 16 | useEffect(() => { 17 | if(newNotificationMessage !== ""){ 18 | if(newNotificationStatus === 1)NotificationManager.success(newNotificationMessage, 'Success') 19 | if(newNotificationStatus === 0)NotificationManager.error( newNotificationMessage, 'Error') 20 | dispatch(removeNotificationMessage()) 21 | } 22 | }, [newNotificationMessage]) 23 | 24 | return( 25 | <> 26 | { /* Left drawer - containing page content and side bar (always open) */ } 27 |
28 | 29 | 30 | 31 |
32 | 33 | { /* Right drawer - containing secondary content like notifications list etc.. */ } 34 | 35 | 36 | 37 | {/** Notification layout container */} 38 | 39 | 40 | {/* Modal layout container */} 41 | 42 | 43 | 44 | ) 45 | } 46 | 47 | export default Layout -------------------------------------------------------------------------------- /src/features/calendar/index.js: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import CalendarView from '../../components/CalendarView' 3 | import moment from 'moment' 4 | import { CALENDAR_INITIAL_EVENTS } from '../../utils/dummyData' 5 | import { useDispatch } from 'react-redux' 6 | import { openRightDrawer } from '../common/rightDrawerSlice' 7 | import { RIGHT_DRAWER_TYPES } from '../../utils/globalConstantUtil' 8 | import { showNotification } from '../common/headerSlice' 9 | 10 | 11 | 12 | const INITIAL_EVENTS = CALENDAR_INITIAL_EVENTS 13 | 14 | function Calendar(){ 15 | 16 | const dispatch = useDispatch() 17 | 18 | const [events, setEvents] = useState(INITIAL_EVENTS) 19 | 20 | // Add your own Add Event handler, like opening modal or random event addition 21 | // Format - {title :"", theme: "", startTime : "", endTime : ""}, typescript version comming soon :) 22 | const addNewEvent = (date) => { 23 | let randomEvent = INITIAL_EVENTS[Math.floor(Math.random() * 10)] 24 | let newEventObj = {title : randomEvent.title, theme : randomEvent.theme, startTime : moment(date).startOf('day'), endTime : moment(date).endOf('day')} 25 | setEvents([...events, newEventObj]) 26 | dispatch(showNotification({message : "New Event Added!", status : 1})) 27 | } 28 | 29 | // Open all events of current day in sidebar 30 | const openDayDetail = ({filteredEvents, title}) => { 31 | dispatch(openRightDrawer({header : title, bodyType : RIGHT_DRAWER_TYPES.CALENDAR_EVENTS, extraObject : {filteredEvents}})) 32 | } 33 | 34 | return( 35 | <> 36 | 41 | 42 | ) 43 | } 44 | 45 | export default Calendar -------------------------------------------------------------------------------- /src/containers/ModalLayout.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { MODAL_BODY_TYPES } from '../utils/globalConstantUtil' 3 | import { useSelector, useDispatch } from 'react-redux' 4 | import { closeModal } from '../features/common/modalSlice' 5 | import AddLeadModalBody from '../features/leads/components/AddLeadModalBody' 6 | import ConfirmationModalBody from '../features/common/components/ConfirmationModalBody' 7 | 8 | 9 | function ModalLayout(){ 10 | 11 | 12 | const {isOpen, bodyType, size, extraObject, title} = useSelector(state => state.modal) 13 | const dispatch = useDispatch() 14 | 15 | const close = (e) => { 16 | dispatch(closeModal(e)) 17 | } 18 | 19 | 20 | 21 | return( 22 | <> 23 | {/* The button to open modal */} 24 | 25 | {/* Put this part before tag */} 26 |
27 |
28 | 29 |

{title}

30 | 31 | 32 | {/* Loading modal body according to different modal type */} 33 | { 34 | { 35 | [MODAL_BODY_TYPES.LEAD_ADD_NEW] : , 36 | [MODAL_BODY_TYPES.CONFIRMATION] : , 37 | [MODAL_BODY_TYPES.DEFAULT] :
38 | }[bodyType] 39 | } 40 |
41 |
42 | 43 | ) 44 | } 45 | 46 | export default ModalLayout -------------------------------------------------------------------------------- /src/features/charts/components/StackBarChart.js: -------------------------------------------------------------------------------- 1 | import { 2 | Chart as ChartJS, 3 | CategoryScale, 4 | LinearScale, 5 | BarElement, 6 | Title, 7 | Tooltip, 8 | Legend, 9 | } from 'chart.js'; 10 | import { Bar } from 'react-chartjs-2'; 11 | import TitleCard from '../../../components/Cards/TitleCard'; 12 | 13 | ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend); 14 | 15 | function StackBarChart(){ 16 | 17 | const options = { 18 | responsive: true, 19 | scales: { 20 | x: { 21 | stacked: true, 22 | }, 23 | y: { 24 | stacked: true, 25 | }, 26 | }, 27 | }; 28 | 29 | const labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July']; 30 | 31 | const data = { 32 | labels, 33 | datasets: [ 34 | { 35 | label: 'Store 1', 36 | data: labels.map(() => { return Math.random() * 1000 + 500 }), 37 | backgroundColor: 'rgba(255, 99, 132, 1)', 38 | }, 39 | { 40 | label: 'Store 2', 41 | data: labels.map(() => { return Math.random() * 1000 + 500 }), 42 | backgroundColor: 'rgba(53, 162, 235, 1)', 43 | }, 44 | { 45 | label: 'Store 3', 46 | data: labels.map(() => { return Math.random() * 1000 + 500 }), 47 | backgroundColor: 'rgba(235, 162, 235, 1)', 48 | }, 49 | ], 50 | }; 51 | 52 | return( 53 | 54 | 55 | 56 | 57 | ) 58 | } 59 | 60 | 61 | export default StackBarChart -------------------------------------------------------------------------------- /src/features/dashboard/components/UserChannels.js: -------------------------------------------------------------------------------- 1 | import TitleCard from "../../../components/Cards/TitleCard" 2 | 3 | const userSourceData = [ 4 | {source : "Facebook Ads", count : "26,345", conversionPercent : 10.2}, 5 | {source : "Google Ads", count : "21,341", conversionPercent : 11.7}, 6 | {source : "Instagram Ads", count : "34,379", conversionPercent : 12.4}, 7 | {source : "Affiliates", count : "12,359", conversionPercent : 20.9}, 8 | {source : "Organic", count : "10,345", conversionPercent : 10.3}, 9 | ] 10 | 11 | function UserChannels(){ 12 | return( 13 | 14 | {/** Table Data */} 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | { 27 | userSourceData.map((u, k) => { 28 | return( 29 | 30 | 31 | 32 | 33 | 34 | 35 | ) 36 | }) 37 | } 38 | 39 |
SourceNo of UsersConversion
{k+1}{u.source}{u.count}{`${u.conversionPercent}%`}
40 |
41 |
42 | ) 43 | } 44 | 45 | export default UserChannels -------------------------------------------------------------------------------- /src/pages/Documentation.js: -------------------------------------------------------------------------------- 1 | import {Link} from 'react-router-dom' 2 | import FeaturesNav from '../features/documentation/components/FeaturesNav' 3 | import GettingStartedContent from '../features/documentation/components/GettingStartedContent' 4 | import GettingStartedNav from '../features/documentation/components/GettingStartedNav' 5 | import Title from '../components/Typography/Title' 6 | import DocComponentsNav from '../features/documentation/components/DocComponentsNav' 7 | import FeaturesContent from '../features/documentation/components/FeaturesContent' 8 | import DocComponentsContent from '../features/documentation/components/DocComponentsContent' 9 | 10 | function Documentation(){ 11 | return( 12 | <> 13 |
14 |
15 |
16 |
17 |

Dashwind

18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 |
26 | 27 | 28 | 29 |
30 |
31 |
32 |
33 | 34 | 35 | ) 36 | } 37 | 38 | export default Documentation -------------------------------------------------------------------------------- /src/features/charts/index.js: -------------------------------------------------------------------------------- 1 | import LineChart from './components/LineChart' 2 | import BarChart from './components/BarChart' 3 | import DoughnutChart from './components/DoughnutChart' 4 | import PieChart from './components/PieChart' 5 | import ScatterChart from './components/ScatterChart' 6 | import StackBarChart from './components/StackBarChart' 7 | import Datepicker from "react-tailwindcss-datepicker"; 8 | import { useState } from 'react' 9 | 10 | 11 | 12 | 13 | function Charts(){ 14 | 15 | const [dateValue, setDateValue] = useState({ 16 | startDate: new Date(), 17 | endDate: new Date() 18 | }); 19 | 20 | const handleDatePickerValueChange = (newValue) => { 21 | console.log("newValue:", newValue); 22 | setDateValue(newValue); 23 | } 24 | 25 | return( 26 | <> 27 | 38 | {/** ---------------------- Different charts ------------------------- */} 39 |
40 | 41 | 42 |
43 | 44 | 45 |
46 | 47 | 48 |
49 | 50 |
51 | 52 | 53 |
54 | 55 | ) 56 | } 57 | 58 | export default Charts -------------------------------------------------------------------------------- /src/features/charts/components/DoughnutChart.js: -------------------------------------------------------------------------------- 1 | import { 2 | Chart as ChartJS, 3 | Filler, 4 | ArcElement, 5 | Title, 6 | Tooltip, 7 | Legend, 8 | } from 'chart.js'; 9 | import { Doughnut } from 'react-chartjs-2'; 10 | import TitleCard from '../../../components/Cards/TitleCard'; 11 | import Subtitle from '../../../components/Typography/Subtitle'; 12 | 13 | ChartJS.register(ArcElement, Tooltip, Legend, 14 | Tooltip, 15 | Filler, 16 | Legend); 17 | 18 | function DoughnutChart(){ 19 | 20 | const options = { 21 | responsive: true, 22 | plugins: { 23 | legend: { 24 | position: 'top', 25 | }, 26 | }, 27 | }; 28 | 29 | const labels = ['Electronics', 'Home Applicances', 'Beauty', 'Furniture', 'Watches', 'Apparel']; 30 | 31 | const data = { 32 | labels, 33 | datasets: [ 34 | { 35 | label: '# of Orders', 36 | data: [122, 219, 30, 51, 82, 13], 37 | backgroundColor: [ 38 | 'rgba(255, 99, 132, 0.8)', 39 | 'rgba(54, 162, 235, 0.8)', 40 | 'rgba(255, 206, 86, 0.8)', 41 | 'rgba(75, 192, 192, 0.8)', 42 | 'rgba(153, 102, 255, 0.8)', 43 | 'rgba(255, 159, 64, 0.8)', 44 | ], 45 | borderColor: [ 46 | 'rgba(255, 99, 132, 1)', 47 | 'rgba(54, 162, 235, 1)', 48 | 'rgba(255, 206, 86, 1)', 49 | 'rgba(75, 192, 192, 1)', 50 | 'rgba(153, 102, 255, 1)', 51 | 'rgba(255, 159, 64, 1)', 52 | ], 53 | borderWidth: 1, 54 | } 55 | ], 56 | }; 57 | 58 | return( 59 | 60 | 61 | 62 | ) 63 | } 64 | 65 | 66 | export default DoughnutChart -------------------------------------------------------------------------------- /src/features/dashboard/components/DoughnutChart.js: -------------------------------------------------------------------------------- 1 | import { 2 | Chart as ChartJS, 3 | Filler, 4 | ArcElement, 5 | Title, 6 | Tooltip, 7 | Legend, 8 | } from 'chart.js'; 9 | import { Doughnut } from 'react-chartjs-2'; 10 | import TitleCard from '../../../components/Cards/TitleCard'; 11 | import Subtitle from '../../../components/Typography/Subtitle'; 12 | 13 | ChartJS.register(ArcElement, Tooltip, Legend, 14 | Tooltip, 15 | Filler, 16 | Legend); 17 | 18 | function DoughnutChart(){ 19 | 20 | const options = { 21 | responsive: true, 22 | plugins: { 23 | legend: { 24 | position: 'top', 25 | }, 26 | }, 27 | }; 28 | 29 | const labels = ['Electronics', 'Home Applicances', 'Beauty', 'Furniture', 'Watches', 'Apparel']; 30 | 31 | const data = { 32 | labels, 33 | datasets: [ 34 | { 35 | label: '# of Orders', 36 | data: [122, 219, 30, 51, 82, 13], 37 | backgroundColor: [ 38 | 'rgba(255, 99, 132, 0.8)', 39 | 'rgba(54, 162, 235, 0.8)', 40 | 'rgba(255, 206, 86, 0.8)', 41 | 'rgba(75, 192, 192, 0.8)', 42 | 'rgba(153, 102, 255, 0.8)', 43 | 'rgba(255, 159, 64, 0.8)', 44 | ], 45 | borderColor: [ 46 | 'rgba(255, 99, 132, 1)', 47 | 'rgba(54, 162, 235, 1)', 48 | 'rgba(255, 206, 86, 1)', 49 | 'rgba(75, 192, 192, 1)', 50 | 'rgba(153, 102, 255, 1)', 51 | 'rgba(255, 159, 64, 1)', 52 | ], 53 | borderWidth: 1, 54 | } 55 | ], 56 | }; 57 | 58 | return( 59 | 60 | 61 | 62 | ) 63 | } 64 | 65 | 66 | export default DoughnutChart -------------------------------------------------------------------------------- /src/containers/SidebarSubmenu.js: -------------------------------------------------------------------------------- 1 | import ChevronDownIcon from '@heroicons/react/24/outline/ChevronDownIcon' 2 | import {useEffect, useState} from 'react' 3 | import { Link, useLocation } from 'react-router-dom' 4 | 5 | 6 | function SidebarSubmenu({submenu, name, icon}){ 7 | const location = useLocation() 8 | const [isExpanded, setIsExpanded] = useState(false) 9 | 10 | 11 | /** Open Submenu list if path found in routes, this is for directly loading submenu routes first time */ 12 | useEffect(() => { 13 | if(submenu.filter(m => {return m.path === location.pathname})[0])setIsExpanded(true) 14 | }, []) 15 | 16 | return ( 17 |
18 | 19 | {/** Route header */} 20 |
setIsExpanded(!isExpanded)}> 21 | {icon} {name} 22 | 23 |
24 | 25 | {/** Submenu list */} 26 |
27 |
    28 | { 29 | submenu.map((m, k) => { 30 | return( 31 |
  • 32 | 33 | {m.icon} {m.name} 34 | { 35 | location.pathname == m.path ? () : null 37 | } 38 | 39 |
  • 40 | ) 41 | }) 42 | } 43 |
44 |
45 |
46 | ) 47 | } 48 | 49 | export default SidebarSubmenu -------------------------------------------------------------------------------- /src/features/charts/components/PieChart.js: -------------------------------------------------------------------------------- 1 | import { 2 | Chart as ChartJS, 3 | Filler, 4 | ArcElement, 5 | Title, 6 | Tooltip, 7 | Legend, 8 | } from 'chart.js'; 9 | import { Pie } from 'react-chartjs-2'; 10 | import TitleCard from '../../../components/Cards/TitleCard'; 11 | import Subtitle from '../../../components/Typography/Subtitle'; 12 | 13 | ChartJS.register(ArcElement, Tooltip, Legend, 14 | Tooltip, 15 | Filler, 16 | Legend); 17 | 18 | function PieChart(){ 19 | 20 | const options = { 21 | responsive: true, 22 | plugins: { 23 | legend: { 24 | position: 'top', 25 | }, 26 | }, 27 | }; 28 | 29 | const labels = ['India', 'Middle East', 'Europe', 'US', 'Latin America', 'Asia(non-india)']; 30 | 31 | const data = { 32 | labels, 33 | datasets: [ 34 | { 35 | label: '# of Orders', 36 | data: [122, 219, 30, 51, 82, 13], 37 | backgroundColor: [ 38 | 'rgba(255, 99, 255, 0.8)', 39 | 'rgba(54, 162, 235, 0.8)', 40 | 'rgba(255, 206, 255, 0.8)', 41 | 'rgba(75, 192, 255, 0.8)', 42 | 'rgba(153, 102, 255, 0.8)', 43 | 'rgba(255, 159, 255, 0.8)', 44 | ], 45 | borderColor: [ 46 | 'rgba(255, 99, 255, 1)', 47 | 'rgba(54, 162, 235, 1)', 48 | 'rgba(255, 206, 255, 1)', 49 | 'rgba(75, 192, 255, 1)', 50 | 'rgba(153, 102, 255, 1)', 51 | 'rgba(255, 159, 255, 1)', 52 | ], 53 | borderWidth: 1, 54 | } 55 | ], 56 | }; 57 | 58 | return( 59 | 60 | 61 | 62 | ) 63 | } 64 | 65 | 66 | export default PieChart -------------------------------------------------------------------------------- /src/containers/PageContent.js: -------------------------------------------------------------------------------- 1 | import Header from "./Header" 2 | import { BrowserRouter as Router, Route, Routes } from 'react-router-dom' 3 | import routes from '../routes' 4 | import { Suspense, lazy } from 'react' 5 | import SuspenseContent from "./SuspenseContent" 6 | import { useSelector } from 'react-redux' 7 | import { useEffect, useRef } from "react" 8 | 9 | const Page404 = lazy(() => import('../pages/protected/404')) 10 | 11 | 12 | function PageContent(){ 13 | const mainContentRef = useRef(null); 14 | const {pageTitle} = useSelector(state => state.header) 15 | 16 | 17 | // Scroll back to top on new page load 18 | useEffect(() => { 19 | mainContentRef.current.scroll({ 20 | top: 0, 21 | behavior: "smooth" 22 | }); 23 | }, [pageTitle]) 24 | 25 | return( 26 |
27 |
28 |
29 | }> 30 | 31 | { 32 | routes.map((route, key) => { 33 | return( 34 | } 39 | /> 40 | ) 41 | }) 42 | } 43 | 44 | {/* Redirecting unknown url to 404 page */} 45 | } /> 46 | 47 | 48 |
49 |
50 |
51 | ) 52 | } 53 | 54 | 55 | export default PageContent 56 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | Daisy UI Admin Dashboard Template - DashWind 28 | 29 | 30 | 31 | 32 |
33 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/routes/index.js: -------------------------------------------------------------------------------- 1 | // All components mapping with path for internal routes 2 | 3 | import { lazy } from 'react' 4 | 5 | const Dashboard = lazy(() => import('../pages/protected/Dashboard')) 6 | const Welcome = lazy(() => import('../pages/protected/Welcome')) 7 | const Page404 = lazy(() => import('../pages/protected/404')) 8 | const Blank = lazy(() => import('../pages/protected/Blank')) 9 | const Charts = lazy(() => import('../pages/protected/Charts')) 10 | const Leads = lazy(() => import('../pages/protected/Leads')) 11 | const Integration = lazy(() => import('../pages/protected/Integration')) 12 | const Calendar = lazy(() => import('../pages/protected/Calendar')) 13 | const Team = lazy(() => import('../pages/protected/Team')) 14 | const Transactions = lazy(() => import('../pages/protected/Transactions')) 15 | const Bills = lazy(() => import('../pages/protected/Bills')) 16 | const ProfileSettings = lazy(() => import('../pages/protected/ProfileSettings')) 17 | const GettingStarted = lazy(() => import('../pages/GettingStarted')) 18 | const DocFeatures = lazy(() => import('../pages/DocFeatures')) 19 | const DocComponents = lazy(() => import('../pages/DocComponents')) 20 | 21 | 22 | const routes = [ 23 | { 24 | path: '/dashboard', // the url 25 | component: Dashboard, // view rendered 26 | }, 27 | { 28 | path: '/welcome', // the url 29 | component: Welcome, // view rendered 30 | }, 31 | { 32 | path: '/leads', 33 | component: Leads, 34 | }, 35 | { 36 | path: '/settings-team', 37 | component: Team, 38 | }, 39 | { 40 | path: '/calendar', 41 | component: Calendar, 42 | }, 43 | { 44 | path: '/transactions', 45 | component: Transactions, 46 | }, 47 | { 48 | path: '/settings-profile', 49 | component: ProfileSettings, 50 | }, 51 | { 52 | path: '/settings-billing', 53 | component: Bills, 54 | }, 55 | { 56 | path: '/getting-started', 57 | component: GettingStarted, 58 | }, 59 | { 60 | path: '/features', 61 | component: DocFeatures, 62 | }, 63 | { 64 | path: '/components', 65 | component: DocComponents, 66 | }, 67 | { 68 | path: '/integration', 69 | component: Integration, 70 | }, 71 | { 72 | path: '/charts', 73 | component: Charts, 74 | }, 75 | { 76 | path: '/404', 77 | component: Page404, 78 | }, 79 | { 80 | path: '/blank', 81 | component: Blank, 82 | }, 83 | ] 84 | 85 | export default routes 86 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "admin-dashboard-template-dashwind", 3 | "version": "1.0.0", 4 | "description": "Admin Dashboard template built with create-react-app, tailwind css and daisy UI. Template uses rich tailwind css utility classes and have components of daisy UI, also have redux toolkit implemented for store management.", 5 | "scripts": { 6 | "start": "react-scripts start", 7 | "build": "react-scripts build", 8 | "test": "react-scripts test", 9 | "eject": "react-scripts eject" 10 | }, 11 | "dependencies": { 12 | "@heroicons/react": "^2.0.13", 13 | "@reduxjs/toolkit": "^1.9.0", 14 | "@testing-library/jest-dom": "^5.16.5", 15 | "@testing-library/react": "^13.4.0", 16 | "@testing-library/user-event": "^13.5.0", 17 | "axios": "^1.1.3", 18 | "capitalize-the-first-letter": "^1.0.8", 19 | "chart.js": "^4.0.1", 20 | "dayjs": "^1.11.7", 21 | "moment": "^2.29.4", 22 | "react": "^18.2.0", 23 | "react-chartjs-2": "^5.0.1", 24 | "react-dom": "^18.2.0", 25 | "react-notifications": "^1.7.4", 26 | "react-redux": "^8.0.5", 27 | "react-router-dom": "^6.4.3", 28 | "react-scripts": "5.0.1", 29 | "react-tailwindcss-datepicker": "^1.6.0", 30 | "theme-change": "^2.2.0", 31 | "web-vitals": "^2.1.4" 32 | }, 33 | "repository": { 34 | "type": "git", 35 | "url": "git+https://github.com/srobbin01/tailwind-dashboard-template-dashwind" 36 | }, 37 | "keywords": [ 38 | "reactjs", 39 | "tailwind-css", 40 | "starter-kit", 41 | "saas-starter-kit", 42 | "reduxt-toolkit-dashboard-template", 43 | "daisyui-template", 44 | "dashboard-template", 45 | "react-router", 46 | "react-charts" 47 | ], 48 | "author": "srobbin01", 49 | "license": "ISC", 50 | "bugs": { 51 | "url": "https://github.com/srobbin01/tailwind-dashboard-template-dashwind/issues" 52 | }, 53 | "homepage": "", 54 | "eslintConfig": { 55 | "extends": [ 56 | "react-app", 57 | "react-app/jest" 58 | ] 59 | }, 60 | "browserslist": { 61 | "production": [ 62 | ">0.2%", 63 | "not dead", 64 | "not op_mini all" 65 | ], 66 | "development": [ 67 | "last 1 chrome version", 68 | "last 1 firefox version", 69 | "last 1 safari version" 70 | ] 71 | }, 72 | "devDependencies": { 73 | "@tailwindcss/typography": "^0.5.8", 74 | "autoprefixer": "^10.4.13", 75 | "daisyui": "^4.4.19", 76 | "postcss": "^8.4.19", 77 | "tailwindcss": "^3.3.6" 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/features/settings/profilesettings/index.js: -------------------------------------------------------------------------------- 1 | import moment from "moment" 2 | import { useEffect, useState } from "react" 3 | import { useDispatch, useSelector } from "react-redux" 4 | import TitleCard from "../../../components/Cards/TitleCard" 5 | import { showNotification } from '../../common/headerSlice' 6 | import InputText from '../../../components/Input/InputText' 7 | import TextAreaInput from '../../../components/Input/TextAreaInput' 8 | import ToogleInput from '../../../components/Input/ToogleInput' 9 | 10 | function ProfileSettings(){ 11 | 12 | 13 | const dispatch = useDispatch() 14 | 15 | // Call API to update profile settings changes 16 | const updateProfile = () => { 17 | dispatch(showNotification({message : "Profile Updated", status : 1})) 18 | } 19 | 20 | const updateFormValue = ({updateType, value}) => { 21 | console.log(updateType) 22 | } 23 | 24 | return( 25 | <> 26 | 27 | 28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 |
36 |
37 | 38 |
39 | 40 | 41 | 42 |
43 | 44 |
45 |
46 | 47 | ) 48 | } 49 | 50 | 51 | export default ProfileSettings -------------------------------------------------------------------------------- /src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/features/leads/components/AddLeadModalBody.js: -------------------------------------------------------------------------------- 1 | import { useState } from "react" 2 | import { useDispatch } from "react-redux" 3 | import InputText from '../../../components/Input/InputText' 4 | import ErrorText from '../../../components/Typography/ErrorText' 5 | import { showNotification } from "../../common/headerSlice" 6 | import { addNewLead } from "../leadSlice" 7 | 8 | const INITIAL_LEAD_OBJ = { 9 | first_name : "", 10 | last_name : "", 11 | email : "" 12 | } 13 | 14 | function AddLeadModalBody({closeModal}){ 15 | const dispatch = useDispatch() 16 | const [loading, setLoading] = useState(false) 17 | const [errorMessage, setErrorMessage] = useState("") 18 | const [leadObj, setLeadObj] = useState(INITIAL_LEAD_OBJ) 19 | 20 | 21 | const saveNewLead = () => { 22 | if(leadObj.first_name.trim() === "")return setErrorMessage("First Name is required!") 23 | else if(leadObj.email.trim() === "")return setErrorMessage("Email id is required!") 24 | else{ 25 | let newLeadObj = { 26 | "id": 7, 27 | "email": leadObj.email, 28 | "first_name": leadObj.first_name, 29 | "last_name": leadObj.last_name, 30 | "avatar": "https://reqres.in/img/faces/1-image.jpg" 31 | } 32 | dispatch(addNewLead({newLeadObj})) 33 | dispatch(showNotification({message : "New Lead Added!", status : 1})) 34 | closeModal() 35 | } 36 | } 37 | 38 | const updateFormValue = ({updateType, value}) => { 39 | setErrorMessage("") 40 | setLeadObj({...leadObj, [updateType] : value}) 41 | } 42 | 43 | return( 44 | <> 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | {errorMessage} 54 |
55 | 56 | 57 |
58 | 59 | ) 60 | } 61 | 62 | export default AddLeadModalBody -------------------------------------------------------------------------------- /src/containers/LeftSidebar.js: -------------------------------------------------------------------------------- 1 | import routes from '../routes/sidebar' 2 | import { NavLink, Routes, Link , useLocation} from 'react-router-dom' 3 | import SidebarSubmenu from './SidebarSubmenu'; 4 | import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon' 5 | import { useDispatch } from 'react-redux'; 6 | 7 | function LeftSidebar(){ 8 | const location = useLocation(); 9 | 10 | const dispatch = useDispatch() 11 | 12 | 13 | const close = (e) => { 14 | document.getElementById('left-sidebar-drawer').click() 15 | } 16 | 17 | return( 18 |
19 | 20 |
    21 | 24 | 25 |
  • 26 | 27 | DashWind LogoDashWind
  • 28 | { 29 | routes.map((route, k) => { 30 | return( 31 |
  • 32 | { 33 | route.submenu ? 34 | : 35 | ( `${isActive ? 'font-semibold bg-base-200 ' : 'font-normal'}`} > 39 | {route.icon} {route.name} 40 | { 41 | location.pathname === route.path ? () : null 43 | } 44 | ) 45 | } 46 | 47 |
  • 48 | ) 49 | }) 50 | } 51 | 52 |
53 |
54 | ) 55 | } 56 | 57 | export default LeftSidebar -------------------------------------------------------------------------------- /src/containers/RightSidebar.js: -------------------------------------------------------------------------------- 1 | import XMarkIcon from '@heroicons/react/24/solid/XMarkIcon' 2 | import { useDispatch, useSelector } from 'react-redux' 3 | import NotificationBodyRightDrawer from '../features/common/components/NotificationBodyRightDrawer' 4 | import { closeRightDrawer } from '../features/common/rightDrawerSlice' 5 | import { RIGHT_DRAWER_TYPES } from '../utils/globalConstantUtil' 6 | import CalendarEventsBodyRightDrawer from '../features/calendar/CalendarEventsBodyRightDrawer' 7 | 8 | 9 | function RightSidebar(){ 10 | 11 | const {isOpen, bodyType, extraObject, header} = useSelector(state => state.rightDrawer) 12 | const dispatch = useDispatch() 13 | 14 | const close = (e) => { 15 | dispatch(closeRightDrawer(e)) 16 | } 17 | 18 | 19 | 20 | return( 21 |
22 | 23 |
24 | 25 |
26 | 27 | {/* Header */} 28 |
29 | 32 | {header} 33 |
34 | 35 | 36 | {/* ------------------ Content Start ------------------ */} 37 |
38 |
39 | {/* Loading drawer body according to different drawer type */} 40 | { 41 | { 42 | [RIGHT_DRAWER_TYPES.NOTIFICATION] : , 43 | [RIGHT_DRAWER_TYPES.CALENDAR_EVENTS] : , 44 | [RIGHT_DRAWER_TYPES.DEFAULT] :
45 | }[bodyType] 46 | } 47 | 48 |
49 |
50 | {/* ------------------ Content End ------------------ */} 51 |
52 | 53 |
54 | 55 |
close()} >
56 |
57 | ) 58 | } 59 | 60 | export default RightSidebar -------------------------------------------------------------------------------- /src/features/dashboard/components/DashboardTopBar.js: -------------------------------------------------------------------------------- 1 | import SelectBox from "../../../components/Input/SelectBox" 2 | import ArrowDownTrayIcon from '@heroicons/react/24/outline/ArrowDownTrayIcon' 3 | import ShareIcon from '@heroicons/react/24/outline/ShareIcon' 4 | import EnvelopeIcon from '@heroicons/react/24/outline/EnvelopeIcon' 5 | import EllipsisVerticalIcon from '@heroicons/react/24/outline/EllipsisVerticalIcon' 6 | import ArrowPathIcon from '@heroicons/react/24/outline/ArrowPathIcon' 7 | import { useState } from "react" 8 | import Datepicker from "react-tailwindcss-datepicker"; 9 | 10 | 11 | 12 | const periodOptions = [ 13 | {name : "Today", value : "TODAY"}, 14 | {name : "Yesterday", value : "YESTERDAY"}, 15 | {name : "This Week", value : "THIS_WEEK"}, 16 | {name : "Last Week", value : "LAST_WEEK"}, 17 | {name : "This Month", value : "THIS_MONTH"}, 18 | {name : "Last Month", value : "LAST_MONTH"}, 19 | ] 20 | 21 | function DashboardTopBar({updateDashboardPeriod}){ 22 | 23 | const [dateValue, setDateValue] = useState({ 24 | startDate: new Date(), 25 | endDate: new Date() 26 | }); 27 | 28 | const handleDatePickerValueChange = (newValue) => { 29 | console.log("newValue:", newValue); 30 | setDateValue(newValue); 31 | updateDashboardPeriod(newValue) 32 | } 33 | 34 | 35 | return( 36 |
37 |
38 | 49 | {/* */} 58 |
59 |
60 | 61 | 62 | 63 |
64 | 65 | 69 |
70 |
71 |
72 | ) 73 | } 74 | 75 | export default DashboardTopBar -------------------------------------------------------------------------------- /src/features/user/Login.js: -------------------------------------------------------------------------------- 1 | import {useState, useRef} from 'react' 2 | import {Link} from 'react-router-dom' 3 | import LandingIntro from './LandingIntro' 4 | import ErrorText from '../../components/Typography/ErrorText' 5 | import InputText from '../../components/Input/InputText' 6 | 7 | function Login(){ 8 | 9 | const INITIAL_LOGIN_OBJ = { 10 | password : "", 11 | emailId : "" 12 | } 13 | 14 | const [loading, setLoading] = useState(false) 15 | const [errorMessage, setErrorMessage] = useState("") 16 | const [loginObj, setLoginObj] = useState(INITIAL_LOGIN_OBJ) 17 | 18 | const submitForm = (e) =>{ 19 | e.preventDefault() 20 | setErrorMessage("") 21 | 22 | if(loginObj.emailId.trim() === "")return setErrorMessage("Email Id is required! (use any value)") 23 | if(loginObj.password.trim() === "")return setErrorMessage("Password is required! (use any value)") 24 | else{ 25 | setLoading(true) 26 | // Call API to check user credentials and save token in localstorage 27 | localStorage.setItem("token", "DumyTokenHere") 28 | setLoading(false) 29 | window.location.href = '/app/welcome' 30 | } 31 | } 32 | 33 | const updateFormValue = ({updateType, value}) => { 34 | setErrorMessage("") 35 | setLoginObj({...loginObj, [updateType] : value}) 36 | } 37 | 38 | return( 39 |
40 |
41 |
42 |
43 | 44 |
45 |
46 |

Login

47 |
submitForm(e)}> 48 | 49 |
50 | 51 | 52 | 53 | 54 | 55 |
56 | 57 |
Forgot Password? 58 |
59 | 60 | {errorMessage} 61 | 62 | 63 |
Don't have an account yet? Register
64 |
65 |
66 |
67 |
68 |
69 | ) 70 | } 71 | 72 | export default Login -------------------------------------------------------------------------------- /src/features/dashboard/index.js: -------------------------------------------------------------------------------- 1 | import DashboardStats from './components/DashboardStats' 2 | import AmountStats from './components/AmountStats' 3 | import PageStats from './components/PageStats' 4 | 5 | import UserGroupIcon from '@heroicons/react/24/outline/UserGroupIcon' 6 | import UsersIcon from '@heroicons/react/24/outline/UsersIcon' 7 | import CircleStackIcon from '@heroicons/react/24/outline/CircleStackIcon' 8 | import CreditCardIcon from '@heroicons/react/24/outline/CreditCardIcon' 9 | import UserChannels from './components/UserChannels' 10 | import LineChart from './components/LineChart' 11 | import BarChart from './components/BarChart' 12 | import DashboardTopBar from './components/DashboardTopBar' 13 | import { useDispatch } from 'react-redux' 14 | import {showNotification} from '../common/headerSlice' 15 | import DoughnutChart from './components/DoughnutChart' 16 | import { useState } from 'react' 17 | 18 | const statsData = [ 19 | {title : "New Users", value : "34.7k", icon : , description : "↗︎ 2300 (22%)"}, 20 | {title : "Total Sales", value : "$34,545", icon : , description : "Current month"}, 21 | {title : "Pending Leads", value : "450", icon : , description : "50 in hot leads"}, 22 | {title : "Active Users", value : "5.6k", icon : , description : "↙ 300 (18%)"}, 23 | ] 24 | 25 | 26 | 27 | function Dashboard(){ 28 | 29 | const dispatch = useDispatch() 30 | 31 | 32 | const updateDashboardPeriod = (newRange) => { 33 | // Dashboard range changed, write code to refresh your values 34 | dispatch(showNotification({message : `Period updated to ${newRange.startDate} to ${newRange.endDate}`, status : 1})) 35 | } 36 | 37 | return( 38 | <> 39 | {/** ---------------------- Select Period Content ------------------------- */} 40 | 41 | 42 | {/** ---------------------- Different stats content 1 ------------------------- */} 43 |
44 | { 45 | statsData.map((d, k) => { 46 | return ( 47 | 48 | ) 49 | }) 50 | } 51 |
52 | 53 | 54 | 55 | {/** ---------------------- Different charts ------------------------- */} 56 |
57 | 58 | 59 |
60 | 61 | {/** ---------------------- Different stats content 2 ------------------------- */} 62 | 63 |
64 | 65 | 66 |
67 | 68 | {/** ---------------------- User source channels table ------------------------- */} 69 | 70 |
71 | 72 | 73 |
74 | 75 | ) 76 | } 77 | 78 | export default Dashboard -------------------------------------------------------------------------------- /src/features/user/Register.js: -------------------------------------------------------------------------------- 1 | import {useState, useRef} from 'react' 2 | import {Link} from 'react-router-dom' 3 | import LandingIntro from './LandingIntro' 4 | import ErrorText from '../../components/Typography/ErrorText' 5 | import InputText from '../../components/Input/InputText' 6 | 7 | function Register(){ 8 | 9 | const INITIAL_REGISTER_OBJ = { 10 | name : "", 11 | password : "", 12 | emailId : "" 13 | } 14 | 15 | const [loading, setLoading] = useState(false) 16 | const [errorMessage, setErrorMessage] = useState("") 17 | const [registerObj, setRegisterObj] = useState(INITIAL_REGISTER_OBJ) 18 | 19 | const submitForm = (e) =>{ 20 | e.preventDefault() 21 | setErrorMessage("") 22 | 23 | if(registerObj.name.trim() === "")return setErrorMessage("Name is required! (use any value)") 24 | if(registerObj.emailId.trim() === "")return setErrorMessage("Email Id is required! (use any value)") 25 | if(registerObj.password.trim() === "")return setErrorMessage("Password is required! (use any value)") 26 | else{ 27 | setLoading(true) 28 | // Call API to check user credentials and save token in localstorage 29 | localStorage.setItem("token", "DumyTokenHere") 30 | setLoading(false) 31 | window.location.href = '/app/welcome' 32 | } 33 | } 34 | 35 | const updateFormValue = ({updateType, value}) => { 36 | setErrorMessage("") 37 | setRegisterObj({...registerObj, [updateType] : value}) 38 | } 39 | 40 | return( 41 |
42 |
43 |
44 |
45 | 46 |
47 |
48 |

Register

49 |
submitForm(e)}> 50 | 51 |
52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
60 | 61 | {errorMessage} 62 | 63 | 64 |
Already have an account? Login
65 |
66 |
67 |
68 |
69 |
70 | ) 71 | } 72 | 73 | export default Register -------------------------------------------------------------------------------- /src/features/integration/index.js: -------------------------------------------------------------------------------- 1 | import { useState } from "react" 2 | import { useDispatch } from "react-redux" 3 | import TitleCard from "../../components/Cards/TitleCard" 4 | import { showNotification } from "../common/headerSlice" 5 | 6 | 7 | const INITIAL_INTEGRATION_LIST = [ 8 | {name : "Slack", icon : "https://cdn-icons-png.flaticon.com/512/2111/2111615.png", isActive : true, description : "Slack is an instant messaging program designed by Slack Technologies and owned by Salesforce."}, 9 | {name : "Facebook", icon : "https://cdn-icons-png.flaticon.com/512/124/124010.png", isActive : false, description : "Meta Platforms, Inc., doing business as Meta and formerly named Facebook, Inc., and TheFacebook."}, 10 | {name : "Linkedin", icon : "https://cdn-icons-png.flaticon.com/512/174/174857.png", isActive : true, description : "LinkedIn is a business and employment-focused social media platform that works through websites and mobile apps."}, 11 | {name : "Google Ads", icon : "https://cdn-icons-png.flaticon.com/512/2301/2301145.png", isActive : false, description : "Google Ads is an online advertising platform developed by Google, where advertisers bid to display brief advertisements, service offerings"}, 12 | {name : "Gmail", icon : "https://cdn-icons-png.flaticon.com/512/5968/5968534.png", isActive : false, description : "Gmail is a free email service provided by Google. As of 2019, it had 1.5 billion active users worldwide."}, 13 | {name : "Salesforce", icon : "https://cdn-icons-png.flaticon.com/512/5968/5968880.png", isActive : false, description : "It provides customer relationship management software and applications focused on sales, customer service, marketing automation."}, 14 | {name : "Hubspot", icon : "https://cdn-icons-png.flaticon.com/512/5968/5968872.png", isActive : false, description : "American developer and marketer of software products for inbound marketing, sales, and customer service."}, 15 | ] 16 | 17 | function Integration(){ 18 | 19 | const dispatch = useDispatch() 20 | 21 | const [integrationList, setIntegrationList] = useState(INITIAL_INTEGRATION_LIST) 22 | 23 | 24 | const updateIntegrationStatus = (index) => { 25 | let integration = integrationList[index] 26 | setIntegrationList(integrationList.map((i, k) => { 27 | if(k===index)return {...i, isActive : !i.isActive} 28 | return i 29 | })) 30 | dispatch(showNotification({message : `${integration.name} ${integration.isActive ? "disabled" : "enabled"}` , status : 1})) 31 | } 32 | 33 | 34 | return( 35 | <> 36 |
37 | { 38 | integrationList.map((i, k) => { 39 | return( 40 | 41 | 42 |

43 | icon 44 | {i.description} 45 |

46 |
47 | updateIntegrationStatus(k)}/> 48 |
49 | 50 |
51 | ) 52 | 53 | }) 54 | } 55 |
56 | 57 | ) 58 | } 59 | 60 | export default Integration -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ![Logo](https://ik.imagekit.io/vu5t8xb15vzcx/tr:h-100/android-chrome-512x512_EiumvYoXeA.png?ik-sdk-version=javascript-1.4.3&updatedAt=1669548997842) 3 | 4 | # Daisy UI Admin Dashboard Template - DashWind 5 | [![MIT License](https://img.shields.io/badge/License-MIT-green.svg)](https://choosealicense.com/licenses/mit/) 6 | 7 | This is a free admin dashboard template that uses **Daisy UI** and React js. It has **fully customizable and themable CSS** CSS and is powered by Tailwind CSS utility classes. Additionally, it comes with **redux toolkit** and other libraries already set up. 8 | 9 | 10 | ## Preview 11 | 12 | 🚀 [Live preview](https://tailwind-dashboard-template-dashwind.vercel.app/) 13 | 14 | 15 | ![App Screenshot](https://ik.imagekit.io/vu5t8xb15vzcx/tr:h-600/Screenshot_2023-05-09_at_12.57.37_PM_z94SiShUDS.png?updatedAt=1683617550144) 16 | 17 | 18 | 19 | ## Features 20 | 21 | - **Light/dark** mode toggle 22 | - Token based user **authentication** 23 | - **Submenu support** in sidebar 24 | - Store management using **redux toolkit** 25 | - **Daisy UI** components and **Tailwind** support 26 | - **Right and left sidebar**, Universal loader, notifications 27 | - **Calendar**, global modal, **chart js 2** and other components 28 | 29 | ## Typescript Nest Js Version 30 | 31 | [Link](https://github.com/robbins23/admin-dashboard-nextjs-typescript-daisyui) 32 | 33 | 34 | ## Installation 35 | 36 | Go to project directory and run (make sure you have node installed first) 37 | 38 | ```bash 39 | npm install 40 | npm start 41 | ``` 42 | 43 | ## Core Libraries Used 44 | 45 | - [React JS v18.2.0](https://reactjs.org/) 46 | - [React Router v6.4.3](https://reactrouter.com/en/main) 47 | - [Tailwind CSS v3.3.6](https://tailwindcss.com/) 48 | - [Daisy UI v4.4.19](https://daisyui.com/) 49 | - [HeroIcons](https://heroicons.com/) 50 | - [Redux toolkit v1.9](https://redux-toolkit.js.org/) 51 | - [React ChartJS 2 v5](https://react-chartjs-2.js.org/) 52 | 53 | ## Documentation 54 | 55 | [Documentation](https://tailwind-dashboard-template-dashwind.vercel.app/documentation) 56 | 57 | ## Page Examples 58 | 59 | | | | 60 | :-------------------------:|:-------------------------: 61 | ![Dark Mode](https://ik.imagekit.io/vu5t8xb15vzcx/tr:h-600/Screenshot_2023-05-09_at_12.57.37_PM_z94SiShUDS.png?updatedAt=1683617550144) | ![Transations Screenshot](https://ik.imagekit.io/vu5t8xb15vzcx/Screenshot_2023-05-09_at_1.01.54_PM_YiG__JTFu.png?updatedAt=1683619541458) 62 | ![Leads Screenshot](https://ik.imagekit.io/vu5t8xb15vzcx/Screenshot_2023-05-09_at_1.34.56_PM_cdSamaaCmA.png?updatedAt=1683619597855) | ![Setting Screenshot](https://ik.imagekit.io/vu5t8xb15vzcx/Screenshot_2023-01-20_at_12.43.25_PM_xZBThuZdU.png?ik-sdk-version=javascript-1.4.3&updatedAt=1674198832089) 63 | ![Calendar Screenshot](https://ik.imagekit.io/vu5t8xb15vzcx/Screenshot_2023-05-09_at_1.02.03_PM_pObZm43gl.png?updatedAt=1683617549958) | ![Register Screenshot](https://ik.imagekit.io/vu5t8xb15vzcx/Screenshot_2023-01-20_at_12.43.00_PM_1fkpMRG90.png?ik-sdk-version=javascript-1.4.3&updatedAt=1674198831908) 64 | 65 | 66 | 67 | 68 | 69 | ## Preview 70 | 71 | 🚀 [Live preview](https://tailwind-dashboard-template-dashwind.vercel.app/) 72 | 73 | 74 | ## Roadmap 75 | 76 | - Addition of users, chat/ inbox page 77 | - Calendar improments 78 | - Seperate templates based on business functions like CRM, Sales, Project Management 79 | 80 | 81 | ## Contributing 82 | 83 | Contributions are always welcome! 84 | 85 | ## License 86 | 87 | [![MIT License](https://img.shields.io/badge/License-MIT-green.svg)](https://choosealicense.com/licenses/mit/) 88 | 89 | 90 | ## Feedback 91 | 92 | If you have any feedback, please reach out [here](https://forms.gle/8G7PsvQp8X1Swcf29) 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /src/features/user/ForgotPassword.js: -------------------------------------------------------------------------------- 1 | import {useState, useRef} from 'react' 2 | import {Link} from 'react-router-dom' 3 | import LandingIntro from './LandingIntro' 4 | import ErrorText from '../../components/Typography/ErrorText' 5 | import InputText from '../../components/Input/InputText' 6 | import CheckCircleIcon from '@heroicons/react/24/solid/CheckCircleIcon' 7 | 8 | function ForgotPassword(){ 9 | 10 | const INITIAL_USER_OBJ = { 11 | emailId : "" 12 | } 13 | 14 | const [loading, setLoading] = useState(false) 15 | const [errorMessage, setErrorMessage] = useState("") 16 | const [linkSent, setLinkSent] = useState(false) 17 | const [userObj, setUserObj] = useState(INITIAL_USER_OBJ) 18 | 19 | const submitForm = (e) =>{ 20 | e.preventDefault() 21 | setErrorMessage("") 22 | 23 | if(userObj.emailId.trim() === "")return setErrorMessage("Email Id is required! (use any value)") 24 | else{ 25 | setLoading(true) 26 | // Call API to send password reset link 27 | setLoading(false) 28 | setLinkSent(true) 29 | } 30 | } 31 | 32 | const updateFormValue = ({updateType, value}) => { 33 | setErrorMessage("") 34 | setUserObj({...userObj, [updateType] : value}) 35 | } 36 | 37 | return( 38 |
39 |
40 |
41 |
42 | 43 |
44 |
45 |

Forgot Password

46 | 47 | { 48 | linkSent && 49 | <> 50 |
51 |

Link Sent

52 |

Check your email to reset password

53 |
54 | 55 | 56 | } 57 | 58 | { 59 | !linkSent && 60 | <> 61 |

We will send password reset link on your email Id

62 |
submitForm(e)}> 63 | 64 |
65 | 66 | 67 | 68 | 69 |
70 | 71 | {errorMessage} 72 | 73 | 74 |
Don't have an account yet?
75 |
76 | 77 | } 78 | 79 |
80 |
81 |
82 |
83 | ) 84 | } 85 | 86 | export default ForgotPassword -------------------------------------------------------------------------------- /src/features/settings/billing/index.js: -------------------------------------------------------------------------------- 1 | import moment from "moment" 2 | import { useEffect, useState } from "react" 3 | import { useDispatch, useSelector } from "react-redux" 4 | import TitleCard from "../../../components/Cards/TitleCard" 5 | import { showNotification } from '../../common/headerSlice' 6 | 7 | 8 | 9 | const BILLS = [ 10 | {invoiceNo : "#4567", amount : "23,989", description : "Product usages", status : "Pending", generatedOn : moment(new Date()).add(-30*1, 'days').format("DD MMM YYYY"), paidOn : "-"}, 11 | 12 | {invoiceNo : "#4523", amount : "34,989", description : "Product usages", status : "Pending", generatedOn : moment(new Date()).add(-30*2, 'days').format("DD MMM YYYY"), paidOn : "-"}, 13 | 14 | {invoiceNo : "#4453", amount : "39,989", description : "Product usages", status : "Paid", generatedOn : moment(new Date()).add(-30*3, 'days').format("DD MMM YYYY"), paidOn : moment(new Date()).add(-24*2, 'days').format("DD MMM YYYY")}, 15 | 16 | {invoiceNo : "#4359", amount : "28,927", description : "Product usages", status : "Paid", generatedOn : moment(new Date()).add(-30*4, 'days').format("DD MMM YYYY"), paidOn : moment(new Date()).add(-24*3, 'days').format("DD MMM YYYY")}, 17 | 18 | {invoiceNo : "#3359", amount : "28,927", description : "Product usages", status : "Paid", generatedOn : moment(new Date()).add(-30*5, 'days').format("DD MMM YYYY"), paidOn : moment(new Date()).add(-24*4, 'days').format("DD MMM YYYY")}, 19 | 20 | {invoiceNo : "#3367", amount : "28,927", description : "Product usages", status : "Paid", generatedOn : moment(new Date()).add(-30*6, 'days').format("DD MMM YYYY"), paidOn : moment(new Date()).add(-24*5, 'days').format("DD MMM YYYY")}, 21 | 22 | {invoiceNo : "#3359", amount : "28,927", description : "Product usages", status : "Paid", generatedOn : moment(new Date()).add(-30*7, 'days').format("DD MMM YYYY"), paidOn : moment(new Date()).add(-24*6, 'days').format("DD MMM YYYY")}, 23 | 24 | {invoiceNo : "#2359", amount : "28,927", description : "Product usages", status : "Paid", generatedOn : moment(new Date()).add(-30*8, 'days').format("DD MMM YYYY"), paidOn : moment(new Date()).add(-24*7, 'days').format("DD MMM YYYY")}, 25 | 26 | 27 | ] 28 | 29 | function Billing(){ 30 | 31 | 32 | const [bills, setBills] = useState(BILLS) 33 | 34 | const getPaymentStatus = (status) => { 35 | if(status === "Paid")return
{status}
36 | if(status === "Pending")return
{status}
37 | else return
{status}
38 | } 39 | 40 | return( 41 | <> 42 | 43 | 44 | 45 | {/* Invoice list in table format loaded constant */} 46 |
47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | { 60 | bills.map((l, k) => { 61 | return( 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | ) 71 | }) 72 | } 73 | 74 |
Invoice NoInvoice Generated OnDescriptionAmountStatusInvoice Paid On
{l.invoiceNo}{l.generatedOn}{l.description}${l.amount}{getPaymentStatus(l.status)}{l.paidOn}
75 |
76 |
77 | 78 | ) 79 | } 80 | 81 | 82 | export default Billing -------------------------------------------------------------------------------- /src/features/leads/index.js: -------------------------------------------------------------------------------- 1 | import moment from "moment" 2 | import { useEffect } from "react" 3 | import { useDispatch, useSelector } from "react-redux" 4 | import TitleCard from "../../components/Cards/TitleCard" 5 | import { openModal } from "../common/modalSlice" 6 | import { deleteLead, getLeadsContent } from "./leadSlice" 7 | import { CONFIRMATION_MODAL_CLOSE_TYPES, MODAL_BODY_TYPES } from '../../utils/globalConstantUtil' 8 | import TrashIcon from '@heroicons/react/24/outline/TrashIcon' 9 | import { showNotification } from '../common/headerSlice' 10 | 11 | const TopSideButtons = () => { 12 | 13 | const dispatch = useDispatch() 14 | 15 | const openAddNewLeadModal = () => { 16 | dispatch(openModal({title : "Add New Lead", bodyType : MODAL_BODY_TYPES.LEAD_ADD_NEW})) 17 | } 18 | 19 | return( 20 |
21 | 22 |
23 | ) 24 | } 25 | 26 | function Leads(){ 27 | 28 | const {leads } = useSelector(state => state.lead) 29 | const dispatch = useDispatch() 30 | 31 | useEffect(() => { 32 | dispatch(getLeadsContent()) 33 | }, []) 34 | 35 | 36 | 37 | const getDummyStatus = (index) => { 38 | if(index % 5 === 0)return
Not Interested
39 | else if(index % 5 === 1)return
In Progress
40 | else if(index % 5 === 2)return
Sold
41 | else if(index % 5 === 3)return
Need Followup
42 | else return
Open
43 | } 44 | 45 | const deleteCurrentLead = (index) => { 46 | dispatch(openModal({title : "Confirmation", bodyType : MODAL_BODY_TYPES.CONFIRMATION, 47 | extraObject : { message : `Are you sure you want to delete this lead?`, type : CONFIRMATION_MODAL_CLOSE_TYPES.LEAD_DELETE, index}})) 48 | } 49 | 50 | return( 51 | <> 52 | 53 | }> 54 | 55 | {/* Leads List in table format loaded from slice after api call */} 56 |
57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | { 70 | leads.map((l, k) => { 71 | return( 72 | 73 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | ) 93 | }) 94 | } 95 | 96 |
NameEmail IdCreated AtStatusAssigned To
74 |
75 |
76 |
77 | Avatar 78 |
79 |
80 |
81 |
{l.first_name}
82 |
{l.last_name}
83 |
84 |
85 |
{l.email}{moment(new Date()).add(-5*(k+2), 'days').format("DD MMM YY")}{getDummyStatus(k)}{l.last_name}
97 |
98 |
99 | 100 | ) 101 | } 102 | 103 | 104 | export default Leads -------------------------------------------------------------------------------- /src/features/settings/team/index.js: -------------------------------------------------------------------------------- 1 | import moment from "moment" 2 | import { useEffect, useState } from "react" 3 | import { useDispatch, useSelector } from "react-redux" 4 | import TitleCard from "../../../components/Cards/TitleCard" 5 | import { showNotification } from '../../common/headerSlice' 6 | 7 | const TopSideButtons = () => { 8 | 9 | const dispatch = useDispatch() 10 | 11 | const addNewTeamMember = () => { 12 | dispatch(showNotification({message : "Add New Member clicked", status : 1})) 13 | } 14 | 15 | return( 16 |
17 | 18 |
19 | ) 20 | } 21 | 22 | 23 | const TEAM_MEMBERS = [ 24 | {name : "Alex", avatar : "https://reqres.in/img/faces/1-image.jpg", email : "alex@dashwind.com", role : "Owner", joinedOn : moment(new Date()).add(-5*1, 'days').format("DD MMM YYYY"), lastActive : "5 hr ago"}, 25 | {name : "Ereena", avatar : "https://reqres.in/img/faces/2-image.jpg", email : "ereena@dashwind.com", role : "Admin", joinedOn : moment(new Date()).add(-5*2, 'days').format("DD MMM YYYY"), lastActive : "15 min ago"}, 26 | {name : "John", avatar : "https://reqres.in/img/faces/3-image.jpg", email : "jhon@dashwind.com", role : "Admin", joinedOn : moment(new Date()).add(-5*3, 'days').format("DD MMM YYYY"), lastActive : "20 hr ago"}, 27 | {name : "Matrix", avatar : "https://reqres.in/img/faces/4-image.jpg", email : "matrix@dashwind.com", role : "Manager", joinedOn : moment(new Date()).add(-5*4, 'days').format("DD MMM YYYY"), lastActive : "1 hr ago"}, 28 | {name : "Virat", avatar : "https://reqres.in/img/faces/5-image.jpg", email : "virat@dashwind.com", role : "Support", joinedOn : moment(new Date()).add(-5*5, 'days').format("DD MMM YYYY"), lastActive : "40 min ago"}, 29 | {name : "Miya", avatar : "https://reqres.in/img/faces/6-image.jpg", email : "miya@dashwind.com", role : "Support", joinedOn : moment(new Date()).add(-5*7, 'days').format("DD MMM YYYY"), lastActive : "5 hr ago"}, 30 | 31 | ] 32 | 33 | function Team(){ 34 | 35 | 36 | const [members, setMembers] = useState(TEAM_MEMBERS) 37 | 38 | const getRoleComponent = (role) => { 39 | if(role === "Admin")return
{role}
40 | if(role === "Manager")return
{role}
41 | if(role === "Owner")return
{role}
42 | if(role === "Support")return
{role}
43 | else return
{role}
44 | } 45 | 46 | return( 47 | <> 48 | 49 | }> 50 | 51 | {/* Team Member list in table format loaded constant */} 52 |
53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | { 65 | members.map((l, k) => { 66 | return( 67 | 68 | 80 | 81 | 82 | 83 | 84 | 85 | ) 86 | }) 87 | } 88 | 89 |
NameEmail IdJoined OnRoleLast Active
69 |
70 |
71 |
72 | Avatar 73 |
74 |
75 |
76 |
{l.name}
77 |
78 |
79 |
{l.email}{l.joinedOn}{getRoleComponent(l.role)}{l.lastActive}
90 |
91 |
92 | 93 | ) 94 | } 95 | 96 | 97 | export default Team -------------------------------------------------------------------------------- /src/containers/Header.js: -------------------------------------------------------------------------------- 1 | import { themeChange } from 'theme-change' 2 | import React, { useEffect, useState } from 'react' 3 | import { useSelector, useDispatch } from 'react-redux' 4 | import BellIcon from '@heroicons/react/24/outline/BellIcon' 5 | import Bars3Icon from '@heroicons/react/24/outline/Bars3Icon' 6 | import MoonIcon from '@heroicons/react/24/outline/MoonIcon' 7 | import SunIcon from '@heroicons/react/24/outline/SunIcon' 8 | import { openRightDrawer } from '../features/common/rightDrawerSlice'; 9 | import { RIGHT_DRAWER_TYPES } from '../utils/globalConstantUtil' 10 | 11 | import { NavLink, Routes, Link , useLocation} from 'react-router-dom' 12 | 13 | 14 | function Header(){ 15 | 16 | const dispatch = useDispatch() 17 | const {noOfNotifications, pageTitle} = useSelector(state => state.header) 18 | const [currentTheme, setCurrentTheme] = useState(localStorage.getItem("theme")) 19 | 20 | useEffect(() => { 21 | themeChange(false) 22 | if(currentTheme === null){ 23 | if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ) { 24 | setCurrentTheme("dark") 25 | }else{ 26 | setCurrentTheme("light") 27 | } 28 | } 29 | // 👆 false parameter is required for react project 30 | }, []) 31 | 32 | 33 | // Opening right sidebar for notification 34 | const openNotification = () => { 35 | dispatch(openRightDrawer({header : "Notifications", bodyType : RIGHT_DRAWER_TYPES.NOTIFICATION})) 36 | } 37 | 38 | 39 | function logoutUser(){ 40 | localStorage.clear(); 41 | window.location.href = '/' 42 | } 43 | 44 | return( 45 | // navbar fixed flex-none justify-between bg-base-300 z-10 shadow-md 46 | 47 | <> 48 |
49 | 50 | 51 | {/* Menu toogle for mobile view or small screen */} 52 |
53 | 55 |

{pageTitle}

56 |
57 | 58 | 59 | 60 |
61 | 62 | {/* Multiple theme selection, uncomment this if you want to enable multiple themes selection, 63 | also includes corporate and retro themes in tailwind.config file */} 64 | 65 | {/* */} 72 | 73 | 74 | {/* Light and dark theme selection toogle **/} 75 | 80 | 81 | 82 | {/* Notification icon */} 83 | 89 | 90 | 91 | {/* Profile icon, opening menu on click */} 92 |
93 | 98 |
    99 |
  • 100 | 101 | Profile Settings 102 | New 103 | 104 |
  • 105 |
  • Bill History
  • 106 |
    107 |
  • Logout
  • 108 |
109 |
110 |
111 |
112 | 113 | 114 | ) 115 | } 116 | 117 | export default Header -------------------------------------------------------------------------------- /src/routes/sidebar.js: -------------------------------------------------------------------------------- 1 | /** Icons are imported separatly to reduce build time */ 2 | import BellIcon from '@heroicons/react/24/outline/BellIcon' 3 | import DocumentTextIcon from '@heroicons/react/24/outline/DocumentTextIcon' 4 | import Squares2X2Icon from '@heroicons/react/24/outline/Squares2X2Icon' 5 | import TableCellsIcon from '@heroicons/react/24/outline/TableCellsIcon' 6 | import WalletIcon from '@heroicons/react/24/outline/WalletIcon' 7 | import CodeBracketSquareIcon from '@heroicons/react/24/outline/CodeBracketSquareIcon' 8 | import DocumentIcon from '@heroicons/react/24/outline/DocumentIcon' 9 | import ExclamationTriangleIcon from '@heroicons/react/24/outline/ExclamationTriangleIcon' 10 | import CalendarDaysIcon from '@heroicons/react/24/outline/CalendarDaysIcon' 11 | import ArrowRightOnRectangleIcon from '@heroicons/react/24/outline/ArrowRightOnRectangleIcon' 12 | import UserIcon from '@heroicons/react/24/outline/UserIcon' 13 | import Cog6ToothIcon from '@heroicons/react/24/outline/Cog6ToothIcon' 14 | import BoltIcon from '@heroicons/react/24/outline/BoltIcon' 15 | import ChartBarIcon from '@heroicons/react/24/outline/ChartBarIcon' 16 | import CurrencyDollarIcon from '@heroicons/react/24/outline/CurrencyDollarIcon' 17 | import InboxArrowDownIcon from '@heroicons/react/24/outline/InboxArrowDownIcon' 18 | import UsersIcon from '@heroicons/react/24/outline/UsersIcon' 19 | import KeyIcon from '@heroicons/react/24/outline/KeyIcon' 20 | import DocumentDuplicateIcon from '@heroicons/react/24/outline/DocumentDuplicateIcon' 21 | 22 | const iconClasses = `h-6 w-6` 23 | const submenuIconClasses = `h-5 w-5` 24 | 25 | const routes = [ 26 | 27 | { 28 | path: '/app/dashboard', 29 | icon: , 30 | name: 'Dashboard', 31 | }, 32 | { 33 | path: '/app/leads', // url 34 | icon: , // icon component 35 | name: 'Leads', // name that appear in Sidebar 36 | }, 37 | { 38 | path: '/app/transactions', // url 39 | icon: , // icon component 40 | name: 'Transactions', // name that appear in Sidebar 41 | }, 42 | { 43 | path: '/app/charts', // url 44 | icon: , // icon component 45 | name: 'Analytics', // name that appear in Sidebar 46 | }, 47 | { 48 | path: '/app/integration', // url 49 | icon: , // icon component 50 | name: 'Integration', // name that appear in Sidebar 51 | }, 52 | { 53 | path: '/app/calendar', // url 54 | icon: , // icon component 55 | name: 'Calendar', // name that appear in Sidebar 56 | }, 57 | 58 | { 59 | path: '', //no url needed as this has submenu 60 | icon: , // icon component 61 | name: 'Pages', // name that appear in Sidebar 62 | submenu : [ 63 | { 64 | path: '/login', 65 | icon: , 66 | name: 'Login', 67 | }, 68 | { 69 | path: '/register', //url 70 | icon: , // icon component 71 | name: 'Register', // name that appear in Sidebar 72 | }, 73 | { 74 | path: '/forgot-password', 75 | icon: , 76 | name: 'Forgot Password', 77 | }, 78 | { 79 | path: '/app/blank', 80 | icon: , 81 | name: 'Blank Page', 82 | }, 83 | { 84 | path: '/app/404', 85 | icon: , 86 | name: '404', 87 | }, 88 | ] 89 | }, 90 | { 91 | path: '', //no url needed as this has submenu 92 | icon: , // icon component 93 | name: 'Settings', // name that appear in Sidebar 94 | submenu : [ 95 | { 96 | path: '/app/settings-profile', //url 97 | icon: , // icon component 98 | name: 'Profile', // name that appear in Sidebar 99 | }, 100 | { 101 | path: '/app/settings-billing', 102 | icon: , 103 | name: 'Billing', 104 | }, 105 | { 106 | path: '/app/settings-team', // url 107 | icon: , // icon component 108 | name: 'Team Members', // name that appear in Sidebar 109 | }, 110 | ] 111 | }, 112 | { 113 | path: '', //no url needed as this has submenu 114 | icon: , // icon component 115 | name: 'Documentation', // name that appear in Sidebar 116 | submenu : [ 117 | { 118 | path: '/app/getting-started', // url 119 | icon: , // icon component 120 | name: 'Getting Started', // name that appear in Sidebar 121 | }, 122 | { 123 | path: '/app/features', 124 | icon: , 125 | name: 'Features', 126 | }, 127 | { 128 | path: '/app/components', 129 | icon: , 130 | name: 'Components', 131 | } 132 | ] 133 | }, 134 | 135 | ] 136 | 137 | export default routes 138 | 139 | 140 | -------------------------------------------------------------------------------- /src/features/transactions/index.js: -------------------------------------------------------------------------------- 1 | import moment from "moment" 2 | import { useEffect, useState } from "react" 3 | import { useDispatch, useSelector } from "react-redux" 4 | import { showNotification } from "../common/headerSlice" 5 | import TitleCard from "../../components/Cards/TitleCard" 6 | import { RECENT_TRANSACTIONS } from "../../utils/dummyData" 7 | import FunnelIcon from '@heroicons/react/24/outline/FunnelIcon' 8 | import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon' 9 | import SearchBar from "../../components/Input/SearchBar" 10 | 11 | const TopSideButtons = ({removeFilter, applyFilter, applySearch}) => { 12 | 13 | const [filterParam, setFilterParam] = useState("") 14 | const [searchText, setSearchText] = useState("") 15 | const locationFilters = ["Paris", "London", "Canada", "Peru", "Tokyo"] 16 | 17 | const showFiltersAndApply = (params) => { 18 | applyFilter(params) 19 | setFilterParam(params) 20 | } 21 | 22 | const removeAppliedFilter = () => { 23 | removeFilter() 24 | setFilterParam("") 25 | setSearchText("") 26 | } 27 | 28 | useEffect(() => { 29 | if(searchText == ""){ 30 | removeAppliedFilter() 31 | }else{ 32 | applySearch(searchText) 33 | } 34 | }, [searchText]) 35 | 36 | return( 37 |
38 | 39 | {filterParam != "" && } 40 |
41 | 42 | 51 |
52 |
53 | ) 54 | } 55 | 56 | 57 | function Transactions(){ 58 | 59 | 60 | const [trans, setTrans] = useState(RECENT_TRANSACTIONS) 61 | 62 | const removeFilter = () => { 63 | setTrans(RECENT_TRANSACTIONS) 64 | } 65 | 66 | const applyFilter = (params) => { 67 | let filteredTransactions = RECENT_TRANSACTIONS.filter((t) => {return t.location == params}) 68 | setTrans(filteredTransactions) 69 | } 70 | 71 | // Search according to name 72 | const applySearch = (value) => { 73 | let filteredTransactions = RECENT_TRANSACTIONS.filter((t) => {return t.email.toLowerCase().includes(value.toLowerCase()) || t.email.toLowerCase().includes(value.toLowerCase())}) 74 | setTrans(filteredTransactions) 75 | } 76 | 77 | return( 78 | <> 79 | 80 | }> 81 | 82 | {/* Team Member list in table format loaded constant */} 83 |
84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | { 96 | trans.map((l, k) => { 97 | return( 98 | 99 | 111 | 112 | 113 | 114 | 115 | 116 | ) 117 | }) 118 | } 119 | 120 |
NameEmail IdLocationAmountTransaction Date
100 |
101 |
102 |
103 | Avatar 104 |
105 |
106 |
107 |
{l.name}
108 |
109 |
110 |
{l.email}{l.location}${l.amount}{moment(l.date).format("D MMM")}
121 |
122 |
123 | 124 | ) 125 | } 126 | 127 | 128 | export default Transactions -------------------------------------------------------------------------------- /src/utils/dummyData.js: -------------------------------------------------------------------------------- 1 | const moment = require("moment"); 2 | 3 | module.exports = Object.freeze({ 4 | CALENDAR_INITIAL_EVENTS : [ 5 | {title : "Product call", theme : "GREEN", startTime : moment().add(-12, 'd').startOf('day'), endTime : moment().add(-12, 'd').endOf('day')}, 6 | {title : "Meeting with tech team", theme : "PINK", startTime : moment().add(-8, 'd').startOf('day'), endTime : moment().add(-8, 'd').endOf('day')}, 7 | {title : "Meeting with Cristina", theme : "PURPLE", startTime : moment().add(-2, 'd').startOf('day'), endTime : moment().add(-2, 'd').endOf('day')}, 8 | {title : "Meeting with Alex", theme : "BLUE", startTime : moment().startOf('day'), endTime : moment().endOf('day')}, 9 | {title : "Product Call", theme : "GREEN", startTime : moment().startOf('day'), endTime : moment().endOf('day')}, 10 | {title : "Client Meeting", theme : "PURPLE", startTime : moment().startOf('day'), endTime : moment().endOf('day')}, 11 | {title : "Client Meeting", theme : "ORANGE", startTime : moment().add(3, 'd').startOf('day'), endTime : moment().add(3, 'd').endOf('day')}, 12 | {title : "Product meeting", theme : "PINK", startTime : moment().add(5, 'd').startOf('day'), endTime : moment().add(5, 'd').endOf('day')}, 13 | {title : "Sales Meeting", theme : "GREEN", startTime : moment().add(8, 'd').startOf('day'), endTime : moment().add(8, 'd').endOf('day')}, 14 | {title : "Product Meeting", theme : "ORANGE", startTime : moment().add(8, 'd').startOf('day'), endTime : moment().add(8, 'd').endOf('day')}, 15 | {title : "Marketing Meeting", theme : "PINK", startTime : moment().add(8, 'd').startOf('day'), endTime : moment().add(8, 'd').endOf('day')}, 16 | {title : "Client Meeting", theme : "GREEN", startTime : moment().add(8, 'd').startOf('day'), endTime : moment().add(8, 'd').endOf('day')}, 17 | {title : "Sales meeting", theme : "BLUE", startTime : moment().add(12, 'd').startOf('day'), endTime : moment().add(12, 'd').endOf('day')}, 18 | {title : "Client meeting", theme : "PURPLE", startTime : moment().add(16, 'd').startOf('day'), endTime : moment().add(16, 'd').endOf('day')}, 19 | ], 20 | 21 | RECENT_TRANSACTIONS : [ 22 | {name : "Alex", avatar : "https://reqres.in/img/faces/1-image.jpg", email : "alex@dashwind.com", location : "Paris", amount : 100, date : moment().endOf('day')}, 23 | {name : "Ereena", avatar : "https://reqres.in/img/faces/2-image.jpg", email : "ereena@dashwind.com", location : "London", amount : 190, date : moment().add(-1, 'd').endOf('day')}, 24 | {name : "John", avatar : "https://reqres.in/img/faces/3-image.jpg", email : "jhon@dashwind.com", location : "Canada", amount : 112, date : moment().add(-1, 'd').endOf('day')}, 25 | {name : "Matrix", avatar : "https://reqres.in/img/faces/4-image.jpg", email : "matrix@dashwind.com", location : "Peru", amount : 111, date : moment().add(-1, 'd').endOf('day')}, 26 | {name : "Virat", avatar : "https://reqres.in/img/faces/5-image.jpg", email : "virat@dashwind.com", location : "London", amount : 190, date : moment().add(-2, 'd').endOf('day')}, 27 | {name : "Miya", avatar : "https://reqres.in/img/faces/6-image.jpg", email : "miya@dashwind.com", location : "Paris", amount : 230, date : moment().add(-2, 'd').endOf('day')}, 28 | {name : "Virat", avatar : "https://reqres.in/img/faces/3-image.jpg", email : "virat@dashwind.com", location : "Canada", amount : 331, date : moment().add(-2, 'd').endOf('day')}, 29 | {name : "Matrix", avatar : "https://reqres.in/img/faces/1-image.jpg", email : "matrix@dashwind.com", location : "London", amount : 581, date : moment().add(-2, 'd').endOf('day')}, 30 | {name : "Ereena", avatar : "https://reqres.in/img/faces/3-image.jpg", email : "ereena@dashwind.com", location : "Tokyo", amount : 151, date : moment().add(-2, 'd').endOf('day')}, 31 | {name : "John", avatar : "https://reqres.in/img/faces/2-image.jpg", email : "jhon@dashwind.com", location : "Paris", amount : 91, date : moment().add(-2, 'd').endOf('day')}, 32 | {name : "Virat", avatar : "https://reqres.in/img/faces/3-image.jpg", email : "virat@dashwind.com", location : "Canada", amount : 161, date : moment().add(-3, 'd').endOf('day')}, 33 | {name : "Matrix", avatar : "https://reqres.in/img/faces/4-image.jpg", email : "matrix@dashwind.com", location : "US", amount : 121, date : moment().add(-3, 'd').endOf('day')}, 34 | {name : "Ereena", avatar : "https://reqres.in/img/faces/6-image.jpg", email : "jhon@dashwind.com", location : "Tokyo", amount : 713, date : moment().add(-3, 'd').endOf('day')}, 35 | {name : "John", avatar : "https://reqres.in/img/faces/2-image.jpg", email : "ereena@dashwind.com", location : "London", amount : 217, date : moment().add(-3, 'd').endOf('day')}, 36 | {name : "Virat", avatar : "https://reqres.in/img/faces/3-image.jpg", email : "virat@dashwind.com", location : "Paris", amount : 117, date : moment().add(-3, 'd').endOf('day')}, 37 | {name : "Miya", avatar : "https://reqres.in/img/faces/7-image.jpg", email : "jhon@dashwind.com", location : "Canada", amount : 612, date : moment().add(-3, 'd').endOf('day')}, 38 | {name : "Matrix", avatar : "https://reqres.in/img/faces/3-image.jpg", email : "matrix@dashwind.com", location : "London", amount : 631, date : moment().add(-3, 'd').endOf('day')}, 39 | {name : "Virat", avatar : "https://reqres.in/img/faces/2-image.jpg", email : "ereena@dashwind.com", location : "Tokyo", amount : 151, date : moment().add(-3, 'd').endOf('day')}, 40 | {name : "Ereena", avatar : "https://reqres.in/img/faces/3-image.jpg", email : "virat@dashwind.com", location : "Paris", amount : 617, date : moment().add(-3, 'd').endOf('day')}, 41 | 42 | 43 | ] 44 | }); 45 | -------------------------------------------------------------------------------- /src/features/documentation/components/DocComponentsContent.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { useDispatch } from 'react-redux' 3 | import InputText from '../../../components/Input/InputText' 4 | import Title from '../../../components/Typography/Title' 5 | import Subtitle from '../../../components/Typography/Subtitle' 6 | import ErrorText from '../../../components/Typography/ErrorText' 7 | import HelperText from '../../../components/Typography/HelperText' 8 | 9 | import { setPageTitle, showNotification } from '../../common/headerSlice' 10 | import TitleCard from '../../../components/Cards/TitleCard' 11 | 12 | function DocComponentsContent(){ 13 | 14 | const dispatch = useDispatch() 15 | 16 | const updateFormValue = () => { 17 | // Dummy function for input text component 18 | } 19 | 20 | return( 21 | <> 22 |
23 |

Components

24 | 25 | We have added some global components that are used commonly inside the project. 26 | 27 | {/* Typography*/} 28 |

Typography

29 |
30 | These components are present under /components/Typography folder. It accepts styleClass as props which can be used to pass additional className for style. It has following components which you can import and use it - 31 |
32 |
{'import  Title from "../components/Typography/Title"\n  Your Title here'}
33 |
34 |
    35 |
  • Title - Use this component to show title 36 | Title Example 37 |
  • 38 |
  • Subtitle - Component that shows text smaller than title 39 | Subtitle Example 40 |
  • 41 |
  • ErrorText - Used for showing error messages 42 | Error Text Example 43 |
  • 44 |
  • HelperText - Used for showing secondary message 45 | Helper Text Example
  • 46 |
47 |
48 | 49 | 50 | {/* Form Input*/} 51 |

Form Input

52 |

53 | Many times we have to use form input like text, select one or toogle and in every file we have to handle its state management, here we have added global form component that can be used in any file and state variables can be managed by passing props to it. It is present in /components/Input folder. 54 |

55 | Ex- 56 |
57 |
{'const INITIAL_LEAD_OBJ = {\n   first_name : "", \n   last_name : "", \n   email : "" \n  } \n   const [leadObj, setLeadObj] = useState(INITIAL_LEAD_OBJ) \n   const updateFormValue = ({updateType, value}) => {\n    setErrorMessage("") \n    setLeadObj({...leadObj, [updateType] : value})\n   }\n\n'}
58 |
59 | 60 | 61 | 62 |

This example is from add new lead modal, here we are importing component for creating text input and passing some props to handle its content and state variable. Description of props are as follows -

63 |
    64 |
  • type - Input type value like number, date, time etc..
  • 65 |
  • updateType - This is used to update state variable in parent component
  • 66 |
  • containerStyle - Style class for container of input, which include label as well
  • 67 |
  • labelTitle - Title of the label
  • 68 |
  • updateFormValue - Function of parent component to update state variable
  • 69 |
70 | 71 | 72 | 73 | 74 | {/* Cards */} 75 |

Cards

76 |

77 | Daisy UI already have many cards layout, on top of that we have added one card component that accept title props and shows children inside its body. Also there is a divider between title and body of card. On more provision has been added to add buttons on top left side of card using TopSideButtons props (check leads page). 78 | 79 |

80 | Ex - 81 |
82 |
{' 

Card Body

'}
83 |
84 |
85 |

Card Body

86 |
87 | 88 | 89 | 90 | 91 |
92 | 93 | 94 |
95 | 96 | ) 97 | } 98 | 99 | export default DocComponentsContent -------------------------------------------------------------------------------- /src/components/CalendarView/index.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import ChevronLeftIcon from "@heroicons/react/24/solid/ChevronLeftIcon"; 3 | import ChevronRightIcon from "@heroicons/react/24/solid/ChevronRightIcon"; 4 | import moment from "moment"; 5 | import { CALENDAR_EVENT_STYLE } from "./util"; 6 | 7 | const THEME_BG = CALENDAR_EVENT_STYLE 8 | 9 | function CalendarView({calendarEvents, addNewEvent, openDayDetail}){ 10 | 11 | const today = moment().startOf('day') 12 | const weekdays = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"]; 13 | const colStartClasses = [ 14 | "", 15 | "col-start-2", 16 | "col-start-3", 17 | "col-start-4", 18 | "col-start-5", 19 | "col-start-6", 20 | "col-start-7", 21 | ]; 22 | 23 | const [firstDayOfMonth, setFirstDayOfMonth] = useState(moment().startOf('month')) 24 | const [events, setEvents] = useState([]) 25 | const [currMonth, setCurrMonth] = useState(() => moment(today).format("MMM-yyyy")); 26 | 27 | useEffect(() => { 28 | setEvents(calendarEvents) 29 | }, [calendarEvents]) 30 | 31 | 32 | const allDaysInMonth = ()=> { 33 | let start = moment(firstDayOfMonth).startOf('week') 34 | let end = moment(moment(firstDayOfMonth).endOf('month')).endOf('week') 35 | var days = []; 36 | var day = start; 37 | while (day <= end) { 38 | days.push(day.toDate()); 39 | day = day.clone().add(1, 'd'); 40 | } 41 | return days 42 | } 43 | 44 | const getEventsForCurrentDate = (date) => { 45 | let filteredEvents = events.filter((e) => {return moment(date).isSame(moment(e.startTime), 'day') } ) 46 | if(filteredEvents.length > 2){ 47 | let originalLength = filteredEvents.length 48 | filteredEvents = filteredEvents.slice(0, 2) 49 | filteredEvents.push({title : `${originalLength - 2} more`, theme : "MORE"}) 50 | } 51 | return filteredEvents 52 | } 53 | 54 | const openAllEventsDetail = (date, theme) => { 55 | if(theme != "MORE")return 1 56 | let filteredEvents = events.filter((e) => {return moment(date).isSame(moment(e.startTime), 'day') } ).map((e) => {return {title : e.title, theme : e.theme}}) 57 | openDayDetail({filteredEvents, title : moment(date).format("D MMM YYYY")}) 58 | } 59 | 60 | const isToday = (date) => { 61 | return moment(date).isSame(moment(), 'day'); 62 | } 63 | 64 | const isDifferentMonth = (date) => { 65 | return moment(date).month() != moment(firstDayOfMonth).month() 66 | } 67 | 68 | const getPrevMonth = (event) => { 69 | const firstDayOfPrevMonth = moment(firstDayOfMonth).add(-1, 'M').startOf('month'); 70 | setFirstDayOfMonth(firstDayOfPrevMonth) 71 | setCurrMonth(moment(firstDayOfPrevMonth).format("MMM-yyyy")); 72 | }; 73 | 74 | const getCurrentMonth = (event) => { 75 | const firstDayOfCurrMonth = moment().startOf('month'); 76 | setFirstDayOfMonth(firstDayOfCurrMonth) 77 | setCurrMonth(moment(firstDayOfCurrMonth).format("MMM-yyyy")); 78 | }; 79 | 80 | const getNextMonth = (event) => { 81 | const firstDayOfNextMonth = moment(firstDayOfMonth).add(1, 'M').startOf('month'); 82 | setFirstDayOfMonth(firstDayOfNextMonth) 83 | setCurrMonth(moment(firstDayOfNextMonth).format("MMM-yyyy")); 84 | }; 85 | 86 | return( 87 | <> 88 |
89 |
90 |
91 |

92 | {moment(firstDayOfMonth).format("MMMM yyyy").toString()}Beta 93 |

94 | 95 | 99 | 102 | 106 |
107 |
108 | 109 |
110 | 111 |
112 |
113 |
114 | {weekdays.map((day, key) => { 115 | return ( 116 |
117 | {day} 118 |
119 | ); 120 | })} 121 |
122 | 123 | 124 |
125 | {allDaysInMonth().map((day, idx) => { 126 | return ( 127 |
128 |

addNewEvent(day)}> { moment(day).format("D") }

129 | { 130 | getEventsForCurrentDate(day).map((e, k) => { 131 | return

openAllEventsDetail(day, e.theme)} className={`text-xs px-2 mt-1 truncate ${THEME_BG[e.theme] || ""}`}>{e.title}

132 | }) 133 | } 134 |
135 | ); 136 | })} 137 |
138 | 139 | 140 |
141 | 142 | ) 143 | } 144 | 145 | 146 | export default CalendarView -------------------------------------------------------------------------------- /src/features/documentation/components/FeaturesContent.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { useDispatch } from 'react-redux' 3 | import Subtitle from '../../../components/Typography/Subtitle' 4 | import { setPageTitle, showNotification } from '../../common/headerSlice' 5 | 6 | function FeaturesContent(){ 7 | 8 | const dispatch = useDispatch() 9 | 10 | return( 11 | <> 12 |
13 |

Features

14 | 15 | 16 | 17 | {/* Authentication*/} 18 |

Authentication

19 |

20 | JWT based Authentication logic is present in /app/auth.js. In the file you can see we are adding bearer token in header for every request. Every routes under /routes/ folder will need authentication. For public routes like login, register you will have to add routes in App.js file and also include the path in PUBLIC_ROUTES variable under /app/auth.js file so that auto redirect to login page is not triggered. 21 | 22 |

23 | 24 | 25 | 26 | 27 | {/* Left Sidebar*/} 28 |

Left Sidebar

29 |

30 | This is main internal navigation (for pages that will come after login only), all sidebar menu items with their icons are present in /routes/sidebar.js file, while path and page components mapping are respectively present in /routes/index.js file. 31 |

32 | 33 | 34 | 35 | {/* Add New Page*/} 36 |

Add New Page

37 |

All public routes are present in App.js file. Steps to add new public page - 38 |

39 | 40 |
    41 |
  • Create Page inside /pages folder
  • 42 |
  • Go to App.js and import the component and add its path
  • 43 |
  • Add your new route path in /app/auth.js file under PUBLIC_ROUTES variable, this will allow the page to open without login.
  • 44 |
45 | 46 |

All protected routes are present in /routes/sidebar.js file

47 | 48 |
    49 |
  • Create your page inside /pages/protected folder
  • 50 |
  • Add your new routes in /routes/sidebar.js, this will show your new page in sidebar
  • 51 |
  • Import your new routes component and map its path in /routes/index.js
  • 52 |
53 | 54 | 55 | 56 | {/* Right Sidebar*/} 57 |

Right Sidebar

58 |
59 | This is used for showing long list contents like notifications, settings etc.. We are using redux to show and hide and it is single component and can be called from any file with dispatch method. 60 | To add new content follow following steps: 61 |
    62 |
  • Create new component file containing main body of your content
  • 63 |
  • Create new variable in /utils/globalConstantUtils.js file under RIGHT_DRAWER_TYPES variable
  • 64 |
  • Now include the file mapped with the new variable in /containers/RightSidebar.js file using switch.
    65 | For ex- If you new component name is TestRightSideBar.js and variable name is TEST_RIGHT_SIDEBAR, then add following code inside switch code block 66 |
    67 |
    68 |
    {`[RIGHT_DRAWER_TYPES.TEST_RIGHT_SIDEBAR] : \n`}
    69 |
    70 | Here extraObject have variables that is passed from parent component while calling openRightDrawer method 71 |
  • 72 |
  • Now the last step, call dispatch method as follows 73 |
    74 |
    {'import { useDispatch } from "react-redux"\n  const dispatch = useDispatch()\n  dispatch(openRightDrawer({header : "Test Right Drawer", \n  bodyType : RIGHT_DRAWER_TYPES.TEST_RIGHT_SIDEBAR}))'}
    75 |
    76 |
  • 77 |
78 |
79 | 80 | 81 | {/* Themes*/} 82 |

Themes

83 |

84 | By default we have added light and dark theme and Daisy UI comes with a number of themes, which you can use with no extra effort, you just have to include it in tailwind.config.js file, you can add themes like cupcake, corporate, reto etc... Also we can configure themes colors in config file, for more documentation on themes checkout Daisy UI documentation. 85 |

86 | 87 | 88 | 89 | 90 | {/* Modal*/} 91 |

Modal

92 |
93 | With global modal functionality you dont have to create seperate modal for each page. We are using redux to show and hide and it is a single component and can be called from any file with dispatch method. 94 | Code for showing modal is present in modalSlice and layout container component. To show modal just call openModal() function of modalSlice using dispatch. 95 |
96 | To add new modal in any page follow following steps: 97 |
    98 |
  • Create new component file containing main body of your modal content
  • 99 |
  • Create new variable in /utils/globalConstantUtils.js file under MODAL_BODY_TYPES variable
  • 100 |
  • Now include the file mapped with the new variable in /containers/ModalLayout.js file using switch.
    101 | For ex- If you new component name is TestModal.js and variable name is TEST_MODAL, then add following code inside switch code block 102 |
    103 |
    104 |
    {`[RIGHT_DRAWER_TYPES.TEST_MODAL] : \n`}
    105 |
    106 | Here extraObject have variables that is passed from parent component while calling openModal method 107 |
  • 108 |
  • Now the last step, call dispatch method as follows 109 |
    110 |
    {'import { useDispatch } from "react-redux"\n  const dispatch = useDispatch()\n   dispatch(openModal({title : "Test Modal Title", \n   bodyType : MODAL_BODY_TYPES.TEST_MODAL}))'}
    111 |
    112 |
  • 113 |
114 |
115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | {/* Notification*/} 123 |

Notification

124 |

Many times we have to show notification to user be it on successfull form submission or any api success. And requirement can come to show notification from any page, so global notification handling is needed.

125 | 126 |

Code for showing notification is present in headerSlice and layout container component. To show notification just call showNotification() function of headerSlice using dispatch. To show success message notification pass status as 1 and for showing error message pass status as 0.

127 | 128 |
129 |
{'import { useDispatch } from "react-redux"\n  const dispatch = useDispatch()\n  dispatch(showNotification({message : "Message here", status : 1}))'}
130 |
131 | 132 |

Click on this button to check

133 | 134 | 135 | 136 | 137 | 138 | 139 |
140 | 141 | 142 |
143 | 144 | ) 145 | } 146 | 147 | export default FeaturesContent -------------------------------------------------------------------------------- /src/features/documentation/components/GettingStartedContent.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react' 2 | import { useDispatch } from 'react-redux' 3 | import Subtitle from '../../../components/Typography/Subtitle' 4 | import { setPageTitle } from '../../common/headerSlice' 5 | 6 | function GettingStartedContent(){ 7 | 8 | const dispatch = useDispatch() 9 | 10 | 11 | 12 | return( 13 | <> 14 |
15 |

Getting Started

16 | 17 | 18 | {/* Introduction */} 19 |

Introduction

20 |

A free dashboard template using Daisy UI and react js. With the help of Dasisy UI, it comes with fully customizable and themable CSS and power of Tailwind CSS utility classes. We have also added redux toolkit and configured it for API calls and state management.

21 |

User authentication has been implemented using JWT token method (ofcourse you need backend API for generating and verifying token). This template can be used to start your next SaaS project or build new internal tools in your company.

22 |

Core libraries used -

23 | 32 |

Major features -

33 |

Almost all major UI components are available in Daisy UI library. Apart from this logic has been added for following -

34 |
    35 |
  • Light/dark mode toggle
  • 36 |
  • Token based user authentication
  • 37 |
  • Submenu support in sidebar
  • 38 |
  • Store management using redux toolkit
  • 39 |
  • Daisy UI components
  • 40 |
  • Right and left sidebar, Universal loader, notifications and other components
  • 41 |
  • React chart js 2 examples
  • 42 |
43 | 44 | 45 | 46 | 47 | 48 | {/* How to Use */} 49 |

How to use?

50 |

51 | Just clone the repo from github and then run following command (Make sure you have node js installed )
52 | Repo Link 53 |
54 | npm install
55 | npm start 56 |

57 | 58 | 59 | {/* Tailwind CSS*/} 60 |

Tailwind CSS

61 |

62 | Tailwind CSS is a utility-first CSS framework with predefined classes that you can use to build and design the UI directly in the JSX. We have also included Daisy UI Component, that is based on tailwind CSS. 63 |

64 | 65 | {/* Daisy UI */} 66 |

Daisy UI

67 | 68 |

Daisy UI, a popular free and opensource tailwind component library has been used for this template. It has a rich collection of components, layouts and is fully customizable and themeable.

69 | 70 |

Apart from this it also helps in making HTML code more cleaner as we don't have to include all utility classes of tailwind to make the UI. Check components documentation here. For Ex-

71 | 72 |
73 |

Creating a button

74 |
75 |
76 | 77 |
78 |

using only utility classes of tailwind

79 |
80 |
{'Button'}
81 |
82 | 83 |
84 | 85 |
86 | 87 |
88 |

using daisyUI component classes

89 |
90 |
{'\nButton'}
91 |
92 | 93 |
94 |
95 | 96 | 97 | 98 | {/* Chart JS */} 99 |

Chart JS

100 |

101 | Chart JS library has rich components of different charts available. It is based on Chart.js library, the most popular charting library. We have added this library and added couple of examples in seperate page. 102 |

103 | 104 | 105 | 106 | {/* Redux Toolkit */} 107 |

Redux Toolkit

108 |

109 | The Redux Toolkit package helps in writing redux logic easily. It was originally created to help address three common concerns about Redux: 110 |

  • Configuring a Redux store is too complicated
  • 111 |
  • I have to add a lot of packages to get Redux to do anything useful
  • 112 |
  • Redux requires too much boilerplate code"
  • 113 | This library has been configured and used for showing notifications, modals and loading data from API in leads page. 114 |

    115 | 116 | 117 | {/* Hero Icons */} 118 |

    Hero Icons

    119 |

    HeroIcons library has been used for all the icons in this templates. It has a rich collection of SVG icons, and is made by the makers of Tailwind CSS.

    120 | 121 |

    Each icon can be imported individually as a React component, check documentation

    122 | 123 |
    {"import BeakerIcon from '@heroicons/react/24/solid/BeakerIcon'"}
    124 |

    Use as follows in your component

    125 |
    {""}
    126 | 127 |
    128 | 129 |
    130 |
    Note: Importing all icons in single line will increase your build time
    131 |
    132 | 133 |

    Don't import like this (will load all icons and increase build time)

    134 |
    {"import {BeakerIcon, BellIcon } from '@heroicons/react/24/solid'"}
    135 | 136 |

    Instead import as follows

    137 |
    {"import BeakerIcon from '@heroicons/react/24/solid/BeakerIcon'"}
    138 | {"import BellIcon from '@heroicons/react/24/solid/BellIcon'"}
    139 | 140 |
    This is better way for importing icons
    141 | 142 | 143 | 144 | {/* Project Structure */} 145 |

    Project Structure

    146 |

    Folders -

    147 |
      148 |
    • app - store management, auth and libraries settings are present
    • 149 |
    • components - this include all common components to be used in project
    • 150 |
    • containers - components related to layout like sidebar, page layout, header etc..
    • 151 |
    • features - main folder where all page logic resides, there will be folder for each page and additional folder inside that to group different functionalities like components, modals etc... Redux slice file will also present inside page specific folder.
    • 152 |
    • pages - this contain one single file related to one page, if you want to divide page into different components file, use features folder and create seperate folder related to that page
    • 153 |
    • routes - all settings related to routes
    • 154 |
    155 | 156 |

    Files -

    157 |
      158 |
    • App.js - Main file containing different routes and components
    • 159 |
    • index.css - Additional global css if required
    • 160 |
    • index.js - Entry point of project
    • 161 |
    • package.json - All dependencies and npm scripts
    • 162 |
    • tailwind.config.js - Tailwind CSS configuration file, add theme customization and new themes in this file
    • 163 |
    164 | 165 | 166 |
    167 | 168 |
    169 | 170 | ) 171 | } 172 | 173 | export default GettingStartedContent --------------------------------------------------------------------------------