├── .babelrc
├── .eslintrc.json
├── .github
└── workflows
│ └── linters.yml
├── .gitignore
├── .stylelintrc.json
├── LICENSE
├── README.md
├── murple_logo.png
├── package-lock.json
├── package.json
├── public
├── assets
│ └── bg.jpg
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
└── src
├── App.css
├── App.jsx
├── assets
└── bg.jpg
├── components
├── Buttons.css
├── Buttons.js
├── Calculator.css
├── Calculator.js
├── navBar.css
├── navBar.js
├── quote.css
└── quote.js
├── index.css
├── index.js
├── logic
├── calculate.js
└── operate.js
└── routes
├── calcuatorPage.css
├── calculatorPage.js
├── homePage.css
├── homePage.js
├── quotePage.css
└── quotePage.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "@babel/preset-react"
4 | ],
5 | "plugins": ["@babel/plugin-syntax-jsx"]
6 | }
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "es6": true,
5 | "jest": true
6 | },
7 | "parser": "@babel/eslint-parser",
8 | "parserOptions": {
9 | "ecmaFeatures": {
10 | "jsx": true
11 | },
12 | "ecmaVersion": 2018,
13 | "sourceType": "module"
14 | },
15 | "extends": ["airbnb", "plugin:react/recommended", "plugin:react-hooks/recommended"],
16 | "plugins": ["react"],
17 | "rules": {
18 | "react/jsx-filename-extension": ["warn", { "extensions": [".js", ".jsx"] }],
19 | "react/react-in-jsx-scope": "off",
20 | "import/no-unresolved": "off",
21 | "no-shadow": "off"
22 | },
23 | "overrides": [
24 | {
25 | // feel free to replace with your preferred file pattern - eg. 'src/**/*Slice.js' or 'redux/**/*Slice.js'
26 | "files": ["src/**/*Slice.js"],
27 | // avoid state param assignment
28 | "rules": { "no-param-reassign": ["error", { "props": false }] }
29 | }
30 | ],
31 | "ignorePatterns": [
32 | "dist/",
33 | "build/"
34 | ]
35 | }
--------------------------------------------------------------------------------
/.github/workflows/linters.yml:
--------------------------------------------------------------------------------
1 | name: Linters
2 |
3 | on: pull_request
4 |
5 | env:
6 | FORCE_COLOR: 1
7 |
8 | jobs:
9 | eslint:
10 | name: ESLint
11 | runs-on: ubuntu-22.04
12 | steps:
13 | - uses: actions/checkout@v3
14 | - uses: actions/setup-node@v3
15 | with:
16 | node-version: "18.x"
17 | - name: Setup ESLint
18 | run: |
19 | npm install --save-dev eslint@7.x eslint-config-airbnb@18.x eslint-plugin-import@2.x eslint-plugin-jsx-a11y@6.x eslint-plugin-react@7.x eslint-plugin-react-hooks@4.x @babel/eslint-parser@7.x @babel/core@7.x @babel/plugin-syntax-jsx@7.x @babel/preset-env@7.x @babel/preset-react@7.x
20 | [ -f .eslintrc.json ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/react-redux/.eslintrc.json
21 | [ -f .babelrc ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/react-redux/.babelrc
22 | - name: ESLint Report
23 | run: npx eslint "**/*.{js,jsx}"
24 | stylelint:
25 | name: Stylelint
26 | runs-on: ubuntu-22.04
27 | steps:
28 | - uses: actions/checkout@v3
29 | - uses: actions/setup-node@v3
30 | with:
31 | node-version: "18.x"
32 | - name: Setup Stylelint
33 | run: |
34 | npm install --save-dev stylelint@13.x stylelint-scss@3.x stylelint-config-standard@21.x stylelint-csstree-validator@1.x
35 | [ -f .stylelintrc.json ] || wget https://raw.githubusercontent.com/microverseinc/linters-config/master/react-redux/.stylelintrc.json
36 | - name: Stylelint Report
37 | run: npx stylelint "**/*.{css,scss}"
38 | nodechecker:
39 | name: node_modules checker
40 | runs-on: ubuntu-22.04
41 | steps:
42 | - uses: actions/checkout@v3
43 | - name: Check node_modules existence
44 | run: |
45 | if [ -d "node_modules/" ]; then echo -e "\e[1;31mThe node_modules/ folder was pushed to the repo. Please remove it from the GitHub repository and try again."; echo -e "\e[1;32mYou can set up a .gitignore file with this folder included on it to prevent this from happening in the future." && exit 1; fi
--------------------------------------------------------------------------------
/.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 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/.stylelintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["stylelint-config-standard"],
3 | "plugins": ["stylelint-scss", "stylelint-csstree-validator"],
4 | "rules": {
5 | "at-rule-no-unknown": [
6 | true,
7 | {
8 | "ignoreAtRules": ["tailwind", "apply", "variants", "responsive", "screen"]
9 | }
10 | ],
11 | "scss/at-rule-no-unknown": [
12 | true,
13 | {
14 | "ignoreAtRules": ["tailwind", "apply", "variants", "responsive", "screen"]
15 | }
16 | ],
17 | "csstree/validator": true
18 | },
19 | "ignoreFiles": ["build/**", "dist/**", "**/reset*.css", "**/bootstrap*.css", "**/*.js", "**/*.jsx"]
20 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2021, Andres Zamorano Medina
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this Hello Microverse! and associated documentation files, to deal in the Hello Microverse! without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Hello Microverse!, and to permit persons to whom the Hello Microverse! is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Hello Microverse!.
6 |
7 | THE Hello Microverse! IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE Hello Microverse! OR THE USE OR OTHER DEALINGS IN THE Hello Microverse!.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
Math Magicians project.
8 |
9 |
10 |
11 |
12 |
13 | # 📗 Table of Contents
14 |
15 | - [📖 About the Project](#about-project)
16 | - [🛠 Built With](#built-with)
17 | - [Tech Stack](#tech-stack)
18 | - [Key Features](#key-features)
19 | - [🚀 Live Demo](#live-demo)
20 | - [💻 Getting Started](#getting-started)
21 | - [Prerequisites](#prerequisites)
22 | - [Setup](#setup)
23 | - [Install](#install)
24 | - [Usage](#usage)
25 | - [Run tests](#run-tests)
26 | - [Deployment](#deployment)
27 | - [👥 Authors](#authors)
28 | - [🔭 Future Features](#future-features)
29 | - [🤝 Contributing](#contributing)
30 | - [⭐️ Show your support](#support)
31 | - [🙏 Acknowledgements](#acknowledgements)
32 | - [❓ FAQ (OPTIONAL)](#faq)
33 | - [📝 License](#license)
34 |
35 |
36 |
37 | # 📖 [Math Magicians]
38 |
39 | **[Math magicians]** is a website for all fans of mathematics. It is a Single Page App (SPA)
40 |
41 | ## 🛠 Built With
42 |
43 | ### Tech Stack
44 |
45 |
46 | Client
47 |
50 |
51 |
52 |
53 | Linters
54 |
55 | The project use linters to looking for code error
56 |
57 |
58 |
59 |
60 |
61 | ### Key Features
62 |
63 | - **[Use of React.js]**
64 | - **[Use motivational quotes]**
65 | - **[Use of route to SPA]**
66 |
67 | (back to top )
68 |
69 |
70 |
71 |
78 |
79 |
80 |
81 | ## 💻 Getting Started
82 |
83 | To get a local copy up and running, follow these steps.
84 |
85 | ### Prerequisites
86 |
87 | You need a updated browser
88 |
89 | ### Setup
90 |
91 | Clone this repository to your desired folder:
92 |
93 | sh
94 | cd my-folder
95 | git clone https://github.com/Dachrono/MathMagicians.git
96 |
97 | ### Install
98 |
99 | Install this project with:
100 |
101 | sh
102 | cd my-project
103 | npm init -y
104 |
105 | ### Usage
106 |
107 | To run the project, execute the following command:
108 |
109 | sh
110 | npm start
111 |
112 | ### Run tests
113 |
114 | To run tests, run the following command:
115 |
116 | sh
117 | npm test
118 |
119 |
122 |
123 | (back to top )
124 |
125 |
126 |
127 | ## 👥 Authors
128 |
129 | 👤 **Andy Zam**
130 |
131 | - GitHub: [Andres Zamorano](https://github.com/Dachrono)
132 | - Twitter: [Andres Zamorano](https://twitter.com/Dachrono)
133 | - LinkedIn: [Andres Zamorano](https://www.linkedin.com/in/andres-zamorano-785b77a1/)
134 |
135 | (back to top )
136 |
137 |
138 |
139 | ## 🔭 Future Features
140 |
141 | - [1] **[Create support pages]**
142 | - [2] **[Create calculator]**
143 |
144 | (back to top )
145 |
146 | ## 🤝 Contributing
147 |
148 | Contributions, issues, and feature requests are welcome!
149 |
150 | Feel free to check the [issues page](https://github.com/Dachrono/MathMagicians/issues).
151 |
152 | (back to top )
153 |
154 |
155 |
156 | ## ⭐️ Show your support
157 |
158 | If you like this project please feel fre to send me corrections for make it better I would feel glad to read your comments
159 |
160 | (back to top )
161 |
162 |
163 |
164 | ## 🙏 Acknowledgments
165 |
166 |
167 |
168 | (back to top )
169 |
170 | ## ❓ FAQ (OPTIONAL)
171 |
172 |
173 | - **[Can I use with a templeate your project?]**
174 |
175 | - [Of course I would feel honored]
176 |
177 | - **[Your project is free license?]**
178 |
179 | - [Yeah, you can use it completly]
180 |
181 | (back to top )
182 |
183 |
184 |
185 | ## 📝 License
186 |
187 | this project is [MIT](./LICENSE) licensed.
188 |
189 | (back to top )
--------------------------------------------------------------------------------
/murple_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dachrono/MathMagicians/51fa84b1b418d6b922e64f37ea88548f24ee483d/murple_logo.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "math",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.16.5",
7 | "@testing-library/react": "^13.4.0",
8 | "@testing-library/user-event": "^13.5.0",
9 | "big.js": "^6.2.1",
10 | "prop-types": "^15.8.1",
11 | "react": "^18.2.0",
12 | "react-dom": "^18.2.0",
13 | "react-router-dom": "^6.14.1",
14 | "react-scripts": "5.0.1",
15 | "web-vitals": "^2.1.4"
16 | },
17 | "scripts": {
18 | "start": "react-scripts start",
19 | "build": "react-scripts build",
20 | "test": "react-scripts test",
21 | "eject": "react-scripts eject"
22 | },
23 | "eslintConfig": {
24 | "extends": [
25 | "react-app",
26 | "react-app/jest"
27 | ]
28 | },
29 | "browserslist": {
30 | "production": [
31 | ">0.2%",
32 | "not dead",
33 | "not op_mini all"
34 | ],
35 | "development": [
36 | "last 1 chrome version",
37 | "last 1 firefox version",
38 | "last 1 safari version"
39 | ]
40 | },
41 | "devDependencies": {
42 | "@babel/core": "^7.22.5",
43 | "@babel/eslint-parser": "^7.22.5",
44 | "@babel/plugin-syntax-jsx": "^7.22.5",
45 | "@babel/preset-react": "^7.22.5",
46 | "eslint": "^7.32.0",
47 | "eslint-config-airbnb": "^18.2.1",
48 | "eslint-plugin-import": "^2.27.5",
49 | "eslint-plugin-jsx-a11y": "^6.7.1",
50 | "eslint-plugin-react": "^7.32.2",
51 | "eslint-plugin-react-hooks": "^4.6.0",
52 | "stylelint": "^13.13.1",
53 | "stylelint-config-standard": "^21.0.0",
54 | "stylelint-csstree-validator": "^1.9.0",
55 | "stylelint-scss": "^3.21.0"
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/public/assets/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dachrono/MathMagicians/51fa84b1b418d6b922e64f37ea88548f24ee483d/public/assets/bg.jpg
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dachrono/MathMagicians/51fa84b1b418d6b922e64f37ea88548f24ee483d/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 | You need to enable JavaScript to run this app.
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dachrono/MathMagicians/51fa84b1b418d6b922e64f37ea88548f24ee483d/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dachrono/MathMagicians/51fa84b1b418d6b922e64f37ea88548f24ee483d/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .container {
2 | display: flex;
3 | flex-direction: column;
4 | justify-content: center;
5 | align-items: center;
6 | background-color: #fff;
7 | }
8 |
--------------------------------------------------------------------------------
/src/App.jsx:
--------------------------------------------------------------------------------
1 | import './App.css';
2 | import Calculator from './components/Calculator';
3 | import Quote from './components/quote';
4 |
5 | function App() {
6 | return (
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | export default App;
15 |
--------------------------------------------------------------------------------
/src/assets/bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dachrono/MathMagicians/51fa84b1b418d6b922e64f37ea88548f24ee483d/src/assets/bg.jpg
--------------------------------------------------------------------------------
/src/components/Buttons.css:
--------------------------------------------------------------------------------
1 | .panel {
2 | display: grid;
3 | grid-template-columns: 1fr 1fr 1fr 1fr;
4 | grid-template-rows: 50px 50px 50px 50px 50px;
5 | }
6 |
7 | .btn {
8 | all: initial;
9 | cursor: pointer;
10 | display: flex;
11 | align-items: center;
12 | justify-content: center;
13 | background-color: #dcdcdc;
14 | border: 0.5px solid #808080;
15 | }
16 |
17 | #div,
18 | #mul,
19 | #sum,
20 | #res,
21 | #equal {
22 | background-color: orange;
23 | }
24 |
25 | #zero {
26 | grid-column: span 2;
27 | }
28 |
--------------------------------------------------------------------------------
/src/components/Buttons.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import './Buttons.css';
3 |
4 | function Buttons({ handleClick }) {
5 | return (
6 | <>
7 |
8 | handleClick('AC')} id="AC" type="button">AC
9 | handleClick('+/-')} id="+/-" type="button">+/-
10 | handleClick('%')} id="%" type="button">%
11 | handleClick('÷')} id="div" type="button">/
12 | handleClick('7')} id="7" type="button">7
13 | handleClick('8')} id="8" type="button">8
14 | handleClick('9')} id="9" type="button">9
15 | handleClick('x')} id="mul" type="button">x
16 | handleClick('4')} id="4" type="button">4
17 | handleClick('5')} id="5" type="button">5
18 | handleClick('6')} id="6" type="button">6
19 | handleClick('-')} id="res" type="button">-
20 | handleClick('1')} id="1" type="button">1
21 | handleClick('2')} id="2" type="button">2
22 | handleClick('3')} id="3" type="button">3
23 | handleClick('+')} id="sum" type="button">+
24 | handleClick('0')} id="zero" type="button">0
25 | handleClick('.')} id="." type="button">.
26 | handleClick('=')} id="equal" type="button">=
27 |
28 | >
29 | );
30 | }
31 |
32 | Buttons.propTypes = {
33 | handleClick: PropTypes.func.isRequired,
34 | };
35 |
36 | export default Buttons;
37 |
--------------------------------------------------------------------------------
/src/components/Calculator.css:
--------------------------------------------------------------------------------
1 | .calc {
2 | width: 50%;
3 | margin: 15px 0;
4 | display: flex;
5 | flex-direction: column;
6 | background-color: #808080;
7 | }
8 |
9 | .result {
10 | margin: 5px 0;
11 | padding: 10px 5px;
12 | display: flex;
13 | justify-content: flex-end;
14 | color: #fff;
15 | font-size: 30px;
16 | background-color: #808080;
17 | }
18 |
--------------------------------------------------------------------------------
/src/components/Calculator.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import './Calculator.css';
3 | import Buttons from './Buttons';
4 | import calculate from '../logic/calculate';
5 |
6 | function Calculator() {
7 | const [calcRes, setOper] = useState({});
8 | const handleClick = (butName) => {
9 | const result = calculate(calcRes, butName);
10 | setOper(result);
11 | };
12 |
13 | return (
14 |
15 |
16 |
17 | { (JSON.stringify(calcRes) === '{}') ? '0' : null }
18 | {calcRes.total || ''}
19 | {calcRes.operation || ''}
20 | {calcRes.next || ''}
21 |
22 |
23 |
24 |
25 |
26 | );
27 | }
28 |
29 | export default Calculator;
30 |
--------------------------------------------------------------------------------
/src/components/navBar.css:
--------------------------------------------------------------------------------
1 | .NavBar {
2 | width: 100%;
3 | display: flex;
4 | justify-content: space-between;
5 | }
6 |
7 | .navTitle {
8 | margin: 0;
9 | padding: 0 0 0 20px;
10 | }
11 |
12 | .navItems {
13 | margin: 0;
14 | padding: 0 20px 0 0;
15 | list-style: none;
16 | display: flex;
17 | align-items: center;
18 | gap: 10px;
19 | }
20 |
--------------------------------------------------------------------------------
/src/components/navBar.js:
--------------------------------------------------------------------------------
1 | import './navBar.css';
2 | import { Link } from 'react-router-dom';
3 |
4 | function NavBar() {
5 | return (
6 | <>
7 |
8 |
Math Magicians
9 |
10 | Home
11 | |
12 | Calculator
13 | |
14 | Quote
15 |
16 |
17 | >
18 | );
19 | }
20 |
21 | export default NavBar;
22 |
--------------------------------------------------------------------------------
/src/components/quote.css:
--------------------------------------------------------------------------------
1 | .quote {
2 | width: 75%;
3 | margin: 15px 0;
4 | display: flex;
5 | text-align: center;
6 | }
7 |
--------------------------------------------------------------------------------
/src/components/quote.js:
--------------------------------------------------------------------------------
1 | import './quote.css';
2 | import { useEffect, useState } from 'react';
3 |
4 | function Quote() {
5 | const [quote, setQuote] = useState({});
6 | const [isLoaded, setIsLoaded] = useState(true);
7 | const [error, setError] = useState(false);
8 |
9 | const getQuote = async () => {
10 | const header = {
11 | 'X-Api-Key': 'Vm6ia/wNgoTh9/qxQLj/Gg==BwWcWYV2d97bnWwv',
12 | 'Content-type': 'application/json',
13 | };
14 |
15 | try {
16 | const response = await fetch('https://api.api-ninjas.com/v1/quotes?category=fear', { headers: header });
17 | const data = await response.json();
18 | setQuote(data);
19 | setIsLoaded(false);
20 | } catch {
21 | setError(true);
22 | setIsLoaded(false);
23 | }
24 | };
25 |
26 | useEffect(() => {
27 | getQuote();
28 | }, []);
29 |
30 | if (isLoaded) {
31 | return Loading...
;
32 | }
33 |
34 | if (error) {
35 | return Error
;
36 | }
37 |
38 | return (
39 |
40 |
41 | {quote[0]?.quote}
42 | {' - - '}
43 | {quote[0]?.author}
44 | {' - - '}
45 |
46 |
47 | );
48 | }
49 |
50 | export default Quote;
51 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | background-image: url('./assets/bg.jpg');
5 | font-family:
6 | -apple-system,
7 | BlinkMacSystemFont,
8 | 'Segoe UI',
9 | 'Roboto',
10 | 'Oxygen',
11 | 'Ubuntu',
12 | 'Cantarell',
13 | 'Fira Sans',
14 | 'Droid Sans',
15 | 'Helvetica Neue',
16 | sans-serif;
17 | -webkit-font-smoothing: antialiased;
18 | -moz-osx-font-smoothing: grayscale;
19 | }
20 |
21 | code {
22 | font-family:
23 | source-code-pro,
24 | Menlo,
25 | Monaco,
26 | Consolas,
27 | 'Courier New',
28 | monospace;
29 | }
30 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import { createBrowserRouter, RouterProvider } from 'react-router-dom';
4 | import './index.css';
5 | import HomePage from './routes/homePage';
6 | import CalculatorPage from './routes/calculatorPage';
7 | import QuotePage from './routes/quotePage';
8 |
9 | const router = createBrowserRouter([
10 | {
11 | path: '/',
12 | element: ,
13 | errorElement: 404
,
14 | },
15 | {
16 | path: '/calculator',
17 | element: ,
18 | },
19 | {
20 | path: '/quote',
21 | element: ,
22 | },
23 | ]);
24 |
25 | const root = ReactDOM.createRoot(document.getElementById('root'));
26 | root.render(
27 |
28 |
29 | ,
30 | );
31 |
--------------------------------------------------------------------------------
/src/logic/calculate.js:
--------------------------------------------------------------------------------
1 | import operate from './operate';
2 |
3 | function isNumber(item) {
4 | return !!item.match(/[0-9]+/);
5 | }
6 |
7 | /**
8 | * Given a button name and a calculator data object, return an updated
9 | * calculator data object.
10 | *
11 | * Calculator data object contains:
12 | * total:s the running total
13 | * next:String the next number to be operated on with the total
14 | * operation:String +, -, etc.
15 | */
16 | export default function calculate(obj, buttonName) {
17 | if (buttonName === 'AC') {
18 | return {
19 |
20 | };
21 | }
22 |
23 | if (isNumber(buttonName)) {
24 | if (buttonName === '0' && obj.next === '0') {
25 | return {};
26 | }
27 | // If there is an operation, update next
28 | if (obj.operation) {
29 | if (obj.next && obj.next !== '0') {
30 | return { ...obj, next: obj.next + buttonName };
31 | }
32 | return { ...obj, next: buttonName };
33 | }
34 | // If there is no operation, update next and clear the value
35 | if (obj.next && obj.next !== '0') {
36 | return {
37 | next: obj.next + buttonName,
38 | total: null,
39 | };
40 | }
41 | return {
42 | next: buttonName,
43 | total: null,
44 | };
45 | }
46 |
47 | if (buttonName === '.') {
48 | if (obj.next) {
49 | if (obj.next.includes('.')) {
50 | return { ...obj };
51 | }
52 | return { ...obj, next: `${obj.next}.` };
53 | }
54 | if (obj.operation) {
55 | return { ...obj, next: '0.' };
56 | }
57 | if (obj.total) {
58 | if (obj.total.includes('.')) {
59 | return {};
60 | }
61 | return { ...obj, next: `${obj.total}.` };
62 | }
63 | return { ...obj, next: '0.' };
64 | }
65 |
66 | if (buttonName === '=') {
67 | if (obj.next && obj.operation) {
68 | return {
69 | total: operate(obj.total, obj.next, obj.operation),
70 | next: null,
71 | operation: null,
72 | };
73 | }
74 | // '=' with no operation, nothing to do
75 | return {};
76 | }
77 |
78 | if (buttonName === '+/-') {
79 | if (obj.next) {
80 | return { ...obj, next: (-1 * parseFloat(obj.next)).toString() };
81 | }
82 | if (obj.total) {
83 | return { ...obj, total: (-1 * parseFloat(obj.total)).toString() };
84 | }
85 | return {};
86 | }
87 |
88 | // Button must be an operation
89 |
90 | // When the user presses an operation button without having entered
91 | // a number first, do nothing.
92 | // if (!obj.next && !obj.total) {
93 | // return {};
94 | // }
95 |
96 | // User pressed an operation after pressing '='
97 | if (!obj.next && obj.total && !obj.operation) {
98 | return { ...obj, operation: buttonName };
99 | }
100 |
101 | // User pressed an operation button and there is an existing operation
102 | if (obj.operation) {
103 | if (obj.total && !obj.next) {
104 | return { ...obj, operation: buttonName };
105 | }
106 |
107 | if (!obj.total) {
108 | return { total: 0, operation: buttonName };
109 | }
110 |
111 | return {
112 | total: operate(obj.total, obj.next, obj.operation),
113 | next: null,
114 | operation: buttonName,
115 | };
116 | }
117 |
118 | // no operation yet, but the user typed one
119 |
120 | // The user hasn't typed a number yet, just save the operation
121 | if (!obj.next) {
122 | return { operation: buttonName };
123 | }
124 |
125 | // save the operation and shift 'next' into 'total'
126 | return {
127 | total: obj.next,
128 | next: null,
129 | operation: buttonName,
130 | };
131 | }
132 |
--------------------------------------------------------------------------------
/src/logic/operate.js:
--------------------------------------------------------------------------------
1 | import Big from 'big.js';
2 |
3 | export default function operate(numberOne, numberTwo, operation) {
4 | const one = Big(numberOne);
5 | const two = Big(numberTwo);
6 | if (operation === '+') {
7 | return one.plus(two).toString();
8 | }
9 | if (operation === '-') {
10 | return one.minus(two).toString();
11 | }
12 | if (operation === 'x') {
13 | return one.times(two).toString();
14 | }
15 | if (operation === '÷') {
16 | try {
17 | return one.div(two).toString();
18 | } catch (err) {
19 | return "Can't divide by 0.";
20 | }
21 | }
22 | if (operation === '%') {
23 | try {
24 | return one.mod(two).toString();
25 | } catch (err) {
26 | return "Can't find modulo as can't divide by 0.";
27 | }
28 | }
29 | throw Error(`Unknown operation '${operation}'`);
30 | }
31 |
--------------------------------------------------------------------------------
/src/routes/calcuatorPage.css:
--------------------------------------------------------------------------------
1 | .containerCalculator {
2 | height: 100vh;
3 | background-color: #ffffffe6;
4 | }
5 |
6 | .itemsCalc {
7 | padding: 0 20px;
8 | display: flex;
9 | justify-content: space-between;
10 | gap: 50px;
11 | }
12 |
--------------------------------------------------------------------------------
/src/routes/calculatorPage.js:
--------------------------------------------------------------------------------
1 | import './calcuatorPage.css';
2 | import NavBar from '../components/navBar';
3 | import Calculator from '../components/Calculator';
4 |
5 | function CalculatorPage() {
6 | return (
7 |
8 |
9 |
10 |
Lets do some math!
11 |
12 |
13 |
14 | );
15 | }
16 |
17 | export default CalculatorPage;
18 |
--------------------------------------------------------------------------------
/src/routes/homePage.css:
--------------------------------------------------------------------------------
1 | .containerHome {
2 | height: 100vh;
3 | background-color: #ffffffe6;
4 | }
5 |
6 | .titleHome {
7 | padding: 20px;
8 | }
9 |
10 | .pharHome {
11 | padding: 20px;
12 | text-align: justify;
13 | }
14 |
--------------------------------------------------------------------------------
/src/routes/homePage.js:
--------------------------------------------------------------------------------
1 | import './homePage.css';
2 | import NavBar from '../components/navBar';
3 |
4 | function HomePage() {
5 | return (
6 |
7 |
8 |
Welcome to our page
9 |
10 | Lorem ipsum dolor sit amet consectetur, adipisicing elit.
11 | Inventore, porro provident dignissimos
12 | incidunt delectus sequi iste minus rem exercitationem
13 | debitis, laudantium molestias modi deleniti?
14 | Inventore eum qui quidem necessitatibus cum?
15 | Lorem ipsum dolor sit amet consectetur, adipisicing elit.
16 | Inventore, porro provident dignissimos
17 | incidunt delectus sequi iste minus rem exercitationem
18 | debitis, laudantium molestias modi deleniti?
19 | Inventore eum qui quidem necessitatibus cum?
20 |
21 |
22 | Lorem ipsum dolor sit amet consectetur, adipisicing elit.
23 | Inventore, porro provident dignissimos
24 | incidunt delectus sequi iste minus rem exercitationem
25 | debitis, laudantium molestias modi deleniti?
26 | Inventore eum qui quidem necessitatibus cum?
27 | Lorem ipsum dolor sit amet consectetur, adipisicing elit.
28 | Inventore, porro provident dignissimos
29 | incidunt delectus sequi iste minus rem exercitationem
30 | debitis, laudantium molestias modi deleniti?
31 | Inventore eum qui quidem necessitatibus cum?
32 |
33 |
34 | );
35 | }
36 |
37 | export default HomePage;
38 |
--------------------------------------------------------------------------------
/src/routes/quotePage.css:
--------------------------------------------------------------------------------
1 | .containerQuote {
2 | height: 100vh;
3 | background-color: #ffffffe6;
4 | }
5 |
6 | .itemsQuote {
7 | padding: 50px 20px;
8 | display: flex;
9 | justify-content: center;
10 | gap: 50px;
11 | }
12 |
--------------------------------------------------------------------------------
/src/routes/quotePage.js:
--------------------------------------------------------------------------------
1 | import './quotePage.css';
2 | import NavBar from '../components/navBar';
3 | import Quote from '../components/quote';
4 |
5 | function QuotePage() {
6 | return (
7 |
13 | );
14 | }
15 |
16 | export default QuotePage;
17 |
--------------------------------------------------------------------------------