rpf13 / sportsshooting_react

This repo is used for the Code Institute's Project Portfolio 5 with the main focus on creating the frontend application, which consumes the APIs of the sportsshooting_drf repo.
0 stars 1 forks source link

SportsShooting

SportsShooting is a site, which should support Sportsshooters and their related clubs, to create match events or gather information about matches. The main target audience are licensed IPSC (International Practical Shooting Confederation) shooters. IPSC is a worldwide organized confederation of practical shooters.

The site is not limited to licensed IPSC shooters, it can also be used for other shooting club related events.

It should build a plattform, where the registered user can gain more information about a particular match. He has, for example, the option to "attend" a match by clicking the related button, which will make it possible for other user, to see who is attending.

SportsShooting Mockup

We as IPSC Shooters often attend matches and therefore travelling is essential. This app should help to find other IPSC shooters, who attend the same match and therefore can travel together. IPSC Matches are all classified within "Levels", which have a distinct meaning:

For this reason, the plattform provides predefined "Level" filters in order to navigate quicker.

A registered user will also have the possibility to comment on match listings and therefore get in contact with fellow colleagues.

If one is attending lots of matches, it can become difficult to track them, therefore the app shows all upcoming events, where a user has registered for. A dedicated Upcoming Popular Matches component is visibile on many occasions, displaying the most popular matches. It should support the shooter to attend them too.

The plattform also gives the IPSC Shooter the option to create his own and private gun collection site. There he can inventorise his collection.

Link to deployed SportsShooting site: SportsShooting

Link to the deployed backend Django API: SportsShooting API

Link to the backend Django API repository: SportsShooting API Repo


User Stories

Nav & Auth

Matches Add & Attend

Match Detail

Profile

MySchedule

MyGuns

Testing & Documentation & Deployment

Stretch User Stories - Not implemented

Shooters - Messages


UX & Design

The overalll goal of the application was to achieve the desired functionality with a minimalistic and clear design. Colors should only be used to give an accent to something or display a certain function, like the buttons or the navbar active elements. Overall, the application is mobile friendly, the use of mobile devices has always been part of the design decision process.

Color Scheme

Coolors.co has been used to create the color palette. There are two sets of color schemes used in the application, where as they have many similarities. The main application uses a mixture of white / grey colors, paired with red to give some accents. The main background is #f5f5f5, which is a light grey color. It should give a simple accent over the pure white #ffffff navbar and component background.

Since also the individual match and gun collection items use the pure white as background, scrolling over the elements gives a nice "floating" effect.

Main Colors

The navbar but mostly the buttons are using a mixture of red colors paired with either black or sort of grey. Two sorts of red are used, either the standard red #ff0000 or the #fff1f1. Either the background or the font color is using one of them, also the hover effect is done with red. The background of the buttons is otherwise mostly the grey'ish #cfced3 paired with red or black font color.

Button Colors

I am aware of the fact that this combination does partially not fullfil the contrast check. However, it is almost impossible to pair red with any other light color and pass a contrast check. Since the whole color scheme is around the SportsShooting Logo, which contains a red centered target, I wanted to use it throughout the site. However, I am pretty confident that due to the fact that the contrast issue is only on a few button and hover effect occasion, it would also be very well usable for visual impaired users.


Typography

Google Fonts has been used to create the fonts. The logo uses the quite special Milonga font, which gives a nice touch to the image of the logo. The rest of the document uses Roboto with a alternative font of sans-serif.

Milonga Font Roboto


Wireframes

The Wireframes are the prototype of this project and show the base idea and the skeleton of the app. They have been slightly adjusted during the development of the project but their main concept and design idea never changed. I've used Balsamiq to design my site wireframes.

Wireframe Main site ![Main Site](docs/wireframes/desktop/d_main.png) Match Detail ![Match Detail](docs/wireframes/desktop/d_match_detail.png) MySchedule ![MySchedule](docs/wireframes/desktop/d_myschedule.png) MyGuns ![MyGuns](docs/wireframes/desktop/d_myguns.png) Profile ![Profile](docs/wireframes/desktop/d_profile.png)

Data Model

This application, built with React has not a data model by itself, since it consumes API's from the back end. The whole code and documentation of the data model can be found in the corresponding DRF API repository: SportsShooting API Repo


Features

This section will explain each feature of the application

Navigation (Navbar)

The navbar is the heart of the whole application. It welcomes the user with a very clear and distinct design. The usage should be pretty clear by looking at it.

Navbar unauthenticated

As a (new) user entering the page, it will be in unauthenticated state. The navbar displays the distinct logo, which is an active link where as clicking on it, will bring the user always back to the home url. furthermore, the user can see three icons

The matches icon appears red because it is active, it is the home url. This should give the user already a hint about the functionality. Hovering over the SignIn or SignUp icons will change their color, indicating that the user can click on it. Once clicked, the icon remains acive and hence turns color to red.

Navbar authenticated

If a user is authenticated, the navbar looks slightly different but keeps the previously mentioned concept of functionality and design. The following additional icons will show up:

SignUp | SignIn

A user who wants to interract on the site and not just watch some content, needs to create a profile and therefore sign up. The SignUp icon on the navbar will bring him to the form, where he has to add minimal data. The form uses auto validation of the fields, meaning for example a too short password will display an error.

The image on the signup site shows some bullets, once in upward position. It should illustrate the purpose of this form, to "sign up". If someone has clicked on the sing up by accident but already has an account, there is a cross link to the sign in form.

SignUp

The sign in form welcomes the user with the sentence "Are you ready". This is taken from the IPSC rules, which we follow as part of our sport. It is basically one of the commands the shooter gets told, before he can start his run on a particular stage. The image should illustrate the ready condition as well, the bullet comes from the magazine and gets loaded into the barrel.

SignIn

Once the user is signed in, the sign out icon is always visible in the navbar.

Matches | Main Site

The matches site is the main and home view of the application. It consists of different reusable components, which will show up independently on other sites.

Matches

The following elemets are part of the matches main site:

All of theses elements are available to all users, independet of their sign in status. The matches list is sorted showing the last added match first. This will help users to see the latest additions quite easily, without searching a lot. Furthermore, the list will also contain matches from the past, since this part of the application should also act as kind of archive.

There is an infinite scroll of matches in place, while loading from the back end, a loading spinner will be dispalyed to the user.

Matches search & Level filter

The search bar on top of the matches site give the user the ability to search after the most common keywords like title, location, advertiser

Matches search

There is also a pre defined Level Filter in place. As explained in the introduction section of this application, in IPSC shooting, all matches are categorised into levels, each of them having a clear meaning.

Matches filter

The two features can be combined to further filter down possible matches. This is exactly what a shooter who is looking after matches, wants. Search and Level filter will give this option.

Search & Level Filter

Matches attend & comments

Besides match detail information, each match is also displaying the two active elements of attending with its attendings count as well as the comment and comments count

Matches active components

If a user is logged in, he can click the attend icon to add himself to the list of attending shooters. If so, the icon will be transformed to red and keep this color until the logged in user clicks again on it to unattend.

It is important to note, that also the user who added the match can attend his own match. This is a must have feature. The count displays how many shooters are attending. Furthermore, he can click on the comments icon, which brings him to the match detail site, where he can see and add a comment. The count displays how many comments have been written.

If a user is not logged in, he can see both components, however, he will not be able to attend a match. While trying to attend, a message will be displayed that only logged in users can use this feature.

Matches active components unauth

Clicking on the comments field will also bring this user to the match detail site, where he can read the comments but is unable to add a comment.

Upcoming popular Matches Component

The Upcoming popular Matches component is a dedicated separated component, visible on the matches site. It contains a list of the most popular matches, measured on how many shooters are attending. To keep the list kind of visible, it is limited to 5 entries on desktop and 4 entries on mobile.

Upcoming Popular Matches

The list only contains matches hapening in the future, popular matches from past are filtered out. Furthermore it is sorted by the most recent match being first in the list. If the user is hovering over the events, the will change the color to red, to show it is an active link. With this, the navigation is inline with the rest of the site. Clicking on such a link will bring the user to the match detail page.

Match Detail

Once the user clicks on an individual match in the matches list, or he clicks on one of the listed matches in the Upcoming Popular Matches component, he will be presented with the details of the particular match, which contains a variety of additional information but still keep the design minimalistic.

Match Detail

On the top, the avatar and username of the advertiser, the one who added the match, is displayed. There is an active link behind, if clicked, the user profile will be displayed. Furthermore the date when the event was last updated is shown, next to the edit icon.

Besides the displayed image, the main title of the match, together with the event date is shown. Further infos like the match location, IPSC Level, Division and match details are shown. Underneath that, the two active components attending with its attendings count as well as the comment and comments count are displayed. Their usage has already been explained in the matches section.

Comments

The comments section lets the users see all comments, the logged in user will also see the form to add a comment. The avatar is again an active link to the user's profile.

Comment add

The user has also the option to edit or delete his comment. All comments of the logged in user will display the edit icon, which will give the option to edit or delete.

Comment edit

The comments section is also using the infinite scroll, displaying a loading spinner once more data is fetched from the API.

Add Match

The Add Match icon on the navbar will redirect the logged in user to a form, where he can create a new match entry.

Add Match

The form gives the option to add the following mandatory fields:

These fields are mandatory becasue without them, an advertisement of a match does not make sense...furthermore the application is based on "visuals", hence a match entry without an image would not be nice. The image upload is limited to max. 2MB or 4096 x 4096 pixels in order to stay within the Cloudinary's free hosting plan. If the user tries to submit the form and violating one of the mandatory fields, a respective error is displayed.

The following fields are optional:

Clicking on the cancel button will bring the user back to the site he came from.

Edit | Delete Match

If the owner of a particular match is logged in and has navigated to the match detail view of a particular match, he has the option to edit. The respective icon is only visible for the owner of the match and once clicked, the icon becomes active and displays the opton to delete or edit a match.

Edit & Delete

The delete functionality is straight forward, however in order to prevent unwanted deletion, a confirmation modal message is presenten upon pressing the delete button.

Match Delete Modal

The user has then the choice to either cancel deletion or confirm it. Deleting the match entry will delete all related child entries like comments, attendings, ...

If the user decides to edit a match, he can do so via clicking the respective icon.

Match Edit

The edit form gets displayed where all the fields are pre populated with the existing data. The user can adjust any of them or choose to cancel the operation, which will bring him back to the match detail view. All the attendings or comments are kept in any case (updating or cancellign the update operation).

Participating Shooters

The Participating Shooters component, is a reusable component, which got added here.

Participating Shooters Desktop

This component displays all shooters who have clicked attend. It should give the user or a possible organisator / advertiser of a match, an overview on how many will attend and who. It is also interesting for fellow shooters, since some have preferences. The list can be extensively long, therefore I have implemented a limit in size. On desktop the component is allowed to grow max. to 400px in height, on mobile it is limited to only 90px height, which is just engough to display two rows of avatars. The rest of the content, if exceeding the limit, will be hidden and accessible via the scrollbar.

Participating Shooters Mobile

If the user clicks on an avatar, he will be redirected to the respective user profile component.

MySchedule

MySchedule is only accessible for a logged in user. It is not a component or a page by itself, it is only re-using existing parts and components. This showcases the beauty of such a React app.

MySchedule

It's look is almost identical to the Matches page, but this time it is optimised for a particular user. The MySchedule site, as the name implies, is personal. It will display all matches a particular user is attending. The main pourpose is to help the shooter to have a list of his upcoming events.

All filter functionality, including the additional featurs of attending an event or commenting on an event, remain the same as for the matches site. Clicking on a particular match, will bring the user again to the match detail view, which has been previously described. In addition to the personal schedule, alos the component with the Upcoming popular Matches is displayed again, which should help the shooter to see whether he is missing an popular event or not.

MyGuns

The MyGuns site is also only available for logged in user. Furthermore it is personal. A user cannot see content of another user.

MyGuns

This site acts as a personal database of the shooters own gun collection. It is not really related to the IPSC sport, he can add whatever gun he wishes. Many shooters are also in other clubs, for example for precision rifle shooting, long distance shooting. This part of the application should give the option to store and sort the collection.

The main component is the gun database entry itself, dispalying the add and updated fields. This can be great value, depending on how a collector is managing his collection. By default the list of guns is sorted with the most recent entry first. Below the image section, there is the brand and type field - probalby the most important fields. In addition to that, the type field (pre defined as either handgun or rifle) can be seen. The last field is the content field, where the user can add whatever he wants in order to describe the item.

MyGuns Search and Type filter

On the top, the user gets displayed the (familiar) search and selection option. He can search based on a brand, model or serialnumber. The filter option is there to differentiate between handgun and rifle. If a user has a large collection, this can be a handy feature. Furthermore, filter and search can be combined.

MyGuns Search & Filter

MyGuns Upcoming Popular Matches Component

Like in the match detail view, also in the MyGuns list as well as in the Gun detail view, the Upcoming popular Matches component gets reused. Since this site has its primary focus on matches listing, it should encourage the user as much as possible to attend as well. In a future version, another component will be added at this place, see Future Features section.

Add Gun

The Gun add icon, located in the navbar, will direct the logged in user to the gun create form.

Gun Create

Mandatory fields are

If these fields are not filled, an error message will be displayed.

Gun Form Error

The other fields are optional:

If the user decides to cancel, he will be redirected back to where he came from.

Gun Detail | Edit & Delete

Once the user clicks on a particular entry in his gun database, he will see the details of such an entry.

Gun Detail

The information, which he will be presented is pretty much the same as on the list view, but here he has the option to edit or delete an entry. The concept is the same like on match entry. If he selects deletion, a modal will be presented to ask for confirmation. Cancel will bring him back to the detail view.

Gun Delete

The edit buton will open the edit form, with all the data pre populated. The user can edit all data, including the image. The cancel button will close the form and bring him back to the detail view.

Gun edit

Profiles

The last section is the profiles site. The site itself is accessible for all visitors, even if not signed in. When the profile / avatar is clicked in any of the components as well as the navbar, the user will be displayed the profile page.

Profile Page

The difference between a signed in and a signed out user is, that once the user is signed in and visiting his own profile, he will be displayed the edit profile button.

The site displays the bio of the shooter aas well as some more club and shooter related information. As separate section with contact details is shown. The site will also display all matches, created by this particular user. This can be very handy and an alterntive way, besides the search functionality, to find content of a particular shooter. Clicking on a match event, will bring him to the match detail site.

The Upcoming popular Matches component is reused again. The functionality of it has been described previously.

Edit Profile

Initially, once the user has signed up, all fields will be empty, so it is very much desired, that a user visits this section. The signed in user can edit his profile via clicking on the edit icon.

Profile Edit

He is displayed with the option to edit his username, his password or the profile. Edit username or password will bring him to the respective form, where as its containing cancel button will bring him back to the profile section.

Edit Username Edit Password

The edit profile section will let him update all the fields.

Profile Edit Form

All of the profile edit form fields are optional, meaning no error gets displayed, if the user submits an empty form. This is intentionally correct because instead of pressing the cancel button, the user might just press submit. Also the avatar image is not mandatory, if not changed, the default image will be used further. The mail and social media fields contain a placeholder text, just to make sure the user will add them in the correct form. If not, an error will be shown - however, the fields can be left blank.

If the new user cancels the form submission or submits it empty, he will be sent back to the profile details. If everything is empty and he did not add a match yet, the empty logo will be displayed.

Empty Profile

Certianly a profile update and submussion will result in updating the profile section as well as updating the avatar image on all components and related comments, match entries.


Features left to implement

Keeping the deadline of this project in mind and also the agile approach of development, the current state covers a great MVP solution. However, the application can be improved in future product iterations. One feature in particular did not make it to the front end implementation and that was the usermessage feature. It is covered with the user stories

where as both of them would have been part of a new Shooters Component, covered with the stories

The aim should be to create a new component, dedicated to the shooters, listing all of them and give a variety of filter and choice field options. Furthermore it should act a the "direct messaging" center, where it is possible for a logged in user to send messages to another user. Maybe the whole idea could be transformed even futher into a live chat functionality.

Anyway, the back end part of the messaging feature got already implemented as a stretch objective of the DRF API project. In the README of the back end project, there is a chapter dedicated to the usermessages, including the related code. The code got removed on the final deployed project, since no unused code should be deployed.

Future Features

In future iterations some more additional features could be implemented. Here some examples, which are on the list:


Re-useable components and helpers

Asset.js (spinner)

The Asset component is a reuseable component to display a spinner, an image, or a message based on the props passed to it.

The Asset component uses some further styling, which is defined in the Asset.module.css file. This component has been used widely in the application to display the loading spinner, while fetching more data from the API.

Avatar.js

The Avatar component provides a reuseable component, mainly used in the app for the user profiles.

The styling comes from the Avatar.module.css file.

DeleteModal.js

The DeleteModal component is used in two places of the application, when deleting a match or when deleting a gun object. It uses the following elements

I did not use any custom styling since I think the bootstrap styling for this modal looks great.

ErrorModal.js

The ErrorModal component serves as a notification system for displaying error messages to the user. Since it is not a nice and good idea to keep all the console.log elements in the code, I wanted to create something "useful" from user perspective. The try, catch blocks are set, why also not using the catch?

The ErrorModal component serves as a notification system for displaying error messages to the user.

I did leave the styling to the default bootstrap modal styling, which I think looks good.

Integration into the App:

To provide centralized management of the error state and to make the modal accessible throughout the application, the ErrorModal was integrated using React's Context API Link

MoreDropdown.js

The MoreDropdown component, provides a dropdown menu represented by the three dots (...), visible on any content, where a user respectively the owner of an object, can edit it. It contains two main actions: "Edit" and "Delete". When clicked, each respective action is taken.

Profile Edit Dropdown

The ProfileEditDropdown is a similar dropdown like the MoreDropdown but specifically for the profile actions. Instead of general actions like the MoreDropdown, it contains three actions that relate are used in the profile section: "Edit Profile", "Change Username", and "Change Password".

The component uses the useHistory hook to handle navigation for each dropdown action.

The styling is handled by the MoreDropdown.module.css file

NotFound.js

The NotFound component is used to inform users that the page they're trying to access doesn't exist or cannot be found. This component provides a user-friendly response to potential navigation errors or mistyped URLs.

Styling is defined in the NotFound.module.css.

FormatDay.js helper

I did set the dateTime format already in the backend to a custom value. However, in the front end, I wanted that there is a dot after the day, like 13. Jun 2023. I am so used to this format, that I wanted to have it in my app.

So the FormatDay function is an utility that formats the date string to include a dot after the day segment.

Page components

If we look at the individual pages used for "MyGuns" as well as "Matches", they also make use of of reuseable components or elements. The Match.js and the Gun.js are also reused inside the pages. The "singular form", like Gun.js is always the base, fetching the data. Then GunPage.js and GunsPage.js take it a step further, use other components like the ÀttendingShooters or PopularMatches, and integrate them.


Custom Hooks

The following custom hooks are used in this project

useClickOutsideToggle

The useClickOutsideToggle is a custom hook, which provides a mechanism to handle the expanded state of our navbar dropdown compnent and toggles it off when a click is detected outside of the component. It uses the React embedded hooks useEffect, useRef, useState It initialises the state via the useState hook and sets the value to false. The useRef hook also gets initialise with a value of null, the ref will then be assigned to a DOM element.

The useEffect hook adds the event Listener to the document, that check if there is a mouse Up event. Inside the handleClickOutside function, it checks if the click event's target is outside the element referred to by ref. If it is, it sets expanded to false.

The useEffect also returns a cleanup function, which makes sure, that the event listener is removed when the component that uses this hook is unmounted or if the ref changes The return value of the hook is the object with the expanded state, the setExpanded function to toggle this state, and the ref that is assigned to the DOM element to detect clicks outside of it.

Code snippet ```jsx import { useEffect, useRef, useState } from "react"; const useClickOutsideToggle = () => { // functionality to expand and close the navbar const [expanded, setExpanded] = useState(false); const ref = useRef(null); useEffect(() => { const handleClickOutside = (event) => { if (ref.current && !ref.current.contains(event.target)) { setExpanded(false); } }; document.addEventListener("mouseup", handleClickOutside); return () => { document.removeEventListener("mouseup", handleClickOutside); }; }, [ref]); return { expanded, setExpanded, ref }; }; export default useClickOutsideToggle; ```

useRedirect

useRedirect is another custom hook used in this project. It listens for changes in the user's authentication status. When there's a change, it tries to refresh the users authentication token. Depending on if thats a success or failure and the passed userAuthStatus, it redirects the user to the main route, which is the matches list.

The useRedirect Hook takes a single parameter, userAuthStatus, which indicates the user's authentication status. It makes use of the useEffect hook, which contains an async function of handleMount. A POST request is made to /dj-rest-auth/token/refresh/ to refresh the users authentication token. If the request is successful and the userAuthStatus is "loggedIn", the user will be redirected to the root path, which is the matches list. If the request fails and hence, the user is logged out, it will also be redirected to the same root path.

It gets used on various places in the application.

Code snippet ```jsx import axios from "axios"; import { useEffect } from "react"; import { useHistory } from "react-router-dom"; export const useRedirect = (userAuthStatus) => { const history = useHistory(); useEffect(() => { const handleMount = async () => { try { await axios.post("/dj-rest-auth/token/refresh/"); // if user is logged in, the following code will run if (userAuthStatus === "loggedIn") { history.push("/"); } } catch (err) { // if user is not logged in, 401 error, following code will run if (userAuthStatus === "loggedOut") { history.push("/"); } } }; handleMount(); }, [history, userAuthStatus]); }; ```

Technologies, Libraries & Dependencies

There are a variety of libraries and dependencies required to run this project. The package.json file contains a list of required packages, in order to have the deployed version used the correct ones. The following list is a summary of the packages, including a link to the reference and a short description.

Tools, Frameworks


Development

The following chapter describes how I made use of the very useful commit message feature.

Code Notes

At the final stage of the application, once doing the defensive programming tests, I did find quite some things, which are maybe not optimal. I have spent many hours trying to find solutions or alternative ways on how to tackle an issue. However, some things cannot just be changed, they would cause a redesign of the app.

One can say, that this is the lessons learned part and I somehow agree. I have learnt many things. For example I did not know until the end, that if I use react-bootstrap and "technically" just hide some content in the mobile view, it still gets rendered from a DOM perspective. So this fact causes some nasty problems and is also not very supportive for the loading time.

One particular change I did at the end I want to point out, is the following: I did change the behavior on how the MyGuns site behaves. Initially I had the below visible code in it. It would cover the case that if an unauthenticated user is trying to access the guns site, via directly entering the url in the browser like /guns, he would see a message telling: "You are not authorized to view this content. Create an account and login first."

However, I did not like that...I mean, this is just for a case, where the user is trying to do something, which he is not intended to do. Therefore I did implement current solution of redirecting the user back to the main route "/" if he tries to do the above mentioned. Now in such cases it would be nice to display a particular error Modal message, which brought me to the problem that my ErrorModal implementaiton would have to be refactored to accept dynamic inputs. I did not want to refactor this at the stage the app has been, fully tested and ready to submit. I did open a "future feature" for it.

Here the code snippet for the GunsPage.js with the previously mentioned error message to be displayed (imports not included in the snippet).

Code snippet ```jsx function GunsPage({ message }) { useRedirect('loggedOut') const [guns, setGuns] = useState({ results: [] }); const [hasLoaded, setHasLoaded] = useState(false); const [hasError, setHasError] = useState(false); const { pathname } = useLocation(); const currentUser = useCurrentUser(); // used for search query const [query, setQuery] = useState(""); const [gunType, setGunType] = useState(""); useEffect(() => { const fetchGuns = async () => { try { const { data } = await axiosReq.get(`/guns?search=${query}&type=${gunType}`); setGuns(data); setHasLoaded(true); } catch { setHasError(true); setHasLoaded(true); } }; // Only fetch guns when a user is logged in if (currentUser) { setHasLoaded(false); const timer = setTimeout(() => { fetchGuns(); }, 1000); return () => { clearTimeout(timer); }; } else { // If no user is logged in, set 'hasLoaded' and 'hasError' to true // which will cause re-render and display the not authorized error setHasLoaded(true); setHasError(true); setGuns({ results: [] }); // clear the guns state } }, [pathname, query, currentUser, gunType]); return (
event.preventDefault()} > setQuery(event.target.value)} type="text" className="mr-sm-2" placeholder="Search by brand, model, serialnumber" /> setGunType(event.target.value)} className="mb-3" > {hasLoaded ? ( hasError ? (

You are not authorized to view this content.
Create an account and login first.

) : ( <> {guns.results.length ? ( { return ; })} dataLength={guns.results.length} loader={} hasMore={!!guns.next} next={() => fetchMoreData(guns, setGuns)} /> ) : ( )} ) ) : ( )}
); } export default GunsPage; ```

Commit messages

I have decided to mostly use multiline commit messages. Commit messages are an essential part of the whole project and a single line commit message is just not enough to explain. After reading this interesting article, it was clear to me, that I have to use it.

I have decided to use (mostly) multiline commits, but using tags as described this cheatsheet or as also described in the LMS of the Code Institute. I did use the following syntax guidline:

  • feat: for feature which may or may not include a CSS part
  • fix: for a bugfix
  • style: for changes to CSS or to give style to the code itself
  • docs: for changes related to documentation
  • refactor: for refactored code, re-written code
  • maint: for general maintenance

Agile Development Process

Github Projects

Github Projects has been used as the Agile tool during the development phase of this project. The Kanban board was very useful to keep track on the tasks. I have created columns (ToDo, In Progress, On Hold, Done) and moved the stories accordingly. The On Hold column has served as a "parking spaces", when a story was partially done, but not completely finished.

Github Kanban

GitHub Issues

Github Issues has been used to create all the stories, before they were placed on the projects Kanban board. I have created an issues templates to simplify creation. Each issue has a label for the MoSCoW prioritization.

Once a story has been created via the template, it will be automatically added to the Kanban board in the Todo column.

Github Issues

MoSCoW Prioritization

The MoSCoW prioritization has been used to divide all epics and stories into the following categories:

  • MustHave: guaranteed to be delivered
  • ShouldHave: adds significant value, but not mandatory for MVP
  • CouldHave: adds value, would be nice to have
  • WontHave: no priority for this iteration, acts as placeholder for future implementation

A related Github label has been created for each category and added to each epic, story - which makes it easy to identify and see the value it brings.


Testing

Testing is covered in a separate page, view TESTING.md


Deployment

The live deployed application can be found deployed on Heroku. Since the application is bound ot the Django REST API SportsShooting API, there is not direct database, media storage like cloudinary, ... needed. Everything gets consumbed via the API.

Heroku Deployment

This project uses Heroku, a platform as a service (PaaS) that enables developers to build, run, and operate applications entirely in the cloud.

Deployment steps are as follows, after account setup:

  • Select New in the top-right corner of your Heroku Dashboard, and select Create new app from the dropdown menu.
  • Your app name must be unique, and then choose a region closest to you (EU or USA), and finally, select Create App.
  • No environment variables are required

Heroku needs two additional files in order to deploy properly.

  • package.json file
  • Procfile

The package.json file gets automatically built, when you install a package via the npm install command

The Procfile must contain the following command:

  • web: serve -s build

For Heroku deployment, follow these steps to connect your own GitHub repository to the newly created app:

Either:

  • Select Automatic Deployment from the Heroku app.

Or:

  • In the Terminal/CLI, connect to Heroku using this command: heroku login -i
  • Set the remote for Heroku: heroku git:remote -a app_name (replace app_name with your app name)
  • After performing the standard Git add, commit, and push to GitHub, you can now type:
    • git push heroku main

The project should now be connected and deployed to Heroku!

Local Deployment

This project can be cloned or forked in order to make a local copy on your own system. Depending on your local setup, npm needs to be installed. Do also make sure, that all required packages as mentioned in the package.json file are installed on your local machine.

Depending on the node version you are using on the local environment, a workaround is needed to start the server via the npm start command.

Before starting the server, the follwing command has to be entered, which tells nvm - the node version manager - the version he has to use.

nvm install 16 && nvm use 16

Cloning

You can clone the repository by following these steps:

  1. Go to the GitHub repository
  2. Locate the Code button above the list of files and click it
  3. Select if you prefer to clone using HTTPS, SSH, or GitHub CLI and click the copy button to copy the URL to your clipboard
  4. Open Git Bash or Terminal
  5. Change the current working directory to the one where you want the cloned directory
  6. In your IDE Terminal, type the following command to clone my repository:
    • git clone https://github.com/rpf13/sportsshooting_react
  7. Press Enter to create your local clone.

Alternatively, if using Gitpod, you can click below to create your own workspace using this repository.

Open in Gitpod

Please note that in order to directly open the project in Gitpod, you need to have the browser extension installed. A tutorial on how to do that can be found here.

Forking

By forking the GitHub Repository, we make a copy of the original repository on our GitHub account to view and/or make changes without affecting the original owner's repository. You can fork this repository by using the following steps:

  1. Log in to GitHub and locate the GitHub Repository
  2. At the top of the Repository (not top of page) just above the "Settings" Button on the menu, locate the "Fork" Button.
  3. Once clicked, you should now have a copy of the original repository in your own GitHub account!

Credits

Code

I have done lots of research, especially on the React side, to create this project. The following list will show some of the resources I have used. First and foremost, the Code Institute's own material, like the "Moments" walkthrough project, was extremely helpful and gave a general guidance, many of the taught concepts have been reused and adopted for my application.

Source Location Notes
Code Institute Tutorials whole application The code institute Moments Walkthrough tutorial was extremely helpful
Very Academy React Project whole application I've watched a lot of the content from Very Academy
React Context Handling Error.context.Provider in App.js Used to understand the context provider and how to add the error context provider
React Hooks whole application I needed to read more about hooks in general
Try Catch Error whole application I've used this MDN site to understand more about the try, catch, (finally) error handling
React Bootstrap Modal Modal used to implement the modal for the delete verification
React Functional Components whole site helped me to understand the concepts
Components & Props whole site helped me to understand more about props. Really had some issues to understand that
JS logial OR whole site used in the date formater, revisited this article
JS replace date formater used this method in the date formater helper
Conditional Ternary Operator whole app I had to read more about the conecpt, had some issues with nesting them

Code for jest unit testing

Besides the CI content for jest tsting, I have used the following resources and articles for creating my Unit Testing for some of the components. In particular, the NavBar, the DeleteModal and the NotFound component have been tested via jest.

  • Main JEST Documentation to review the global concept Link
  • Mock functions as used in the DeleteModal test Link
  • Matchers like the .toHaveBeenCalled() as used in the DeleteModal Link
  • Main React Testing Library Documentation Link
  • Queries lke the getByText as used in the Modal Link
  • User Events like fireEvent Link
  • Async Utilitiees like findBy Link

Media

I have used the following media files and resources

  • Unsplash has been used to get demo images for all the guns and matches. I did not want to use real match images of real events, since I was unsure about the respective license. In order to have images to showcase the functionaltiy, I did search through unsplash.com
  • Uxwing has been used for the favicon. After this favicon, I did crate a matching logo
  • FreeLogoDesign has been used to create the Logo
  • FreeLogoDesign has been used to create the match upload image
  • FreeLogoDesign has been used to create the gun upload image
  • FreeLogoDesign has been used to create the empty search and empty content image
  • Unsplash used for the sign in image
  • Unsplash used for the sign up image

Acknowledgements

  • Without the support of my wife and my little son, it would not have been possible to spend endless hours, working on this project and doing research. Many thanks to my little son for giving me a smile and very welcomed distraction, during times I was frustrated.
  • My Mentor Aleksei Konovalov was a big support for this project. He helped me to understand certain concepts and gave me very welcomed guidance. THANK YOU VERY MUCH! You are such a great person and very skilled developer!
  • A big Thank You to the tutor team from Code Institute, who has helped me with a few very nasty issues in the project
  • A big Thank You also goes to the awesome Code Institute Slack community, who was always very supportive!