{"id":21241233,"url":"https://github.com/icyjoseph/forza","last_synced_at":"2025-03-15T03:44:54.701Z","repository":{"id":98747441,"uuid":"150623080","full_name":"icyJoseph/forza","owner":"icyJoseph","description":"Predictions App build as a challenge","archived":false,"fork":false,"pushed_at":"2018-10-03T19:22:54.000Z","size":157,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-21T19:41:36.628Z","etag":null,"topics":["football","react","reactjs","reactjs-ui"],"latest_commit_sha":null,"homepage":"https://talented-reaction.surge.sh/","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/icyJoseph.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-09-27T17:22:01.000Z","updated_at":"2018-12-17T20:42:05.000Z","dependencies_parsed_at":"2023-05-25T03:00:18.086Z","dependency_job_id":null,"html_url":"https://github.com/icyJoseph/forza","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icyJoseph%2Fforza","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icyJoseph%2Fforza/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icyJoseph%2Fforza/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/icyJoseph%2Fforza/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/icyJoseph","download_url":"https://codeload.github.com/icyJoseph/forza/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243681005,"owners_count":20330155,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["football","react","reactjs","reactjs-ui"],"created_at":"2024-11-21T00:55:02.780Z","updated_at":"2025-03-15T03:44:54.694Z","avatar_url":"https://github.com/icyJoseph.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# \u003ca id=\"top\"\u003e\u003c/a\u003eForza Football\n\nBuild as part of a coding challenge for Forza Football\n\n## Content\n\n1. [Demo](#demo)\n\n2. [Running Locally](#local)\n\n3. [Challenge](#challenge)\n\n4. [Solution](#sold)\n\n5. [UI](#ui)\n\n6. [Assumptions](#assumptions)\n\n## \u003ca id=\"demo\"\u003e\u003c/a\u003eDemo\n\n[top](#top)\n\nA deployed version of the solution: [in this link](https://talented-reaction.surge.sh).\n\nDetails about the solution can be found in the [Solution](#sol) section below.\n\n## \u003ca id=\"local\"\u003e\u003c/a\u003eRunning Locally\n\n[top](#top)\n\n1.  Clone the repository.\n\n    ```\n    git clone https://github.com/icyJoseph/forza.git\n    ```\n\n2.  Go into the repository.\n\n    ```\n    cd forza\n    ```\n\n3.  Install dependencies.\n\n    ```\n    yarn\n    ```\n\n    or\n\n    ```\n    npm install\n    ```\n\n4.  Build the App.\n\n    ```\n    yarn build\n    ```\n\n    or\n\n    ```\n    npm run build\n    ```\n\n5.  Serve the build.\n\n    ```\n    serve -s build\n    ```\n\n6.  Open `http://localhost:5000` in your browser.\n\n7.  To see test coverage:\n\n    ```\n    yarn test:report\n    ```\n\nWhy not run locally as developer?\n\n\u003e The URL to fetch data is selected depending on the environment you are in.\n\n\u003e For development, it looks for http://localhost:3000/, while for production it looks for the given end point.\n\n\u003e It is better to go to the [Demo](#demo).\n\nTo change this behavior, go to `src/config.js` and change the url to:\n\n```javascript\nexport const url = \"the end point you have me\"; // :)\n```\n\n## \u003ca id=\"challenge\"\u003e\u003c/a\u003eChallenge\n\n[top](#top)\n\nThe new football season brings with it a sense of excitement among fans as everything\nstarts again. At this time of year many fans enjoy making predictions about how the\nseason will go, who will win and who will be top scorer?\nIn this test, we would like to see how you create a small mobile first web app where the\nuser can predict the top 3 teams in the upcoming Premier League season. They will\nselect who they think we finish 1st, 2nd and 3rd. Additionally it would be great if they\ncould also select who they think will be top scorer. Once they have made their\nprediction they should then see a summary of their selections.\n\nFeel free to experiment with the UI solution. How can you use the provided data and\npresent it? How will the user interact and make their predictions? We are mostly looking\nat functionality, but presentation is also important.\nIdeally your solution will be written in plain javascript however if you are more\ncomfortable in React or other framework then that would be fine as well.\nNote:​ Remember that this is just a small project to get something for us to discuss about coding\ntogether, you don’t need to spend days on this. If you find stuff that you would like to improve in\nyour solution after sending it to us, write it down and bring your own feedback to the\npresentation.\n\n## \u003ca id=\"sol\"\u003e\u003c/a\u003eSolution\n\n[top](#top)\n\nThe proposed solution is a React-Redux application.\n\n### React Tree\n\nThe application layout is as follows at a container level:\n\n```jsx\nconst App = () =\u003e (\n  \u003cProvider\u003e\n    \u003cRoutes\u003e\n      \u003cTopMenu /\u003e\n      \u003cLanding /\u003e\n      \u003cLeague /\u003e\n      \u003cPrediction /\u003e\n      \u003cFloatingActionButtons /\u003e\n    \u003c/Routes\u003e\n  \u003c/Provider\u003e\n);\n```\n\n#### TopMenu\n\nStateless component which renders a Material UI AppBar and the share, clear buttons when the user navigates inside a league.\n\nWhen inside a league it also renders the name and country of the league as MainTitle.\n\n#### Landing\n\nFetches leagues data and renders a card for each one of them.\n\n#### League\n\nShows the user's predictions for a league. It also renders a card for each team or player in the league.\n\n#### Prediction\n\nA set of buttons that will attach to the card selected by the user. This is a singleton. In mobile view they attack to the Floating Action Buttons. It also includes label in the middle of the screen which indicates the current selection.\n\n#### FloatingActionsButtons\n\nNormally two buttons. Back and sort by goals.\n\nIn mobile view the Prediction container attaches to the Floating Action Buttons.\n\n### Redux Store\n\nSimple redux store with keys for predictions, all leagues and sorting status.\n\n#### Middleware\n\n1. The store uses two middlewares. One is to show Redux store activity in Chrome dev tools.\n\n2. The other middleware copies the store to the local storage at every new action, with the updated state.\n\n\u003e This last middleware allows the user the refresh, the page and come back right where they left.\n\n#### Store Structure\n\n1. Predictions is an object where we store each league name and predictions as values.\n\n2. All leagues is an object storing all leagueName as keys, and league data as values.\n\n3. Sorting simply checks if the user has clicked the sorting button.\n\n\u003e This could have been a local state, but since we are caching the store state at every new action, we can in fact, also save the user sorting criteria.\n\n## \u003ca id=\"ui\"\u003e\u003c/a\u003eUser Interaction\n\n[top](#top)\n\nUpon landing the leagues are fetched. The user can select one, which will navigate to `/leagueId`.\n\n- There the user can click on the team cards or navigate to the players tab, where the cards are also clickable.\n\n\u003e For mobile view the buttons are either pinned to the bottom right, while for desktop these float on top of the card.\n\n- The user selections are reflected on the top panel\n\n\u003e The user may clear all selections by clicking clear on the Top Menu.\n\n- The user can sort by goals scored last season, clicking the ball icon.\n\n- The user can go back to the league with the pinned back button at the bottom right.\n\n## \u003ca id=\"assumptions\"\u003e\u003c/a\u003eAsumptions\n\n[top](#top)\n\nAll leagues is better an as object. Worldwide there might be thousands of leagues, each with only about 30 teams on average.\n\n\u003e Mapping, filtering or reducing over 1000+ items can result in bad UX. Selecting from an equally large object is better.\n\n\u003e Fetching such large number of leagues is also rather tedious. Instead we cache the response and add an expiration time of one hour.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficyjoseph%2Fforza","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ficyjoseph%2Fforza","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ficyjoseph%2Fforza/lists"}