├── .gitignore
├── README.md
├── client
├── .github
│ └── workflows
│ │ └── main.yml
├── .gitignore
├── CHANGELOG.md
├── Documentation
│ └── documentation.html
├── ISSUE_TEMPLATE.md
├── LICENSE
├── README.md
├── gulpfile.js
├── jsconfig.json
├── package-lock.json
├── package.json
├── public
│ ├── apple-icon.png
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
└── src
│ ├── App.js
│ ├── assets
│ ├── css
│ │ ├── argon-dashboard-react.css
│ │ ├── argon-dashboard-react.css.map
│ │ └── argon-dashboard-react.min.css
│ ├── fonts
│ │ ├── nucleo.eot
│ │ ├── nucleo.ttf
│ │ ├── nucleo.woff
│ │ └── nucleo.woff2
│ ├── img
│ │ ├── brand
│ │ │ ├── argon-react-white.png
│ │ │ ├── argon-react.png
│ │ │ ├── blue.png
│ │ │ ├── bug-tracker-logo.png
│ │ │ ├── favicon.png
│ │ │ └── white.png
│ │ ├── icons
│ │ │ └── common
│ │ │ │ ├── github.svg
│ │ │ │ └── google.svg
│ │ └── theme
│ │ │ ├── angular.jpg
│ │ │ ├── bootstrap.jpg
│ │ │ ├── profile-cover.jpg
│ │ │ ├── react.jpg
│ │ │ ├── sketch.jpg
│ │ │ ├── team-1-800x800.jpg
│ │ │ ├── team-2-800x800.jpg
│ │ │ ├── team-3-800x800.jpg
│ │ │ ├── team-4-800x800.jpg
│ │ │ └── vue.jpg
│ ├── plugins
│ │ └── nucleo
│ │ │ ├── css
│ │ │ ├── nucleo-svg.css
│ │ │ └── nucleo.css
│ │ │ └── fonts
│ │ │ ├── nucleo-icons.eot
│ │ │ ├── nucleo-icons.svg
│ │ │ ├── nucleo-icons.ttf
│ │ │ ├── nucleo-icons.woff
│ │ │ └── nucleo-icons.woff2
│ └── scss
│ │ ├── argon-dashboard-react.scss
│ │ ├── argon-dashboard
│ │ ├── custom
│ │ │ ├── _alert.scss
│ │ │ ├── _avatar.scss
│ │ │ ├── _badge.scss
│ │ │ ├── _buttons.scss
│ │ │ ├── _card.scss
│ │ │ ├── _chart.scss
│ │ │ ├── _close.scss
│ │ │ ├── _components.scss
│ │ │ ├── _content.scss
│ │ │ ├── _custom-forms.scss
│ │ │ ├── _dropdown.scss
│ │ │ ├── _footer.scss
│ │ │ ├── _forms.scss
│ │ │ ├── _functions.scss
│ │ │ ├── _header.scss
│ │ │ ├── _icons.scss
│ │ │ ├── _input-group.scss
│ │ │ ├── _list-group.scss
│ │ │ ├── _map.scss
│ │ │ ├── _mask.scss
│ │ │ ├── _mixins.scss
│ │ │ ├── _modal.scss
│ │ │ ├── _nav.scss
│ │ │ ├── _navbar.scss
│ │ │ ├── _pagination.scss
│ │ │ ├── _popover.scss
│ │ │ ├── _progress.scss
│ │ │ ├── _reboot.scss
│ │ │ ├── _section.scss
│ │ │ ├── _separator.scss
│ │ │ ├── _tables.scss
│ │ │ ├── _type.scss
│ │ │ ├── _utilities.scss
│ │ │ ├── _variables.scss
│ │ │ ├── _vendors.scss
│ │ │ ├── alerts
│ │ │ │ ├── _alert-dismissible.scss
│ │ │ │ └── _alert.scss
│ │ │ ├── avatars
│ │ │ │ ├── _avatar-group.scss
│ │ │ │ └── _avatar.scss
│ │ │ ├── badges
│ │ │ │ ├── _badge-circle.scss
│ │ │ │ ├── _badge-dot.scss
│ │ │ │ └── _badge.scss
│ │ │ ├── buttons
│ │ │ │ ├── _button-brand.scss
│ │ │ │ ├── _button-icon.scss
│ │ │ │ └── _button.scss
│ │ │ ├── cards
│ │ │ │ ├── _card-animations.scss
│ │ │ │ ├── _card-blockquote.scss
│ │ │ │ ├── _card-profile.scss
│ │ │ │ ├── _card-stats.scss
│ │ │ │ └── _card.scss
│ │ │ ├── charts
│ │ │ │ └── _chart.scss
│ │ │ ├── close
│ │ │ │ └── _close.scss
│ │ │ ├── custom-forms
│ │ │ │ ├── _custom-checkbox.scss
│ │ │ │ ├── _custom-control.scss
│ │ │ │ ├── _custom-form.scss
│ │ │ │ ├── _custom-radio.scss
│ │ │ │ └── _custom-toggle.scss
│ │ │ ├── dropdowns
│ │ │ │ └── _dropdown.scss
│ │ │ ├── footers
│ │ │ │ └── _footer.scss
│ │ │ ├── forms
│ │ │ │ ├── _form-validation.scss
│ │ │ │ ├── _form.scss
│ │ │ │ └── _input-group.scss
│ │ │ ├── headers
│ │ │ │ └── _header.scss
│ │ │ ├── icons
│ │ │ │ ├── _icon-shape.scss
│ │ │ │ └── _icon.scss
│ │ │ ├── list-groups
│ │ │ │ └── _list-group.scss
│ │ │ ├── maps
│ │ │ │ └── _map.scss
│ │ │ ├── masks
│ │ │ │ └── _mask.scss
│ │ │ ├── mixins
│ │ │ │ ├── _alert.scss
│ │ │ │ ├── _background-variant.scss
│ │ │ │ ├── _badge.scss
│ │ │ │ ├── _buttons.scss
│ │ │ │ ├── _forms.scss
│ │ │ │ ├── _icon.scss
│ │ │ │ ├── _modals.scss
│ │ │ │ └── _popover.scss
│ │ │ ├── modals
│ │ │ │ └── _modal.scss
│ │ │ ├── navbars
│ │ │ │ ├── _navbar-collapse.scss
│ │ │ │ ├── _navbar-dropdown.scss
│ │ │ │ ├── _navbar-search.scss
│ │ │ │ ├── _navbar-vertical.scss
│ │ │ │ └── _navbar.scss
│ │ │ ├── navs
│ │ │ │ ├── _nav-pills.scss
│ │ │ │ └── _nav.scss
│ │ │ ├── paginations
│ │ │ │ └── _pagination.scss
│ │ │ ├── popovers
│ │ │ │ └── _popover.scss
│ │ │ ├── progresses
│ │ │ │ └── _progress.scss
│ │ │ ├── separators
│ │ │ │ └── _separator.scss
│ │ │ ├── tables
│ │ │ │ └── _table.scss
│ │ │ ├── type
│ │ │ │ ├── _article.scss
│ │ │ │ ├── _display.scss
│ │ │ │ ├── _heading.scss
│ │ │ │ └── _type.scss
│ │ │ ├── utilities
│ │ │ │ ├── _backgrounds.scss
│ │ │ │ ├── _blurable.scss
│ │ │ │ ├── _floating.scss
│ │ │ │ ├── _helper.scss
│ │ │ │ ├── _image.scss
│ │ │ │ ├── _opacity.scss
│ │ │ │ ├── _overflow.scss
│ │ │ │ ├── _position.scss
│ │ │ │ ├── _shadows.scss
│ │ │ │ ├── _sizing.scss
│ │ │ │ ├── _spacing.scss
│ │ │ │ ├── _text.scss
│ │ │ │ └── _transform.scss
│ │ │ └── vendors
│ │ │ │ ├── _bootstrap-datepicker.scss
│ │ │ │ ├── _headroom.scss
│ │ │ │ ├── _nouislider.scss
│ │ │ │ └── _scrollbar.scss
│ │ └── docs
│ │ │ ├── _clipboard-js.scss
│ │ │ ├── _component-examples.scss
│ │ │ ├── _content.scss
│ │ │ ├── _footer.scss
│ │ │ ├── _nav.scss
│ │ │ ├── _prism.scss
│ │ │ ├── _sidebar.scss
│ │ │ └── _variables.scss
│ │ └── react
│ │ ├── _buttons.scss
│ │ ├── _mixins.scss
│ │ ├── _navbar-dropdown.scss
│ │ ├── _navbar.scss
│ │ ├── _tables.scss
│ │ ├── bootstrap
│ │ └── _spinners.scss
│ │ ├── plugins
│ │ └── _plugin-react-datetime.scss
│ │ └── react-differences.scss
│ ├── components
│ ├── Charts
│ │ └── TicketsPieChart.js
│ ├── Footers
│ │ ├── AdminFooter.js
│ │ └── AuthFooter.js
│ ├── Forms
│ │ ├── AddTeamMember.js
│ │ ├── CreateProject.js
│ │ ├── CreateTicket.js
│ │ ├── UpdateProject.js
│ │ ├── UpdateTicket.js
│ │ └── useForm.js
│ ├── Headers
│ │ ├── Header.js
│ │ └── UserHeader.js
│ ├── Modal
│ │ └── Modal.js
│ ├── Navbars
│ │ ├── AdminNavbar.js
│ │ └── AuthNavbar.js
│ ├── Sidebar
│ │ ├── GeneralSidebar.js
│ │ └── UniversalSidebar.js
│ ├── Tables
│ │ ├── DataTable.js
│ │ ├── PaginationComponent.js
│ │ ├── ProjectTeamTable.js
│ │ ├── ProjectTicketsTable.js
│ │ ├── ProjectsTable.js
│ │ └── UsersCell.js
│ └── Tickets
│ │ └── SelectedTicket.js
│ ├── contexts
│ └── AuthContext.js
│ ├── index.css
│ ├── index.js
│ ├── layouts
│ ├── Auth.js
│ ├── General.js
│ └── Main.js
│ ├── reportWebVitals.js
│ ├── routes.js
│ ├── setupTests.js
│ ├── utils
│ ├── API.js
│ └── formValidation
│ │ ├── loginValidation.js
│ │ ├── registerValidation.js
│ │ └── ticketValidation.js
│ ├── variables
│ └── charts.js
│ └── views
│ ├── Administration.js
│ ├── Index.js
│ ├── Login.js
│ ├── Project.js
│ ├── Register.js
│ ├── Tables.css
│ └── Tickets.js
├── controllers
├── availableUsersController.js
├── commentController.js
├── devAssignmentsController.js
├── projectController.js
├── ticketController.js
├── userController.js
└── userProjectController.js
├── db.js
├── middleware
└── authorization.js
├── package-lock.json
├── package.json
├── routes
├── api
│ ├── auth.js
│ ├── availableUsers.js
│ ├── comment.js
│ ├── devAssignments.js
│ ├── index.js
│ ├── login.js
│ ├── project.js
│ ├── ticket.js
│ ├── user.js
│ └── userProjects.js
└── index.js
├── server.js
└── utils
└── jwtGenerator.js
/.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
21 |
22 | /schema
23 |
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 | requests.rest
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # BugTracker
2 |
3 | *Project Management - Clean and Responsive*
4 |
5 | ## Purpose
6 | Bug Tracker is a project management tool to track progress of multiple projects and teams. Users are able to create projects and assign developers to the project. Within a project, users can generate tickets for bugs, feature requests, etc and follow comment streams on individual tickets.
7 |
8 | ## Usage
9 | Log into BugTracker after creating an account and begin by adding a new project from the dashboard.
10 |
11 | ## Technologies Used
12 | - React
13 | - Node.js
14 | - PostgreSQL
15 | - Authorization / Authentication utilizing JSON Web Tokens
16 | - Deployed through Heroku
17 |
18 | ## Development Notes
19 | ### Prerequisites
20 | **Node**
21 |
22 | Before you can install Node, you’ll need to install two other applications. Fortunately, once you have these on your machine, installing Node takes just a few minutes.[1]
23 |
24 | **Mac OS**
25 | > - **XCode** Apple’s XCode development software is used to build Mac and iOS apps, but it also includes the tools you need to compile software for use on your Mac. XCode is free and you can find it in the Apple App Store.
26 | >
27 | > - Via Terminal `xcode-select --install`
28 | >
29 | > - **Homebrew** Homebrew is a package manager for the Mac — it makes installing most open source sofware (like Node) as simple as writing `brew install node`.
30 | > - To install Homebrew just open Terminal and type `ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"`. You’ll see messages in the Terminal explaining what you need to do to complete the installation process. Now type `brew install node`.
31 |
32 | **Windows Installation Steps**[2]
33 | > - Download the Windows installer from the [Nodes.js®](http://nodejs.org/) web site.
34 | > - Run the installer (the .msi file you downloaded in the previous step.)
35 | > - Follow the prompts in the installer (Accept the license agreement, click the NEXT button a bunch of times and accept the default installation settings).
36 | > - Restart your computer. You won’t be able to run Node.js until you restart your computer.
37 |
38 | ## Contributing
39 | - Fork it (https://github.com/connorleee/BugTracker/fork)
40 | - Create your feature branch `git checkout -b feature/newFeature`
41 | - Commit your changes `git commit -am 'Add your Message Here'`
42 | - Push to the branch `git push origin feature/newFeature`
43 | - Create a new Pull Request within Github
44 |
45 | ## Support
46 | - Open a new issue [here](https://github.com/connorleee/BugTracker/issues/) for support.
47 |
48 | ## Team
49 | - **Connor Lee** - https://connorleee.github.io/portfolio-official/
50 |
51 |
52 | ## Acknowledgments
53 |
54 | [1] Adapted from instructions found here: https://blog.teamtreehouse.com/install-node-js-npm-mac
55 |
56 | [2] Adapted from instructions found here: https://blog.teamtreehouse.com/install-node-js-npm-windows
57 |
58 | [3] Utilizes Front End Template by Creative-Tim: https://www.creative-tim.com/product/argon-dashboard-react
59 |
--------------------------------------------------------------------------------
/client/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: Autocloser
2 | on: [issues]
3 | jobs:
4 | autoclose:
5 | runs-on: ubuntu-latest
6 | steps:
7 | - name: Issue auto-closer
8 | uses: roots/issue-closer-action@v1.1
9 | with:
10 | repo-token: ${{ secrets.GITHUB_TOKEN }}
11 | issue-close-message: "@${issue.user.login} this issue was automatically closed because it did not follow our rules:\n\n
\n\n\n\nIMPORTANT: Please use the following link to create a new issue:\n\nhttps://www.creative-tim.com/new-issue/argon-dashboard-react\n\n**If your issue was not created using the app above, it will be closed immediately.**\n\n\n\nLove Creative Tim? Do you need Angular, React, Vuejs or HTML? You can visit:\n👉 https://www.creative-tim.com/bundles\n👉 https://www.creative-tim.com\n\n\n \n\n"
12 | issue-pattern: (\#\#\# Version([\S\s.*]*?)\#\#\# Reproduction link([\S\s.*]*?)\#\#\# Operating System([\S\s.*]*?)\#\#\# Device([\S\s.*]*?)\#\#\# Browser & Version([\S\s.*]*?)\#\#\# Steps to reproduce([\S\s.*]*?)\#\#\# What is expected([\S\s.*]*?)\#\#\# What is actually happening([\S\s.*]*?)---([\S\s.*]*?)\#\#\# Solution([\S\s.*]*?)\#\#\# Additional comments([\S\s.*]*?)\<\!-- generated by creative-tim-issues\. DO NOT REMOVE --\>)|(\#\#\# What is your enhancement([\S\s.*]*?)\<\!-- generated by creative-tim-issues\. DO NOT REMOVE --\>)
13 |
--------------------------------------------------------------------------------
/client/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /node_modules
3 | package-lock.json
4 | /build
5 | .eslintcache
6 |
--------------------------------------------------------------------------------
/client/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
8 |
9 |
14 |
--------------------------------------------------------------------------------
/client/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Creative Tim
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/client/gulpfile.js:
--------------------------------------------------------------------------------
1 | const gulp = require("gulp");
2 | const gap = require("gulp-append-prepend");
3 |
4 | gulp.task("licenses", async function () {
5 | // this is to add Creative Tim licenses in the production mode for the minified js
6 | gulp
7 | .src("build/static/js/*chunk.js", { base: "./" })
8 | .pipe(
9 | gap.prependText(`/*!
10 |
11 | =========================================================
12 | * Argon Dashboard React - v1.2.0
13 | =========================================================
14 |
15 | * Product Page: https://www.creative-tim.com/product/argon-dashboard-react
16 | * Copyright 2021 Creative Tim (https://www.creative-tim.com)
17 | * Licensed under MIT (https://github.com/creativetimofficial/argon-dashboard-react/blob/master/LICENSE.md)
18 |
19 | * Coded by Creative Tim
20 |
21 | =========================================================
22 |
23 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
24 |
25 | */`)
26 | )
27 | .pipe(gulp.dest("./", { overwrite: true }));
28 |
29 | // this is to add Creative Tim licenses in the production mode for the minified html
30 | gulp
31 | .src("build/index.html", { base: "./" })
32 | .pipe(
33 | gap.prependText(``)
50 | )
51 | .pipe(gulp.dest("./", { overwrite: true }));
52 |
53 | // this is to add Creative Tim licenses in the production mode for the minified css
54 | gulp
55 | .src("build/static/css/*chunk.css", { base: "./" })
56 | .pipe(
57 | gap.prependText(`/*!
58 |
59 | =========================================================
60 | * Argon Dashboard React - v1.2.0
61 | =========================================================
62 |
63 | * Product Page: https://www.creative-tim.com/product/argon-dashboard-react
64 | * Copyright 2021 Creative Tim (https://www.creative-tim.com)
65 | * Licensed under MIT (https://github.com/creativetimofficial/argon-dashboard-react/blob/master/LICENSE.md)
66 |
67 | * Coded by Creative Tim
68 |
69 | =========================================================
70 |
71 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
72 |
73 | */`)
74 | )
75 | .pipe(gulp.dest("./", { overwrite: true }));
76 | return;
77 | });
78 |
--------------------------------------------------------------------------------
/client/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "src",
4 | "paths": {
5 | "*": ["src/*"]
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bug-tracker-client",
3 | "version": "1.2.0",
4 | "description": "",
5 | "main": "index.js",
6 | "keywords": [
7 | "react",
8 | "reactjs",
9 | "argon",
10 | "argon-react",
11 | "dashboard",
12 | "dashboard-react",
13 | "argon-dashboard",
14 | "argon-dashboard-react"
15 | ],
16 | "author": "Connor Lee",
17 | "license": "MIT",
18 | "scripts": {
19 | "start": "react-scripts start",
20 | "build": "react-scripts build",
21 | "test": "react-scripts test",
22 | "eject": "react-scripts eject",
23 | "install:clean": "rm -rf node_modules/ && rm -rf package-lock.json && npm install && npm start",
24 | "compile:scss": "node-sass --importer node_modules/node-sass-package-importer/dist/cli.js src/assets/scss/argon-dashboard-react.scss src/assets/css/argon-dashboard-react.css",
25 | "minify:scss": "node-sass --importer node_modules/node-sass-package-importer/dist/cli.js src/assets/scss/argon-dashboard-react.scss src/assets/css/argon-dashboard-react.min.css --output-style compressed",
26 | "map:scss": "node-sass --importer node_modules/node-sass-package-importer/dist/cli.js src/assets/scss/argon-dashboard-react.scss src/assets/css/argon-dashboard-react.css --source-map true",
27 | "build:scss": "npm run compile:scss && npm run minify:scss && npm run map:scss"
28 | },
29 | "eslintConfig": {
30 | "extends": "react-app"
31 | },
32 | "browserslist": [
33 | ">0.2%",
34 | "not dead",
35 | "not ie <= 11",
36 | "not op_mini all"
37 | ],
38 | "dependencies": {
39 | "@fortawesome/fontawesome-free": "5.15.2",
40 | "axios": "^0.21.1",
41 | "bootstrap": "4.6.0",
42 | "chart.js": "2.9.4",
43 | "classnames": "2.2.6",
44 | "moment": "^2.29.1",
45 | "node-sass": "4.14.1",
46 | "node-sass-package-importer": "5.3.2",
47 | "nouislider": "14.6.3",
48 | "react": "17.0.1",
49 | "react-chartjs-2": "2.11.1",
50 | "react-copy-to-clipboard": "5.0.3",
51 | "react-datetime": "3.0.4",
52 | "react-dom": "17.0.1",
53 | "react-router-dom": "5.2.0",
54 | "react-scripts": "4.0.1",
55 | "reactstrap": "8.9.0"
56 | },
57 | "devDependencies": {
58 | "gulp": "4.0.2",
59 | "gulp-append-prepend": "1.0.8"
60 | },
61 | "optionalDependencies": {
62 | "eslint-plugin-flowtype": "5.2.0",
63 | "jquery": "3.5.1",
64 | "typescript": "4.1.3"
65 | },
66 | "proxy": "http://localhost:3001"
67 | }
68 |
--------------------------------------------------------------------------------
/client/public/apple-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/public/apple-icon.png
--------------------------------------------------------------------------------
/client/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/public/favicon.ico
--------------------------------------------------------------------------------
/client/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
14 |
15 |
16 |
21 |
22 |
26 | Bug Tracker
27 |
28 |
29 | You need to enable JavaScript to run this app.
30 |
31 |
32 |
42 |
43 |
--------------------------------------------------------------------------------
/client/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/public/logo192.png
--------------------------------------------------------------------------------
/client/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/public/logo512.png
--------------------------------------------------------------------------------
/client/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "BLK Design System React",
3 | "name": "BLK Design System React by Creative Tim",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/client/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/client/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import { BrowserRouter, Route, Switch, Redirect } from "react-router-dom";
3 | import MainLayout from "layouts/Main.js";
4 | import AuthLayout from "layouts/Auth.js";
5 |
6 | const App = () => {
7 | const [isAuthenticated, setIsAuthenticated] = useState(true);
8 | const [authLevel, setAuthLevel] = useState("");
9 |
10 | let token = localStorage.getItem("token");
11 |
12 | useEffect(() => {
13 | if (token == null) {
14 | setIsAuthenticated(false);
15 | }
16 | }, [token]);
17 |
18 | const setAuth = (boolean) => {
19 | setIsAuthenticated(boolean);
20 | };
21 |
22 | return (
23 |
24 |
25 | {
28 | if (!isAuthenticated) {
29 | return (
30 |
35 | );
36 | }
37 | }}
38 | />
39 |
40 |
43 | isAuthenticated && token !== null ? (
44 |
50 | ) : (
51 |
52 | )
53 | }
54 | />
55 |
56 |
57 | 404 No page found
58 |
59 |
60 |
61 | );
62 | };
63 |
64 | export default App;
65 |
--------------------------------------------------------------------------------
/client/src/assets/fonts/nucleo.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/fonts/nucleo.eot
--------------------------------------------------------------------------------
/client/src/assets/fonts/nucleo.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/fonts/nucleo.ttf
--------------------------------------------------------------------------------
/client/src/assets/fonts/nucleo.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/fonts/nucleo.woff
--------------------------------------------------------------------------------
/client/src/assets/fonts/nucleo.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/fonts/nucleo.woff2
--------------------------------------------------------------------------------
/client/src/assets/img/brand/argon-react-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/img/brand/argon-react-white.png
--------------------------------------------------------------------------------
/client/src/assets/img/brand/argon-react.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/img/brand/argon-react.png
--------------------------------------------------------------------------------
/client/src/assets/img/brand/blue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/img/brand/blue.png
--------------------------------------------------------------------------------
/client/src/assets/img/brand/bug-tracker-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/img/brand/bug-tracker-logo.png
--------------------------------------------------------------------------------
/client/src/assets/img/brand/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/img/brand/favicon.png
--------------------------------------------------------------------------------
/client/src/assets/img/brand/white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/img/brand/white.png
--------------------------------------------------------------------------------
/client/src/assets/img/icons/common/github.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | UI/icons/dark/github
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/client/src/assets/img/icons/common/google.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | UI/icons/color/google
5 | Created with Sketch.
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/client/src/assets/img/theme/angular.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/img/theme/angular.jpg
--------------------------------------------------------------------------------
/client/src/assets/img/theme/bootstrap.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/img/theme/bootstrap.jpg
--------------------------------------------------------------------------------
/client/src/assets/img/theme/profile-cover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/img/theme/profile-cover.jpg
--------------------------------------------------------------------------------
/client/src/assets/img/theme/react.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/img/theme/react.jpg
--------------------------------------------------------------------------------
/client/src/assets/img/theme/sketch.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/img/theme/sketch.jpg
--------------------------------------------------------------------------------
/client/src/assets/img/theme/team-1-800x800.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/img/theme/team-1-800x800.jpg
--------------------------------------------------------------------------------
/client/src/assets/img/theme/team-2-800x800.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/img/theme/team-2-800x800.jpg
--------------------------------------------------------------------------------
/client/src/assets/img/theme/team-3-800x800.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/img/theme/team-3-800x800.jpg
--------------------------------------------------------------------------------
/client/src/assets/img/theme/team-4-800x800.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/img/theme/team-4-800x800.jpg
--------------------------------------------------------------------------------
/client/src/assets/img/theme/vue.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/img/theme/vue.jpg
--------------------------------------------------------------------------------
/client/src/assets/plugins/nucleo/css/nucleo-svg.css:
--------------------------------------------------------------------------------
1 | /* Generated using nucleoapp.com */
2 | /* --------------------------------
3 |
4 | Icon colors
5 |
6 | -------------------------------- */
7 |
8 | .icon {
9 | display: inline-block;
10 | /* icon primary color */
11 | color: #111111;
12 | height: 1em;
13 | width: 1em;
14 | }
15 |
16 | .icon use {
17 | /* icon secondary color - fill */
18 | fill: #7ea6f6;
19 | }
20 |
21 | .icon.icon-outline use {
22 | /* icon secondary color - stroke */
23 | stroke: #7ea6f6;
24 | }
25 |
26 | /* --------------------------------
27 |
28 | Change icon size
29 |
30 | -------------------------------- */
31 |
32 | .icon-xs {
33 | height: 0.5em;
34 | width: 0.5em;
35 | }
36 |
37 | .icon-sm {
38 | height: 0.8em;
39 | width: 0.8em;
40 | }
41 |
42 | .icon-lg {
43 | height: 1.6em;
44 | width: 1.6em;
45 | }
46 |
47 | .icon-xl {
48 | height: 2em;
49 | width: 2em;
50 | }
51 |
52 | /* --------------------------------
53 |
54 | Align icon and text
55 |
56 | -------------------------------- */
57 |
58 | .icon-text-aligner {
59 | /* add this class to parent element that contains icon + text */
60 | display: flex;
61 | align-items: center;
62 | }
63 |
64 | .icon-text-aligner .icon {
65 | color: inherit;
66 | margin-right: 0.4em;
67 | }
68 |
69 | .icon-text-aligner .icon use {
70 | color: inherit;
71 | fill: currentColor;
72 | }
73 |
74 | .icon-text-aligner .icon.icon-outline use {
75 | stroke: currentColor;
76 | }
77 |
78 | /* --------------------------------
79 |
80 | Icon reset values - used to enable color customizations
81 |
82 | -------------------------------- */
83 |
84 | .icon {
85 | fill: currentColor;
86 | stroke: none;
87 | }
88 |
89 | .icon.icon-outline {
90 | fill: none;
91 | stroke: currentColor;
92 | }
93 |
94 | .icon use {
95 | stroke: none;
96 | }
97 |
98 | .icon.icon-outline use {
99 | fill: none;
100 | }
101 |
102 | /* --------------------------------
103 |
104 | Stroke effects - Nucleo outline icons
105 |
106 | - 16px icons -> up to 1px stroke (16px outline icons do not support stroke changes)
107 | - 24px, 32px icons -> up to 2px stroke
108 | - 48px, 64px icons -> up to 4px stroke
109 |
110 | -------------------------------- */
111 |
112 | .icon-outline.icon-stroke-1 {
113 | stroke-width: 1px;
114 | }
115 |
116 | .icon-outline.icon-stroke-2 {
117 | stroke-width: 2px;
118 | }
119 |
120 | .icon-outline.icon-stroke-3 {
121 | stroke-width: 3px;
122 | }
123 |
124 | .icon-outline.icon-stroke-4 {
125 | stroke-width: 4px;
126 | }
127 |
128 | .icon-outline.icon-stroke-1 use,
129 | .icon-outline.icon-stroke-3 use {
130 | -webkit-transform: translateX(0.5px) translateY(0.5px);
131 | -moz-transform: translateX(0.5px) translateY(0.5px);
132 | -ms-transform: translateX(0.5px) translateY(0.5px);
133 | -o-transform: translateX(0.5px) translateY(0.5px);
134 | transform: translateX(0.5px) translateY(0.5px);
135 | }
--------------------------------------------------------------------------------
/client/src/assets/plugins/nucleo/fonts/nucleo-icons.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/plugins/nucleo/fonts/nucleo-icons.eot
--------------------------------------------------------------------------------
/client/src/assets/plugins/nucleo/fonts/nucleo-icons.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/plugins/nucleo/fonts/nucleo-icons.ttf
--------------------------------------------------------------------------------
/client/src/assets/plugins/nucleo/fonts/nucleo-icons.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/plugins/nucleo/fonts/nucleo-icons.woff
--------------------------------------------------------------------------------
/client/src/assets/plugins/nucleo/fonts/nucleo-icons.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/connorleee/BugTracker/ff8ed286ec72b32a04da6768208b3aab202c8e63/client/src/assets/plugins/nucleo/fonts/nucleo-icons.woff2
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard-react.scss:
--------------------------------------------------------------------------------
1 | /*!
2 |
3 | =========================================================
4 | * Argon Dashboard React - v1.2.0
5 | =========================================================
6 |
7 | * Product Page: https://www.creative-tim.com/product/argon-dashboard-react
8 | * Copyright 2021 Creative Tim (https://www.creative-tim.com)
9 | * Licensed under MIT (https://github.com/creativetimofficial/argon-dashboard-react/blob/master/LICENSE.md)
10 |
11 | * Coded by Creative Tim
12 |
13 | =========================================================
14 |
15 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
16 |
17 | */
18 |
19 | // Core
20 |
21 | @import "argon-dashboard/custom/functions";
22 | @import "argon-dashboard/custom/variables";
23 | @import "argon-dashboard/custom/mixins";
24 |
25 | // bootstrap (4.6.0) components
26 |
27 | @import "~bootstrap/scss/root";
28 | @import "~bootstrap/scss/reboot";
29 | @import "~bootstrap/scss/type";
30 | @import "~bootstrap/scss/images";
31 | @import "~bootstrap/scss/code";
32 | @import "~bootstrap/scss/grid";
33 | @import "~bootstrap/scss/tables";
34 | @import "~bootstrap/scss/forms";
35 | @import "~bootstrap/scss/buttons";
36 | @import "~bootstrap/scss/transitions";
37 | @import "~bootstrap/scss/dropdown";
38 | @import "~bootstrap/scss/button-group";
39 | @import "~bootstrap/scss/input-group";
40 | @import "~bootstrap/scss/custom-forms";
41 | @import "~bootstrap/scss/nav";
42 | @import "~bootstrap/scss/navbar";
43 | @import "~bootstrap/scss/card";
44 | @import "~bootstrap/scss/breadcrumb";
45 | @import "~bootstrap/scss/pagination";
46 | @import "~bootstrap/scss/badge";
47 | @import "~bootstrap/scss/jumbotron";
48 | @import "~bootstrap/scss/alert";
49 | @import "~bootstrap/scss/progress";
50 | @import "~bootstrap/scss/media";
51 | @import "~bootstrap/scss/list-group";
52 | @import "~bootstrap/scss/close";
53 | @import "~bootstrap/scss/modal";
54 | @import "~bootstrap/scss/tooltip";
55 | @import "~bootstrap/scss/popover";
56 | @import "~bootstrap/scss/carousel";
57 | @import "~bootstrap/scss/utilities";
58 | @import "~bootstrap/scss/print";
59 |
60 | // Argon utilities and components
61 |
62 | @import "argon-dashboard/custom/reboot";
63 | @import "argon-dashboard/custom/utilities";
64 | @import "argon-dashboard/custom/components";
65 |
66 | // Vendor (Plugins)
67 |
68 | @import "argon-dashboard/custom/vendors";
69 |
70 | // Docs components
71 |
72 | @import "argon-dashboard/docs/variables";
73 | @import "argon-dashboard/docs/nav";
74 | @import "argon-dashboard/docs/clipboard-js";
75 | @import "argon-dashboard/docs/component-examples";
76 | @import "argon-dashboard/docs/prism";
77 | @import "argon-dashboard/docs/content";
78 | @import "argon-dashboard/docs/sidebar";
79 | @import "argon-dashboard/docs/footer";
80 |
81 | // React Differences
82 | @import "react/react-differences";
83 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_alert.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Alert
3 | //
4 |
5 | @import "alerts/alert";
6 | @import "alerts/alert-dismissible";
7 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_avatar.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Avatar
3 | //
4 |
5 | @import "avatars/avatar";
6 | @import "avatars/avatar-group";
7 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_badge.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Badge
3 | //
4 |
5 | @import "badges/badge";
6 | @import "badges/badge-circle";
7 | @import "badges/badge-dot";
8 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_buttons.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Button
3 | //
4 |
5 | @import "buttons/button";
6 | @import "buttons/button-icon";
7 | @import "buttons/button-brand";
8 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_card.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Cards
3 | //
4 |
5 | @import "cards/card";
6 | @import "cards/card-profile";
7 | @import "cards/card-animations";
8 | @import "cards/card-stats";
9 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_chart.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Chart
3 | //
4 |
5 | @import "charts/chart";
6 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_close.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Close
3 | //
4 |
5 | @import "close/close"
6 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_components.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Components
3 | //
4 |
5 | @import "alert";
6 | @import "avatar";
7 | @import "badge";
8 | @import "buttons";
9 | @import "card";
10 | @import "chart";
11 | @import "close";
12 | @import "content";
13 | @import "custom-forms";
14 | @import "dropdown";
15 | @import "footer";
16 | @import "forms";
17 | @import "header";
18 | @import "icons";
19 | @import "input-group";
20 | @import "list-group";
21 | @import "map";
22 | @import "mask";
23 | @import "modal";
24 | @import "nav";
25 | @import "navbar";
26 | @import "pagination";
27 | @import "popover";
28 | @import "progress";
29 | @import "separator";
30 | @import "tables";
31 | @import "type";
32 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_content.scss:
--------------------------------------------------------------------------------
1 | .main-content {
2 | position: relative;
3 |
4 | // Navbar
5 | .navbar-top {
6 | position: absolute;
7 | left: 0;
8 | top: 0;
9 | width: 100%;
10 | z-index: 1;
11 | background-color: transparent;
12 | padding-left: 0 !important;
13 | padding-right: 0 !important;
14 | }
15 |
16 | // Container
17 | .container-fluid {
18 | @include media-breakpoint-up(md) {
19 | padding-left: ($main-content-padding-x + $grid-gutter-width / 2) !important;
20 | padding-right: ($main-content-padding-x + $grid-gutter-width / 2) !important;
21 | }
22 | }
23 | }
24 |
25 |
26 | // Offsets the main content depending on the sidebar positioning
27 |
28 | .navbar-vertical.navbar-expand {
29 |
30 | @each $breakpoint,
31 | $dimension in $grid-breakpoints {
32 |
33 | &-#{$breakpoint} {
34 |
35 | @include media-breakpoint-up(#{$breakpoint}) {
36 |
37 | // Left
38 | &.fixed-left + .main-content {
39 | margin-left: $navbar-vertical-width;
40 | } // Right
41 | &.fixed-right + .main-content {
42 | margin-right: $navbar-vertical-width;
43 | }
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_custom-forms.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Custom form
3 | //
4 |
5 | @import "custom-forms/custom-form";
6 | @import "custom-forms/custom-control";
7 | @import "custom-forms/custom-checkbox";
8 | @import "custom-forms/custom-radio";
9 | @import "custom-forms/custom-toggle";
10 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_dropdown.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Dropdown
3 | //
4 |
5 | @import "dropdowns/dropdown";
6 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_footer.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Footer
3 | //
4 |
5 | @import "footers/footer";
6 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_forms.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Forms
3 | //
4 |
5 | @import "forms/form";
6 | @import "forms/form-validation";
7 | @import "forms/input-group";
8 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_functions.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Functions
3 | //
4 |
5 | // Bootstrap default functions
6 |
7 | @import "~bootstrap/scss/functions";
8 |
9 |
10 | // Retrieve color Sass maps
11 |
12 | @function section-color($key: "primary") {
13 | @return map-get($section-colors, $key);
14 | }
15 |
16 |
17 | // Lines colors
18 |
19 | @function shapes-primary-color($key: "step-1-gradient-bg") {
20 | @return map-get($shapes-primary-colors, $key);
21 | }
22 |
23 | @function shapes-default-color($key: "step-1-gradient-bg") {
24 | @return map-get($shapes-default-colors, $key);
25 | }
26 |
27 | @function lines-light-color($key: "step-1-gradient-bg") {
28 | @return map-get($shapes-light-colors, $key);
29 | }
30 |
31 | @function shapes-dark-color($key: "step-1-gradient-bg") {
32 | @return map-get($shapes-dark-colors, $key);
33 | }
34 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_header.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Header
3 | //
4 |
5 | @import "headers/header";
6 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_icons.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Icon
3 | //
4 |
5 | @import "icons/icon";
6 | @import "icons/icon-shape";
7 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_input-group.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Input group
3 | //
4 |
5 | @import "forms/input-group";
6 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_list-group.scss:
--------------------------------------------------------------------------------
1 | //
2 | // List group
3 | //
4 |
5 | @import "list-groups/list-group";
6 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_map.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Maps
3 | //
4 |
5 | @import "maps/map";
6 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_mask.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Mask
3 | //
4 |
5 | @import "masks/mask";
6 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_mixins.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Mixins
3 | //
4 |
5 | // Bootstrap default mixins
6 |
7 | @import "~bootstrap/scss/mixins";
8 |
9 |
10 | // Custom mixins
11 |
12 | @import "mixins/alert";
13 | @import "mixins/badge";
14 | @import "mixins/background-variant";
15 | @import "mixins/buttons";
16 | @import "mixins/forms";
17 | @import "mixins/icon";
18 | @import "mixins/modals";
19 | @import "mixins/popover";
20 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_modal.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Modal
3 | //
4 |
5 | @import "modals/modal";
6 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_nav.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Nav
3 | //
4 |
5 |
6 | @import "navs/nav";
7 | @import "navs/nav-pills";
8 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_navbar.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Navbar
3 | //
4 |
5 | @import "navbars/navbar";
6 | @import "navbars/navbar-vertical";
7 | @import "navbars/navbar-search";
8 | @import "navbars/navbar-dropdown";
9 | @import "navbars/navbar-collapse";
10 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_pagination.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Pagination
3 | //
4 |
5 | @import "paginations/pagination";
6 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_popover.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Popover
3 | //
4 |
5 |
6 | @import "popovers/popover";
7 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_progress.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Progress
3 | //
4 |
5 | @import "progresses/progress";
6 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_reboot.scss:
--------------------------------------------------------------------------------
1 | iframe {
2 | border: 0;
3 | }
4 |
5 | figcaption,
6 | figure,
7 | main {
8 | display: block;
9 | }
10 |
11 | main {
12 | overflow: hidden;
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_section.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Sections
3 | //
4 |
5 |
6 | // Nucleo icons for presentation purpose
7 |
8 | .section-nucleo-icons {
9 |
10 | --icon-size: 5rem;
11 | --icon-sm-size: 3.75rem;
12 | --gutter: 7rem;
13 |
14 | .icons-container {
15 | position: relative;
16 | max-width: 100%;
17 | height: 360px;
18 | margin: 0 auto;
19 | z-index: 1;
20 |
21 | i {
22 | position: absolute;
23 | display: inline-flex;
24 | align-items: center;
25 | justify-content: center;
26 | border-radius: 50%;
27 | background: $white;
28 | z-index: 1;
29 | transform: translate(-50%, -50%);
30 | @include box-shadow($box-shadow);
31 | transition: all .2s cubic-bezier(.25,.65,.9,.75);
32 |
33 | &.icon {
34 | width: var(--icon-size);
35 | height: var(--icon-size);
36 | font-size: 1.7em;
37 | }
38 |
39 | &.icon-sm {
40 | width: var(--icon-sm-size);
41 | height: var(--icon-sm-size);
42 | font-size: 1.5em;
43 | }
44 |
45 | &:nth-child(1) {
46 | font-size: 42px;
47 | color: theme-color("warning");
48 | z-index: 2;
49 | }
50 | }
51 |
52 | &:not(.on-screen) {
53 | i {
54 | transform: translate(-50%, -50%);
55 | left: 50%;
56 | top: 50%;
57 |
58 | &:not(:nth-child(1)) {
59 | opacity: 0;
60 | }
61 | }
62 | }
63 |
64 | &.on-screen {
65 |
66 | i {
67 | opacity: 1;
68 |
69 | &:nth-child(1) {
70 | left: 50%;
71 | top: 50%;
72 | font-size: 42px;
73 | color: theme-color("warning");
74 | }
75 |
76 | &:nth-child(2) {
77 | left: calc(50% + (var(--gutter) * 1.7));
78 | top: 50%;
79 | }
80 |
81 | &:nth-child(3) {
82 | left: calc(50% + var(--gutter));
83 | top: calc(50% + var(--gutter));
84 | }
85 |
86 | &:nth-child(4) {
87 | left: calc(50% + var(--gutter));
88 | top: calc(50% - var(--gutter));
89 | }
90 |
91 | &:nth-child(5) {
92 | left: calc(50% + (var(--gutter) * 4));
93 | top: 50%;
94 | }
95 |
96 | &:nth-child(6) {
97 | left: calc(50% + (var(--gutter) * 2.7));
98 | top: calc(50% + (var(--gutter) * 1.5));
99 | }
100 |
101 | &:nth-child(7) {
102 | left: calc(50% + (var(--gutter) * 2.7));
103 | top: calc(50% - (var(--gutter) * 1.5));
104 | }
105 |
106 | &:nth-child(8) {
107 | left: calc(50% - (var(--gutter) * 1.7));
108 | top: 50%;
109 | }
110 |
111 | &:nth-child(9) {
112 | left: calc(50% - var(--gutter));
113 | top: calc(50% + var(--gutter));
114 | }
115 |
116 | &:nth-child(10) {
117 | left: calc(50% - var(--gutter));
118 | top: calc(50% - var(--gutter));
119 | }
120 |
121 | &:nth-child(11) {
122 | left: calc(50% - (var(--gutter) * 4));
123 | top: 50%;
124 | }
125 |
126 | &:nth-child(12) {
127 | left: calc(50% - (var(--gutter) * 2.7));
128 | top: calc(50% + (var(--gutter) * 1.5));
129 | }
130 |
131 | &:nth-child(13) {
132 | left: calc(50% - (var(--gutter) * 2.7));
133 | top: calc(50% - (var(--gutter) * 1.5));
134 | }
135 | }
136 |
137 | }
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_separator.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Separator
3 | //
4 |
5 | @import "separators/separator";
6 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_tables.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Tables
3 | //
4 |
5 | @import "tables/table";
6 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_type.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Typography
3 | //
4 |
5 | @import "type/type";
6 | @import "type/heading";
7 | @import "type/display";
8 | @import "type/article";
9 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_utilities.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Utilities
3 | //
4 |
5 | @import "utilities/backgrounds";
6 | @import "utilities/floating";
7 | @import "utilities/helper";
8 | @import "utilities/image";
9 | @import "utilities/opacity";
10 | @import "utilities/overflow";
11 | @import "utilities/position";
12 | @import "utilities/sizing";
13 | @import "utilities/spacing";
14 | @import "utilities/shadows";
15 | @import "utilities/text";
16 | @import "utilities/transform";
17 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/_vendors.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Vendors
3 | // include plugin styles
4 | //
5 |
6 |
7 | @import "vendors/bootstrap-datepicker";
8 | @import "vendors/nouislider";
9 | @import "vendors/scrollbar";
10 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/alerts/_alert-dismissible.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Dismissible alert
3 | //
4 |
5 | .alert-dismissible {
6 | .close {
7 | top: 50%;
8 | right: $alert-padding-x;
9 | padding: 0;
10 | transform: translateY(-50%);
11 | color: rgba($white, .6);
12 | opacity: 1;
13 |
14 | &:hover,
15 | &:focus {
16 | color: rgba($white, .9);
17 | opacity: 1 !important;
18 | }
19 |
20 | @include media-breakpoint-down(xs) {
21 | top: 1rem;
22 | right: .5rem;
23 | }
24 |
25 | &>span:not(.sr-only) {
26 | font-size: 1.5rem;
27 | background-color: transparent;
28 | color: rgba($white, .6);
29 | }
30 |
31 | &:hover,
32 | &:focus {
33 | &>span:not(.sr-only) {
34 | background-color: transparent;
35 | color: rgba($white, .9);
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/alerts/_alert.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Alert
3 | //
4 |
5 | .alert {
6 | font-size: $font-size-sm;
7 | }
8 |
9 | // Alert heading
10 |
11 | .alert-heading {
12 | font-weight: $font-weight-bold;
13 | font-size: $h4-font-size;
14 | margin-top: .15rem;
15 | }
16 |
17 |
18 | // Alert icon
19 | .alert-icon {
20 | font-size: 1.25rem;
21 | margin-right: 1.25rem;
22 | display: inline-block;
23 | vertical-align: middle;
24 |
25 | i.ni {
26 | position: relative;
27 | top: 1px;
28 | }
29 | }
30 |
31 |
32 | // Alert text next to an alert icon
33 | .alert-text {
34 | display: inline-block;
35 | vertical-align: middle;
36 | }
37 |
38 |
39 | // Alert links
40 |
41 | [class*="alert-"] {
42 | .alert-link {
43 | color: $white;
44 | border-bottom: 1px dotted rgba($white, .5);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/avatars/_avatar-group.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Avatar group
3 | //
4 |
5 | // General styles
6 |
7 | .avatar-group {
8 | .avatar {
9 | position: relative;
10 | z-index: 2;
11 | border: 2px solid $card-bg;
12 |
13 | &:hover {
14 | z-index: 3;
15 | }
16 | }
17 |
18 | .avatar + .avatar {
19 | margin-left: -1rem;
20 |
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/avatars/_avatar.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Avatar
3 | //
4 |
5 | // General styles
6 |
7 | .avatar {
8 | color: $white;
9 | background-color: $gray-500;
10 | display: inline-flex;
11 | align-items: center;
12 | justify-content: center;
13 | font-size: 1rem;
14 | border-radius: 50%;
15 | height: 48px;
16 | width: 48px;
17 |
18 | img {
19 | width: 100%;
20 | border-radius: 50%;
21 | }
22 |
23 | + .avatar-content {
24 | display: inline-block;
25 | margin-left: .75rem;
26 | }
27 | }
28 |
29 |
30 | // Avatar size variations
31 |
32 | .avatar-lg {
33 | width: 58px;
34 | height: 58px;
35 | font-size: $font-size-sm;
36 | }
37 |
38 | .avatar-sm {
39 | width: 36px;
40 | height: 36px;
41 | font-size: $font-size-sm;
42 | }
43 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/badges/_badge-circle.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Circle badge
3 | //
4 |
5 |
6 | // General styles
7 |
8 | .badge-circle {
9 | text-align: center;
10 | display: inline-flex;
11 | align-items: center;
12 | justify-content: center;
13 | border-radius: 50%;
14 | width: 2rem;
15 | height: 2rem;
16 | font-size: .875rem;
17 | }
18 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/badges/_badge-dot.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Dot badge
3 | //
4 |
5 |
6 | // General styles
7 |
8 | .badge-dot {
9 | padding-left: 0;
10 | padding-right: 0;
11 | background: transparent;
12 | font-weight: $font-weight-normal;
13 | font-size: $font-size-sm;
14 | text-transform: none;
15 |
16 | strong {
17 | color: $gray-800;
18 | }
19 |
20 | i {
21 | display: inline-block;
22 | vertical-align: middle;
23 | width: .375rem;
24 | height: .375rem;
25 | border-radius: 50%;
26 | margin-right: .375rem;
27 | }
28 |
29 | &.badge-md {
30 | i {
31 | width: .5rem;
32 | height: .5rem;
33 | }
34 | }
35 |
36 | &.badge-lg {
37 | i {
38 | width: .625rem;
39 | height: .625rem;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/badges/_badge.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Badge
3 | //
4 |
5 |
6 | // General styles
7 |
8 | .badge {
9 | text-transform: $badge-text-transfom;
10 |
11 | a {
12 | color: $white;
13 | }
14 | }
15 |
16 |
17 | // Size variations
18 |
19 | .badge-md {
20 | padding: .65em 1em;
21 | }
22 |
23 | .badge-lg {
24 | padding: .85em 1.375em;
25 | }
26 |
27 |
28 | // Multiple inline badges
29 |
30 | .badge-inline {
31 | margin-right: .625rem;
32 |
33 | + span {
34 | top: 2px;
35 | position: relative;
36 |
37 | > a {
38 | text-decoration: underline;
39 | }
40 | }
41 | }
42 |
43 |
44 | // Badge spacing inside a btn with some text
45 |
46 | .btn {
47 | .badge {
48 | &:not(:first-child) {
49 | margin-left: .5rem;
50 | }
51 | &:not(:last-child) {
52 | margin-right: .5rem;
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/buttons/_button-brand.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Brand buttons
3 | //
4 |
5 |
6 | // Color variations
7 |
8 | @each $color, $value in $brand-colors {
9 | .btn-#{$color} {
10 | @include button-variant($value, $value);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/buttons/_button-icon.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Icon buttons
3 | //
4 |
5 | .btn-icon {
6 | .btn-inner--icon {
7 | img {
8 | width: 20px;
9 | }
10 | }
11 |
12 | .btn-inner--text:not(:first-child) {
13 | margin-left: 0.75em;
14 | }
15 |
16 | .btn-inner--text:not(:last-child) {
17 | margin-right: 0.75em;
18 | }
19 | }
20 |
21 |
22 | // Button only with icon and NO text
23 |
24 | .btn-icon-only {
25 | width: 2.375rem;
26 | height: 2.375rem;
27 | padding: 0;
28 | }
29 |
30 | a.btn-icon-only {
31 | line-height: 2.5;
32 | }
33 |
34 | .btn-icon-only.btn-sm {
35 | width: 2rem;
36 | height: 2rem;
37 | }
38 |
39 |
40 | //
41 | // Clipboard button
42 | // dedicated element for copying icons
43 | //
44 |
45 | .btn-icon-clipboard {
46 | margin: 0;
47 | padding: 1.5rem;
48 | font-size: $font-size-base;
49 | font-weight: $font-weight-normal;
50 | line-height: 1.25;
51 | color: $gray-800;
52 | background-color: $gray-100;
53 | border-radius: $border-radius;
54 | border: 0;
55 | text-align: left;
56 | font-family: inherit;
57 | display: inline-block;
58 | vertical-align: middle;
59 | text-decoration: none;
60 | -moz-appearance: none;
61 | cursor: pointer;
62 | width: 100%;
63 | margin: .5rem 0;
64 |
65 | &:hover {
66 | background-color: $white;
67 | box-shadow: rgba(0, 0, 0, .1) 0 0 0 1px, rgba(0, 0, 0, .1) 0 4px 16px;
68 | }
69 |
70 | > div {
71 | align-items: center;
72 | display: flex;
73 | }
74 |
75 | i {
76 | box-sizing: content-box;
77 | color: theme-color("primary");
78 | vertical-align: middle;
79 | font-size: 1.5rem;
80 | }
81 |
82 | span {
83 | display: inline-block;
84 | font-size: 0.875rem;
85 | line-height: 1.5;
86 | margin-left: 16px;
87 | overflow: hidden;
88 | white-space: nowrap;
89 | text-overflow: ellipsis;
90 | vertical-align: middle;
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/buttons/_button.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Icon buttons
3 | //
4 |
5 | // General styles
6 |
7 | .btn {
8 | position: relative;
9 | text-transform: $btn-text-transform;
10 | transition: $transition-base;
11 | letter-spacing: $btn-letter-spacing;
12 | font-size: $input-btn-font-size;
13 | will-change: transform;
14 |
15 | &:hover {
16 | @include box-shadow($btn-hover-box-shadow);
17 | transform: translateY($btn-hover-translate-y);
18 | }
19 |
20 | &:not(:last-child) {
21 | margin-right: .5rem;
22 | }
23 |
24 |
25 | // Icons
26 |
27 | i:not(:first-child),
28 | svg:not(:first-child) {
29 | margin-left: .5rem;
30 | }
31 |
32 | i:not(:last-child),
33 | svg:not(:last-child) {
34 | margin-right: .5rem;
35 | }
36 | }
37 |
38 |
39 | // Remove translateY and margin animation when btn is included in a btn-group or input-group
40 |
41 | .btn-group,
42 | .input-group {
43 | .btn {
44 | margin-right: 0;
45 | transform: translateY(0);
46 | }
47 | }
48 |
49 |
50 | // Size variations
51 |
52 | .btn-sm {
53 | font-size: $input-btn-font-size-sm;
54 | }
55 |
56 | .btn-lg {
57 | font-size: $input-btn-font-size-lg;
58 | }
59 |
60 |
61 | // Some quick fixes (to revise)
62 |
63 | // Fixes
64 | [class*="btn-outline-"] {
65 | border-width: 1px;
66 | }
67 |
68 | .btn-outline-secondary {
69 | color: darken(theme-color("secondary"), 50%);
70 | }
71 |
72 | .btn-inner--icon {
73 | i:not(.fa) {
74 | position: relative;
75 | top: 2px;
76 | }
77 | }
78 |
79 | .btn-link {
80 | font-weight: $btn-font-weight;
81 | box-shadow: none;
82 |
83 | &:hover {
84 | box-shadow: none;
85 | transform: none;
86 | }
87 | }
88 |
89 | .btn-neutral {
90 | color: theme-color("primary");
91 | }
92 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/cards/_card-animations.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Card with hover animations
3 | //
4 |
5 | .card-lift--hover {
6 | &:hover {
7 | transform: translateY(-20px);
8 | @include transition($transition-base);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/cards/_card-blockquote.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Card with blockquote
3 | //
4 |
5 | .card-blockquote {
6 | padding: 2rem;
7 | position: relative;
8 |
9 | .svg-bg {
10 | display: block;
11 | width: 100%;
12 | height: 95px;
13 | position: absolute;
14 | top: -94px;
15 | left: 0;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/cards/_card-profile.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Profile card
3 | //
4 |
5 | .card-profile-image {
6 | position: relative;
7 |
8 | img {
9 | max-width: 180px;
10 | border-radius: $border-radius;
11 | @extend .shadow;
12 | transform: translate(-50%,-30%);
13 | position: absolute;
14 | left: 50%;
15 | transition: $transition-base;
16 |
17 | &:hover {
18 | transform: translate(-50%, -33%);
19 | }
20 | }
21 | }
22 |
23 | .card-profile-stats {
24 | padding: 1rem 0;
25 |
26 | > div {
27 | text-align: center;
28 | margin-right: 1rem;
29 | padding: .875rem;
30 |
31 | &:last-child {
32 | margin-right: 0;
33 | }
34 |
35 | .heading {
36 | font-size: 1.1rem;
37 | font-weight: bold;
38 | display: block;
39 | }
40 | .description {
41 | font-size: .875rem;
42 | color: $gray-500;
43 | }
44 | }
45 | }
46 |
47 | .card-profile-actions {
48 | padding: .875rem;
49 | }
50 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/cards/_card-stats.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Card stats
3 | //
4 |
5 | .card-stats {
6 | .card-body {
7 | padding: 1rem 1.5rem;
8 | }
9 |
10 | .card-status-bullet {
11 | position: absolute;
12 | top: 0;
13 | right: 0;
14 | transform: translate(50%, -50%);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/cards/_card.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Card
3 | //
4 |
5 |
6 | .card-translucent {
7 | background-color: rgba(18, 91, 152, 0.08);
8 | }
9 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/charts/_chart.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Chart
3 | //
4 |
5 | .chart {
6 | position: relative;
7 | height: $chart-height;
8 | }
9 |
10 |
11 | // Size variations
12 |
13 | .chart-sm {
14 | height: $chart-height-sm;
15 | }
16 |
17 |
18 | // Legend
19 |
20 | .chart-legend {
21 | display: flex;
22 | justify-content: center;
23 | margin-top: $chart-legend-margin-top;
24 | font-size: $chart-legend-font-size;
25 | text-align: center;
26 | color: $chart-legend-color;
27 | }
28 |
29 | .chart-legend-item {
30 | display: inline-flex;
31 | align-items: center;
32 |
33 | + .chart-legend-item {
34 | margin-left: 1rem;
35 | }
36 | }
37 |
38 | .chart-legend-indicator {
39 | display: inline-block;
40 | width: 0.5rem;
41 | height: 0.5rem;
42 | margin-right: 0.375rem;
43 | border-radius: 50%;
44 | }
45 |
46 |
47 | // Tooltip
48 |
49 | #chart-tooltip {
50 | z-index: 0;
51 |
52 | .arrow {
53 | top: 100%;
54 | left: 50%;
55 | transform: translateX(-50%) translateX(-.5rem);
56 | }
57 | }
58 |
59 |
60 | // Chart info overlay
61 |
62 | .chart-info-overlay {
63 | position: absolute;
64 | top: 0;
65 | left: 5%;
66 | max-width: 350px;
67 | padding: 20px;
68 | z-index: 1;
69 | }
70 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/close/_close.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Close
3 | //
4 |
5 | .close {
6 | @if $enable-transitions {
7 | transition: $transition-base;
8 | }
9 |
10 | &>span:not(.sr-only) {
11 | background-color: $close-bg;
12 | color: $close-color;
13 | line-height: 17px;
14 | height: 1.25rem;
15 | width: 1.25rem;
16 | border-radius: 50%;
17 | font-size: 1.25rem;
18 | display: block;
19 | @if $enable-transitions {
20 | transition: $transition-base;
21 | }
22 | }
23 |
24 | &:hover,
25 | &:focus {
26 | background-color: $close-hover-bg;
27 | color: $close-hover-color;
28 | outline: none;
29 |
30 | span:not(.sr-only) {
31 | background-color: $close-hover-bg;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/custom-forms/_custom-checkbox.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Custom checkbox
3 | //
4 |
5 | .custom-checkbox {
6 | .custom-control-input ~ .custom-control-label {
7 | cursor: pointer;
8 | font-size: $font-size-sm;
9 | }
10 |
11 | .custom-control-input {
12 | &:checked {
13 | ~ .custom-control-label {
14 | &::before {
15 | border-color: $custom-control-indicator-checked-border-color;
16 | }
17 | &::after {
18 | background-image: $custom-checkbox-indicator-icon-checked;
19 | }
20 | }
21 | }
22 |
23 | &:disabled {
24 | ~ .custom-control-label {
25 | &::before {
26 | border-color: $custom-control-indicator-disabled-bg;
27 | }
28 | }
29 |
30 | &:checked {
31 | &::before {
32 | border-color: $custom-control-indicator-checked-disabled-bg;
33 | }
34 | }
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/custom-forms/_custom-control.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Custom control
3 | // additional styles for custom checkboxes, radios and other
4 | //
5 |
6 | .custom-control-label {
7 | // Background-color and (when enabled) gradient
8 | &::before {
9 | border: $custom-control-indicator-border-width solid $custom-control-indicator-border-color;
10 | @if $enable-transitions {
11 | transition: $input-transition;
12 | }
13 | }
14 |
15 | span {
16 | position: relative;
17 | top: 2px;
18 | }
19 | }
20 |
21 | .custom-control-label {
22 | margin-bottom: 0;
23 | }
24 |
25 |
26 | // Alternative style
27 |
28 | .custom-control-alternative {
29 | .custom-control-label {
30 | // Background-color and (when enabled) gradient
31 | &::before {
32 | border: 0;
33 | box-shadow: $input-alternative-box-shadow;
34 | }
35 | }
36 |
37 | .custom-control-input {
38 | &:checked {
39 | ~ .custom-control-label {
40 | &::before {
41 | box-shadow: $input-focus-alternative-box-shadow;
42 | }
43 | }
44 | }
45 |
46 | &:active~.custom-control-label::before,
47 | &:focus~.custom-control-label::before {
48 | box-shadow: $input-alternative-box-shadow;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/custom-forms/_custom-form.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Custom checkbox
3 | //
4 |
5 | .custom-checkbox {
6 | .custom-control-input ~ .custom-control-label {
7 | cursor: pointer;
8 | font-size: $font-size-sm;
9 | }
10 |
11 | .custom-control-input {
12 | &:checked {
13 | ~ .custom-control-label {
14 | &::before {
15 | border-color: $custom-control-indicator-checked-border-color;
16 | }
17 | &::after {
18 | background-image: $custom-checkbox-indicator-icon-checked;
19 | }
20 | }
21 | }
22 |
23 | &:disabled {
24 | ~ .custom-control-label {
25 | &::before {
26 | border-color: $custom-control-indicator-disabled-bg;
27 | }
28 | }
29 |
30 | &:checked {
31 | &::before {
32 | border-color: $custom-control-indicator-checked-disabled-bg;
33 | }
34 | }
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/custom-forms/_custom-radio.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Custom radio
3 | //
4 |
5 | .custom-radio {
6 | .custom-control-input ~ .custom-control-label {
7 | cursor: pointer;
8 | font-size: $font-size-sm;
9 | }
10 |
11 | .custom-control-input {
12 | &:checked {
13 | ~ .custom-control-label {
14 | &::before {
15 | border-color: $custom-control-indicator-checked-border-color;
16 | }
17 | &::after {
18 | background-image: $custom-radio-indicator-icon-checked;
19 | }
20 | }
21 | }
22 |
23 | &:disabled {
24 | ~ .custom-control-label {
25 | &::before {
26 | border-color: $custom-control-indicator-disabled-bg;
27 | }
28 | }
29 |
30 | &:checked {
31 | &::before {
32 | border-color: $custom-control-indicator-checked-disabled-bg;
33 | }
34 | }
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/custom-forms/_custom-toggle.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Custom toggle
3 | //
4 |
5 | .custom-toggle {
6 | position: relative;
7 | display: inline-block;
8 | width: $custom-toggle-width;
9 | height: 1.5rem;
10 |
11 | input {
12 | display: none;
13 |
14 | &:checked {
15 | + .custom-toggle-slider {
16 | border: $custom-control-indicator-border-width solid $custom-control-indicator-checked-border-color;
17 |
18 | &:before {
19 | background: $custom-toggle-checked-bg;
20 | transform: translateX(1.625rem);
21 | }
22 | }
23 | }
24 |
25 | &:disabled {
26 | + .custom-toggle-slider {
27 | border: $custom-control-indicator-border-width solid $custom-control-indicator-disabled-bg;
28 | }
29 |
30 | &:checked {
31 | + .custom-toggle-slider {
32 | border: $custom-control-indicator-border-width solid $custom-control-indicator-disabled-bg;
33 |
34 | &:before {
35 | background-color: lighten($custom-control-indicator-checked-bg, 10%);
36 | }
37 | }
38 | }
39 | }
40 | }
41 | }
42 |
43 | .custom-toggle-slider {
44 | position: absolute;
45 | cursor: pointer;
46 | top: 0;
47 | left: 0;
48 | right: 0;
49 | bottom: 0;
50 | border: $custom-control-indicator-border-width solid $input-border-color;
51 | border-radius: 34px !important;
52 | background-color: transparent;
53 |
54 |
55 | &:before {
56 | position: absolute;
57 | content: "";
58 | height: 18px;
59 | width: 18px;
60 | left: 2px;
61 | bottom: 2px;
62 | border-radius: 50% !important;
63 | background-color: $custom-toggle-slider-bg;
64 | transition: $input-transition;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/dropdowns/_dropdown.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Dropdown
3 | //
4 |
5 | // General styles
6 |
7 | .dropdown,
8 | .dropup,
9 | .dropright,
10 | .dropleft {
11 | display: inline-block;
12 | }
13 |
14 | .dropdown-menu {
15 | min-width: 12rem;
16 |
17 | .dropdown-item {
18 | padding: .5rem 1rem;
19 | font-size: $font-size-sm;
20 | > i,
21 | > svg {
22 | margin-right: 1rem;
23 | font-size: 1rem;
24 | vertical-align: -17%;
25 | }
26 | }
27 | }
28 |
29 | .dropdown-header {
30 | padding-left: 1rem;
31 | padding-right: 1rem;
32 | color: $gray-100;
33 | font-size: .625rem;
34 | text-transform: uppercase;
35 | font-weight: 700;
36 | }
37 |
38 |
39 | // Media components inside dropdown link
40 |
41 | .dropdown-menu {
42 | a.media {
43 |
44 | > div {
45 | &:first-child {
46 | line-height: 1;
47 | }
48 | }
49 |
50 | p {
51 | color: $gray-600;
52 | }
53 |
54 | &:hover {
55 | .heading,
56 | p {
57 | color: theme-color("default") !important;
58 | }
59 | }
60 | }
61 | }
62 |
63 |
64 | // Size variations
65 |
66 | .dropdown-menu-sm {
67 | min-width: 100px;
68 | border: $border-radius-lg;
69 | }
70 |
71 | .dropdown-menu-lg {
72 | min-width: 260px;
73 | border-radius: $border-radius-lg;
74 | }
75 |
76 | .dropdown-menu-xl {
77 | min-width: 450px;
78 | border-radius: $border-radius-lg;
79 | }
80 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/footers/_footer.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Footer
3 | //
4 |
5 |
6 | // General styles
7 |
8 | .footer {
9 | background: $footer-bg;
10 | padding: $footer-padding-y $footer-padding-x;
11 |
12 | .col-footer {
13 | .heading {
14 | color: $footer-heading-color;
15 | letter-spacing: 0;
16 | font-size: $footer-heading-font-size;
17 | text-transform: uppercase;
18 | font-weight: $font-weight-bold;
19 | margin-bottom: 1rem;
20 | }
21 | }
22 |
23 | .nav .nav-item .nav-link,
24 | .footer-link {
25 | color: $footer-link-color !important;
26 |
27 | &:hover {
28 | color: $footer-link-hover-color !important;
29 | }
30 | }
31 |
32 | .list-unstyled li a {
33 | display: inline-block;
34 | padding: .125rem 0;
35 | color: $footer-link-color;
36 | font-size: $footer-link-font-size;
37 |
38 | &:hover {
39 | color: $footer-link-hover-color;
40 | }
41 | }
42 |
43 | .copyright {
44 | font-size: $font-size-sm;
45 | }
46 | }
47 |
48 |
49 | // Dark footer
50 |
51 | .footer-dark {
52 | .col-footer .heading {
53 | color: $white;
54 | }
55 | }
56 |
57 |
58 | // Footer nav used for copyright and some links, but not limited to this
59 |
60 | .nav-footer {
61 | .nav-link {
62 | font-size: $font-size-sm;
63 | }
64 |
65 | .nav-item:last-child {
66 | .nav-link {
67 | padding-right: 0;
68 | }
69 | }
70 | }
71 |
72 |
73 | // Footer with cards over
74 |
75 | .footer.has-cards {
76 | overflow: hidden;
77 | padding-top: 500px;
78 | margin-top: -420px;
79 | position: relative;
80 | background: transparent;
81 | pointer-events: none;
82 |
83 | &:before {
84 | content: "";
85 | position: absolute;
86 | left: 0;
87 | right: 0;
88 | top: 600px;
89 | height: 2000px;
90 | background: theme-color("secondary");
91 | transform: skew(0,-8deg);
92 | }
93 |
94 | .container {
95 | pointer-events: auto;
96 | position: relative;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/forms/_form-validation.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Form validation
3 | //
4 |
5 | // Validation
6 |
7 | .has-success,
8 | .has-danger {
9 | position: relative;
10 |
11 | &:after, {
12 | width: 19px;
13 | height: 19px;
14 | line-height: 19px;
15 | text-align: center;
16 | font-family: 'NucleoIcons';
17 | display: inline-block;
18 | position: absolute;
19 | right: 15px;
20 | top: 2px;
21 | transform: translateY(50%);
22 | border-radius: 50%;
23 | font-size: 9px;
24 | opacity: 1;
25 | }
26 | }
27 |
28 | .has-success {
29 | &:after {
30 | content: "\ea26";
31 | color: daken($form-feedback-valid-color, 18%);
32 | background-color: $form-feedback-valid-bg;
33 | }
34 |
35 | .form-control {
36 | background-color: $input-focus-bg;
37 |
38 | &:focus {
39 | border-color: $input-focus-border-color;
40 | }
41 |
42 |
43 | // Placeholder
44 |
45 | &::placeholder {
46 | color: $form-feedback-valid-color;
47 | }
48 | }
49 | }
50 |
51 | .has-danger {
52 | &:after {
53 | content: "\ea53";
54 | color: daken($form-feedback-invalid-color, 18%);
55 | background-color: $form-feedback-invalid-bg;
56 | }
57 |
58 | .form-control {
59 | background-color: $input-focus-bg;
60 |
61 | &:focus {
62 | border-color: $input-focus-border-color;
63 | }
64 |
65 | // Placeholder
66 |
67 | &::placeholder {
68 | color: $form-feedback-invalid-color;
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/forms/_form.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Forms
3 | //
4 |
5 |
6 | // Labels
7 |
8 | .form-control-label {
9 | color: $gray-700;
10 | font-size: $font-size-sm;
11 | font-weight: $font-weight-bold;
12 | }
13 |
14 |
15 | // Text inputs
16 |
17 | .form-control {
18 | font-size: $input-btn-font-size;
19 |
20 | &:focus {
21 | &::placeholder {
22 | color: $input-focus-placeholder-color;
23 | }
24 | }
25 | }
26 |
27 |
28 | // Textarea
29 |
30 | textarea[resize="none"] {
31 | resize: none!important;
32 | }
33 |
34 | textarea[resize="both"] {
35 | resize: both!important;
36 | }
37 |
38 | textarea[resize="vertical"] {
39 | resize: vertical!important;
40 | }
41 |
42 | textarea[resize="horizontal"] {
43 | resize: horizontal!important;
44 | }
45 |
46 |
47 | // Form input variations
48 |
49 | // Muted input
50 |
51 | .form-control-muted {
52 | background-color: $input-muted-bg;
53 | border-color: $input-muted-bg;
54 | box-shadow: none;
55 |
56 | &:focus {
57 | background-color: $input-focus-muted-bg;
58 | }
59 | }
60 |
61 |
62 | // Alternative input
63 |
64 | .form-control-alternative {
65 | box-shadow: $input-alternative-box-shadow;
66 | border: 0;
67 | transition: box-shadow .15s ease;
68 |
69 | &:focus {
70 | box-shadow: $input-focus-alternative-box-shadow;
71 | }
72 | }
73 |
74 | // Size variations: Fixes to the bootstrap defaults
75 |
76 | .form-control-lg {
77 | font-size: $font-size-base;
78 | }
79 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/forms/_input-group.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Input group
3 | //
4 |
5 | .input-group {
6 | box-shadow: $input-box-shadow;
7 | border-radius: $input-border-radius;
8 | transition: $transition-base;
9 |
10 | .form-control {
11 | box-shadow: none;
12 |
13 | &:not(:first-child) {
14 | border-left: 0;
15 | padding-left: 0;
16 | }
17 | &:not(:last-child) {
18 | border-right: 0;
19 | padding-right: 0;
20 | }
21 | &:focus {
22 | box-shadow: none;
23 | }
24 | }
25 | }
26 |
27 | .input-group-text {
28 | transition: $input-transition;
29 | }
30 |
31 |
32 | // Alternative input groups related to .form-control-alternative
33 |
34 |
35 | .input-group-alternative {
36 | box-shadow: $input-alternative-box-shadow;
37 | border: 0;
38 | transition: box-shadow .15s ease;
39 |
40 | .form-control,
41 | .input-group-text {
42 | border: 0;
43 | box-shadow: none;
44 | }
45 | }
46 |
47 | .focused {
48 | .input-group-alternative {
49 | box-shadow: $input-focus-alternative-box-shadow !important;
50 | }
51 | }
52 |
53 |
54 | // .focus class is applied dinamycally from theme.js
55 |
56 | .focused {
57 | .input-group {
58 | box-shadow: $input-focus-box-shadow;
59 | }
60 |
61 | .input-group-text {
62 | color: $input-group-addon-focus-color;
63 | background-color: $input-group-addon-focus-bg;
64 | border-color: $input-group-addon-focus-border-color;
65 | }
66 |
67 | .form-control {
68 | border-color: $input-group-addon-focus-border-color;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/headers/_header.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Header
3 | //
4 |
5 | .header {
6 | position: relative;
7 | }
8 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/icons/_icon-shape.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Icon shape
3 | //
4 |
5 |
6 | .icon-shape {
7 | padding: 12px;
8 | text-align: center;
9 | display: inline-flex;
10 | align-items: center;
11 | justify-content: center;
12 | border-radius: 50%;
13 |
14 |
15 | i, svg {
16 | font-size: 1.25rem;
17 | }
18 |
19 | &.icon-lg {
20 | i, svg {
21 | font-size: 1.625rem;
22 | }
23 | }
24 |
25 | &.icon-sm {
26 | i, svg {
27 | font-size: .875rem;
28 | }
29 | }
30 |
31 | svg {
32 | width: 30px;
33 | height: 30px;
34 | }
35 |
36 | }
37 |
38 | @each $color, $value in $theme-colors {
39 | .icon-shape-#{$color} {
40 | @include icon-shape-variant(theme-color($color));
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/icons/_icon.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Icon
3 | //
4 |
5 | .icon {
6 | width: $icon-size;
7 | height: $icon-size;
8 |
9 | i, svg {
10 | font-size: $icon-size - .75;
11 | }
12 |
13 | + .icon-text {
14 | padding-left: 1rem;
15 | width: calc(100% - #{$icon-size} - 1);
16 | }
17 | }
18 |
19 |
20 | // Extra large icons
21 |
22 | .icon-xl {
23 | width: $icon-size-xl;
24 | height: $icon-size-xl;
25 |
26 | i, svg {
27 | font-size: $icon-size-xl - .75;
28 | }
29 |
30 | + .icon-text {
31 | width: calc(100% - #{$icon-size-xl} - 1);
32 | }
33 | }
34 |
35 |
36 | // Large icons
37 |
38 | .icon-lg {
39 | width: $icon-size-lg;
40 | height: $icon-size-lg;
41 |
42 | i, svg {
43 | font-size: $icon-size-lg - .75;
44 | }
45 |
46 | + .icon-text {
47 | width: calc(100% - #{$icon-size-lg} - 1);
48 | }
49 | }
50 |
51 |
52 | // Small icon
53 |
54 | .icon-sm {
55 | width: $icon-size-sm;
56 | height: $icon-size-sm;
57 |
58 | i, svg {
59 | font-size: $icon-size-sm - .75;
60 | }
61 |
62 | + .icon-text {
63 | width: calc(100% - #{$icon-size-sm} - 1);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/list-groups/_list-group.scss:
--------------------------------------------------------------------------------
1 | //
2 | // List group
3 | //
4 |
5 |
6 | // Space list items
7 |
8 | .list-group-space {
9 | .list-group-item {
10 | margin-bottom: 1.5rem;
11 | @include border-radius($list-group-border-radius);
12 | }
13 | }
14 |
15 |
16 | // Extended list group components
17 |
18 | .list-group-img {
19 | width: 3rem;
20 | height: 3rem;
21 | border-radius: 50%;
22 | vertical-align: top;
23 | margin: -.1rem 1.2rem 0 -.2rem;
24 | }
25 |
26 | .list-group-content {
27 | flex: 1;
28 | min-width: 0;
29 |
30 | > p {
31 | color: $gray-500;
32 | line-height: 1.5;
33 | margin: .2rem 0 0;
34 | }
35 | }
36 |
37 | .list-group-heading {
38 | font-size: $font-size-base;
39 | color: $gray-800;
40 |
41 | > small {
42 | float: right;
43 | color: $gray-500;
44 | font-weight: 500;
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/maps/_map.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Map
3 | //
4 |
5 | .map-canvas {
6 | position: relative;
7 | width: 100%;
8 | height: $map-height;
9 | border-radius: $border-radius;
10 | }
11 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/masks/_mask.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Mask
3 | //
4 |
5 | .mask {
6 | position: absolute;
7 | top: 0;
8 | left: 0;
9 | width: 100%;
10 | height: 100%;
11 | @include transition($transition-base);
12 | }
13 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/mixins/_alert.scss:
--------------------------------------------------------------------------------
1 | @mixin alert-variant($background, $border, $color) {
2 | color: color-yiq($background);
3 | @include gradient-bg($background);
4 | border-color: $border;
5 |
6 | hr {
7 | border-top-color: darken($border, 5%);
8 | }
9 |
10 | .alert-link {
11 | color: darken($color, 10%);
12 | }
13 | }
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/mixins/_background-variant.scss:
--------------------------------------------------------------------------------
1 | // Contextual backgrounds
2 | @mixin bg-variant($parent, $color, $ignore-warning: true) {
3 | #{$parent} {
4 | background-color: $color !important;
5 | }
6 | a#{$parent},
7 | button#{$parent} {
8 | @include hover-focus {
9 | background-color: darken($color, 10%) !important;
10 | }
11 | }
12 | }
13 |
14 | @mixin bg-gradient-variant($parent, $color) {
15 | #{$parent} {
16 | background: linear-gradient(87deg, $color 0, adjust-hue($color, 25%) 100%) !important;
17 | }
18 | }
19 |
20 | @mixin bg-translucent-variant($parent, $color) {
21 | #{$parent} {
22 | background-color: darken(rgba($color, $translucent-color-opacity), 7%) !important;
23 | }
24 | a#{$parent},
25 | button#{$parent} {
26 | @include hover-focus {
27 | background-color: darken(rgba($color, $translucent-color-opacity), 12%) !important;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/mixins/_badge.scss:
--------------------------------------------------------------------------------
1 | @mixin badge-variant($bg) {
2 | color: saturate(darken($bg, 10%), 10);
3 | background-color: transparentize(lighten($bg, 25%), .5);
4 |
5 | &[href] {
6 | @include hover-focus {
7 | color: color-yiq($bg);
8 | text-decoration: none;
9 | background-color: darken($bg, 10%);
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/mixins/_buttons.scss:
--------------------------------------------------------------------------------
1 | @mixin button-variant($background, $border, $hover-background: darken($background, 0%), $hover-border: darken($border, 0%), $active-background: darken($background, 10%), $active-border: darken($border, 0%)) {
2 | color: color-yiq($background);
3 | @include gradient-bg($background);
4 | border-color: $border;
5 | @include box-shadow($btn-box-shadow);
6 |
7 | @include hover {
8 | color: color-yiq($hover-background);
9 | @include gradient-bg($hover-background);
10 | border-color: $hover-border;
11 | }
12 |
13 | &:focus,
14 | &.focus {
15 | // Avoid using mixin so we can pass custom focus shadow properly
16 | @if $enable-shadows {
17 | box-shadow: $btn-box-shadow, 0 0 0 $btn-focus-width rgba($border, .5);
18 | }
19 | @else {
20 | box-shadow: 0 0 0 $btn-focus-width rgba($border, .5);
21 | }
22 | } // Disabled comes first so active can properly restyle
23 | &.disabled,
24 | &:disabled {
25 | color: color-yiq($background);
26 | background-color: $background;
27 | border-color: $border;
28 | }
29 |
30 | &:not(:disabled):not(.disabled):active,
31 | &:not(:disabled):not(.disabled).active,
32 | .show>&.dropdown-toggle {
33 | color: color-yiq($active-background);
34 | background-color: $active-background;
35 | @if $enable-gradients {
36 | background-image: none; // Remove the gradient for the pressed/active state
37 | }
38 | border-color: $active-border;
39 |
40 | &:focus {
41 | // Avoid using mixin so we can pass custom focus shadow properly
42 | @if $enable-shadows {
43 | box-shadow: $btn-active-box-shadow, 0 0 0 $btn-focus-width rgba($border, .5);
44 | }
45 | @else {
46 | box-shadow: 0 0 0 $btn-focus-width rgba($border, .5);
47 | }
48 | }
49 | }
50 | }
51 |
52 | @mixin button-outline-variant($color, $color-hover: color-yiq($color), $active-background: $color, $active-border: $color) {
53 | color: $color;
54 | background-color: transparent;
55 | background-image: none;
56 | border-color: $color;
57 |
58 | &:hover {
59 | color: $color-hover;
60 | background-color: $active-background;
61 | border-color: $active-border;
62 | }
63 |
64 | &:focus,
65 | &.focus {
66 | box-shadow: 0 0 0 $btn-focus-width rgba($color, .5);
67 | }
68 |
69 | &.disabled,
70 | &:disabled {
71 | color: $color;
72 | background-color: transparent;
73 | }
74 |
75 | &:not(:disabled):not(.disabled):active,
76 | &:not(:disabled):not(.disabled).active,
77 | .show>&.dropdown-toggle {
78 | color: color-yiq($active-background);
79 | background-color: $active-background;
80 | border-color: $active-border;
81 |
82 | &:focus {
83 | // Avoid using mixin so we can pass custom focus shadow properly
84 | @if $enable-shadows and $btn-active-box-shadow !=none {
85 | box-shadow: $btn-active-box-shadow, 0 0 0 $btn-focus-width rgba($color, .5);
86 | }
87 | @else {
88 | box-shadow: 0 0 0 $btn-focus-width rgba($color, .5);
89 | }
90 | }
91 | }
92 | }
93 |
94 | // Button sizes
95 | @mixin button-size($padding-y, $padding-x, $font-size, $line-height, $border-radius) {
96 | padding: $padding-y $padding-x;
97 | font-size: $font-size;
98 | line-height: $line-height; // Manually declare to provide an override to the browser default
99 | @if $enable-rounded {
100 | border-radius: $border-radius;
101 | }
102 | @else {
103 | border-radius: 0;
104 | }
105 | }
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/mixins/_forms.scss:
--------------------------------------------------------------------------------
1 | @mixin form-control-focus($ignore-warning) {
2 | &:focus {
3 | color: $input-focus-color;
4 | background-color: $input-focus-bg;
5 | border-color: $input-focus-border-color;
6 | outline: 0;
7 | // Avoid using mixin so we can pass custom focus shadow properly
8 | @if $enable-shadows {
9 | box-shadow: $input-box-shadow, $input-focus-box-shadow;
10 | } @else {
11 | box-shadow: $input-focus-box-shadow;
12 | }
13 | }
14 | }
15 |
16 |
17 | @mixin form-validation-state($state, $color, $icon) {
18 | .#{$state}-feedback {
19 | display: none;
20 | width: 100%;
21 | margin-top: $form-feedback-margin-top;
22 | font-size: $form-feedback-font-size;
23 | color: $color;
24 | }
25 |
26 | .#{$state}-tooltip {
27 | position: absolute;
28 | top: 100%;
29 | z-index: 5;
30 | display: none;
31 | max-width: 100%; // Contain to parent when possible
32 | padding: .5rem;
33 | margin-top: .1rem;
34 | font-size: .875rem;
35 | line-height: 1;
36 | color: #fff;
37 | background-color: rgba($color, .8);
38 | border-radius: .2rem;
39 | }
40 |
41 | .form-control,
42 | .custom-select {
43 | .was-validated &:#{$state},
44 | &.is-#{$state} {
45 | border-color: $color;
46 |
47 | &:focus {
48 | border-color: $color;
49 | //box-shadow: 0 1px $input-focus-width 0 rgba($color, .75);
50 | }
51 |
52 | ~ .#{$state}-feedback,
53 | ~ .#{$state}-tooltip {
54 | display: block;
55 | }
56 | }
57 | }
58 |
59 | .form-check-input {
60 | .was-validated &:#{$state},
61 | &.is-#{$state} {
62 | ~ .form-check-label {
63 | color: $color;
64 | }
65 |
66 | ~ .#{$state}-feedback,
67 | ~ .#{$state}-tooltip {
68 | display: block;
69 | }
70 | }
71 | }
72 |
73 | .custom-control-input {
74 | .was-validated &:#{$state},
75 | &.is-#{$state} {
76 | ~ .custom-control-label {
77 | color: $color;
78 |
79 | &::before {
80 | background-color: lighten($color, 25%);
81 | border-color: lighten($color, 25%);
82 | }
83 | }
84 |
85 | ~ .#{$state}-feedback,
86 | ~ .#{$state}-tooltip {
87 | display: block;
88 | }
89 |
90 | &:checked {
91 | ~ .custom-control-label::before {
92 | @include gradient-bg(lighten($color, 10%));
93 | border-color: lighten($color, 25%);
94 | }
95 | }
96 |
97 | &:focus {
98 | ~ .custom-control-label::before {
99 | box-shadow: 0 0 0 1px $body-bg, 0 0 0 $input-focus-width rgba($color, .25);
100 | }
101 | }
102 | }
103 | }
104 |
105 | // custom file
106 | .custom-file-input {
107 | .was-validated &:#{$state},
108 | &.is-#{$state} {
109 | ~ .custom-file-label {
110 | border-color: $color;
111 |
112 | &::before { border-color: inherit; }
113 | }
114 |
115 | ~ .#{$state}-feedback,
116 | ~ .#{$state}-tooltip {
117 | display: block;
118 | }
119 |
120 | &:focus {
121 | ~ .custom-file-label {
122 | box-shadow: 0 0 0 $input-focus-width rgba($color, .25);
123 | }
124 | }
125 | }
126 | }
127 | }
128 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/mixins/_icon.scss:
--------------------------------------------------------------------------------
1 | @mixin icon-shape-variant($color) {
2 | color: saturate(darken($color, 10%), 10);
3 | background-color: transparentize(lighten($color, 10%), .5);
4 | }
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/mixins/_modals.scss:
--------------------------------------------------------------------------------
1 | @mixin modal-variant($background) {
2 | .modal-title {
3 | color: color-yiq($background);
4 | }
5 | .modal-header,
6 | .modal-footer {
7 | border-color: rgba(color-yiq($background), .075);
8 | }
9 | .modal-content {
10 | background-color: $background;
11 | color: color-yiq($background);
12 |
13 | .heading {
14 | color: color-yiq($background);
15 | }
16 | }
17 |
18 | .close {
19 | &>span:not(.sr-only) {
20 | color: $white;
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/mixins/_popover.scss:
--------------------------------------------------------------------------------
1 | @mixin popover-variant($background) {
2 |
3 | background-color: $background;
4 |
5 | .popover-header {
6 | background-color: $background;
7 | color: color-yiq($background);
8 | }
9 |
10 | .popover-body {
11 | color: color-yiq($background);
12 | }
13 | .popover-header{
14 | border-color: rgba(color-yiq($background), .2);
15 | }
16 | &.bs-popover-top {
17 | .arrow::after {
18 | border-top-color: $background;
19 | }
20 | }
21 | &.bs-popover-right {
22 | .arrow::after {
23 | border-right-color: $background;
24 | }
25 | }
26 | &.bs-popover-bottom {
27 | .arrow::after {
28 | border-bottom-color: $background;
29 | }
30 | }
31 | &.bs-popover-left {
32 | .arrow::after {
33 | border-left-color: $background;
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/modals/_modal.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Modal
3 | //
4 |
5 |
6 | // Fluid modal
7 |
8 | .modal-fluid {
9 | .modal-dialog {
10 | margin-top: 0;
11 | margin-bottom: 0;
12 | }
13 | .modal-content {
14 | border-radius: 0;
15 | }
16 | }
17 |
18 |
19 | // Background color variations
20 |
21 | @each $color, $value in $theme-colors {
22 | .modal-#{$color} {
23 | @include modal-variant($value);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/navbars/_navbar-collapse.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Navabar collapse
3 | //
4 |
5 | // Collapse
6 |
7 | .navbar-collapse-header {
8 | display: none;
9 | }
10 |
11 | @include media-breakpoint-down(sm) {
12 | .navbar-nav {
13 | .nav-link {
14 | padding: .625rem 0;
15 | color: theme-color("default") !important;
16 | }
17 |
18 | .dropdown-menu {
19 | box-shadow: none;
20 | min-width: auto;
21 |
22 | .media {
23 | svg {
24 | width: 30px;
25 | }
26 | }
27 | }
28 | }
29 |
30 | .navbar-collapse {
31 | width: calc(100% - 1.4rem);
32 | position: absolute;
33 | top: 0;
34 | left: 0;
35 | right: 0;
36 | z-index: 1050;
37 | margin: .7rem;
38 | overflow-y: auto;
39 | height: auto !important;
40 | opacity: 0;
41 |
42 | .navbar-toggler {
43 | width: 20px;
44 | height: 20px;
45 | position: relative;
46 | cursor: pointer;
47 | display: inline-block;
48 | padding: 0;
49 |
50 | span {
51 | display: block;
52 | position: absolute;
53 | width: 100%;
54 | height: 2px;
55 | border-radius: 2px;
56 | opacity: 1;
57 | background: #283448;
58 | }
59 |
60 | :nth-child(1) {
61 | transform: rotate(135deg);
62 | }
63 |
64 | :nth-child(2) {
65 | transform: rotate(-135deg);
66 | }
67 | }
68 |
69 | .navbar-collapse-header {
70 | display: block;
71 | padding-bottom: 1rem;
72 | margin-bottom: 1rem;
73 | border-bottom: 1px solid rgba(0, 0, 0, .1);
74 | }
75 |
76 | .collapse-brand {
77 | img {
78 | height: 36px;
79 | }
80 | }
81 |
82 | .collapse-close {
83 | text-align: right;
84 | }
85 | }
86 |
87 | .navbar-collapse.collapsing,
88 | .navbar-collapse.show {
89 | padding: 1.5rem;
90 | border-radius: $border-radius;
91 | background: #FFF;
92 | box-shadow: 0 50px 100px rgba(50,50,93,.1),0 15px 35px rgba(50,50,93,.15),0 5px 15px rgba(0,0,0,.1);
93 | animation: show-navbar-collapse .2s ease forwards;
94 | }
95 |
96 | .navbar-collapse.collapsing-out {
97 | animation: hide-navbar-collapse .2s ease forwards;
98 | }
99 | }
100 |
101 | @keyframes show-navbar-collapse {
102 | 0% {
103 | opacity: 0;
104 | transform: scale(.95);
105 | transform-origin: 100% 0;
106 | }
107 |
108 | 100% {
109 | opacity: 1;
110 | transform: scale(1);
111 | }
112 | }
113 |
114 | @keyframes hide-navbar-collapse {
115 | from {
116 | opacity: 1;
117 | transform: scale(1);
118 | transform-origin: 100% 0;
119 | }
120 |
121 | to {
122 | opacity: 0;
123 | transform: scale(.95);
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/navbars/_navbar-dropdown.scss:
--------------------------------------------------------------------------------
1 | // Dropdown menu
2 |
3 | @include media-breakpoint-up(md) {
4 | .navbar {
5 | .dropdown-menu {
6 | opacity: 0;
7 | pointer-events: none;
8 | margin: 0;
9 | }
10 |
11 | .dropdown-menu-arrow {
12 | &:before {
13 | background: $dropdown-bg;
14 | box-shadow: none;
15 | content: '';
16 | display: block;
17 | height: 12px;
18 | width: 12px;
19 | left: 20px;
20 | position: absolute;
21 | bottom: 100%;
22 | transform: rotate(-45deg) translateY(12px);
23 | z-index: -5;
24 | border-radius: 2px;
25 | }
26 | }
27 |
28 | .dropdown-menu-right {
29 | &:before {
30 | right: 20px;
31 | left: auto;
32 | }
33 | }
34 |
35 | &:not(.navbar-nav-hover) {
36 | .dropdown-menu {
37 | &.show {
38 | opacity: 1;
39 | pointer-events: auto;
40 | animation: show-navbar-dropdown .25s ease forwards;
41 | }
42 |
43 | &.close {
44 | display: block;
45 | animation: hide-navbar-dropdown .15s ease backwards;
46 | }
47 | }
48 | }
49 |
50 | &.navbar-nav-hover {
51 | .dropdown-menu {
52 | opacity: 0;
53 | display: block;
54 | pointer-events: none;
55 | transform: translate(0, 10px) perspective(200px) rotateX(-2deg);
56 | transition: visibility 0.25s, opacity 0.25s, transform 0.25s;
57 | }
58 |
59 | .nav-item.dropdown:hover > .dropdown-menu {
60 | display: block;
61 | opacity: 1;
62 | pointer-events: auto;
63 | visibility: visible;
64 | transform: translate(0, 0);
65 | animation: none;
66 | }
67 | }
68 |
69 | .dropdown-menu-inner {
70 | position: relative;
71 | padding: 1rem;
72 | }
73 |
74 |
75 | // Keyframes
76 |
77 | @keyframes show-navbar-dropdown {
78 | 0% {
79 | opacity: 0;
80 | transform: translate(0, 10px) perspective(200px) rotateX(-2deg);
81 | transition: visibility 0.25s, opacity 0.25s, transform 0.25s;
82 | }
83 |
84 | 100% {
85 | transform: translate(0, 0);
86 | opacity: 1;
87 | }
88 | }
89 |
90 | @keyframes hide-navbar-dropdown {
91 | from {
92 | opacity: 1;
93 | }
94 |
95 | to {
96 | opacity: 0;
97 | transform: translate(0, 10px);
98 | }
99 | }
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/navbars/_navbar-search.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Navbar search
3 | //
4 |
5 | .navbar-search {
6 | .input-group {
7 | border-radius: $navbar-search-border-radius;
8 | border: $navbar-search-border-width solid;
9 | background-color: transparent;
10 |
11 | .input-group-text {
12 | background-color: transparent;
13 | padding-left: 1rem;
14 | }
15 | }
16 |
17 | .form-control {
18 | width: $navbar-search-width;
19 | background-color: transparent;
20 | }
21 | }
22 |
23 | .navbar-search-dark {
24 | .input-group {
25 | border-color: $navbar-search-dark-border-color;
26 | }
27 |
28 | .input-group-text {
29 | color: $navbar-search-dark-color;
30 | }
31 |
32 | .form-control {
33 | color: $navbar-search-dark-focus-color;
34 |
35 | &::placeholder {
36 | color: $navbar-search-dark-color;
37 | }
38 | }
39 |
40 | .focused {
41 | .input-group {
42 | border-color: $navbar-search-dark-focus-border-color;
43 | }
44 | }
45 | }
46 |
47 | .navbar-search-light {
48 | .input-group {
49 | border-color: $navbar-search-light-border-color;
50 | }
51 |
52 | .input-group-text {
53 | color: $navbar-search-light-color;
54 | }
55 |
56 | .form-control {
57 | color: $navbar-search-light-focus-color;
58 |
59 | &::placeholder {
60 | color: $navbar-search-light-color;
61 | }
62 | }
63 |
64 | .focused {
65 | .input-group {
66 | border-color: $navbar-search-light-focus-border-color;
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/navbars/_navbar.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Navbar
3 | //
4 |
5 |
6 | // Navbar links
7 |
8 | .navbar-horizontal {
9 | .navbar-nav {
10 | .nav-link {
11 | font-size: $navbar-nav-link-font-size;
12 | font-weight: $navbar-nav-link-font-weight;
13 | text-transform: $navbar-nav-link-text-transform;
14 | letter-spacing: $navbar-nav-link-letter-spacing;
15 | @include transition($navbar-transition);
16 |
17 | .nav-link-inner--text {
18 | margin-left: .25rem;
19 | }
20 | }
21 | }
22 |
23 |
24 | // Navbar brand (logo)
25 |
26 | .navbar-brand {
27 | font-size: $font-size-sm;
28 | font-weight: 600;
29 | text-transform: uppercase;
30 | font-size: .875rem;
31 | letter-spacing: .05px;
32 |
33 | img {
34 | height: 30px;
35 | }
36 | }
37 |
38 | .navbar-dark {
39 | .navbar-brand {
40 | color: $white;
41 | }
42 | }
43 |
44 | .navbar-light {
45 | .navbar-brand {
46 | color: $gray-800;
47 | }
48 | }
49 |
50 | .navbar-nav {
51 | .nav-item {
52 | .media:not(:last-child){
53 | margin-bottom: 1.5rem;
54 | }
55 | }
56 | }
57 |
58 | @include media-breakpoint-up(lg) {
59 | .navbar-nav {
60 | .nav-item {
61 | margin-right: .5rem;
62 |
63 | [data-toggle="dropdown"]::after {
64 | transition: $transition-base;
65 | }
66 |
67 | &.show {
68 | [data-toggle="dropdown"]::after {
69 | transform: rotate(180deg);
70 | }
71 | }
72 | }
73 | .nav-link {
74 | padding-top: $navbar-nav-link-padding-y;
75 | padding-bottom: $navbar-nav-link-padding-y;
76 | border-radius: $navbar-nav-link-border-radius;
77 |
78 | i {
79 | margin-right: .625rem;
80 | }
81 | }
82 |
83 | .nav-link-icon {
84 | padding-left: .5rem !important;
85 | padding-right: .5rem !important;
86 | font-size: 1rem;
87 | border-radius: $navbar-nav-link-border-radius;
88 |
89 | i {
90 | margin-right: 0;
91 | }
92 | }
93 | }
94 | }
95 |
96 |
97 | // Transparent navbar
98 |
99 | .navbar-transparent {
100 | position: absolute;
101 | top: 0;
102 | width: 100%;
103 | z-index: 100;
104 | background-color: transparent;
105 | border: 0;
106 | box-shadow: none;
107 |
108 | .navbar-brand {
109 | color: rgba(255, 255, 255, 1);
110 | }
111 |
112 | .navbar-toggler {
113 | color: rgba(255, 255, 255, 1);
114 | }
115 |
116 | .navbar-toggler-icon {
117 | background-image: $navbar-dark-toggler-icon-bg;
118 | }
119 | }
120 |
121 | @include media-breakpoint-up(md) {
122 | .navbar-transparent {
123 | .navbar-nav {
124 | .nav-link {
125 | color: $navbar-dark-color;
126 |
127 | @include hover-focus {
128 | color: $navbar-dark-hover-color;
129 | }
130 |
131 | &.disabled {
132 | color: $navbar-dark-disabled-color;
133 | }
134 | }
135 |
136 | .show > .nav-link,
137 | .active > .nav-link,
138 | .nav-link.show,
139 | .nav-link.active {
140 | color: $navbar-dark-active-color;
141 | }
142 | }
143 |
144 | .navbar-brand {
145 | color: $navbar-dark-color;
146 |
147 | @include hover-focus {
148 | color: $navbar-dark-color;
149 | }
150 | }
151 | }
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/navs/_nav-pills.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Nav pills
3 | //
4 |
5 |
6 | // General styles
7 |
8 | .nav-pills {
9 | .nav-item:not(:last-child) {
10 | padding-right: $nav-pills-space-x;
11 | }
12 |
13 | .nav-link {
14 | padding: $nav-pills-padding-y $nav-pills-padding-x;
15 | color: $nav-pills-link-color;
16 | font-weight: 500;
17 | font-size: $font-size-sm;
18 | box-shadow: $nav-pills-box-shadow;
19 | background-color: $nav-pills-bg;
20 | transition: $transition-base;
21 |
22 | &:hover {
23 | color: $nav-pills-link-hover-color;
24 | }
25 | }
26 |
27 | .nav-link.active,
28 | .show > .nav-link {
29 | color: $nav-pills-link-active-color;
30 | background-color: $nav-pills-link-active-bg;
31 | }
32 |
33 | @include media-breakpoint-down(xs) {
34 | .nav-item {
35 | margin-bottom: $spacer;
36 | }
37 | }
38 | }
39 |
40 | @include media-breakpoint-down(sm) {
41 | .nav-pills:not(.nav-pills-circle) {
42 | .nav-item {
43 | padding-right: 0;
44 | }
45 | }
46 | }
47 |
48 |
49 | // Rounded circle nav pills
50 |
51 | .nav-pills-circle {
52 | .nav-link {
53 | text-align: center;
54 | height: 60px;
55 | width: 60px;
56 | padding: 0;
57 | line-height: 60px;
58 | border-radius: 50%;
59 | }
60 |
61 | .nav-link-icon {
62 | i, svg {
63 | font-size: 1rem;
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/navs/_nav.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Nav
3 | //
4 |
5 |
6 | // Nav wrapper (container)
7 |
8 | // Nav wrapper
9 | .nav-wrapper {
10 | padding: 1rem 0;
11 | @include border-top-radius($card-border-radius);
12 |
13 | + .card {
14 | @include border-top-radius(0);
15 | @include border-bottom-radius($card-border-radius);
16 | }
17 | }
18 |
19 |
20 | // Nav links
21 |
22 | .nav-link {
23 | color: $nav-link-color;
24 |
25 | &:hover {
26 | color: $nav-link-hover-color;
27 | }
28 |
29 | i.ni {
30 | position: relative;
31 | top: 2px;
32 | }
33 | }
34 |
35 | @media (min-width: 992px){
36 | .nav-item.active-pro {
37 | position: absolute;
38 | width: 100%;
39 | bottom: 10px;
40 | background: $table-head-bg;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/paginations/_pagination.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Pagination
3 | //
4 |
5 |
6 | .page-item {
7 | &.active .page-link {
8 | box-shadow: $pagination-active-box-shadow;
9 | }
10 |
11 | .page-link,
12 | span {
13 | display: flex;
14 | align-items: center;
15 | justify-content: center;
16 | padding: 0;
17 | margin: 0 3px;
18 | border-radius: 50% !important;
19 | width: 36px;
20 | height: 36px;
21 | font-size: $font-size-sm;
22 | }
23 | }
24 |
25 |
26 | // Size variations
27 |
28 | .pagination-lg {
29 | .page-item {
30 | .page-link,
31 | span {
32 | width: 46px;
33 | height: 46px;
34 | line-height: 46px;
35 | }
36 | }
37 | }
38 |
39 | .pagination-sm {
40 | .page-item {
41 | .page-link,
42 | span {
43 | width: 30px;
44 | height: 30px;
45 | line-height: 30px;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/popovers/_popover.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Popover
3 | //
4 |
5 |
6 | .popover {
7 | border: 0;
8 | }
9 |
10 | .popover-header {
11 | font-weight: $font-weight-bold;
12 | }
13 |
14 |
15 | // Alternative colors
16 |
17 | @each $color, $value in $theme-colors {
18 | .popover-#{$color} {
19 | @include popover-variant($value);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/progresses/_progress.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Progress
3 | //
4 |
5 |
6 | // Progress container
7 |
8 | .progress-wrapper {
9 | position: relative;
10 | padding-top: 1.5rem;
11 | }
12 |
13 |
14 | // General styles
15 |
16 | .progress {
17 | height: 8px;
18 | margin-bottom: $spacer;
19 | overflow: hidden;
20 | border-radius: $border-radius-sm;
21 | background-color: $progress-bg;
22 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
23 |
24 | .sr-only {
25 | width: auto;
26 | height: 20px;
27 | margin: 0 0 0 30px;
28 | left: 0;
29 | clip: auto;
30 | line-height: 20px;
31 | font-size: 13px;
32 | }
33 | }
34 |
35 |
36 | // Progress inner elements
37 |
38 | .progress-heading {
39 | font-size: 14px;
40 | font-weight: 500;
41 | margin: 0 0 2px;
42 | padding: 0;
43 | }
44 |
45 | .progress-bar {
46 | box-shadow: none;
47 | border-radius: 0;
48 | height: auto;
49 | }
50 |
51 | .progress-info{
52 | margin-bottom: .5rem;
53 | display: flex;
54 | align-items: center;
55 | justify-content: space-between;
56 | }
57 |
58 | .progress-label {
59 | span {
60 | display: inline-block;
61 | color: $primary;
62 | font-size: .625rem;
63 | font-weight: 600;
64 | text-transform: uppercase;
65 | background: rgba($primary, .1);
66 | padding: .25rem 1rem;
67 | border-radius: 30px;
68 | }
69 | }
70 |
71 | .progress-percentage {
72 | text-align: right;
73 | span {
74 | display: inline-block;
75 | color: $gray-600;
76 | font-size: .875rem;
77 | font-weight: 600;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/separators/_separator.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Separator
3 | // add svg on top or bottom of a section for a more stylish visual
4 | //
5 |
6 |
7 | .separator {
8 | position: absolute;
9 | top: auto;
10 | left: 0;
11 | right: 0;
12 | width: 100%;
13 | height: 150px;
14 | transform: translateZ(0);
15 | overflow: hidden;
16 | pointer-events: none;
17 |
18 | svg {
19 | position: absolute;
20 | pointer-events: none;
21 | }
22 | }
23 |
24 | .separator-top {
25 | top: 0;
26 | bottom: auto;
27 |
28 | svg {
29 | top: 0;
30 | }
31 | }
32 |
33 | .separator-bottom {
34 | top: auto;
35 | bottom: 0;
36 |
37 | svg {
38 | bottom: 0;
39 | }
40 | }
41 |
42 | .separator-inverse {
43 | transform: rotate(180deg);
44 | }
45 |
46 | // Styles
47 |
48 | .separator-skew {
49 | height: 60px;
50 |
51 | @include media-breakpoint-up(xl) {
52 | height: 70px;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/tables/_table.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Table
3 | //
4 |
5 |
6 | // General styles
7 |
8 | .table {
9 | thead th {
10 | padding-top: $table-head-spacer-y;
11 | padding-bottom: $table-head-spacer-y;
12 | font-size: $table-head-font-size;
13 | text-transform: $table-head-text-transform;
14 | letter-spacing: $table-head-letter-spacing;
15 | border-bottom: $table-border-width solid $table-border-color;
16 | }
17 |
18 | th {
19 | font-weight: $table-head-font-weight;
20 | }
21 |
22 | td {
23 | .progress {
24 | height: 3px;
25 | width: 120px;
26 | margin: 0;
27 | }
28 | }
29 |
30 | td,
31 | th {
32 | font-size: $table-body-font-size;
33 | white-space: nowrap;
34 | }
35 |
36 |
37 | // Vetical align table content
38 |
39 | &.align-items-center {
40 | td,
41 | th {
42 | vertical-align: middle;
43 | }
44 | }
45 |
46 |
47 | // Styles for dark table
48 |
49 | .thead-dark {
50 | th {
51 | background-color: $table-dark-head-bg;
52 | color: $table-dark-head-color;
53 | }
54 | }
55 |
56 |
57 | // Styles for light table
58 |
59 | .thead-light {
60 | th {
61 | background-color: $table-head-bg;
62 | color: $table-head-color;
63 | }
64 | }
65 | }
66 |
67 |
68 | // Add transition for hover state
69 |
70 | .table-hover {
71 | tr {
72 | @include transition($transition-base);
73 | }
74 | }
75 |
76 |
77 | // Flush tables
78 |
79 | .table-flush {
80 | td,
81 | th {
82 | border-left: 0;
83 | border-right: 0;
84 | }
85 |
86 | tbody {
87 | tr {
88 | &:first-child {
89 | td,
90 | th {
91 | border-top: 0;
92 | }
93 | }
94 |
95 | &:last-child {
96 | td,
97 | th {
98 | border-bottom: 0;
99 | }
100 | }
101 | }
102 | }
103 | }
104 |
105 |
106 | // Tables inside cards
107 |
108 | .card {
109 | .table {
110 | margin-bottom: 0;
111 |
112 | td,
113 | th {
114 | padding-left: $card-spacer-x;
115 | padding-right: $card-spacer-x;
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/type/_article.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Article
3 | //
4 |
5 | article {
6 | h4:not(:first-child),
7 | h5:not(:first-child) {
8 | margin-top: 3rem;
9 | }
10 |
11 | h4, h5 {
12 | margin-bottom: 1.5rem;
13 | }
14 |
15 | figure {
16 | margin: 3rem 0;
17 | }
18 |
19 | h5 + figure {
20 | margin-top: 0;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/type/_display.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Display
3 | //
4 |
5 |
6 | .display-1,
7 | .display-2,
8 | .display-3,
9 | .display-4 {
10 | span {
11 | display: block;
12 | font-weight: $font-weight-light;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/type/_heading.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Heading
3 | //
4 |
5 |
6 | // General styles
7 |
8 | .heading {
9 | letter-spacing: $heading-letter-spacing;
10 | font-size: $heading-font-size;
11 | text-transform: $heading-text-transform;
12 | font-weight: $heading-font-weight;
13 | }
14 |
15 |
16 | // Heading variations
17 |
18 | .heading-small {
19 | padding-top: .25rem;
20 | padding-bottom: .25rem;
21 | font-size: .75rem;
22 | text-transform: uppercase;
23 | letter-spacing: .04em;
24 | }
25 |
26 | .heading-title {
27 | letter-spacing: $heading-title-letter-spacing;
28 | font-size: $heading-title-font-size;
29 | font-weight: $heading-title-font-weight;
30 | text-transform: $heading-title-text-transform;
31 | }
32 |
33 | .heading-section {
34 | letter-spacing: $heading-section-letter-spacing;
35 | font-size: $heading-section-font-size;
36 | font-weight: $heading-section-font-weight;
37 | text-transform: $heading-section-text-transform;
38 |
39 | img {
40 | display: block;
41 | width: 72px;
42 | height: 72px;
43 | margin-bottom: 1.5rem;
44 | }
45 |
46 | &.text-center {
47 | img {
48 | margin-left: auto;
49 | margin-right: auto;
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/type/_type.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Type
3 | //
4 |
5 |
6 | // Paragraphs
7 |
8 | p {
9 | font-size: $paragraph-font-size;
10 | font-weight: $paragraph-font-weight;
11 | line-height: $paragraph-line-height;
12 | }
13 |
14 | .lead {
15 | font-size: $lead-font-size;
16 | font-weight: $lead-font-weight;
17 | line-height: $paragraph-line-height;
18 | margin-top: 1.5rem;
19 |
20 | + .btn-wrapper {
21 | margin-top: 3rem;
22 | }
23 | }
24 |
25 | .description {
26 | font-size: $font-size-sm;
27 | }
28 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/utilities/_backgrounds.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Backgrounds
3 | //
4 |
5 |
6 | @each $color, $value in $colors {
7 | @include bg-variant(".bg-#{$color}", $value);
8 | }
9 |
10 | @each $color, $value in $theme-colors {
11 | @include bg-gradient-variant(".bg-gradient-#{$color}", $value);
12 | }
13 |
14 | @each $color, $value in $colors {
15 | @include bg-gradient-variant(".bg-gradient-#{$color}", $value);
16 | }
17 |
18 |
19 | // Background colors with transparency
20 |
21 | @each $color, $value in $theme-colors {
22 | @include bg-translucent-variant(".bg-translucent-#{$color}", $value);
23 | }
24 |
25 |
26 | // Sections backgrounds
27 |
28 | @each $color, $value in $section-colors {
29 | @include bg-variant(".section-#{$color}", $value);
30 | }
31 |
32 | @each $color, $value in $theme-colors {
33 | @include bg-gradient-variant(".bg-gradient-#{$color}", $value);
34 | }
35 |
36 |
37 | // Shape (svg) fill colors
38 |
39 | @each $color, $value in $theme-colors {
40 | .fill-#{$color} {
41 | fill: $value;
42 | }
43 |
44 | .stroke-#{$color} {
45 | stroke: $value;
46 | }
47 | }
48 |
49 | .fill-opacity-8 {
50 | fill-opacity: .8;
51 | }
52 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/utilities/_blurable.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Blurable
3 | // add a blue effect on hover on any element with .blur--hover class
4 | //
5 |
6 | .blur--hover {
7 | position: relative;
8 |
9 | .blur-item {
10 | transition: 1s cubic-bezier(.19,1,.22,1);
11 | will-change: transform;
12 | filter: blur(0);
13 | opacity: 1;
14 | }
15 |
16 | .blur-hidden {
17 | position: absolute;
18 | top: calc(50% + 7px);
19 | left: 50%;
20 | transform: translate(-50%, -50%);
21 | opacity: 0;
22 | transition: $transition-base;
23 | z-index: 100;
24 | }
25 | &:hover {
26 | .blur-item {
27 | opacity: .8;
28 | filter: blur(10px);
29 | transform: scale(.95);
30 | z-index: 1;
31 | }
32 | .blur-hidden {
33 | opacity: 1;
34 | top: 50%;
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/utilities/_floating.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Floating
3 | // floating animation utility class
4 | //
5 |
6 |
7 | .floating {
8 | animation: floating 3s ease infinite;
9 | will-change: transform;
10 |
11 | &:hover {
12 | animation-play-state: paused;
13 | }
14 | }
15 |
16 |
17 | // Size variations
18 |
19 | .floating-lg {
20 | animation: floating-lg 3s ease infinite;
21 | }
22 |
23 | .floating-sm {
24 | animation: floating-sm 3s ease infinite;
25 | }
26 |
27 |
28 | // Keyframes
29 |
30 | @keyframes floating-lg {
31 | 0% {
32 | transform: translateY(0px)
33 | }
34 | 50% {
35 | transform: translateY(15px)
36 | }
37 | 100% {
38 | transform: translateY(0px)
39 | }
40 | }
41 |
42 | @keyframes floating {
43 | 0% {
44 | transform: translateY(0px)
45 | }
46 | 50% {
47 | transform: translateY(10px)
48 | }
49 | 100% {
50 | transform: translateY(0px)
51 | }
52 | }
53 |
54 | @keyframes floating-sm {
55 | 0% {
56 | transform: translateY(0px)
57 | }
58 | 50% {
59 | transform: translateY(5px)
60 | }
61 | 100% {
62 | transform: translateY(0px)
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/utilities/_helper.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Helper
3 | // helper classes for different cases
4 | //
5 |
6 |
7 | // Clearfix for sections that use float property
8 |
9 | .floatfix {
10 | &:before,
11 | &:after {
12 | content: '';
13 | display: table;
14 | }
15 | &:after {
16 | clear: both;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/utilities/_image.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Image
3 | //
4 |
5 | .img-center {
6 | display: block;
7 | margin-left: auto;
8 | margin-right: auto;
9 | }
10 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/utilities/_opacity.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Opacity
3 | // modify the transparency of an element with this quick modifier classes
4 | //
5 |
6 | .opacity-1 {
7 | opacity: .1 !important;
8 | }
9 | .opacity-2 {
10 | opacity: .2 !important;
11 | }
12 | .opacity-3 {
13 | opacity: .3 !important;
14 | }
15 | .opacity-4 {
16 | opacity: .4 !important;
17 | }
18 | .opacity-5 {
19 | opacity: .5 !important;
20 | }
21 | .opacity-6 {
22 | opacity: .6 !important;
23 | }
24 | .opacity-7 {
25 | opacity: .7 !important;
26 | }
27 | .opacity-8 {
28 | opacity: .8 !important;
29 | }
30 | .opacity-8 {
31 | opacity: .9 !important;
32 | }
33 | .opacity-10 {
34 | opacity: 1 !important;
35 | }
36 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/utilities/_overflow.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Overflow
3 | //
4 |
5 | .overflow-visible {
6 | overflow: visible !important;
7 | }
8 |
9 | .overflow-hidden {
10 | overflow: hidden !important;
11 | }
12 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/utilities/_position.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Position
3 | // modifier classes to be applied on an abosolute positioned element
4 | // use it next to .position-absolute class
5 | //
6 |
7 | @each $size, $value in $spacers {
8 | .top-#{$size} {
9 | top: $value;
10 | }
11 | .right-#{$size} {
12 | right: $value;
13 | }
14 | .bottom-#{$size} {
15 | bottom: $value;
16 | }
17 | .left-#{$size} {
18 | left: $value;
19 | }
20 | }
21 |
22 | .center {
23 | left: 50%;
24 | transform: translateX(-50%);
25 | }
26 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/utilities/_shadows.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Shadows
3 | //
4 |
5 | // General styles
6 | [class*="shadow"] {
7 | @if $enable-transitions {
8 | transition: $transition-base;
9 | }
10 | }
11 |
12 |
13 | // Size variations
14 | .shadow-sm--hover:hover {
15 | box-shadow: $box-shadow-sm !important;
16 | }
17 |
18 | .shadow--hover:hover {
19 | box-shadow: $box-shadow !important;
20 | }
21 |
22 | .shadow-lg--hover:hover {
23 | box-shadow: $box-shadow-lg !important;
24 | }
25 |
26 | .shadow-none--hover:hover {
27 | box-shadow: none !important;
28 | }
29 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/utilities/_sizing.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Height
3 | //
4 |
5 | .h-100vh {
6 | height: 100vh !important;
7 | }
8 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/utilities/_spacing.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Spacing
3 | //
4 |
5 | .row.row-grid > [class*="col-"] + [class*="col-"] {
6 | margin-top: 3rem;
7 | }
8 |
9 | @include media-breakpoint-up(lg) {
10 | .row.row-grid > [class*="col-lg-"] + [class*="col-lg-"] {
11 | margin-top: 0;
12 | }
13 | }
14 | @include media-breakpoint-up(md) {
15 | .row.row-grid > [class*="col-md-"] + [class*="col-md-"] {
16 | margin-top: 0;
17 | }
18 | }
19 | @include media-breakpoint-up(sm) {
20 | .row.row-grid > [class*="col-sm-"] + [class*="col-sm-"] {
21 | margin-top: 0;
22 | }
23 | }
24 |
25 | .row-grid + .row-grid {
26 | margin-top: 3rem;
27 | }
28 |
29 |
30 | // Negative margins and paddings
31 |
32 | @media(min-width: 992px) {
33 | [class*="mt--"],
34 | [class*="mr--"],
35 | [class*="mb--"],
36 | [class*="ml--"] {
37 |
38 | }
39 |
40 |
41 | // Large negative margins in pixels
42 |
43 | .mt--100 {
44 | margin-top: -100px !important;
45 | }
46 | .mr--100 {
47 | margin-right: -100px !important;
48 | }
49 | .mb--100 {
50 | margin-bottom: -100px !important;
51 | }
52 | .ml--100 {
53 | margin-left: -100px !important;
54 | }
55 | .mt--150 {
56 | margin-top: -150px !important;
57 | }
58 | .mb--150 {
59 | margin-bottom: -150px !important;
60 | }
61 | .mt--200 {
62 | margin-top: -200px !important;
63 | }
64 | .mb--200 {
65 | margin-bottom: -200px !important;
66 | }
67 | .mt--300 {
68 | margin-top: -300px !important;
69 | }
70 | .mb--300 {
71 | margin-bottom: -300px !important;
72 | }
73 |
74 |
75 | // Large margins in pixels
76 |
77 | .pt-100 {
78 | padding-top: 100px !important;
79 | }
80 | .pb-100 {
81 | padding-bottom: 100px !important;
82 | }
83 | .pt-150 {
84 | padding-top: 150px !important;
85 | }
86 | .pb-150 {
87 | padding-bottom: 150px !important;
88 | }
89 | .pt-200 {
90 | padding-top: 200px !important;
91 | }
92 | .pb-200 {
93 | padding-bottom: 200px !important;
94 | }
95 | .pt-250 {
96 | padding-top: 250px !important;
97 | }
98 | .pb-250 {
99 | padding-bottom: 250px !important;
100 | }
101 | .pt-300 {
102 | padding-top: 300px!important;
103 | }
104 | .pb-300 {
105 | padding-bottom: 300px!important;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/utilities/_text.scss:
--------------------------------------------------------------------------------
1 | // Weight and italics
2 |
3 | .font-weight-300 { font-weight: 300 !important; }
4 | .font-weight-400 { font-weight: 400 !important; }
5 | .font-weight-500 { font-weight: 500 !important; }
6 | .font-weight-600 { font-weight: 600 !important; }
7 | .font-weight-700 { font-weight: 700 !important; }
8 | .font-weight-800 { font-weight: 800 !important; }
9 | .font-weight-900 { font-weight: 900 !important; }
10 |
11 |
12 | // Text decorations
13 |
14 | .text-underline { text-decoration: underline; }
15 | .text-through { text-decoration: line-through; }
16 |
17 |
18 | // Text size
19 |
20 | .text-xs { font-size: $font-size-xs !important; }
21 | .text-sm { font-size: $font-size-sm !important; }
22 | .text-lg { font-size: $font-size-lg !important; }
23 | .text-xl { font-size: $font-size-xl !important; }
24 |
25 |
26 | // Line heights
27 |
28 | .lh-100 { line-height: 1; }
29 | .lh-110 { line-height: 1.1; }
30 | .lh-120 { line-height: 1.2; }
31 | .lh-130 { line-height: 1.3; }
32 | .lh-140 { line-height: 1.4; }
33 | .lh-150 { line-height: 1.5; }
34 | .lh-160 { line-height: 1.6; }
35 | .lh-170 { line-height: 1.7; }
36 | .lh-180 { line-height: 1.8; }
37 |
38 |
39 | // Letter spacings
40 |
41 | .ls-1 { letter-spacing: .0625rem; }
42 | .ls-15 { letter-spacing: .09375rem; }
43 | .ls-2 { letter-spacing: 0.125rem; }
44 |
45 | // Color variations
46 |
47 | @each $color, $value in $colors {
48 | @include text-emphasis-variant(".text-#{$color}", $value, $ignore-warning: true);
49 | }
50 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/utilities/_transform.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Tranform
3 | //
4 |
5 |
6 | @include media-breakpoint-up(lg) {
7 | .transform-perspective-right {
8 | transform: scale(1) perspective(1040px) rotateY(-11deg) rotateX(2deg) rotate(2deg);
9 | }
10 | .transform-perspective-left{
11 | transform: scale(1) perspective(2000px) rotateY(11deg) rotateX(2deg) rotate(-2deg)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/vendors/_headroom.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Headroom
3 | //
4 |
5 |
6 | .headroom {
7 | will-change: transform;
8 | background-color: inherit;
9 | @include transition($transition-base);
10 | }
11 | .headroom--pinned {
12 | @extend .position-fixed;
13 | transform: translateY(0%);
14 | }
15 | .headroom--unpinned {
16 | @extend .position-fixed;
17 | transform: translateY(-100%);
18 | }
19 |
20 | .headroom--not-top {
21 | padding-top: .5rem;
22 | padding-bottom: .5rem;
23 | background-color: theme-color("default") !important;
24 | box-shadow: 0 1px 10px rgba(130, 130, 134, 0.1);
25 | }
26 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/custom/vendors/_scrollbar.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Custom scrollbar
3 | //
4 |
5 | .scrollbar-inner {
6 | height: 100%;
7 |
8 | &:not(:hover) .scroll-element {
9 | opacity: 0;
10 | }
11 |
12 | .scroll-element {
13 | transition: opacity 300ms;
14 | margin-right: 2px;
15 |
16 | .scroll-bar,
17 | .scroll-element_track {
18 | transition: background-color 300ms;
19 | }
20 |
21 | .scroll-element_track {
22 | background-color: transparent;
23 | }
24 | }
25 |
26 | .scroll-element.scroll-y {
27 | width: 3px;
28 | right: 0;
29 | }
30 |
31 | .scroll-element.scroll-x {
32 | height: 3px;
33 | bottom: 0;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/docs/_clipboard-js.scss:
--------------------------------------------------------------------------------
1 | // clipboard.js
2 | //
3 | // JS-based `Copy` buttons for code snippets.
4 |
5 | .ct-clipboard {
6 | position: relative;
7 | display: none;
8 | float: right;
9 |
10 | + .highlight {
11 | margin-top: 0;
12 | }
13 | }
14 |
15 | .btn-clipboard {
16 | position: absolute;
17 | top: 1rem;
18 | right: 1rem;
19 | z-index: 10;
20 | display: block;
21 | padding: .25rem .5rem;
22 | font-size: 75%;
23 | cursor: pointer;
24 | background-color: transparent;
25 | border: 0;
26 | border-radius: .25rem;
27 | color: #fff;
28 | background-color: $ct-primary;
29 |
30 | &:hover {
31 | color: #fff;
32 | background-color: darken($ct-primary, 10%);
33 | }
34 | }
35 |
36 | @media (min-width: 768px) {
37 | .ct-clipboard {
38 | display: block;
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/docs/_footer.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Footer
3 | //
4 | .ct-footer {
5 | font-size: 85%;
6 | text-align: center;
7 | background-color: #f7f7f7;
8 |
9 | a {
10 | font-weight: 500;
11 | color: $gray-700;
12 |
13 | &:hover,
14 | &:focus {
15 | color: $link-color;
16 | }
17 | }
18 |
19 | p {
20 | margin-bottom: 0;
21 | }
22 |
23 | @include media-breakpoint-up(sm) {
24 | text-align: left;
25 | }
26 | }
27 |
28 | .ct-footer-links {
29 | padding-left: 0;
30 | margin-bottom: 1rem;
31 |
32 | li {
33 | display: inline-block;
34 |
35 | +li {
36 | margin-left: 1rem;
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/docs/_nav.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Main navbar
3 | //
4 | .ct-navbar {
5 | background-color: $ct-primary;
6 | box-shadow: rgba(116, 129, 141, 0.1) 0px 1px 1px 0px;
7 | padding-top: .5rem;
8 | padding-bottom: .5rem;
9 |
10 | @include media-breakpoint-down(md) {
11 | padding-right: .5rem;
12 | padding-left: .5rem;
13 |
14 | .navbar-nav-scroll {
15 | max-width: 100%;
16 | height: 2.5rem;
17 | margin-top: .25rem;
18 | overflow: hidden;
19 | font-size: .875rem;
20 |
21 | .navbar-nav {
22 | padding-bottom: 2rem;
23 | overflow-x: auto;
24 | white-space: nowrap;
25 | -webkit-overflow-scrolling: touch;
26 | }
27 | }
28 | }
29 |
30 | @include media-breakpoint-up(md) {
31 | @supports (position: sticky) {
32 | position: sticky;
33 | top: 0;
34 | z-index: 1071; // over everything in bootstrap
35 | }
36 | }
37 |
38 | .navbar-nav {
39 | .nav-link {
40 | padding-right: .5rem;
41 | padding-left: .5rem;
42 | color: $ct-primary-light !important;
43 |
44 | &.active,
45 | &:hover {
46 | color: #fff !important;
47 | background-color: transparent !important;
48 | }
49 |
50 | &.active {
51 | font-weight: 500;
52 | }
53 | }
54 | }
55 |
56 | .navbar-nav-svg {
57 | display: inline-block;
58 | width: 1rem;
59 | height: 1rem;
60 | vertical-align: text-top;
61 | }
62 |
63 | .dropdown-menu {
64 | font-size: .875rem;
65 | }
66 |
67 | .dropdown-item.active {
68 | font-weight: 500;
69 | color: $gray-900;
70 | background-color: transparent;
71 | background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3E%3Cpath fill='%23292b2c' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3E%3C/svg%3E");
72 | background-repeat: no-repeat;
73 | background-position: .4rem .87rem;
74 | background-size: .75rem .75rem;
75 | padding-left: 25px;
76 | }
77 | }
78 |
79 | // Github corner
80 | .github-corner {
81 | position: fixed;
82 | right: 0;
83 | z-index: 1080;
84 |
85 | &:hover {
86 | .octo-arm {
87 | animation: octocat-wave 560ms ease-in-out
88 | }
89 | }
90 |
91 | svg {
92 | fill: $white;
93 | color: $ct-primary;
94 | }
95 | }
96 |
97 | @keyframes octocat-wave {
98 | 0%,
99 | 100% {
100 | transform: rotate(0)
101 | }
102 | 20%,
103 | 60% {
104 | transform: rotate(-25deg)
105 | }
106 | 40%,
107 | 80% {
108 | transform: rotate(10deg)
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/docs/_prism.scss:
--------------------------------------------------------------------------------
1 | code[class*="language-"],
2 | pre[class*="language-"] {
3 | font-family: Consolas, Menlo, Monaco, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", "Courier New", Courier, monospace;
4 | font-size: 14px;
5 | line-height: 1.375;
6 | direction: ltr;
7 | text-align: left;
8 | white-space: pre;
9 | word-spacing: normal;
10 | word-break: normal;
11 | -moz-tab-size: 4;
12 | -o-tab-size: 4;
13 | tab-size: 4;
14 | -webkit-hyphens: none;
15 | -moz-hyphens: none;
16 | -ms-hyphens: none;
17 | hyphens: none;
18 | background: #f5f7ff;
19 | color: #5e6687;
20 | border-radius: .25rem;
21 | }
22 |
23 | pre[class*="language-"]::-moz-selection,
24 | pre[class*="language-"] ::-moz-selection,
25 | code[class*="language-"]::-moz-selection,
26 | code[class*="language-"] ::-moz-selection {
27 | text-shadow: none;
28 | background: #dfe2f1;
29 | }
30 |
31 | pre[class*="language-"]::selection,
32 | pre[class*="language-"] ::selection,
33 | code[class*="language-"]::selection,
34 | code[class*="language-"] ::selection {
35 | text-shadow: none;
36 | background: #dfe2f1;
37 | }
38 |
39 |
40 | /* Code blocks */
41 |
42 | pre[class*="language-"] {
43 | padding: 1.25rem;
44 | margin: 0;
45 | overflow: auto;
46 | }
47 |
48 |
49 | /* Inline code */
50 |
51 | :not(pre)>code[class*="language-"] {
52 | padding: .1em;
53 | border-radius: .3em;
54 | }
55 |
56 | .token.comment,
57 | .token.prolog,
58 | .token.doctype,
59 | .token.cdata {
60 | color: #898ea4;
61 | }
62 |
63 | .token.punctuation {
64 | color: #5e6687;
65 | }
66 |
67 | .token.namespace {
68 | opacity: .7;
69 | }
70 |
71 | .token.operator,
72 | .token.boolean,
73 | .token.number {
74 | color: #c76b29;
75 | }
76 |
77 | .token.property {
78 | color: #c08b30;
79 | }
80 |
81 | .token.tag {
82 | color: #3d8fd1;
83 | }
84 |
85 | .token.string {
86 | color: #22a2c9;
87 | }
88 |
89 | .token.selector {
90 | color: #6679cc;
91 | }
92 |
93 | .token.attr-name {
94 | color: #c76b29;
95 | }
96 |
97 | .token.entity,
98 | .token.url,
99 | .language-css .token.string,
100 | .style .token.string {
101 | color: #22a2c9;
102 | }
103 |
104 | .token.attr-value,
105 | .token.keyword,
106 | .token.control,
107 | .token.directive,
108 | .token.unit {
109 | color: #ac9739;
110 | }
111 |
112 | .token.statement,
113 | .token.regex,
114 | .token.atrule {
115 | color: #22a2c9;
116 | }
117 |
118 | .token.placeholder,
119 | .token.variable {
120 | color: #3d8fd1;
121 | }
122 |
123 | .token.deleted {
124 | text-decoration: line-through;
125 | }
126 |
127 | .token.inserted {
128 | border-bottom: 1px dotted #202746;
129 | text-decoration: none;
130 | }
131 |
132 | .token.italic {
133 | font-style: italic;
134 | }
135 |
136 | .token.important,
137 | .token.bold {
138 | font-weight: bold;
139 | }
140 |
141 | .token.important {
142 | color: #c94922;
143 | }
144 |
145 | .token.entity {
146 | cursor: help;
147 | }
148 |
149 | pre>code.highlight {
150 | outline: 0.4em solid #c94922;
151 | outline-offset: .4em;
152 | }
153 |
154 |
155 | /* overrides color-values for the Line Numbers plugin
156 | * http://prismjs.com/plugins/line-numbers/
157 | */
158 |
159 | .line-numbers .line-numbers-rows {
160 | border-right-color: #dfe2f1;
161 | }
162 |
163 | .line-numbers-rows>span:before {
164 | color: #979db4;
165 | }
166 |
167 |
168 | /* overrides color-values for the Line Highlight plugin
169 | * http://prismjs.com/plugins/line-highlight/
170 | */
171 |
172 | .line-highlight {
173 | background: rgba(107, 115, 148, 0.2);
174 | background: -webkit-linear-gradient(left, rgba(107, 115, 148, 0.2) 70%, rgba(107, 115, 148, 0));
175 | background: linear-gradient(to right, rgba(107, 115, 148, 0.2) 70%, rgba(107, 115, 148, 0));
176 | }
--------------------------------------------------------------------------------
/client/src/assets/scss/argon-dashboard/docs/_variables.scss:
--------------------------------------------------------------------------------
1 | // Local docs variables
2 | $ct-primary: theme-color("primary") !default;
3 | $ct-primary-bright: lighten(saturate($ct-primary, 5%), 15%) !default;
4 | $ct-primary-light: rgba(255, 255, 255, .9) !default;
5 | $ct-dark: #2a2730 !default;
6 | $ct-download: #ffe484 !default;
7 | $ct-info: #5bc0de !default;
8 | $ct-warning: #f0ad4e !default;
9 | $ct-danger: #d9534f !default;
10 |
11 | $ct-sidebar-bg: #f5f7f9;
12 | $ct-sidebar-border-color: #e6ecf1;
13 |
14 |
--------------------------------------------------------------------------------
/client/src/assets/scss/react/_buttons.scss:
--------------------------------------------------------------------------------
1 | .btn{
2 | .btn-inner--icon{
3 | margin-right: 4px;
4 | }
5 | }
6 | .btn + .btn {
7 | margin-left: 4px;
8 | }
9 |
--------------------------------------------------------------------------------
/client/src/assets/scss/react/_mixins.scss:
--------------------------------------------------------------------------------
1 | button:focus, :focus {
2 | outline: none;
3 | }
4 |
--------------------------------------------------------------------------------
/client/src/assets/scss/react/_navbar-dropdown.scss:
--------------------------------------------------------------------------------
1 | @keyframes show-navbar-dropdown {
2 | 0% {
3 | opacity: 0;
4 | transition: visibility 0.25s, opacity 0.25s;
5 | }
6 | 100% {
7 | opacity: 1;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/client/src/assets/scss/react/_navbar.scss:
--------------------------------------------------------------------------------
1 | .navbar .collapsing .navbar-toggler{
2 | pointer-events: none;
3 | }
4 | .navbar .nav-item .nav-link-icon.nav-link i{
5 | margin-right: 4px;
6 | }
7 |
--------------------------------------------------------------------------------
/client/src/assets/scss/react/_tables.scss:
--------------------------------------------------------------------------------
1 | .table {
2 | .avatar-group .avatar
3 | {
4 | margin-right: 4px;
5 | }
6 | .badge i{
7 | margin-right: 10px;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/client/src/assets/scss/react/bootstrap/_spinners.scss:
--------------------------------------------------------------------------------
1 | $spinner-width: 2rem !default;
2 | $spinner-height: $spinner-width !default;
3 | $spinner-border-width: .25em !default;
4 |
5 | $spinner-width-sm: 1rem !default;
6 | $spinner-height-sm: $spinner-width-sm !default;
7 | $spinner-border-width-sm: .2em !default;
8 |
9 | //
10 | // Rotating border
11 | //
12 |
13 | @keyframes spinner-border {
14 | to { transform: rotate(360deg); }
15 | }
16 |
17 | .spinner-border {
18 | display: inline-block;
19 | width: $spinner-width;
20 | height: $spinner-height;
21 | vertical-align: text-bottom;
22 | border: $spinner-border-width solid currentColor;
23 | border-right-color: transparent;
24 | // stylelint-disable-next-line property-blacklist
25 | border-radius: 50%;
26 | animation: spinner-border .75s linear infinite;
27 | }
28 |
29 | .spinner-border-sm {
30 | width: $spinner-width-sm;
31 | height: $spinner-height-sm;
32 | border-width: $spinner-border-width-sm;
33 | }
34 |
35 | //
36 | // Growing circle
37 | //
38 |
39 | @keyframes spinner-grow {
40 | 0% {
41 | transform: scale(0);
42 | }
43 | 50% {
44 | opacity: 1;
45 | }
46 | }
47 |
48 | .spinner-grow {
49 | display: inline-block;
50 | width: $spinner-width;
51 | height: $spinner-height;
52 | vertical-align: text-bottom;
53 | background-color: currentColor;
54 | // stylelint-disable-next-line property-blacklist
55 | border-radius: 50%;
56 | opacity: 0;
57 | animation: spinner-grow .75s linear infinite;
58 | }
59 |
60 | .spinner-grow-sm {
61 | width: $spinner-width-sm;
62 | height: $spinner-height-sm;
63 | }
64 |
--------------------------------------------------------------------------------
/client/src/assets/scss/react/react-differences.scss:
--------------------------------------------------------------------------------
1 | // Differences from the HTML to the React product
2 |
3 | // bootstrap
4 | @import "~bootstrap/scss/spinners";
5 | // react plugins
6 | @import "plugins/plugin-react-datetime";
7 | // core components
8 | @import "buttons";
9 | @import "mixins";
10 | @import "navbar-dropdown";
11 | @import "navbar";
12 | @import "tables";
13 |
--------------------------------------------------------------------------------
/client/src/components/Charts/TicketsPieChart.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import Chart from "react-google-charts";
3 |
4 | import { Card, CardHeader, Row, CardBody } from "reactstrap";
5 |
6 | function TicketsPieChart({ focus, userTickets }) {
7 | const [pieChartData, setPieChartData] = useState([]);
8 |
9 | //capitalization function
10 | const capitalize = (s) => {
11 | if (typeof s !== "string") return "";
12 | return s.charAt(0).toUpperCase() + s.slice(1);
13 | };
14 |
15 | useEffect(() => {
16 | let isRendered = true;
17 | let map = {}; //{ticketType: quantity}
18 |
19 | userTickets.forEach((ticket) => {
20 | if (map[capitalize(ticket[focus])]) {
21 | map[capitalize(ticket[focus])]++;
22 | } else {
23 | map[capitalize(ticket[focus])] = 1;
24 | }
25 | });
26 |
27 | if (isRendered) {
28 | setPieChartData(Object.entries(map));
29 | }
30 |
31 | return (isRendered = false);
32 | }, [userTickets, focus]);
33 |
34 | return (
35 |
36 |
37 |
38 |
39 |
40 | {/*
41 | Performance
42 | */}
43 | Tickets by {capitalize(focus)}
44 |
45 |
46 |
47 |
48 | Loading Chart }
53 | data={
54 | pieChartData.length > 0
55 | ? [
56 | [`Ticket ${capitalize(focus)}`, "Number of Tickets"],
57 | ...pieChartData,
58 | ]
59 | : [[`Ticket ${capitalize(focus)}`, "Number of Tickets"]]
60 | }
61 | // options={{
62 | // title: "Tickets by Type",
63 | // }}
64 | rootProps={{ "data-testid": "1" }}
65 | />
66 |
67 |
68 |
69 | );
70 | }
71 |
72 | export default TicketsPieChart;
73 |
--------------------------------------------------------------------------------
/client/src/components/Footers/AdminFooter.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | // reactstrap components
4 | import { Row, Col } from "reactstrap";
5 |
6 | const Footer = () => {
7 | return (
8 |
9 |
10 |
11 |
22 |
23 |
24 |
25 | );
26 | };
27 |
28 | export default Footer;
29 |
--------------------------------------------------------------------------------
/client/src/components/Footers/AuthFooter.js:
--------------------------------------------------------------------------------
1 | /*!
2 |
3 | =========================================================
4 | * Argon Dashboard React - v1.2.0
5 | =========================================================
6 |
7 | * Product Page: https://www.creative-tim.com/product/argon-dashboard-react
8 | * Copyright 2021 Creative Tim (https://www.creative-tim.com)
9 | * Licensed under MIT (https://github.com/creativetimofficial/argon-dashboard-react/blob/master/LICENSE.md)
10 |
11 | * Coded by Creative Tim
12 |
13 | =========================================================
14 |
15 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
16 |
17 | */
18 | /*eslint-disable*/
19 | import React from "react";
20 |
21 | // reactstrap components
22 | import { NavItem, NavLink, Nav, Container, Row, Col } from "reactstrap";
23 |
24 | const Login = () => {
25 | return (
26 | <>
27 |
28 |
29 |
30 |
31 |
42 |
43 |
44 |
45 |
46 | >
47 | );
48 | };
49 |
50 | export default Login;
51 |
--------------------------------------------------------------------------------
/client/src/components/Forms/AddTeamMember.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import API from "../../utils/API";
3 | import { Container, Form, FormGroup, Label, Input, Button } from "reactstrap";
4 |
5 | const AddTeamMember = (props) => {
6 | const { projectId } = props;
7 | const [dbUsers, setDbUsers] = useState([]);
8 | const [selectedUsers, setSelectedUsers] = useState([]);
9 |
10 | useEffect(() => {
11 | const abortController = new AbortController();
12 |
13 | async function fetchData() {
14 | const users = await API.getAvailableUsers(projectId, abortController);
15 |
16 | setDbUsers(users);
17 | }
18 |
19 | fetchData();
20 |
21 | return () => {
22 | abortController.abort();
23 | };
24 | }, [setSelectedUsers, projectId]);
25 |
26 | const handleChange = (event) => {
27 | let values = Array.from(
28 | event.target.selectedOptions,
29 | (option) => option.value
30 | );
31 |
32 | setSelectedUsers(values);
33 | };
34 |
35 | const submit = async (e) => {
36 | e.preventDefault();
37 |
38 | selectedUsers.forEach(async (userId) => {
39 | await API.addTeamMember(projectId, { userId });
40 | });
41 |
42 | const projectTeamRes = await API.getProjectUsers(projectId);
43 |
44 | props.setProjectTeam(projectTeamRes);
45 |
46 | props.toggle();
47 | };
48 |
49 | return (
50 |
51 |
74 |
75 | );
76 | };
77 |
78 | export default AddTeamMember;
79 |
--------------------------------------------------------------------------------
/client/src/components/Forms/CreateProject.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 |
3 | import {
4 | Container,
5 | Row,
6 | Col,
7 | Form,
8 | FormGroup,
9 | Label,
10 | Input,
11 | Button,
12 | } from "reactstrap";
13 | import API from "../../utils/API";
14 |
15 | const CreateProject = (props) => {
16 | const [values, setValues] = useState({ name: "", description: "", team: [] });
17 | const [availableTeamMembers, setAvailableTeamMembers] = useState([]);
18 |
19 | const handleChange = (event) => {
20 | let value;
21 |
22 | if (
23 | event.target.type === "select" ||
24 | event.target.type === "select-multiple"
25 | ) {
26 | value = Array.from(
27 | event.target.selectedOptions,
28 | (option) => option.value
29 | );
30 | } else {
31 | value = event.target.value;
32 | }
33 | const name = event.target.name;
34 |
35 | setValues({
36 | ...values,
37 | [name]: value,
38 | });
39 | };
40 |
41 | useEffect(() => {
42 | let isRendered = true;
43 |
44 | async function fetchUsers() {
45 | const users = await API.getUsers();
46 | if (isRendered === true) setAvailableTeamMembers(users);
47 | }
48 |
49 | fetchUsers();
50 |
51 | return () => {
52 | isRendered = false;
53 | };
54 | }, []);
55 |
56 | async function submit(event) {
57 | event.preventDefault();
58 |
59 | try {
60 | let projectId = await API.createProject(values);
61 |
62 | values.team.forEach(async (userId) => {
63 | await API.addTeamMember(projectId.id, { userId });
64 | });
65 | } catch (err) {
66 | console.log(err);
67 | }
68 |
69 | setValues({ name: "", description: "", team: [] });
70 |
71 | props.toggle();
72 | }
73 |
74 | return (
75 |
76 |
142 |
143 | );
144 | };
145 |
146 | export default CreateProject;
147 |
--------------------------------------------------------------------------------
/client/src/components/Forms/UpdateProject.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 |
3 | import {
4 | Container,
5 | Row,
6 | Form,
7 | FormGroup,
8 | Label,
9 | Input,
10 | Button,
11 | } from "reactstrap";
12 | import API from "../../utils/API";
13 |
14 | const UpdateProject = (props) => {
15 | const [values, setValues] = useState({
16 | name: props.projectData.name,
17 | description: props.projectData.description,
18 | team: props.projectTeam,
19 | });
20 |
21 | const handleChange = (event) => {
22 | let value;
23 |
24 | if (
25 | event.target.type === "select" ||
26 | event.target.type === "select-multiple"
27 | ) {
28 | value = Array.from(
29 | event.target.selectedOptions,
30 | (option) => option.value
31 | );
32 | } else {
33 | value = event.target.value;
34 | }
35 | const name = event.target.name;
36 |
37 | setValues({
38 | ...values,
39 | [name]: value,
40 | });
41 | };
42 |
43 | async function submit(event) {
44 | event.preventDefault();
45 |
46 | try {
47 | await API.updateProject(props.projectData.id, values);
48 | await API.removeAllTeamMembers(props.projectData.id);
49 |
50 | values.team.forEach(async (teammateId) => {
51 | await API.addTeamMember(props.projectData.id, { userId: teammateId });
52 | });
53 | } catch (err) {
54 | console.log(err);
55 | }
56 |
57 | setValues({ name: "", description: "", team: [] });
58 |
59 | props.resetProjectId();
60 | props.toggle();
61 | }
62 |
63 | if (values.team) {
64 | return (
65 |
66 |
126 |
127 | );
128 | } else {
129 | return Loading... ;
130 | }
131 | };
132 |
133 | export default UpdateProject;
134 |
--------------------------------------------------------------------------------
/client/src/components/Forms/useForm.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import { AsYouType } from "libphonenumber-js";
3 |
4 | const useForm = (callback, initialValues, validate) => {
5 | const [values, setValues] = useState(initialValues);
6 |
7 | //new state for errors
8 | const [errors, setErrors] = useState({});
9 |
10 | const [isSubmitting, setIsSubmitting] = useState(false); //isolates the submit callback function to only run if there is an error change.
11 |
12 | let asYouType = new AsYouType("US");
13 |
14 | const handleChange = (event) => {
15 | if (event.target.getAttribute("type") === "phone") {
16 | let phone = asYouType.input(event.target.value);
17 |
18 | setValues({ ...values, phone });
19 | } else {
20 | let value;
21 |
22 | if (event.target.type === "checkbox") {
23 | value = event.target.checked;
24 | } else if (
25 | event.target.type === "select" ||
26 | event.target.type === "select-multiple"
27 | ) {
28 | value = Array.from(
29 | event.target.selectedOptions,
30 | (option) => option.value
31 | );
32 | } else {
33 | value = event.target.value;
34 | }
35 |
36 | const name = event.target.name;
37 |
38 | setValues({
39 | ...values,
40 | [name]: value,
41 | });
42 | }
43 | };
44 |
45 | const handleSubmit = (event) => {
46 | event.preventDefault();
47 |
48 | validate(values).then((res) => {
49 | setIsSubmitting(true);
50 | setErrors(res); //handle validation
51 | });
52 | };
53 |
54 | useEffect(() => {
55 | if (Object.keys(errors).length === 0 && isSubmitting) {
56 | callback();
57 | }
58 | }, [errors]);
59 |
60 | return {
61 | handleChange,
62 | handleSubmit,
63 | values,
64 | errors,
65 | };
66 | };
67 |
68 | export default useForm;
69 |
--------------------------------------------------------------------------------
/client/src/components/Headers/UserHeader.js:
--------------------------------------------------------------------------------
1 | /*!
2 |
3 | =========================================================
4 | * Argon Dashboard React - v1.2.0
5 | =========================================================
6 |
7 | * Product Page: https://www.creative-tim.com/product/argon-dashboard-react
8 | * Copyright 2021 Creative Tim (https://www.creative-tim.com)
9 | * Licensed under MIT (https://github.com/creativetimofficial/argon-dashboard-react/blob/master/LICENSE.md)
10 |
11 | * Coded by Creative Tim
12 |
13 | =========================================================
14 |
15 | * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
16 |
17 | */
18 | import React from "react";
19 |
20 | // reactstrap components
21 | import { Button, Container, Row, Col } from "reactstrap";
22 |
23 | const UserHeader = () => {
24 | return (
25 | <>
26 |
38 | {/* Mask */}
39 |
40 | {/* Header container */}
41 |
42 |
43 |
44 | Hello Jesse
45 |
46 | This is your profile page. You can see the progress you've made
47 | with your work and manage your projects or assigned tasks
48 |
49 | e.preventDefault()}
53 | >
54 | Edit profile
55 |
56 |
57 |
58 |
59 |
60 | >
61 | );
62 | };
63 |
64 | export default UserHeader;
65 |
--------------------------------------------------------------------------------
/client/src/components/Modal/Modal.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Button } from "reactstrap";
3 | import ReactDom from "react-dom";
4 |
5 | const MODAL_STYLES = {
6 | position: "fixed",
7 | top: "50%",
8 | left: "50%",
9 | transform: "translate(-50%, -50%)",
10 | backgroundColor: "#FFF",
11 | padding: "50px",
12 | width: "800px",
13 | zIndex: 1000,
14 | };
15 |
16 | const OVERLAY_STYLES = {
17 | position: "fixed",
18 | top: 0,
19 | left: 0,
20 | right: 0,
21 | bottom: 0,
22 | backgroundColor: "rgba(0, 0, 0, 0.7)",
23 | zIndex: 1000,
24 | };
25 |
26 | export default function Modal({ open, onClose, children }) {
27 | if (!open) return null;
28 |
29 | return ReactDom.createPortal(
30 | <>
31 |
32 |
33 |
34 | X Cancel
35 |
36 | {children}
37 |
38 | >,
39 | document.getElementById("portal")
40 | );
41 | }
42 |
--------------------------------------------------------------------------------
/client/src/components/Navbars/AdminNavbar.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | // reactstrap components
3 |
4 | import { Navbar, Container } from "reactstrap";
5 |
6 | const AdminNavbar = (props) => {
7 | return (
8 | <>
9 |
10 |
11 |
12 | {props.brandText}
13 |
14 |
15 |
16 | >
17 | );
18 | };
19 |
20 | export default AdminNavbar;
21 |
--------------------------------------------------------------------------------
/client/src/components/Navbars/AuthNavbar.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Link } from "react-router-dom";
3 | // reactstrap components
4 | import {
5 | UncontrolledCollapse,
6 | NavbarBrand,
7 | Navbar,
8 | NavItem,
9 | NavLink,
10 | Nav,
11 | Container,
12 | Row,
13 | Col,
14 | } from "reactstrap";
15 |
16 | const AdminNavbar = () => {
17 | return (
18 | <>
19 |
20 |
21 |
22 | Bug Tracker
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | Dashboard
54 |
55 |
56 |
57 |
62 |
63 | Register
64 |
65 |
66 |
67 |
68 |
69 | Login
70 |
71 |
72 |
73 |
78 |
79 | Profile
80 |
81 |
82 |
83 |
84 |
85 |
86 | >
87 | );
88 | };
89 |
90 | export default AdminNavbar;
91 |
--------------------------------------------------------------------------------
/client/src/components/Tables/DataTable.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Table } from "reactstrap";
3 |
4 | //TODO: implement this component with all datatables
5 |
6 | function DataTable({ data }) {
7 | const columns = data[0] && Object.keys(data[0]);
8 |
9 | return (
10 |
11 |
12 | {data[0] && columns.map((heading) => {heading} )}
13 |
14 |
15 | {data.map((row) => (
16 |
17 | {columns.map((column) => (
18 | {row[column]}
19 | ))}
20 |
21 | ))}
22 |
23 |
24 | );
25 | }
26 |
27 | export default DataTable;
28 |
--------------------------------------------------------------------------------
/client/src/components/Tables/PaginationComponent.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useMemo } from "react";
2 | import { Pagination, PaginationItem, PaginationLink } from "reactstrap";
3 |
4 | export default function PaginationComponent({
5 | total = 0,
6 | itemsPerPage = 10,
7 | currentPage = 1,
8 | onPageChange,
9 | }) {
10 | const [totalPages, setTotalPages] = useState(0);
11 |
12 | useEffect(() => {
13 | if (total > 0 && itemsPerPage > 0) {
14 | setTotalPages(Math.ceil(total / itemsPerPage));
15 | }
16 | }, [total, itemsPerPage]);
17 |
18 | const paginationItems = useMemo(() => {
19 | const pages = [];
20 | for (let i = 1; i <= totalPages; i++) {
21 | pages.push(
22 | onPageChange(i)}
26 | >
27 | onPageChange(i)}>{i}
28 |
29 | );
30 | }
31 |
32 | return pages;
33 | }, [totalPages, currentPage, onPageChange]);
34 |
35 | if (totalPages === 0) return null;
36 |
37 | return (
38 |
39 |
40 | onPageChange(currentPage - 1)}
43 | disabled={currentPage === 1}
44 | />
45 |
46 | {paginationItems}
47 |
48 | onPageChange(currentPage + 1)}
51 | disabled={currentPage === totalPages}
52 | />
53 |
54 |
55 | );
56 | }
57 |
--------------------------------------------------------------------------------
/client/src/components/Tables/UsersCell.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import API from "../../utils/API";
3 | import { Row } from "reactstrap";
4 |
5 | const UsersCell = (props) => {
6 | let [projectUsers, setProjectUsers] = useState([]);
7 |
8 | useEffect(() => {
9 | let isRendered = true;
10 |
11 | API.getProjectUsers(props.projectId).then((json) => {
12 | if (isRendered === true) setProjectUsers(json);
13 | });
14 |
15 | return () => {
16 | isRendered = false;
17 | };
18 | }, [props.projectId, props.selectedProjectId]);
19 |
20 | if (projectUsers && projectUsers.length) {
21 | return (
22 | <>
23 | {projectUsers.map((user) => {
24 | return (
25 |
26 | {/* e.preventDefault()}> */}
27 |
28 | {user.first_name} {user.last_name}
29 |
30 | {/* */}
31 |
32 | );
33 | })}
34 | >
35 | );
36 | }
37 |
38 | return (
39 | <>
40 |
41 | No Users Assigned
42 |
43 | >
44 | );
45 | };
46 |
47 | export default UsersCell;
48 |
--------------------------------------------------------------------------------
/client/src/contexts/AuthContext.js:
--------------------------------------------------------------------------------
1 | /*
2 | This file is not currently in use, but might be implemented for a
3 | more global access to auth states
4 | */
5 |
6 | import React, { useContext, useState, useEffect } from "react";
7 |
8 | const AuthContext = React.createContext();
9 |
10 | //call this to access any auth context values
11 | export function useAuth() {
12 | return useContext(AuthContext);
13 | }
14 |
15 | // This is the wrapper for the app that houses the context
16 | export function AuthProvider({ children }) {
17 | const [userAuth, setUserAuth] = useState("");
18 |
19 | useEffect(() => {
20 | const auth = localStorage.getItem("auth");
21 |
22 | console.log(auth);
23 | setUserAuth(auth);
24 | }, []);
25 |
26 | const value = {
27 | userAuth,
28 | };
29 |
30 | return {children} ;
31 | }
32 |
--------------------------------------------------------------------------------
/client/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 |
4 | import "assets/plugins/nucleo/css/nucleo.css";
5 | import "@fortawesome/fontawesome-free/css/all.min.css";
6 | import "assets/scss/argon-dashboard-react.scss";
7 |
8 | import App from "./App";
9 |
10 | ReactDOM.render( , document.getElementById("root"));
11 |
--------------------------------------------------------------------------------
/client/src/layouts/Auth.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useLocation, Route, Switch, Redirect } from "react-router-dom";
3 | // reactstrap components
4 | import { Container, Row, Col } from "reactstrap";
5 |
6 | // core components
7 | import AuthFooter from "components/Footers/AuthFooter.js";
8 |
9 | import routes from "routes.js";
10 |
11 | const Auth = (props) => {
12 | const mainContent = React.useRef(null);
13 | const location = useLocation();
14 |
15 | React.useEffect(() => {
16 | document.body.classList.add("bg-default");
17 | return () => {
18 | document.body.classList.remove("bg-default");
19 | };
20 | }, []);
21 | React.useEffect(() => {
22 | document.documentElement.scrollTop = 0;
23 | document.scrollingElement.scrollTop = 0;
24 | mainContent.current.scrollTop = 0;
25 | }, [location]);
26 |
27 | const getRoutes = (routes) => {
28 | return routes.map((prop, key) => {
29 | if (prop.layout === "auth") {
30 | return (
31 | }
34 | key={key}
35 | />
36 | );
37 | } else {
38 | return null;
39 | }
40 | });
41 | };
42 |
43 | return (
44 | <>
45 |
46 |
47 |
48 |
49 |
50 |
51 | Bug Tracker
52 | Login or register
53 |
54 |
55 |
56 |
57 |
72 |
73 | {/* Page content */}
74 |
75 |
76 |
77 | {getRoutes(routes)}
78 |
79 |
80 |
81 |
82 |
83 |
84 | >
85 | );
86 | };
87 |
88 | export default Auth;
89 |
--------------------------------------------------------------------------------
/client/src/layouts/General.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useLocation, Route, Switch, Redirect } from "react-router-dom";
3 | // reactstrap components
4 | import { Container } from "reactstrap";
5 | // core components
6 | import AdminNavbar from "components/Navbars/AdminNavbar.js";
7 | import AdminFooter from "components/Footers/AdminFooter.js";
8 | import GeneralSidebar from "components/Sidebar/GeneralSidebar.js";
9 |
10 | import routes from "routes.js";
11 |
12 | const General = (props) => {
13 | const mainContent = React.useRef(null);
14 | const location = useLocation();
15 |
16 | React.useEffect(() => {
17 | document.documentElement.scrollTop = 0;
18 | document.scrollingElement.scrollTop = 0;
19 | mainContent.current.scrollTop = 0;
20 | }, [location]);
21 |
22 | const getRoutes = (routes) => {
23 | return routes.map((prop, key) => {
24 | if (prop.layout === "general") {
25 | return (
26 | }
29 | key={key}
30 | />
31 | );
32 | } else {
33 | return null;
34 | }
35 | });
36 | };
37 |
38 | const getBrandText = (path) => {
39 | for (let i = 0; i < routes.length; i++) {
40 | if (routes[i].path.indexOf(":") !== -1) {
41 | if (
42 | props.location.pathname.indexOf(
43 | routes[i].layout +
44 | routes[i].path.slice(0, routes[i].path.indexOf(":"))
45 | ) !== -1
46 | ) {
47 | return routes[i].name;
48 | }
49 | } else if (
50 | props.location.pathname.indexOf(routes[i].layout + routes[i].path) !==
51 | -1
52 | ) {
53 | return routes[i].name;
54 | }
55 | }
56 | return "Brand";
57 | };
58 |
59 | return (
60 | <>
61 | NON ADMIN
62 |
71 |
72 |
76 |
77 | {getRoutes(routes)}
78 |
79 |
80 |
81 |
82 |
83 |
84 | >
85 | );
86 | };
87 |
88 | export default General;
89 |
--------------------------------------------------------------------------------
/client/src/layouts/Main.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from "react";
2 | import { useLocation, Route, Switch, Redirect } from "react-router-dom";
3 | // reactstrap components
4 | import { Container } from "reactstrap";
5 | // core components
6 | import AdminNavbar from "components/Navbars/AdminNavbar.js";
7 | import AdminFooter from "components/Footers/AdminFooter.js";
8 | import UniversalSidebar from "components/Sidebar/UniversalSidebar.js";
9 |
10 | // import { useAuth } from "../contexts/AuthContext";
11 | import routes from "routes.js";
12 |
13 | const Admin = (props) => {
14 | const mainContent = React.useRef(null);
15 | const location = useLocation();
16 |
17 | // let auth = useAuth();
18 |
19 | useEffect(() => {
20 | document.documentElement.scrollTop = 0;
21 | document.scrollingElement.scrollTop = 0;
22 | mainContent.current.scrollTop = 0;
23 | }, [location]);
24 |
25 | const getRoutes = (routes) => {
26 | return routes.map((prop, key) => {
27 | if (prop.layout === "admin") {
28 | return (
29 | }
32 | key={key}
33 | />
34 | );
35 | } else if (prop.layout === "general") {
36 | return (
37 | }
40 | key={key}
41 | />
42 | );
43 | } else {
44 | return null;
45 | }
46 | });
47 | };
48 |
49 | const getBrandText = (path) => {
50 | for (let i = 0; i < routes.length; i++) {
51 | if (routes[i].path.indexOf(":") !== -1) {
52 | if (
53 | props.location.pathname.indexOf(
54 | routes[i].layout +
55 | routes[i].path.slice(0, routes[i].path.indexOf(":"))
56 | ) !== -1
57 | ) {
58 | return routes[i].name;
59 | }
60 | } else if (
61 | props.location.pathname.indexOf(routes[i].layout + routes[i].path) !==
62 | -1
63 | ) {
64 | return routes[i].name;
65 | }
66 | }
67 | return "Brand";
68 | };
69 |
70 | return (
71 | <>
72 |
81 |
82 |
86 |
87 | {getRoutes(routes)}
88 |
89 |
90 |
91 |
92 |
93 |
94 | >
95 | );
96 | };
97 |
98 | export default Admin;
99 |
--------------------------------------------------------------------------------
/client/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 |
--------------------------------------------------------------------------------
/client/src/routes.js:
--------------------------------------------------------------------------------
1 | import Index from "views/Index.js";
2 | import Register from "views/Register.js";
3 | import Login from "views/Login.js";
4 | import Administration from "views/Administration";
5 | import Tickets from "views/Tickets";
6 | import Project from "views/Project";
7 |
8 | var routes = [
9 | {
10 | path: "/index",
11 | name: "Dashboard",
12 | icon: "ni ni-tv-2 text-primary",
13 | component: Index,
14 | layout: "general",
15 | root: "/general",
16 | display: true,
17 | },
18 | {
19 | path: "/tickets",
20 | name: "Tickets",
21 | icon: "ni ni-single-copy-04 text-teal",
22 | component: Tickets,
23 | layout: "general",
24 | root: "/general",
25 | display: true,
26 | },
27 | {
28 | path: "/index",
29 | name: "Dashboard",
30 | icon: "ni ni-tv-2 text-primary",
31 | component: Index,
32 | layout: "admin",
33 | root: "/admin",
34 | display: true,
35 | },
36 | {
37 | path: "/tickets",
38 | name: "Tickets",
39 | icon: "ni ni-single-copy-04 text-teal",
40 | component: Tickets,
41 | layout: "admin",
42 | root: "/admin",
43 | display: true,
44 | },
45 | {
46 | path: "/administration",
47 | name: "Administration",
48 | icon: "ni ni-collection text-red",
49 | component: Administration,
50 | layout: "admin",
51 | root: "/admin",
52 | display: true,
53 | },
54 | {
55 | path: "/login",
56 | name: "Login",
57 | icon: "ni ni-key-25 text-info",
58 | component: Login,
59 | layout: "auth",
60 | root: "/auth",
61 | },
62 | {
63 | path: "/register",
64 | name: "Register",
65 | icon: "ni ni-circle-08 text-pink",
66 | component: Register,
67 | layout: "auth",
68 | root: "/auth",
69 | },
70 | {
71 | path: "/project/:id",
72 | name: "Project",
73 | component: Project,
74 | layout: "general",
75 | root: "/general",
76 | display: false,
77 | },
78 | {
79 | path: "/project/:id",
80 | name: "Project",
81 | component: Project,
82 | layout: "admin",
83 | root: "/admin",
84 | display: false,
85 | },
86 | ];
87 | export default routes;
88 |
--------------------------------------------------------------------------------
/client/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 |
--------------------------------------------------------------------------------
/client/src/utils/formValidation/loginValidation.js:
--------------------------------------------------------------------------------
1 | export default async function validate(values) {
2 | let errors = {};
3 |
4 | //Email validation
5 | if (!values.email) {
6 | errors.email = "Email is required";
7 | }
8 |
9 | //password validation
10 | return errors;
11 | }
12 |
--------------------------------------------------------------------------------
/client/src/utils/formValidation/registerValidation.js:
--------------------------------------------------------------------------------
1 | import API from "../API";
2 | import { isValidPhoneNumber } from "libphonenumber-js";
3 | // import parsePhoneNumber from "libphonenumber-js";
4 |
5 | export default async function registerValidation(values) {
6 | let errors = {};
7 |
8 | //Name validation
9 | if (values.hasOwnProperty("firstName") && !values.firstName) {
10 | errors.firstName = "First name is required";
11 | }
12 |
13 | if (values.hasOwnProperty("lastName") && !values.lastName) {
14 | errors.lastName = "Last name is required";
15 | }
16 |
17 | //phone validation
18 | if (values.hasOwnProperty("phone")) {
19 | if (!values.phone) {
20 | errors.phone = "Phone number is required";
21 | } else if (!isValidPhoneNumber(values.phone, "US")) {
22 | errors.phone = "Please enter valid phone number";
23 | }
24 | }
25 |
26 | //Email validation
27 | if (values.hasOwnProperty("email")) {
28 | if (!values.email) {
29 | errors.email = "Email address is required";
30 | } else if (!/\S+@\S+\.\S+/.test(values.email)) {
31 | errors.email = "Email address is invalid";
32 | } else {
33 | try {
34 | const res = await API.lookupUserByEmail({ email: values.email });
35 |
36 | if (res.length > 0) {
37 | errors.email = "Email already exists";
38 | }
39 | } catch (err) {
40 | console.log(err, "Error looking up email in database");
41 | }
42 | }
43 | }
44 |
45 | // Password validation
46 | if (values.hasOwnProperty("password")) {
47 | if (!values.password) {
48 | errors.password = "Password is required";
49 | } else if (values.password.length < 8) {
50 | errors.password = "Password needs to be 8 or more characters";
51 | }
52 |
53 | if (values.password !== values.confirmPassword) {
54 | errors.confirmPassword = "Passwords entered do not match";
55 | }
56 | }
57 |
58 | // Lease form validation
59 | if (values.hasOwnProperty("property") && !values.property) {
60 | errors.property = "Select a property";
61 | }
62 |
63 | if (values.hasOwnProperty("startDate") && !values.startDate) {
64 | errors.startDate = "Enter lease start date";
65 | }
66 |
67 | if (values.hasOwnProperty("endDate") && !values.endDate) {
68 | errors.endDate = "Enter lease end date";
69 | }
70 |
71 | return errors; //need to make sure promises resolve before returning some how
72 | }
73 |
--------------------------------------------------------------------------------
/client/src/utils/formValidation/ticketValidation.js:
--------------------------------------------------------------------------------
1 | export default async function validate(values) {
2 | let errors = {};
3 |
4 | //Title validation
5 | if (!values.title) {
6 | errors.title = "Title is required";
7 | }
8 |
9 | return errors;
10 | }
11 |
--------------------------------------------------------------------------------
/client/src/views/Index.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | // node.js library that concatenates classes (strings)
3 | // import classnames from "classnames";
4 | // javascipt plugin for creating charts
5 | import Chart from "chart.js";
6 | // react plugin used to create charts
7 | // import { Line, Bar } from "react-chartjs-2";
8 | // reactstrap components
9 | import {
10 | // Button,
11 | // Card,
12 | // CardHeader,
13 | // CardBody,
14 | // NavItem,
15 | // NavLink,
16 | // Nav,
17 | // Progress,
18 | // Table,
19 | Container,
20 | Row,
21 | Col,
22 | } from "reactstrap";
23 |
24 | // core components
25 | import {
26 | chartOptions,
27 | parseOptions,
28 | // chartExample1,
29 | // chartExample2,
30 | } from "variables/charts.js";
31 |
32 | import Header from "components/Headers/Header.js";
33 | import ProjectsTable from "../components/Tables/ProjectsTable";
34 | import TicketsPieChart from "components/Charts/TicketsPieChart";
35 | import API from "../utils/API";
36 |
37 | const Index = (props) => {
38 | const [userTickets, setUserTickets] = useState([]);
39 |
40 | if (window.Chart) {
41 | parseOptions(Chart, chartOptions());
42 | }
43 |
44 | useEffect(() => {
45 | //flag for async useEffect cleanup
46 | const abortController = new AbortController();
47 |
48 | //TODO: fetch user tickets. create backend and front end route
49 | async function fetchUserTickets() {
50 | try {
51 | const userTicketsRes = await (
52 | await API.getUserTickets(abortController)
53 | ).json();
54 |
55 | setUserTickets(userTicketsRes);
56 | } catch (err) {
57 | if (!abortController.signal.aborted) {
58 | console.log("Error fetching user tickets", err);
59 | }
60 | }
61 | }
62 |
63 | fetchUserTickets();
64 | return () => {
65 | abortController.abort();
66 | };
67 | }, []);
68 |
69 | return (
70 | <>
71 |
72 | {/* Page content */}
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 | >
93 | );
94 | };
95 |
96 | export default Index;
97 |
--------------------------------------------------------------------------------
/client/src/views/Tables.css:
--------------------------------------------------------------------------------
1 | .ticketRow:hover {
2 | background-color: #1592ee;
3 | color: #f8fbfd;
4 | cursor: pointer;
5 | }
6 |
7 | .listItem:hover {
8 | background-color: #f4f5f7;
9 | color: black;
10 | cursor: pointer;
11 | }
--------------------------------------------------------------------------------
/controllers/availableUsersController.js:
--------------------------------------------------------------------------------
1 | const pool = require("../db");
2 |
3 | module.exports = {
4 | getAvailableUsers: async function (req, res) {
5 | const client = await pool.connect();
6 |
7 | const { projectId } = req.params;
8 |
9 | try {
10 | const {
11 | rows,
12 | } = await client.query(
13 | "SELECT id, email, first_name, last_name FROM users as U WHERE NOT EXISTS (SELECT user_id FROM user_projects as UP WHERE UP.user_id = U.id AND UP.project_id = $1)",
14 | [projectId]
15 | );
16 |
17 | res.status(201).json(rows);
18 | } catch (err) {
19 | console.log(err);
20 | res.send(500).json({ msg: "Failed to fetch available users" });
21 | }
22 | },
23 | };
24 |
--------------------------------------------------------------------------------
/controllers/commentController.js:
--------------------------------------------------------------------------------
1 | const pool = require("../db");
2 |
3 | module.exports = {
4 | createComment: async (req, res) => {
5 | const { ticketId } = req.params;
6 | const { comment } = req.body;
7 | const authorId = req.user;
8 | const client = await pool.connect();
9 |
10 | try {
11 | await client.query(
12 | "INSERT INTO comments (author_id, ticket_id, comment) VALUES ($1, $2, $3)",
13 | [authorId, ticketId, comment]
14 | );
15 |
16 | res.status(201).json({ msg: `Comment on ticket${ticketId} created` });
17 | } catch (err) {
18 | console.log(`Failed to create message for ${ticketId}: `, "\n", err);
19 | res.status(500).json({ msg: `Please review query` });
20 | } finally {
21 | await client.release();
22 | }
23 | },
24 | getTicketComments: async (req, res) => {
25 | const { ticketId } = req.params;
26 | const client = await pool.connect();
27 |
28 | try {
29 | const { rows } = await client.query(
30 | "SELECT comments.id, comments.ticket_id, comments.comment, comments.created_at, users.id AS author_id, users.first_name, users.last_name FROM comments JOIN users ON comments.author_id = users.id WHERE ticket_id = $1",
31 | [ticketId]
32 | );
33 |
34 | res.json(rows);
35 | } catch (err) {
36 | console.log(`Failed to get ticket for`, "\n", err);
37 | res.status(500).json({ msg: `Please review query` });
38 | } finally {
39 | client.release();
40 | }
41 | },
42 | updateComment: async (req, res) => {
43 | const { ticketId, commentId } = req.params;
44 | const { authorId, comment } = req.body;
45 | const client = await pool.connect();
46 |
47 | try {
48 | await client.query(
49 | "UPDATE comments SET (author_id, comment) = ($1, $2) WHERE id = $3",
50 | [authorId, comment, commentId]
51 | );
52 |
53 | res
54 | .status(201)
55 | .json({ msg: `Comment ${commentId} updated successfully` });
56 | } catch (err) {
57 | console.log(`Failed to update comment: `, "\n", err);
58 | res.status(500).json({ msg: `Please review query` });
59 | } finally {
60 | await client.release();
61 | }
62 | },
63 | deleteComment: async (req, res) => {
64 | const { commentId } = req.params;
65 | const client = await pool.connect();
66 |
67 | try {
68 | await client.query("DELETE FROM comments WHERE id = $1", [commentId]);
69 |
70 | res.status(200).json({ msg: `Comment ${commentId} deleted` });
71 | } catch (err) {
72 | console.log("Failed to delete comment: ", "\n", err);
73 | res.status(500).json({ msg: "Review deletion query" });
74 | } finally {
75 | client.release();
76 | }
77 | },
78 | };
79 |
--------------------------------------------------------------------------------
/controllers/devAssignmentsController.js:
--------------------------------------------------------------------------------
1 | const pool = require("../db");
2 |
3 | module.exports = {
4 | assignDev: async (req, res) => {
5 | const { ticketId } = req.params;
6 | const { devId } = req.body; // If there are multiple users to assign, this will be handled on front end
7 | const client = await pool.connect();
8 |
9 | try {
10 | await client.query(
11 | "INSERT INTO dev_assignments (ticket_id, user_id) VALUES ($1, $2)",
12 | [ticketId, devId]
13 | );
14 |
15 | res
16 | .status(201)
17 | .json({ msg: `User ${devId} assigned to ${ticketId} succesfully` });
18 | } catch (err) {
19 | console.log("assignUsers query error: ", err);
20 | res
21 | .status(400)
22 | .json({ msg: "Please review user project assign creation query" });
23 | } finally {
24 | await client.release();
25 | }
26 | },
27 |
28 | removeDev: async (req, res) => {
29 | const { devId } = req.body;
30 | const client = await pool.connect();
31 |
32 | try {
33 | await client.query("DELETE FROM dev_assignments WHERE id = $1", [devId]);
34 |
35 | res.json(`User removed from ticket`);
36 | } catch (err) {
37 | console.log("getProject query error: ", err);
38 | res
39 | .status(500)
40 | .json({ msg: "Unable to remove dev assignment from database" });
41 | } finally {
42 | await client.release();
43 | }
44 | },
45 | getAssignedDevs: async (req, res) => {
46 | const { ticketId } = req.params;
47 | const client = await pool.connect();
48 |
49 | try {
50 | const {
51 | rows,
52 | } = await client.query(
53 | "SELECT user_id, first_name, last_name, phone, email FROM users JOIN dev_assignments ON (dev_assignments.user_id = users.id) WHERE ticket_id = $1",
54 | [ticketId]
55 | );
56 |
57 | res.json(rows);
58 | } catch (err) {
59 | console.log("getProjectUsers query error: ", err);
60 | res.status(400).json({ msg: "Please review query" });
61 | } finally {
62 | client.release();
63 | }
64 | },
65 | removeAllDevs: async (req, res) => {
66 | const { ticketId } = req.params;
67 | const client = await pool.connect();
68 |
69 | try {
70 | await client.query("DELETE FROM dev_assignments WHERE ticket_id = $1", [
71 | ticketId,
72 | ]);
73 |
74 | res.status(204).json({ msg: "All devs removed from ticket" });
75 | } catch (err) {
76 | console.error(err.message);
77 | res.status(500);
78 | } finally {
79 | client.release();
80 | }
81 | },
82 | };
83 |
--------------------------------------------------------------------------------
/controllers/userProjectController.js:
--------------------------------------------------------------------------------
1 | const pool = require("../db");
2 |
3 | module.exports = {
4 | assignUser: async (req, res) => {
5 | const { projectId } = req.params;
6 | const { userId } = req.body; // If there are multiple users to assign, this will be handled on front end
7 | const client = await pool.connect();
8 |
9 | try {
10 | await client.query(
11 | "INSERT INTO user_projects (project_id, user_id) VALUES ($1, $2)",
12 | [projectId, userId]
13 | );
14 |
15 | res
16 | .status(201)
17 | .json({ msg: `User ${userId} assigned to ${projectId} succesfully` });
18 | } catch (err) {
19 | console.log("assignUsers query error: ", err);
20 | res
21 | .status(400)
22 | .json({ msg: "Please review user project assign creation query" });
23 | } finally {
24 | await client.release();
25 | }
26 | },
27 | removeAllUsers: async (req, res) => {
28 | const { projectId } = req.params;
29 | const client = await pool.connect();
30 |
31 | try {
32 | await client.query("DELETE FROM user_projects WHERE project_id = $1", [
33 | projectId,
34 | ]);
35 |
36 | res.status(202).json(`Project users deleted`);
37 | } catch (err) {
38 | console.log("getProject query error: ", err);
39 | res
40 | .status(500)
41 | .json({ msg: "Unable to remove user_project from database" });
42 | } finally {
43 | await client.release();
44 | }
45 | },
46 | removeUser: async (req, res) => {
47 | const { projectId, userId } = req.params;
48 | const client = await pool.connect();
49 |
50 | try {
51 | await client.query(
52 | "DELETE FROM user_projects WHERE project_id = $1 AND user_id = $2",
53 | [projectId, userId]
54 | );
55 |
56 | res.status(202).json(`User removed from project`);
57 | } catch (err) {
58 | console.log("getProject query error: ", err);
59 | res
60 | .status(500)
61 | .json({ msg: "Unable to remove user_project from database" });
62 | } finally {
63 | await client.release();
64 | }
65 | },
66 | getProjectUsers: async (req, res) => {
67 | const { projectId } = req.params;
68 | const client = await pool.connect();
69 |
70 | try {
71 | const {
72 | rows,
73 | } = await client.query(
74 | "SELECT user_id, first_name, last_name, phone, email FROM users JOIN user_projects ON (user_projects.user_id = users.id) WHERE project_id = $1",
75 | [projectId]
76 | );
77 |
78 | res.json(rows);
79 | } catch (err) {
80 | console.log("getProjectUsers query error: ", err);
81 | res.status(400).json({ msg: "Please review query" });
82 | } finally {
83 | client.release();
84 | }
85 | },
86 | };
87 |
--------------------------------------------------------------------------------
/db.js:
--------------------------------------------------------------------------------
1 | const Pool = require("pg").Pool;
2 | require("dotenv").config();
3 |
4 | const devConfig = {
5 | user: process.env.PGUSER,
6 | host: process.env.PGHOST,
7 | database: process.env.PGDATABASE,
8 | password: process.env.PGPASSWORD,
9 | port: process.env.PGPORT,
10 | max: 20,
11 | connectionTimeoutMillis: 0,
12 | idleTimeoutMillis: 0,
13 | };
14 |
15 | const proConfig = {
16 | connectionString: process.env.DATABASE_URL, //heroku addons
17 | };
18 |
19 | const pool = new Pool(
20 | process.env.NODE_ENV === "production" ? proConfig : devConfig
21 | );
22 |
23 | // the pool will emit an error on behalf of any idle clients
24 | // it contains if a backend error or network partition happens
25 | pool.on("error", (err, client) => {
26 | console.error("Unexpected error on idle client", err);
27 | process.exit(-1);
28 | });
29 |
30 | module.exports = pool;
31 |
--------------------------------------------------------------------------------
/middleware/authorization.js:
--------------------------------------------------------------------------------
1 | const jwt = require("jsonwebtoken");
2 | require("dotenv").config();
3 |
4 | module.exports = async (req, res, next) => {
5 | try {
6 | const jwtToken = req.header("token");
7 |
8 | if (!jwtToken) {
9 | return res.status(403).json("Not Authorized");
10 | }
11 |
12 | const payload = jwt.verify(jwtToken, process.env.JWT_SECRET);
13 |
14 | req.user = payload.user;
15 |
16 | next();
17 | } catch (err) {
18 | console.log(err);
19 | // console.error(err.message);
20 | return res.status(403).json("Not Authorized");
21 | }
22 | };
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bug-tracker-react",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "server.js",
6 | "engines": {
7 | "node": "12.22.1",
8 | "npm": "6.14.12"
9 | },
10 | "scripts": {
11 | "test": "test",
12 | "install-client": "npm install",
13 | "devStart": "concurrently \"npm run server\" \"cd client && npm start\"",
14 | "start": "node server.js",
15 | "heroku-postbuild": "cd client && npm install && npm run build",
16 | "server": "nodemon server.js"
17 | },
18 | "author": "Connor Lee",
19 | "license": "ISC",
20 | "dependencies": {
21 | "bcryptjs": "^2.4.3",
22 | "cors": "^2.8.5",
23 | "dotenv": "^8.2.0",
24 | "express": "^4.17.1",
25 | "jsonwebtoken": "^8.5.1",
26 | "libphonenumber-js": "^1.9.17",
27 | "moment": "^2.27.0",
28 | "pg": "^8.3.0",
29 | "react-google-charts": "^3.0.15",
30 | "react-toastify": "^7.0.4"
31 | },
32 | "devDependencies": {
33 | "concurrently": "^5.2.0"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/routes/api/auth.js:
--------------------------------------------------------------------------------
1 | const router = require("express").Router();
2 | const userController = require("../../controllers/userController");
3 |
4 | // Matches route with "/api/auth/user"
5 | router.route(`/user`).post(userController.lookupUserByEmail);
6 |
7 | module.exports = router;
8 |
--------------------------------------------------------------------------------
/routes/api/availableUsers.js:
--------------------------------------------------------------------------------
1 | const router = require("express").Router();
2 | const availableUsersController = require("../../controllers/availableUsersController");
3 |
4 | router
5 | // Matches route with "/api/availableUsers/:projectId"
6 | .route("/:projectId")
7 | .get(availableUsersController.getAvailableUsers);
8 |
9 | module.exports = router;
10 |
--------------------------------------------------------------------------------
/routes/api/comment.js:
--------------------------------------------------------------------------------
1 | const router = require("express").Router();
2 | const commentController = require("../../controllers/commentController");
3 | const authorization = require("../../middleware/authorization");
4 |
5 | // Matches route with "/api/comments/"
6 | router
7 | .route("/:ticketId")
8 | .post(authorization, commentController.createComment)
9 | .get(authorization, commentController.getTicketComments);
10 |
11 | router
12 | .route("/:ticketId/:commentId")
13 | .put(authorization, commentController.updateComment)
14 | .delete(authorization, commentController.deleteComment);
15 |
16 | module.exports = router;
17 |
--------------------------------------------------------------------------------
/routes/api/devAssignments.js:
--------------------------------------------------------------------------------
1 | const router = require("express").Router();
2 | const devAssignmentsController = require("../../controllers/devAssignmentsController");
3 |
4 | // Matches route with "/api/assigneddev/"
5 | router.route("/").delete(devAssignmentsController.removeDev);
6 |
7 | // Matches route with "/api/assigneddev/:ticketId"
8 | router
9 | .route("/:ticketId")
10 | .post(devAssignmentsController.assignDev)
11 | .get(devAssignmentsController.getAssignedDevs)
12 | .delete(devAssignmentsController.removeAllDevs);
13 |
14 | module.exports = router;
15 |
--------------------------------------------------------------------------------
/routes/api/index.js:
--------------------------------------------------------------------------------
1 | const router = require("express").Router();
2 | const projectRoutes = require("./project");
3 | const userRoutes = require("./user");
4 | const userProjectRoutes = require("./userProjects");
5 | const ticketRoutes = require("./ticket");
6 | const commentRoutes = require("./comment");
7 | const devAssignmentsRoutes = require("./devAssignments");
8 | const loginRoutes = require("./login");
9 | const availableUsersRoutes = require("./availableUsers");
10 | const authRoutes = require("./auth");
11 |
12 | router.use("/projects", projectRoutes);
13 | router.use("/users", userRoutes);
14 | router.use("/userprojects", userProjectRoutes);
15 | router.use("/tickets", ticketRoutes);
16 | router.use("/comments", commentRoutes);
17 | router.use("/devassignments", devAssignmentsRoutes);
18 | router.use("/login", loginRoutes);
19 | router.use("/availableUsers", availableUsersRoutes);
20 | router.use("/auth", authRoutes);
21 |
22 | module.exports = router;
23 |
--------------------------------------------------------------------------------
/routes/api/login.js:
--------------------------------------------------------------------------------
1 | const router = require("express").Router();
2 | const pool = require("../../db");
3 | const bcrypt = require("bcryptjs");
4 | const jwtGenerator = require("../../utils/jwtGenerator");
5 |
6 | //Matches route /login
7 | router.post("/", async (req, res) => {
8 | const client = await pool.connect();
9 |
10 | try {
11 | //1. destructure req.body
12 | const { email, password } = req.body;
13 |
14 | //2. check if user doesn't exist (throw error if not)
15 | const user = await client.query("SELECT * FROM users WHERE email = $1", [
16 | email,
17 | ]);
18 | if (user.rows.length === 0) {
19 | return res.status(401).send("Email or password is incorrect");
20 | }
21 |
22 | //3. check if incoming password is correct
23 | const validPassword = await bcrypt.compare(
24 | password,
25 | user.rows[0].password_hash
26 | );
27 | if (!validPassword) {
28 | return res.status(401).send("Email or password is incorrect");
29 | }
30 |
31 | //4. give jwt token
32 | const token = jwtGenerator(user.rows[0].id);
33 |
34 | res.json({
35 | token,
36 | auth: user.rows[0].user_authority,
37 | });
38 | } catch (err) {
39 | console.error(err.message);
40 | } finally {
41 | client.release();
42 | }
43 | });
44 |
45 | module.exports = router;
46 |
--------------------------------------------------------------------------------
/routes/api/project.js:
--------------------------------------------------------------------------------
1 | const router = require("express").Router();
2 | const projectController = require("../../controllers/projectController");
3 | const authorization = require("../../middleware/authorization");
4 |
5 | // Matches route with "/api/projects/"
6 | router
7 | .route("/")
8 | .get(
9 | // authorization,
10 | projectController.getAll
11 | )
12 | .post(authorization, projectController.createProject);
13 |
14 | router
15 | .route("/:id")
16 | .get(authorization, projectController.getProject)
17 | .put(authorization, projectController.updateProject)
18 | .delete(authorization, projectController.deleteProject);
19 |
20 | module.exports = router;
21 |
--------------------------------------------------------------------------------
/routes/api/ticket.js:
--------------------------------------------------------------------------------
1 | const router = require("express").Router();
2 | const ticketController = require("../../controllers/ticketController");
3 | const authorization = require("../../middleware/authorization");
4 |
5 | // Matches route with "/api/tickets/"
6 | router.route("/").get(authorization, ticketController.getUserTickets);
7 |
8 | router
9 | .route("/:projectId")
10 | .post(authorization, ticketController.createTicket)
11 | .get(ticketController.getProjectTickets);
12 |
13 | router
14 | .route("/:projectId/:ticketId")
15 | .get(ticketController.getTicket)
16 | .put(authorization, ticketController.updateTicket)
17 | .delete(authorization, ticketController.deleteTicket);
18 |
19 | module.exports = router;
20 |
--------------------------------------------------------------------------------
/routes/api/user.js:
--------------------------------------------------------------------------------
1 | const router = require("express").Router();
2 | const userController = require("../../controllers/userController");
3 | const authorization = require("../../middleware/authorization");
4 |
5 | // Matches route with "/api/users/"
6 | router.route("/").get(userController.getAll).post(userController.addUser);
7 |
8 | // Matches route with "/api/users/:id"
9 | router
10 | .route("/:id")
11 | .get(userController.getUser)
12 | .put(authorization, userController.updateUser)
13 | .delete(authorization, userController.deleteUser);
14 |
15 | module.exports = router;
16 |
--------------------------------------------------------------------------------
/routes/api/userProjects.js:
--------------------------------------------------------------------------------
1 | const router = require("express").Router();
2 | const userProjectController = require("../../controllers/userProjectController");
3 | const authorization = require("../../middleware/authorization");
4 |
5 | // Matches route with "/api/userProjects/"
6 | router.route("/");
7 |
8 | // Matches route with "/api/userProjects/:projectId"
9 | router
10 | .route("/:projectId")
11 | .post(authorization, userProjectController.assignUser)
12 | .get(authorization, userProjectController.getProjectUsers)
13 | .delete(authorization, userProjectController.removeAllUsers);
14 |
15 | // Matches route with "/api/userprojects/:projectId/:userId"
16 | router
17 | .route("/:projectId/:userId")
18 | .delete(authorization, userProjectController.removeUser);
19 |
20 | module.exports = router;
21 |
--------------------------------------------------------------------------------
/routes/index.js:
--------------------------------------------------------------------------------
1 | const router = require("express").Router();
2 | const apiRoutes = require("./api");
3 | const authorization = require("../middleware/authorization");
4 |
5 | // API Routes
6 | router.use("/api", apiRoutes);
7 |
8 | // Auth Routes
9 | router.get("/auth/verify", authorization, async (req, res) => {
10 | try {
11 | res.json(true);
12 | } catch (err) {
13 | console.error(err.message);
14 | res.status(500).send("Server Error");
15 | }
16 | });
17 |
18 | module.exports = router;
19 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const app = express();
3 | const routes = require("./routes");
4 | const path = require("path");
5 |
6 | const PORT = process.env.PORT || 3001;
7 | require("dotenv").config();
8 | const cors = require("cors");
9 |
10 | app.use(express.json()); // middleware to acces req.body
11 | app.use(express.urlencoded({ extended: false }));
12 | //middleware to handle any CORS issues
13 | app.use(cors());
14 | app.use((req, res, next) => {
15 | res.header("Access-Control-Allow-Origin", "*");
16 | res.header(
17 | "Access-Control-Allow-Headers",
18 | "Origin, X-Requested-With, Content-Type, Accept, Authorization, token"
19 | );
20 | if (req.method === "options") {
21 | res.header("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, PATCH");
22 | return res.status(200).json({});
23 | }
24 | next();
25 | });
26 |
27 | app.use(routes);
28 |
29 | if (process.env.NODE_ENV === "production") {
30 | app.use(express.static(path.join(__dirname, "client/build")));
31 | }
32 |
33 | app.get("*", (req, res) => {
34 | res.sendFile(path.join(__dirname, "client/build/index.html"));
35 | });
36 |
37 | app.listen(PORT, () => {
38 | console.log(`API Server now listening on port ${PORT}`);
39 | });
40 |
--------------------------------------------------------------------------------
/utils/jwtGenerator.js:
--------------------------------------------------------------------------------
1 | const jwt = require("jsonwebtoken");
2 | require("dotenv").config();
3 |
4 | function jwtGenerator(user_id) {
5 | const payload = {
6 | user: user_id,
7 | };
8 |
9 | return jwt.sign(
10 | payload,
11 | process.env.JWT_SECRET
12 | // { expiresIn: "1hr" }
13 | );
14 | }
15 |
16 | module.exports = jwtGenerator;
17 |
--------------------------------------------------------------------------------