├── .github
└── app-screenshot.png
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
└── manifest.json
├── src
├── assets
│ └── logo.svg
├── components
│ ├── PageTemplate.jsx
│ ├── Whoops404.jsx
│ ├── data-visualization
│ │ ├── BarChart
│ │ │ ├── bar-chart.scss
│ │ │ └── index.jsx
│ │ ├── SectionTemplate.jsx
│ │ ├── index.jsx
│ │ └── routes.jsx
│ ├── front-end-libraries
│ │ ├── PomodoroClock
│ │ │ ├── clock.scss
│ │ │ ├── components.jsx
│ │ │ ├── container.js
│ │ │ ├── index.jsx
│ │ │ └── redux.js
│ │ ├── SectionTemplate.jsx
│ │ ├── index.jsx
│ │ └── routes.jsx
│ ├── index.js
│ ├── javascript-algorithms
│ │ └── index.jsx
│ ├── responsive-web-design
│ │ └── index.jsx
│ └── routes.jsx
├── helpers
│ └── helperFunctions.js
├── index.js
├── index.scss
├── redux
│ ├── middleware.js
│ ├── rootReducer.js
│ ├── state.js
│ └── store.js
├── routes.js
├── tests
│ └── App.test.js
└── workers
│ └── registerServiceWorker.js
└── yarn.lock
/.github/app-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cristianCeamatu/freecodecamp-reactjs-projects/c5012fef06383e553839ab93ce28b94b4ec8dbaf/.github/app-screenshot.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # Using scss, good practice to keep the build products outside of the source control
10 | src/**/*.css
11 |
12 | # production
13 | /build
14 |
15 | # misc
16 | .DS_Store
17 | .env.local
18 | .env.development.local
19 | .env.test.local
20 | .env.production.local
21 |
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # The purpose of this single page application is to bring together all the projects that I built while getting the Freecodecamp qualifications so the employers can visualize easier my work.
2 |
3 | > The website is not finished and its purpose is to move all the web app I created will following the Freecodecamp modules. The web app is created with React and Redux using the `create-react-app` and its purpose is to help my increase my knowledge of using Redux state and Router in a complex app.
4 |
5 | 
6 |
7 | > I decided to build this webiste so I can showcase all the projects that I created while getting the Freecodecamp diplomas for Responsive Web Design, Javascript Algorithms, Front End Libraries, and Data Visualization.
8 |
9 | ## Potential future features
10 |
11 | I still need to add the following projects that I developed using codepen.io (please check them out):
12 | - [React Redux Calculator](https://codepen.io/crisDevMM/full/ZjqKza)
13 | - [React Redux Markdown Previewer](https://codepen.io/crisDevMM/full/pZJQXR)
14 | - [Portofolio](https://codepen.io/crisDevMM/full/PaVEXW)
15 | - [Technical documentation page](https://codepen.io/crisDevMM/full/VdgvXE)
16 | - [Twitch streamers using the twitch api](https://codepen.io/crisDevMM/full/jaYKXP)
17 | - [Wikipedia viewer using the Wikipedia api](https://codepen.io/crisDevMM/full/LzRpEW)
18 | - [Tribute page](https://codepen.io/crisDevMM/full/ayPwab)
19 |
20 | ## Built With
21 |
22 | - React,
23 | - Redux,
24 | - Html,
25 | - Css,
26 | - jquery,
27 | - Api
28 |
29 | To get a local copy up and running follow these simple example steps.
30 |
31 | ### Setup
32 |
33 | Clone the project locally and run `npm install` in both project and client directories.
34 |
35 | ## Available Scripts
36 |
37 | In the project directory, you can run:
38 |
39 | ### `npm start`
40 |
41 | Local: http://localhost:3000/(http://localhost:3000)
42 | On Your Network: http://192.168.56.1:3000/(http://192.168.56.1:3000/)
43 |
44 | The page will reload if you make edits and will sync with other connected devices.
45 | You will also see any lint errors in the console.
46 |
47 | ### `npm run build` from the client folder
48 |
49 | Builds the app for production to the `build` folder.
50 | It correctly bundles React in production mode and optimizes the build for the best performance.
51 |
52 | The build is minified and the filenames include the hashes.
53 | Your app is ready to be deployed!
54 |
55 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
56 |
57 | ### `npm run eject` from the client folder
58 |
59 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
60 |
61 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
62 |
63 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
64 |
65 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
66 |
67 |
68 | ## Authors
69 |
70 | 👤 **Cristian Viorel Ceamatu**
71 |
72 | - Github: [@githubhandle](https://github.com/cristianCeamatu)
73 | - Twitter: [@twitterhandle](https://twitter.com/CristianCeamatu)
74 | - Linkedin: [linkedin](https://www.linkedin.com/in/ceamatu-cristian/)
75 |
76 |
77 | ## Show your support
78 |
79 | Give a ⭐️ if you like this project!
80 |
81 |
82 | ## 📝 License
83 |
84 | This project is [MIT](lic.url) licensed.
85 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "FreecodecampProjects",
3 | "homepage": "http://cristian.devmm.net/freecodecamp/",
4 | "version": "0.1.0",
5 | "private": true,
6 | "dependencies": {
7 | "accurate-interval": "^1.0.9",
8 | "d3": "^5.5.0",
9 | "node-sass-chokidar": "^1.3.3",
10 | "npm-run-all": "^4.1.3",
11 | "react": "^16.4.2",
12 | "react-dom": "^16.4.2",
13 | "react-icons": "^3.0.5",
14 | "react-redux": "^5.0.7",
15 | "react-router": "^4.3.1",
16 | "react-router-dom": "^4.3.1",
17 | "react-scripts": "1.1.4",
18 | "redux": "^4.0.0",
19 | "redux-thunk": "^2.3.0"
20 | },
21 | "scripts": {
22 | "build-css": "node-sass-chokidar src/ -o src/",
23 | "watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive --usePolling --polling-interval 500",
24 | "start-js": "react-scripts start",
25 | "start": "npm-run-all -p watch-css start-js",
26 | "build-js": "react-scripts build",
27 | "build": "npm-run-all build-css build-js",
28 | "test": "react-scripts test --env=jsdom",
29 | "eject": "react-scripts eject"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cristianCeamatu/freecodecamp-reactjs-projects/c5012fef06383e553839ab93ce28b94b4ec8dbaf/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
14 |
15 |
16 |
25 | crisDevMM Portofolio
26 |
27 |
28 |
29 | You need to enable JavaScript to run this app.
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "PomoClock",
3 | "name": "Pomodoro clock for Freecodecamp projects",
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 |
--------------------------------------------------------------------------------
/src/assets/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/components/PageTemplate.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { FaHome } from 'react-icons/fa'
3 | import { NavLink } from 'react-router-dom'
4 |
5 | const MainNav = () =>
6 |
7 |
8 |
9 |
10 | Responsive Web Design
11 | Javascript Algorithms
12 | Front End Libraries
13 | Data Visualization
14 |
15 |
16 | export default ({children}) =>
17 |
18 |
19 | {children}
20 |
--------------------------------------------------------------------------------
/src/components/Whoops404.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import logo from '../assets/logo.svg'
3 | import PageTemplate from './PageTemplate'
4 |
5 | export default ({location}) =>
6 |
7 |
8 |
9 |
10 |
11 | Resource not found at "{location.pathname}". The address you entered is not valid
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/src/components/data-visualization/BarChart/bar-chart.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cristianCeamatu/freecodecamp-reactjs-projects/c5012fef06383e553839ab93ce28b94b4ec8dbaf/src/components/data-visualization/BarChart/bar-chart.scss
--------------------------------------------------------------------------------
/src/components/data-visualization/BarChart/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import './bar-chart.css'
3 | import {FaChartBar} from 'react-icons/fa'
4 | import SectionTemplate from '../SectionTemplate'
5 | import * as d3 from 'd3'
6 | import {getJSON} from '../../../helpers/helperFunctions'
7 |
8 |
9 | export default ({location}) => {
10 | const title = location.pathname.split('/')[2].split('-').join(' ')
11 | var state2 = {}
12 | //d3.json('https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json').then(data => {state = data})
13 | getJSON('https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json').then(
14 | data => {
15 | d3.select('ul').selectAll('li')
16 | .data(data.data)
17 | .enter()
18 | .append('li')
19 | .text(d => `${d[0]} --- ${d[1]}`)
20 | },
21 | error => {
22 |
23 | })
24 | console.log(state2)
25 |
26 |
27 |
28 | return (
29 |
30 |
31 |
32 | This page contains the {title} project
33 |
34 |
39 |
40 | )
41 | }
--------------------------------------------------------------------------------
/src/components/data-visualization/SectionTemplate.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { FaChartLine } from 'react-icons/fa'
3 | import { NavLink } from 'react-router-dom'
4 |
5 | const Menu = () =>
6 |
7 |
8 |
9 |
10 | Bar Chart
11 |
12 |
13 | export default ({children}) =>
14 |
15 |
16 | {children}
17 |
18 |
--------------------------------------------------------------------------------
/src/components/data-visualization/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import logo from '../../assets/logo.svg'
3 | import SectionTemplate from './SectionTemplate'
4 |
5 | export default ({ location }) => {
6 | const title = location.pathname.split('-').join(' ').slice(1)
7 | return (
8 |
9 |
10 |
11 |
12 | Freecodecamp {title} projects
13 |
14 |
15 |
16 | This page contains the required projects by Freecodecamp in order to receive the {title} certification.
17 |
18 | Click on the project below or use the navigation
19 |
20 |
21 |
22 | )
23 | }
--------------------------------------------------------------------------------
/src/components/data-visualization/routes.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Route} from 'react-router-dom'
3 | import PageTemplate from '../PageTemplate'
4 | import DataVisualization from './'
5 | import BarChart from './BarChart'
6 |
7 |
8 | export default () =>
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/components/front-end-libraries/PomodoroClock/clock.scss:
--------------------------------------------------------------------------------
1 | $theme-color: #2e3951;
2 |
3 | #PomodoroClock, button {
4 | background:
5 | linear-gradient(27deg, #151515 5px, transparent 5px) 0 5px,
6 | linear-gradient(207deg, #151515 5px, transparent 5px) 10px 0px,
7 | linear-gradient(27deg, #222 5px, transparent 5px) 0px 10px,
8 | linear-gradient(207deg, #222 5px, transparent 5px) 10px 5px,
9 | linear-gradient(90deg, #1b1b1b 10px, transparent 10px),
10 | linear-gradient(#1d1d1d 25%, #1a1a1a 25%, #1a1a1a 50%, transparent 50%, transparent 75%, #242424 75%, #242424);
11 | background-color: #131313;
12 | background-size: 20px 20px;
13 | }
14 | #display {
15 | box-shadow: inset -12px -8px 40px #464646;
16 | background-color: #6d695c;
17 | background-image:
18 | repeating-linear-gradient(120deg, rgba(255,255,255,.1), rgba(255,255,255,.1) 1px, transparent 1px, transparent 60px),
19 | repeating-linear-gradient(60deg, rgba(255,255,255,.1), rgba(255,255,255,.1) 1px, transparent 1px, transparent 60px),
20 | linear-gradient(60deg, rgba(0,0,0,.1) 25%, transparent 25%, transparent 75%, rgba(0,0,0,.1) 75%, rgba(0,0,0,.1)),
21 | linear-gradient(120deg, rgba(0,0,0,.1) 25%, transparent 25%, transparent 75%, rgba(0,0,0,.1) 75%, rgba(0,0,0,.1));
22 | background-size: 70px 120px;
23 | }
24 | #PomodoroClock {
25 | box-shadow: 5px 5px rgba(0, 0, 0, 0.4),
26 | 10px 10px rgba(0, 0, 0, 0.3),
27 | 15px 15px rgba(0, 0, 0, 0.2),
28 | 20px 20px rgba(0, 0, 0, 0.1),
29 | 25px 25px rgba(0, 0, 0, 0.05);
30 | font-size: 24px;
31 | font-weight: 700;
32 | position: relative;
33 | width: 500px;
34 | height: 500px;
35 | margin: 50px auto;
36 | border-radius: 50%;
37 | display: flex;
38 | flex-direction: column;
39 | align-items: space-between;
40 | justify-content: space-around;
41 | .sessionSection, .breakSection, .togglersSection {
42 | width: 100%;
43 | display: flex;
44 | flex-direction: row;
45 | justify-content: space-between;
46 | align-items: center;
47 | text-align: center;
48 | button {
49 | border-radius: 10px;
50 | color: white;
51 | border: 0;
52 | outline: none;
53 | height: 40px;
54 | width: 50px;
55 | z-index: 99;
56 | i {
57 | position: absolute;
58 | top: 3px;
59 | right: 18px;
60 | z-index: -1;
61 | }
62 | }
63 | .labels {
64 | position: relative;
65 | top: -30px;
66 | color: white;
67 | }
68 | }
69 | .breakSection {
70 | position: relative;
71 | #break-decrement, #break-increment {
72 | transform: rotate(-55deg);
73 | position: relative;
74 | left: 15px;
75 |
76 | }
77 | #break-increment {
78 | transform: rotate(55deg);
79 | left: -15px;
80 | &:focus {
81 | animation: incrementClicked 0.1s linear;
82 | }
83 | }
84 | #break-decrement:focus {
85 | animation: decrementClicked 0.1s linear;
86 | }
87 | }
88 | .sessionSection {
89 | position: relative;
90 | top: -30px;
91 | #session-increment, #session-decrement {
92 | position: relative;
93 | transform: rotate(75deg);
94 | top: -40px;
95 | right: -12px;
96 | }
97 | #session-decrement {
98 | transform: rotate(-75deg);
99 | right: 12px;
100 | &:focus {
101 | animation: sessionDecrement 0.1s linear;
102 | }
103 | }
104 | #session-increment:focus {
105 | animation: sessionIncrement 0.1s linear;
106 | }
107 | }
108 | }
109 | .togglersSection {
110 | #start_stop, #reset {
111 | transform: rotate(-45deg);
112 | position: relative;
113 | top: 40px;
114 | left: 60px;
115 | transition: all 0.1s linear
116 | }
117 | #reset {
118 | transform: rotate(45deg);
119 | left: -60px;
120 | }
121 | #start_stop.active {
122 | left: 65px;
123 | top: 45px;
124 | }
125 | #reset:focus {
126 | animation: resetClicked 0.1s linear;
127 | }
128 | #start_stop::before, #reset::before {
129 | content: '';
130 | display: block;
131 | background: red;
132 | width: 30px;
133 | height: 5px;
134 | position: absolute;
135 | top: -5px;
136 | left: 50%;
137 | margin-left: -15px;
138 |
139 | }
140 | }
141 | #display {
142 | display: block;
143 | text-align: center;
144 | padding:5px 40px;
145 | border-radius: 10px;
146 | margin: 10px auto;
147 | width: 250px;
148 | position: relative;
149 | top: -60px;
150 | &.danger {
151 | border: 3px solid #ff4444;
152 | color: #ff4444;
153 | }
154 | }
155 |
156 | @keyframes incrementClicked {
157 | 0% {
158 | left: -15px;
159 | }
160 | 50% {
161 | left: -20px;
162 | }
163 | 100% {
164 | left: -15px;
165 | }
166 | }
167 |
168 | @keyframes decrementClicked {
169 | 0% {
170 | left: 15px;
171 | }
172 | 50% {
173 | left: 20px;
174 | }
175 | 100% {
176 | left: 15px;
177 | }
178 | }
179 |
180 | @keyframes sessionIncrement {
181 | 0% {
182 | right: -12px;
183 | }
184 | 50% {
185 | right: -7px;
186 | }
187 | 100% {
188 | right: -12px;
189 | }
190 | }
191 |
192 | @keyframes sessionDecrement {
193 | 0% {
194 | right: 12px;
195 | }
196 | 50% {
197 | right: 7px;
198 | }
199 | 100% {
200 | right: 12px;
201 | }
202 | }
203 |
204 |
205 | @keyframes resetClicked {
206 | 50% {
207 | left: -70px;
208 | top: 45px;
209 | }
210 | 100% {
211 | left: -60px;
212 | top: 40px;
213 | }
214 | }
--------------------------------------------------------------------------------
/src/components/front-end-libraries/PomodoroClock/components.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {intToMMSS} from '../../../helpers/helperFunctions.js'
3 |
4 | export const BreakSection = ({breakLength, onIncrementBreak, onDecrementBreak}) => {
5 | return (
6 |
7 | onDecrementBreak()}>
10 |
11 |
12 |
13 | Break
14 | {breakLength}
15 |
16 | onIncrementBreak()}>
19 |
20 |
21 |
22 | )
23 | }
24 |
25 | export const SessionSection = ({sessionLength, onIncrementSession, onDecrementSession}) => {
26 | return (
27 |
28 | onDecrementSession()}>
31 |
32 |
33 |
34 | Session
35 | {sessionLength}
36 |
37 | onIncrementSession()}>
40 |
41 |
42 |
43 | )
44 | }
45 |
46 | export const TogglersSection = ({active, onStartStop, onReset}) => {
47 | return (
48 |
49 | onStartStop(active)}>
53 |
54 |
55 | onReset()}
58 | tabIndex="0">
59 |
60 |
61 |
62 | )
63 | }
64 |
65 | export const DisplaySection = ({timeLeftType, timeLeft}) => {
66 | return (
67 |
68 |
70 |
{timeLeftType}
71 |
{intToMMSS(timeLeft)}
72 |
73 |
79 |
80 | )
81 | }
82 |
83 |
--------------------------------------------------------------------------------
/src/components/front-end-libraries/PomodoroClock/container.js:
--------------------------------------------------------------------------------
1 | import {connect} from 'react-redux'
2 | import {BreakSection, SessionSection, DisplaySection, TogglersSection} from './components'
3 | import {decrementBreak, incrementBreak, decrementSession, incrementSession, startStop, reset, tick} from './redux'
4 | import accurateInterval from 'accurate-interval'
5 |
6 | export const BreakMenu = connect(
7 | state => ({
8 | breakLength: state.pomodoroClock.breakLength
9 | }),
10 | dispatch => ({
11 | onDecrementBreak() {
12 | dispatch(decrementBreak())
13 | },
14 | onIncrementBreak() {
15 | dispatch(incrementBreak())
16 | }
17 | }))(BreakSection)
18 |
19 | export const SessionMenu = connect(
20 | state => ({
21 | sessionLength: state.pomodoroClock.sessionLength
22 | }),
23 | dispatch => ({
24 | onDecrementSession() {
25 | dispatch(decrementSession())
26 | },
27 | onIncrementSession() {
28 | dispatch(incrementSession())
29 | }
30 | }))(SessionSection)
31 |
32 | export const Display = connect(
33 | state => ({
34 | timeLeft: state.pomodoroClock.timeLeft,
35 | timeLeftType: state.pomodoroClock.timeLeftType,
36 | active: state.pomodoroClock.active
37 | }),
38 | null
39 | )(DisplaySection)
40 |
41 | // For clearing the interval
42 | let timer = null
43 | export const Togglers = connect(
44 | state => ({
45 | active: state.pomodoroClock.active
46 | }),
47 | dispatch => ({
48 | onReset() {
49 | timer && timer.clear()
50 | const sound = document.getElementById('beep')
51 | sound.pause()
52 | sound.currentTime = 0
53 | dispatch(reset())
54 | },
55 | onStartStop(status) {
56 | if (status === false) {
57 | timer && timer.clear()
58 | timer = accurateInterval(() => dispatch(tick()), 1000)
59 | } else {
60 | timer.clear()
61 | }
62 | dispatch(startStop())
63 | }
64 | })
65 | )(TogglersSection)
66 |
67 |
--------------------------------------------------------------------------------
/src/components/front-end-libraries/PomodoroClock/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import './clock.css'
3 | import {FaClock} from 'react-icons/fa'
4 | import {BreakMenu, SessionMenu, Display, Togglers} from './container'
5 | import SectionTemplate from '../SectionTemplate'
6 |
7 | export default ({location}) => {
8 | const title = location.pathname.split('/')[2].split('-').join(' ')
9 | return (
10 |
11 |
12 |
13 | This page contains the {title} project
14 |
15 |
16 |
22 |
23 |
24 | )
25 | }
--------------------------------------------------------------------------------
/src/components/front-end-libraries/PomodoroClock/redux.js:
--------------------------------------------------------------------------------
1 | import store from '../../../redux/store'
2 |
3 | //Defining initial state
4 | export const initialState = {
5 | breakLength: 5,
6 | sessionLength: 25,
7 | active: false,
8 | timeLeft: 1500,
9 | timeLeftType: 'Session'
10 | }
11 |
12 | // Defining constants
13 | const Types = {
14 | BREAKINCREMENT: 'BREAKINCREMENT',
15 | BREAKDECREMENT: 'BREAKDECREMENT',
16 | SESSIONINCREMENT: 'SESSIONINCREMENT',
17 | SESSIONDECREMENT: 'SESSIONDECREMENT',
18 | STARTSTOP: 'STARTSTOP',
19 | TICK: 'TICK',
20 | RESET: 'RESET'
21 | }
22 |
23 | // Defining actions
24 | export const incrementBreak = () => {
25 | return {
26 | type: Types.BREAKINCREMENT
27 | }
28 | }
29 |
30 | export const decrementBreak = () => {
31 | return {
32 | type: Types.BREAKDECREMENT
33 | }
34 | }
35 |
36 | export const incrementSession = () => {
37 | return {
38 | type: Types.SESSIONINCREMENT
39 | }
40 | }
41 | export const decrementSession = () => {
42 | return {
43 | type: Types.SESSIONDECREMENT
44 | }
45 | }
46 |
47 | export const reset = () => {
48 | return {
49 | type: Types.RESET
50 | }
51 | }
52 |
53 | export const startStop = () => {
54 | return {
55 | type: Types.STARTSTOP
56 | }
57 | }
58 |
59 | export const tick = () => {
60 | return {
61 | type: Types.TICK
62 | }
63 | }
64 |
65 | // Defining reducers
66 | export const reducer = (state = {}, action) => {
67 | switch(action.type) {
68 | case Types.BREAKINCREMENT:
69 | return (state.breakLength !== 60 && !state.active) ?
70 | (state.timeLeftType === 'Break') ?
71 | {
72 | ...state,
73 | breakLength: state.breakLength + 1,
74 | timeLeft: (state.breakLength + 1) * 60
75 | } : {
76 | ...state,
77 | breakLength: state.breakLength + 1,
78 | }
79 | : state
80 | case Types.BREAKDECREMENT:
81 | return (state.breakLength !== 1 && !state.active) ?
82 | (state.timeLeftType === 'Break') ?
83 | {
84 | ...state,
85 | breakLength: state.breakLength - 1,
86 | timeLeft: (state.breakLength - 1) * 60
87 | } : {
88 | ...state,
89 | breakLength: state.breakLength - 1,
90 | }
91 | : state
92 | case Types.SESSIONINCREMENT:
93 | return (state.sessionLength !== 60 && !state.active) ?
94 | (state.timeLeftType === 'Session') ?
95 | {
96 | ...state,
97 | sessionLength: state.sessionLength + 1,
98 | timeLeft: (state.sessionLength + 1) * 60
99 | } : {
100 | ...state,
101 | sessionLength: state.sessionLength + 1,
102 | }
103 | : state
104 | case Types.SESSIONDECREMENT:
105 | return (state.sessionLength !== 1 && !state.active) ?
106 | (state.timeLeftType === 'Session') ?
107 | {
108 | ...state,
109 | sessionLength: state.sessionLength - 1,
110 | timeLeft: (state.sessionLength - 1) * 60
111 | } : {
112 | ...state,
113 | sessionLength: state.sessionLength - 1,
114 | }
115 | : state
116 | case Types.STARTSTOP:
117 | return (state.active) ?
118 | {
119 | ...state,
120 | active: false,
121 | } :
122 | {
123 | ...state,
124 | active: true
125 | }
126 | case Types.TICK:
127 | return (state.timeLeft === 0) ?
128 | (state.timeLeftType === 'Session') ?
129 | {
130 | ...state,
131 | timeLeftType: 'Break',
132 | timeLeft: state.breakLength * 60
133 | } :
134 | {
135 | ...state,
136 | timeLeftType: 'Session',
137 | timeLeft: state.sessionLength * 60
138 | }
139 | :
140 | {
141 | ...state,
142 | timeLeft: state.timeLeft - 1
143 | }
144 | case Types.RESET:
145 | return {
146 | ...state,
147 | breakLength: 5,
148 | sessionLength: 25,
149 | timeLeft: 1500,
150 | timeLeftType: 'Session',
151 | countdown: false,
152 | active: false
153 | }
154 | default:
155 | return state
156 | }
157 | }
158 |
159 |
160 | // Middlewares
161 | export const focusRemover = store => next => action => {
162 | // Give the document focus
163 | window.focus();
164 |
165 | // Remove focus from any focused element for the css animation to work
166 | if (document.activeElement) {
167 | document.activeElement.blur();
168 | }
169 | next(action)
170 | }
171 |
172 | export const beepPlayer = state => next => action => {
173 | if (store.getState().pomodoroClock.timeLeft === 0) {
174 | const sound = document.getElementById('beep')
175 | sound.play()
176 | }
177 | next(action)
178 | }
179 |
180 | export const middleware = [focusRemover, beepPlayer]
--------------------------------------------------------------------------------
/src/components/front-end-libraries/SectionTemplate.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { FaRocket } from 'react-icons/fa'
3 | import { NavLink } from 'react-router-dom'
4 |
5 | const Menu = () =>
6 |
7 |
8 |
9 |
10 | Pomodoro Clock
11 |
12 |
13 | export default ({children}) =>
14 |
15 |
16 | {children}
17 |
18 |
--------------------------------------------------------------------------------
/src/components/front-end-libraries/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import logo from '../../assets/logo.svg'
3 | import SectionTemplate from './SectionTemplate'
4 |
5 | export default ({location}) => {
6 | const title = location.pathname.split('/')[1].split('-').join(' ')
7 | return (
8 |
9 |
10 |
11 | Freecodecamp {title} projects
12 |
13 |
14 |
15 | This page contains the required projects by Freecodecamp in order to receive the {title} certification.
16 |
17 | Click on the project below or use the navigation
18 |
19 |
20 | )
21 | }
--------------------------------------------------------------------------------
/src/components/front-end-libraries/routes.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {Route} from 'react-router-dom'
3 | import PageTemplate from '../PageTemplate'
4 | import FrontEndLibraries from './index'
5 | import PomodoroClock from './PomodoroClock'
6 |
7 |
8 | export default () =>
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/components/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import logo from '../assets/logo.svg'
3 | import PageTemplate from './PageTemplate'
4 |
5 | export default () =>
6 |
7 |
8 |
9 |
10 | Welcome to ReactRedux and Scss Freecodecamp projects
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/components/javascript-algorithms/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import logo from '../../assets/logo.svg'
3 | import PageTemplate from '../PageTemplate'
4 |
5 | export default ({ location }) => {
6 | const title = location.pathname.split('-').join(' ').slice(1)
7 | return (
8 |
9 |
10 |
11 |
12 | Freecodecamp {title} projects
13 |
14 |
15 |
16 | This page contains the required projects by Freecodecamp in order to receive the {title} certification.
17 |
18 | Click on the project below or use the navigation
19 |
20 |
21 |
22 | )
23 | }
--------------------------------------------------------------------------------
/src/components/responsive-web-design/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import logo from '../../assets/logo.svg'
3 | import PageTemplate from '../PageTemplate'
4 |
5 | export default ({ location }) => {
6 | const title = location.pathname.split('-').join(' ').slice(1)
7 | return (
8 |
9 |
10 |
11 |
12 | Freecodecamp {title} projects
13 |
14 |
15 |
16 | This page contains the required projects by Freecodecamp in order to receive the {title} certification.
17 |
18 | Click on the project below or use the navigation
19 |
20 |
21 |
22 | )
23 | }
--------------------------------------------------------------------------------
/src/components/routes.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {BrowserRouter, Route, Switch} from 'react-router-dom'
3 | import Homepage from './index'
4 | import FrontEndLibrariesRoutes from './front-end-libraries/routes'
5 | import DataVisualizationRoutes from './data-visualization/routes'
6 | import ResponsiveWebDesign from './responsive-web-design'
7 | import JavascriptAlgorithms from './javascript-algorithms'
8 | import Whoops404 from './Whoops404'
9 |
10 |
11 | export default () =>
12 |
13 |
14 |
15 |
16 | .
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/helpers/helperFunctions.js:
--------------------------------------------------------------------------------
1 | export const intToMMSS = (integer) => {
2 | let minutes = Math.floor(integer / 60)
3 | let seconds = integer - (minutes * 60)
4 | minutes = (minutes < 10) ? '0' + minutes.toString() : minutes
5 | seconds = (seconds < 10) ? '0' + seconds.toString() : seconds
6 | return `${minutes}:${seconds}`
7 | }
8 |
9 | export const getJSON = (url) => new Promise((resolves, rejects) => {
10 | const request = new XMLHttpRequest()
11 | request.open('GET', url)
12 | request.onload = () => (request.status === 200) ?
13 | resolves(JSON.parse(request.response))
14 | :
15 | rejects(Error(request.statusText))
16 | request.onerror = err => rejects(err)
17 | request.send()
18 | })
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom'
3 | import {Provider} from 'react-redux'
4 | import './index.css'
5 | import store from './redux/store'
6 | import AppRoutes from './components/routes'
7 |
8 | ReactDOM.render(
9 |
10 |
11 | , document.getElementById('root'))
--------------------------------------------------------------------------------
/src/index.scss:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
7 | .capitalize {
8 | text-transform: capitalize;
9 | }
10 |
11 | .App-logo {
12 | animation: App-logo-spin infinite 5s linear;
13 | height: 80px;
14 | &.no-animation {
15 | animation: none;
16 | }
17 | }
18 |
19 |
20 | .App-header {
21 | background-color: #222;
22 | height: auto;
23 | padding: 30px;
24 | color: white;
25 | display: flex;
26 | flex-direction: row;
27 | }
28 |
29 | .App-title {
30 | font-size: 1.5em;
31 | align-self: center;
32 | }
33 |
34 | .App-intro {
35 | font-size: large;
36 | }
37 |
38 | @keyframes App-logo-spin {
39 | from { transform: rotate(0deg); }
40 | to { transform: rotate(360deg); }
41 | }
42 |
43 | .main-menu {
44 | padding: 5px;
45 | padding-left: 0;
46 | a, a:hover, a:active, a:focus {
47 | text-decoration: none;
48 | outline: none;
49 | color: #222;
50 | padding: 10px;
51 | border-radius: 2%;
52 | }
53 | .active, .active:hover, .active:active, .active:focus {
54 | background: #222;
55 | color: white;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/redux/middleware.js:
--------------------------------------------------------------------------------
1 |
2 | import { middleware as pomodoroClockMiddleware } from '../components/front-end-libraries/PomodoroClock/redux'
3 |
4 |
5 |
6 | export default [...pomodoroClockMiddleware]
--------------------------------------------------------------------------------
/src/redux/rootReducer.js:
--------------------------------------------------------------------------------
1 | import {combineReducers} from 'redux'
2 | import {reducer as pomodoroClockReducer} from '../components/front-end-libraries/PomodoroClock/redux'
3 |
4 |
5 | export default combineReducers(
6 | {
7 | pomodoroClock: pomodoroClockReducer
8 | }
9 | )
--------------------------------------------------------------------------------
/src/redux/state.js:
--------------------------------------------------------------------------------
1 | import {initialState as pomodoroClockInitialState} from '../components/front-end-libraries/PomodoroClock/redux'
2 |
3 | export default {
4 | pomodoroClock: pomodoroClockInitialState
5 | }
--------------------------------------------------------------------------------
/src/redux/store.js:
--------------------------------------------------------------------------------
1 | import {
2 | createStore,
3 | applyMiddleware,
4 | } from 'redux'
5 | import middleware from './middleware'
6 | import initialState from './state'
7 | import rootReducer from './rootReducer'
8 |
9 |
10 | const storeFactory = (state = initialState) =>
11 | applyMiddleware(...middleware)(createStore)(rootReducer, state)
12 | const store = storeFactory()
13 |
14 | export default store
--------------------------------------------------------------------------------
/src/routes.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { BrowserRouter, Route, Switch} from 'react-router-dom'
3 | import Homepage from './components'
4 | import FrontEndLibrariesRoutes from './components/front-end-libraries/routes'
5 | import DataVisualizationRoutes from './components/data-visualization/routes'
6 | import ResponsiveWebDesign from './components/responsive-web-design/ResponsiveWebDesign'
7 | import JavascriptAlgorithms from './components/javascript-algorithms/JavascriptAlgorithms'
8 | import Whoops404 from './components/Whoops404'
9 |
10 |
11 | export const AppRoutes = () => {
12 | return (
13 |
14 |
15 |
16 |
17 | .
18 |
19 |
20 |
21 |
22 | )
23 | }
--------------------------------------------------------------------------------
/src/tests/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from '../components/App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render( , div);
8 | ReactDOM.unmountComponentAtNode(div);
9 | });
10 |
--------------------------------------------------------------------------------
/src/workers/registerServiceWorker.js:
--------------------------------------------------------------------------------
1 | // In production, we register a service worker to serve assets from local cache.
2 |
3 | // This lets the app load faster on subsequent visits in production, and gives
4 | // it offline capabilities. However, it also means that developers (and users)
5 | // will only see deployed updates on the "N+1" visit to a page, since previously
6 | // cached resources are updated in the background.
7 |
8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
9 | // This link also includes instructions on opting out of this behavior.
10 |
11 | const isLocalhost = Boolean(
12 | window.location.hostname === 'localhost' ||
13 | // [::1] is the IPv6 localhost address.
14 | window.location.hostname === '[::1]' ||
15 | // 127.0.0.1/8 is considered localhost for IPv4.
16 | window.location.hostname.match(
17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
18 | )
19 | );
20 |
21 | export default function register() {
22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
23 | // The URL constructor is available in all browsers that support SW.
24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
25 | if (publicUrl.origin !== window.location.origin) {
26 | // Our service worker won't work if PUBLIC_URL is on a different origin
27 | // from what our page is served on. This might happen if a CDN is used to
28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
29 | return;
30 | }
31 |
32 | window.addEventListener('load', () => {
33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
34 |
35 | if (isLocalhost) {
36 | // This is running on localhost. Lets check if a service worker still exists or not.
37 | checkValidServiceWorker(swUrl);
38 |
39 | // Add some additional logging to localhost, pointing developers to the
40 | // service worker/PWA documentation.
41 | navigator.serviceWorker.ready.then(() => {
42 | console.log(
43 | 'This web app is being served cache-first by a service ' +
44 | 'worker. To learn more, visit https://goo.gl/SC7cgQ'
45 | );
46 | });
47 | } else {
48 | // Is not local host. Just register service worker
49 | registerValidSW(swUrl);
50 | }
51 | });
52 | }
53 | }
54 |
55 | function registerValidSW(swUrl) {
56 | navigator.serviceWorker
57 | .register(swUrl)
58 | .then(registration => {
59 | registration.onupdatefound = () => {
60 | const installingWorker = registration.installing;
61 | installingWorker.onstatechange = () => {
62 | if (installingWorker.state === 'installed') {
63 | if (navigator.serviceWorker.controller) {
64 | // At this point, the old content will have been purged and
65 | // the fresh content will have been added to the cache.
66 | // It's the perfect time to display a "New content is
67 | // available; please refresh." message in your web app.
68 | console.log('New content is available; please refresh.');
69 | } else {
70 | // At this point, everything has been precached.
71 | // It's the perfect time to display a
72 | // "Content is cached for offline use." message.
73 | console.log('Content is cached for offline use.');
74 | }
75 | }
76 | };
77 | };
78 | })
79 | .catch(error => {
80 | console.error('Error during service worker registration:', error);
81 | });
82 | }
83 |
84 | function checkValidServiceWorker(swUrl) {
85 | // Check if the service worker can be found. If it can't reload the page.
86 | fetch(swUrl)
87 | .then(response => {
88 | // Ensure service worker exists, and that we really are getting a JS file.
89 | if (
90 | response.status === 404 ||
91 | response.headers.get('content-type').indexOf('javascript') === -1
92 | ) {
93 | // No service worker found. Probably a different app. Reload the page.
94 | navigator.serviceWorker.ready.then(registration => {
95 | registration.unregister().then(() => {
96 | window.location.reload();
97 | });
98 | });
99 | } else {
100 | // Service worker found. Proceed as normal.
101 | registerValidSW(swUrl);
102 | }
103 | })
104 | .catch(() => {
105 | console.log(
106 | 'No internet connection found. App is running in offline mode.'
107 | );
108 | });
109 | }
110 |
111 | export function unregister() {
112 | if ('serviceWorker' in navigator) {
113 | navigator.serviceWorker.ready.then(registration => {
114 | registration.unregister();
115 | });
116 | }
117 | }
118 |
--------------------------------------------------------------------------------