{"id":15764371,"url":"https://github.com/praneshr/falcon","last_synced_at":"2026-04-11T12:45:12.401Z","repository":{"id":79806929,"uuid":"137561313","full_name":"praneshr/falcon","owner":"praneshr","description":"A minimal shopping cart experience built using React, Redux and Webpack.","archived":false,"fork":false,"pushed_at":"2018-06-17T11:55:54.000Z","size":379,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-10-09T17:38:29.810Z","etag":null,"topics":["react","redux","scss","webpack"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/praneshr.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}},"created_at":"2018-06-16T07:08:55.000Z","updated_at":"2020-08-19T23:33:57.000Z","dependencies_parsed_at":"2023-03-10T10:45:33.332Z","dependency_job_id":null,"html_url":"https://github.com/praneshr/falcon","commit_stats":{"total_commits":20,"total_committers":2,"mean_commits":10.0,"dds":"0.050000000000000044","last_synced_commit":"808177fdbac202002cac50852b13b93946b06199"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/praneshr/falcon","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/praneshr%2Ffalcon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/praneshr%2Ffalcon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/praneshr%2Ffalcon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/praneshr%2Ffalcon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/praneshr","download_url":"https://codeload.github.com/praneshr/falcon/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/praneshr%2Ffalcon/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31681201,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-11T08:18:19.405Z","status":"ssl_error","status_checked_at":"2026-04-11T08:17:08.892Z","response_time":54,"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":["react","redux","scss","webpack"],"created_at":"2024-10-04T12:02:54.822Z","updated_at":"2026-04-11T12:45:12.369Z","avatar_url":"https://github.com/praneshr.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Falcon\n\nA minimal shopping cart experience built using React, Redux and Webpack.\n\n![Books Shopping](https://image.ibb.co/gg6pud/ezgif_com_video_to_gif_3.gif)\n\n## Tech Stack\n\n- Babel(ES6/ES7)\n- React\n- Redux\n- React Router\n- SCSS\n- HMR\n\n## Setup\n\n```bash\n# Install dependencies\nyarn install\n\n# Do a production build\nyarn build\n\n# Start the app at port 8080\nyarn start\n\n# Check \"Scripts\" for more options\n```\n\n## Assumptions\n\n- 'Discounts' and 'Type Discounts' are applied over the original price of the book.\n- 'Discounts' and 'Type Discounts' are applied n times equal to the quantity.\n- In the cart page, the price container will stick to the bottom of the page when the user scroll to the end of the page. When he scrolls up again, the price container will stick to the bottom of the page until it reaches it original position.\n\n![Stick to bottom](https://image.ibb.co/eYLhxy/ezgif_com_video_to_gif.gif)\n\nHere, the price container sticks to the bottom as the scroll bar reaches the end of the page. The price container won't unstick as it won't be able to reach it's original position(Depends on the screen height).\n\n![Stick to bottom](https://image.ibb.co/fWqCVJ/ezgif_com_video_to_gif_1.gif)\n\nThis is a more straight forward way. The price container sticks to the top on scroll and unsticks when it reaches its original position.\n\n## Architecture \u0026 Implementation\n\n- The app is built on top of React's unidirectional data flow\n- The `booksList` and `cart` info are stored in Redux store\n```javascript\nconst store = {\n  booksList: [\n    {\n      id: 9090,\n      name: 'Item1',\n      price: 200,\n      discount: 10,\n      type: 'fiction',\n      img_url: 'https://store.lexisnexis.com.au/__data/media/catalog/thumb//placeholder.jpg'\n    },\n    {\n      id: 9091,\n      name: 'Item2',\n      price: 250,\n      discount: 15,\n      type: 'literature',\n      img_url: 'https://store.lexisnexis.com.au/__data/media/catalog/thumb//placeholder.jpg'\n    },\n    ...\n  ],\n  cart: {\n    9090: 5, // Item id as key and quantity as value\n    9091: 1,\n    ...\n  }\n}\n```\n- Only the `cart` info is saved to the localstorage. It is done using Redux's `store.subscribe()` method. Upon refresh, the app boots from the localstorage data.\n\n- The app has two pages, `/books` and `/cart`. `booksList` and `cart` are shared among the pages.\n\n- Updating quantity will modify `cart`. This makes it easy to update the quantity of a item.\n\n- While displaying, keys of `cart` are mapped to ids of `booksList` to get additional info like name, price, discount and etc. To speed up this mapping, an one time indexing of `booksList` is done. This will convert the `booksList` to an object like below\n```javascript\n{\n  9090: {\n    id: 9090,\n    name: 'Item1',\n    price: 200,\n    discount: 10,\n    type: 'fiction',\n    img_url: 'https://store.lexisnexis.com.au/__data/media/catalog/thumb//placeholder.jpg'\n  },\n  9091: {\n    id: 9091,\n    name: 'Item2',\n    price: 250,\n    discount: 15,\n    type: 'literature',\n    img_url: 'https://store.lexisnexis.com.au/__data/media/catalog/thumb//placeholder.jpg'\n  },\n}\n```\n- Price computations are done using 4 compute methods. Can be found under `app/utils/compute.js`\n\n- The app is completely responsive.\n\n## Further Improvements\n\n- Index `booksList` before saving it to the store\n\n- When cart info is loaded from localstorage, check if the products in `cart` are available in `booksList`. If not, notify the user and clear the item from the cart. This ensures no unavailable products are added to the cart.\n\n- Most unit tests for UI elements\n\n## Scripts\n\n**`yarn build`**\n\nBuild app for production\n\n**`yarn start`**\n\nRun app using `serve` (Production)\n\n**`yarn start:dev`**\n\nRun app using webpack dev server with HMR\n\n**`yarn build:dev`**\n\nBuild app for development\n\n**`yarn build:dev:watch`**\n\nBuild app for development in watch mode\n\n**`yarn test`**\n\nRun unit tests\n\n**`yarn test:watch`**\n\nRun unit tests in watch mode\n\n**`yarn lint`**\n\nRun `eslint` on app dir\n\n**`yarn lint:fix`**\n\nRun `eslint` and fix any linting errors\n\n\n## License\n\nApache License, Version 2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpraneshr%2Ffalcon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpraneshr%2Ffalcon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpraneshr%2Ffalcon/lists"}