{"id":28974835,"url":"https://github.com/plcoster/fcc_frontendlibs_project5","last_synced_at":"2026-04-11T04:33:38.711Z","repository":{"id":299016106,"uuid":"479554727","full_name":"PLCoster/fcc_frontendlibs_project5","owner":"PLCoster","description":"Free Code Camp: Front End Libraries Projects - 25 + 5 Clock","archived":false,"fork":false,"pushed_at":"2022-06-02T19:58:46.000Z","size":837,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-24T12:16:52.376Z","etag":null,"topics":["github-actions","jest","nextjs","react","react-bootstrap","react-testing-library"],"latest_commit_sha":null,"homepage":"https://plcoster.github.io/fcc_frontendlibs_project5/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PLCoster.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-04-08T22:26:48.000Z","updated_at":"2022-05-26T01:01:27.000Z","dependencies_parsed_at":"2025-06-14T06:33:03.076Z","dependency_job_id":"61b61eaa-10f2-414e-8da5-5f481559f0fa","html_url":"https://github.com/PLCoster/fcc_frontendlibs_project5","commit_stats":null,"previous_names":["plcoster/fcc_frontendlibs_project5"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/PLCoster/fcc_frontendlibs_project5","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PLCoster%2Ffcc_frontendlibs_project5","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PLCoster%2Ffcc_frontendlibs_project5/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PLCoster%2Ffcc_frontendlibs_project5/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PLCoster%2Ffcc_frontendlibs_project5/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PLCoster","download_url":"https://codeload.github.com/PLCoster/fcc_frontendlibs_project5/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PLCoster%2Ffcc_frontendlibs_project5/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31669116,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T17:19:37.612Z","status":"online","status_checked_at":"2026-04-11T02:00:05.776Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["github-actions","jest","nextjs","react","react-bootstrap","react-testing-library"],"created_at":"2025-06-24T12:07:07.329Z","updated_at":"2026-04-11T04:33:38.688Z","avatar_url":"https://github.com/PLCoster.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Free Code Camp: Front End Libs Project 5 - 25 + 5 Clock\n\n## Pomo-do-it\n\n### Project Aims:\n\nThe aim of this project was to build a Pomodoro Timer with functionality similar to: https://codepen.io/freeCodeCamp/full/XpKrrW\n\nThis project was built using the following technologies:\n\n- **JavaScript** with **[Node.js](https://nodejs.org/en/) / [NPM](https://www.npmjs.com/)** for package management\n- **[React](https://reactjs.org/)** for application view with React Hooks to handle the application state\n- **[React-Bootstrap](https://react-bootstrap.github.io/)** for react components with **[Bootstrap](https://getbootstrap.com/)** styles, along with some custom CSS\n- **[Bootstrap Icons](https://icons.getbootstrap.com/)** for icons\n- **[Next.js](https://nextjs.org/)** as a React Framework to develop and build the project\n- **[Jest](https://jestjs.io/)** and **[React Testing Library](https://testing-library.com/docs/react-testing-library/intro/)** for testing\n- **[GitHub Actions](https://github.com/features/actions)** for automated CI/CD workflows\n\nDrum Samples were provided by **[SampleSwap](https://sampleswap.org/)**\n\nStyling was inspired by **[Pomofocus](https://pomofocus.io/)**\n\n### Project Requirements:\n\n- User Story #1: I can see an element with id=\"break-label\" that contains a string (e.g. \"Break Length\").\n\n- User Story #2: I can see an element with id=\"session-label\" that contains a string (e.g. \"Session Length\").\n\n- User Story #3: I can see two clickable elements with corresponding IDs: id=\"break-decrement\" and id=\"session-decrement\".\n\n- User Story #4: I can see two clickable elements with corresponding IDs: id=\"break-increment\" and id=\"session-increment\".\n\n- User Story #5: I can see an element with a corresponding id=\"break-length\", which by default (on load) displays a value of 5.\n\n- User Story #6: I can see an element with a corresponding id=\"session-length\", which by default displays a value of 25.\n\n- User Story #7: I can see an element with a corresponding id=\"timer-label\", that contains a string indicating a session is initialized (e.g. \"Session\").\n\n- User Story #8: I can see an element with corresponding id=\"time-left\". NOTE: Paused or running, the value in this field should always be displayed in mm:ss format (i.e. 25:00).\n\n- User Story #9: I can see a clickable element with a corresponding id=\"start_stop\".\n\n- User Story #10: I can see a clickable element with a corresponding id=\"reset\".\n\n- User Story #11: When I click the element with the id of reset, any running timer should be stopped, the value within id=\"break-length\" should return to 5, the value within id=\"session-length\" should return to 25, and the element with id=\"time-left\" should reset to its default state.\n\n- User Story #12: When I click the element with the id of break-decrement, the value within id=\"break-length\" decrements by a value of 1, and I can see the updated value.\n\n- User Story #13: When I click the element with the id of break-increment, the value within id=\"break-length\" increments by a value of 1, and I can see the updated value.\n\n- User Story #14: When I click the element with the id of session-decrement, the value within id=\"session-length\" decrements by a value of 1, and I can see the updated value.\n\n- User Story #15: When I click the element with the id of session-increment, the value within id=\"session-length\" increments by a value of 1, and I can see the updated value.\n\n- User Story #16: I should not be able to set a session or break length to \u003c= 0.\n\n- User Story #17: I should not be able to set a session or break length to \u003e 60.\n\n- User Story #18: When I first click the element with id=\"start_stop\", the timer should begin running from the value currently displayed in id=\"session-length\", even if the value has been incremented or decremented from the original value of 25.\n\n- User Story #19: If the timer is running, the element with the id of time-left should display the remaining time in mm:ss format (decrementing by a value of 1 and updating the display every 1000ms).\n\n- User Story #20: If the timer is running and I click the element with id=\"start_stop\", the countdown should pause.\n\n- User Story #21: If the timer is paused and I click the element with id=\"start_stop\", the countdown should resume running from the point at which it was paused.\n\n- User Story #22: When a session countdown reaches zero (NOTE: timer MUST reach 00:00), and a new countdown begins, the element with the id of timer-label should display a string indicating a break has begun.\n\n- User Story #23: When a session countdown reaches zero (NOTE: timer MUST reach 00:00), a new break countdown should begin, counting down from the value currently displayed in the id=\"break-length\" element.\n\n- User Story #24: When a break countdown reaches zero (NOTE: timer MUST reach 00:00), and a new countdown begins, the element with the id of timer-label should display a string indicating a session has begun.\n\n- User Story #25: When a break countdown reaches zero (NOTE: timer MUST reach 00:00), a new session countdown should begin, counting down from the value currently displayed in the id=\"session-length\" element.\n\n- User Story #26: When a countdown reaches zero (NOTE: timer MUST reach 00:00), a sound indicating that time is up should play. This should utilize an HTML5 audio tag and have a corresponding id=\"beep\".\n\n- User Story #27: The audio element with id=\"beep\" must be 1 second or longer.\n\n- User Story #28: The audio element with id of beep must stop playing and be rewound to the beginning when the element with the id of reset is clicked.\n\n### Project Writeup:\n\nFor the final Free Code Camp: Front End Libraries Project, I decided to build the project using the Next.js framework for React. The final project build is a static (i.e. serverless) website built in React, with application state controlled using React Hooks (`useState`, `useEffect`, `useRef`, `useMemo`).\n\nGoing beyond the required user stories above, Pomo-do-it allows users to:\n\n- control whether the next phase of the timer starts automatically after the current one ends\n- view the current time left, timer phase and status summary in the browser tab, even when the app is not currently in focus in the browser\n- keep track of the total time spent productively and on breaks across all completed sessions in Session History\n- view a detailed break down of all completed sessions, their start and end timer as well as real and timer durations in the Detailed History display\n- adjust the volume level of the audio alert that plays when a session has ended (and also the volume of button clicks)\n\nIn addition, a basic unit test suite in Jest / React Testing Library has been created, covering User Stories #1 - # 26. (Note that User Stories #27 and #28 cannot be covered via these unit tests, as the test library does not support HTMLAudioElements - testing these would likely be possible using Cypress). The created tests are run as part of a Github Actions CI/CD workflow. When changes to the project are pushed to the main branch, the project dependencies are installed and the test suite is run. If the test suite completes successfully, a production build of the project is created, and then deployed onto GitHub pages (on the gh-pages branch).\n\n### Project Files:\n\n- `/public` - this folder contains all public content for the app, such as favicon images, the web manifest, and audio files used by the app.\n\n- `/pages` - in the Next.js framework, pages are associated with routes in the app based on the file name. In this app there is only a single route (`/`), and the React components that build the page are in `index.js`.\n\n  - the `_app.js` page file is a special component that wraps every other page. In this project this just renders the `NavBar` component on every page, and adds in the FCC testing script. It also holds as a state variable the current timer phase, which is lifted to this component so that the NavBar can also be styled based on the timer phase.\n  - `index.js` is the only page in this application, it renders the `Timer` component.\n  - `404.js` is a custom error page that is set to redirect users immediately to the app if reached.\n\n- `/__tests__` contains the tests for the application:\n\n  - `index.test.js` contains the React Testing Library unit tests for the application.\n\n- `/styles` contains a global style sheet for the application.\n\n### Components:\n\n- `NavBar.js` is a presentational navbar component, providing links to other projects / sites.\n\n- `Timer.js` is the major stateful component of the application. It contains various state variables for e.g. the length of Sessions, Breaks, the current time remaining on the given timer, whether or not the timer is running or paused, which phase ('Session' or 'Break') the timer is in, etc. It renders various controls in order to set the length of timer phases, start/stop, skip and reset the timer tom initial settings. When timer phases end, an array containing the history of all previous timer phases completed is updated. State variables and handler functions are passed to its child components (`HeadUpdater` and `HistoryDisplay`).\n\n  - `HeadUpdater.js` is a small component that updates the information in the `\u003chead\u003e` element of the application using the Next.js `\u003cHead\u003e` component. This allows the current timer phase, status, and time remaining to be reflected and updated in the browser tab for the application, allowing the timer to remain useful even when no longer in focus in the browser.\n\n  - `HistoryDisplay.js` is the component responsible for displaying the history of timer phases completed so far. It reduces the array of timer history in order to display the total time spent in 'Sessions' and 'Breaks', and will also display a detailed list of all timer phases completed thus far, when 'Show Details' is clicked. The timer history can be cleared using the 'Clear History' button.\n\n### Usage\n\nRequires Node.js / NPM in order to install required packages. After downloading the repo, install required dependencies with:\n\n`npm install`\n\nThe next.js development server can then be started with:\n\n`npm run dev`\n\nThe development server can then be viewed at `http://localhost:3000/` in the browser.\n\nA static production build can be created in the `out/` folder by running:\n\n`npm run build`\n\nAnd then viewed using:\n\n`npm run start`\n\nThe test suite can be run using:\n\n`npm test`\n\n### Extension Ideas:\n\n- Adding a to-do-list component to track items you wish to complete while using the timer\n- Including E2E / Integration tests using Cypress\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplcoster%2Ffcc_frontendlibs_project5","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fplcoster%2Ffcc_frontendlibs_project5","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fplcoster%2Ffcc_frontendlibs_project5/lists"}