{"id":20834725,"url":"https://github.com/irisng/headphones-arena","last_synced_at":"2026-04-04T21:33:44.005Z","repository":{"id":44524466,"uuid":"163383353","full_name":"IrisNg/headphones-arena","owner":"IrisNg","description":"A Headphone Comparison Website","archived":false,"fork":false,"pushed_at":"2022-12-09T09:46:08.000Z","size":1707,"stargazers_count":1,"open_issues_count":13,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-01-03T14:27:28.068Z","etag":null,"topics":["analytics","async","axios","css","express","forum","html","mongodb","nodejs","passport","react","redux","regular-expression","searchbar"],"latest_commit_sha":null,"homepage":"https://headphones-arena.herokuapp.com/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/IrisNg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-12-28T07:57:58.000Z","updated_at":"2021-03-12T08:10:37.000Z","dependencies_parsed_at":"2023-01-25T21:01:01.109Z","dependency_job_id":null,"html_url":"https://github.com/IrisNg/headphones-arena","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/IrisNg/headphones-arena","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IrisNg%2Fheadphones-arena","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IrisNg%2Fheadphones-arena/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IrisNg%2Fheadphones-arena/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IrisNg%2Fheadphones-arena/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/IrisNg","download_url":"https://codeload.github.com/IrisNg/headphones-arena/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/IrisNg%2Fheadphones-arena/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31415110,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T20:09:54.854Z","status":"ssl_error","status_checked_at":"2026-04-04T20:09:44.350Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["analytics","async","axios","css","express","forum","html","mongodb","nodejs","passport","react","redux","regular-expression","searchbar"],"created_at":"2024-11-18T00:20:25.454Z","updated_at":"2026-04-04T21:33:43.983Z","avatar_url":"https://github.com/IrisNg.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Headphones Arena\n\n**A Website Dedicated to Headphones Comparison** \n\nA picture is worth a thousand words, but is a thousand words sufficient to describe a good sounding pair of headphones?\n\nAs a fellow Audiophile with shallow pockets, I have always relied on word-of-mouth (AKA intensive research) to discover great sounding headphones at an affordable price. Specifications always sound good on paper (duh!), but do not always deliver a performing pair of headphones. Scouring the internet for crumbs of reviews is just part of the daily grind. When everyone has a different pair of ears, that is a lot of words we Audiophiles have to process to come to a decision.\n\nTo bring back the fun in discovering Headphones, this website cuts to the chase by gathering hard facts and subjectivities in one place:\n* Shortening words by Tagging Keywords - Tag System ( A superpower to use less words but write more helpful reviews)\n* Reducing words to numbers - Rating System\n* Gathering all the words in one place - Forum\n* Receive enlightening words in real-time - Live Chat\n* Receive enlightening words (introvert version) - Private Messaging\n\n## Features\n\n* Arena\n  - Show more details of the Headphone when selected - rating, popular forum tags, amazon price, description, specifications, related forum posts.  \n  - Designed for Comparison - selected headphones are aligned side by side for ease of comparison. Up to 3 ~ 4 headphones' details can be accomodated depending on the device.\n* Forum\n  - Posts are sorted into four categories (Comparison, Review, Budget Recommendation, General). A mix of the latest and most upvoted posts are picked.\n  - Search Bar - Powered by Regular Expression. Want to know more about a specific headphone? Use the search function! Have a strict budget for your next impulse buy? Use the search function!\n  - Create, Reply, Edit, Delete and Vote Posts \n  - Tag System - A library of pre-defined descriptive \u0026 colorful phrases for you to tag the headphones mentioned in your post with. Every Tag Counts. The most frequently used tags appear in Arena to help new-comers find the perfect headphone for themselves. \n* Blacksmith\n  - Now Showing: Featured videos of DIY Headphones Modding - Direct from this website's official Youtube playlist\n  - Don't like the videos you are seeing? Just refresh the page to load new ones!\n* Dashboard\n  - Rate Headphones - Give a score to those headphones you have had the honor to listen to! Then wear them like badges! Note: this directly affects the headphone's Arena score.\n  - Upload Avatar - and have them display beside your username!\n  - Private Messaging - Send those promo codes to your friends on the website secretly, or seek advice about a certain headphone from a knowledgable mentor\n* Live-chat \n  - A minimalistic chat box to communicate with Users who are online in real-time.\n\n## Technologies Used\n\n* React \n* Redux\n* Redux-thunk\n* React-router\n* Javascript\n* CSS - CSS Flexbox, CSS Grid, Animation (pure CSS, no library)\n* SASS variables\n* Regular Expression\n* Axios\n* Node JS \u0026 Express\n* Passport (Local)\n* Mongo DB\n\n## Important Files\n\n* REACT - REDUX \n  - App component (including paths for React-Router) - /client/src/components/App.js\n  - Components folder (including respective CSS \u0026 SCSS files) - /client/src/components\n  - Action Creators file - /client/src/actions/index.js\n  - Reducers folder - /client/src/\n  - Components Hierarchy Diagram - /client/reference/Headphones Arena Component Diagram.png or [here](https://i.imgur.com/1J4OWiH.png)\n  \n* BACKEND\n  - Server file - /server.js\n  - Routes folder - /routes\n  - Models folder - /models\n  - Middleware file - /middleware/index.js\n\n## Struggle Zones (AKA challenges that made me got smacked around by the technologies I used)\n\n* Restful Routes - planning client-side react router's routes to not conflict with the server-side AJAX routes, else json from the server-side will be sent instead of the React index.html to the Client browser.\n\n* Async Await and Promise on the backend - so as to be able to perform multiple asynchronous CRUD operations in one route (with nested for-loops in each operation) without callback hell. \n\n* Pulling documents or arrays from mongoDB is an art (as with $set, $or, $and, $pull).\n\n* Passport Local Authentication Method - using req.user to check authentication status.\n\n* Axios - fetch data from server without causing page reload on a single page application like this one.\n\n* History Object + plain Router - to navigate between pages, so that the User can be redirected back or to a new url. Also history.listen() to listen for url changes in static default components that render on every page.\n\n* React Router - if param changes but path remains the same, component will not remount automatically, solution is to manually reset component state, and refire action creators.\n\n* Lifecycle Methods - componentWillUnmount to clear timers and getDerivedStateFromProps to update component state after receiving a certain prop value. Also, componentDidUpdate and ComponentDidMount.\n\n* Deep Copying using Map method in React - so as to not mutate arrays and objects in React Props when they are assigned to component state or passed further down as props to children components.\n\n* Props Mapping Collision - avoid mapping the same key-values from redux state multiple times between sibling components, it will cause same-props naming conflict. Instead, map the key-value once to the parent component and pass it down as props to the children.\n\n* Redux Thunk - asynchronously dispatch action only after response from server is fetched, also chaining multiple action creators within an action creator. Using getState to refer to redux state inside action creator.\n\n* CSS Flexbox and Grid - use Flex box for one-dimensional alignment and Grid for more complex two-dimensional alignment. Good for web responsiveness. CSS grid requires html/JSX elements to be structured a certain way as it is not applied to non-direct descendants. Nesting of Grids and Flexboxes are also useful.\n\n* CSS Animation - for smoother and more organic user experience.\n\n* Overflow scrolling and clickable mini pages - if page is very loaded with information, organize them into compartmentalized boxes without overwhelming the user.\n\n* SASS Variables - have not experimented with inheritance, nested rules, mixins yet.\n\n* Regular Expression - searches on React-side and for mongoDB Find operation, its fun! (But slow).\n\n* Fiddling with youtube API\n\n* Error Handling from server-side to client-side - using status code + try and catch blocks + GlobalMessage component.\n\n## Installation Instructions\n\n### Prerequisites\nMake sure you have **[Node.JS](https://nodejs.org/en/), [Postman](https://www.getpostman.com/) and [Mongo DB](https://www.mongodb.com/)** installed locally, [SASS](https://sass-lang.com/) is optional, [Redux DevTools](https://github.com/reduxjs/redux-devtools) is plenty helpful but optional also.\n\n### Dependencies\n    #### Server-side : \n    * body-parser\n    * concurrently\n    * express\n    * express-session\n    * mongoose\n    * passport\n    * passport-local\n    * passport-local-mongoose\n\n    #### Client-side :\n    * axios\n    * moment\n    * react\n    * react-dom\n    * react-moment\n    * react-redux\n    * react-router-dom\n    * redux\n    * redux-thunk\n\n### Steps\n\n1. Clone the repository to any of your local folder\n\n2. Install the following **SERVER-SIDE** dependencies to the main project folder **(i.e. C:/.../headphones-arena-master)** by running the following command in your terminal :\n```\nnpm install body-parser concurrently express express-session mongoose passport passport-local passport-local-mongoose --save\n```\n3. Navigate in your terminal to the 'client' folder by running this command in your terminal :\n```\ncd client\n```\n4. Install the following **CLIENT-SIDE** dependencies to the client folder **(i.e. C:/.../headphones-arena-master/client)** by running the following command in your terminal :\n```\nnpm install axios moment react react-dom react-moment react-redux react-router-dom redux redux-thunk --save\n```\n5. Start the app using the following command in your terminal (make sure your local mongoDB is running beforehand!) :\n```\nnpm run dev\n```\n6. Seed the necessary documents into mongoDB by using [Postman](https://www.getpostman.com/) to send a POST request to \n* http://localhost:3000/headphones/seed\n\n7. All set up! In your browser, go to 'http://localhost:3000', the app should be up and running!\n\n## Contributors\n\nCreated by Iris Ng. \nFeel free to hit me up with those bug reports or places where my code can use some improvement :) thanks!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Firisng%2Fheadphones-arena","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Firisng%2Fheadphones-arena","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Firisng%2Fheadphones-arena/lists"}