├── .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 | ![screenshot](./.github/app-screenshot.png) 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 | 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 | 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 | logo 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 |
35 |
36 |
    37 |
    38 |
    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 | 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 | logo 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 | 12 |
    13 |

    Break

    14 |

    {breakLength}

    15 |
    16 | 21 |
    22 | ) 23 | } 24 | 25 | export const SessionSection = ({sessionLength, onIncrementSession, onDecrementSession}) => { 26 | return ( 27 |
    28 | 33 |
    34 |

    Session

    35 |

    {sessionLength}

    36 |
    37 | 42 |
    43 | ) 44 | } 45 | 46 | export const TogglersSection = ({active, onStartStop, onReset}) => { 47 | return ( 48 |
    49 | 55 | 61 |
    62 | ) 63 | } 64 | 65 | export const DisplaySection = ({timeLeftType, timeLeft}) => { 66 | return ( 67 |
    68 |
    70 |

    {timeLeftType}

    71 |

    {intToMMSS(timeLeft)}

    72 |
    73 |
    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 |
    17 | 18 | 19 | 20 | 21 |
    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 | 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 | logo 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 | logo 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 | logo 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 | logo 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 | --------------------------------------------------------------------------------