EventTrove is a one-stop location for all your event discovery, sharing and organisation needs! This interactive platform includes the option to view, add, edit and delete events and posts to share all kinds of events, big and small! A built in calendar allows visual organisation of your events to make sure you never miss an event!
The project has been split into two parts - the back-end constructed with Django REST Framework and the frontend supercharged with React.
More information on the back-end of the site can be found in the back-end README.
Link to the live site - EventTrove Live Site
Link to the live API - EventTrove Live API
Link to the back-end repository - EventTrove Back-End Repo
The primary goal of this project was to create a full stack application where users can view, add, edit and delete events. These events can be viewed as a list, individually and as a calendar view. Users can add posts about specific events to share and remind other users about the upcoming events, or add "plans" to upcoming events and "memories" to events which have already passed, allowing different users to collate their experiences together in one place.
GitHub Projects served as an Agile tool for this project. It isn't a specialized tool, but with the right tags and project creation/issue assignments, it can be made to work.
These goals were split into four major themes and used as "Epics" for the agile development of the application. The Epics were as follows:
- Account management
- Posts
- Events
- Calendar
Each of the epics were then further split into "user stories", each of which representing one small, contained feature to be integrated into the site. Each user story contained an action statement in the format:
As a role I can capability so that received benefit
Each user story then had a list of acceptance criteria (what the user needs to be able to see/do to consider the story "completed") and a task list (what the developer needs to do in order to complete the story).
Each story was assigned to its respective Epic and classified into one of each of the four MoSCoW categories:
- Must do. High priority. Features that the application needs in order to be used. Should account for approx 60% stories
- Should do. Medium priority. Features that are not required for the feature to run, but significantly improve the application and/or user experience. Should account for approx 20% stories
- Could do. Low priority. Features that are not required for the application to run, but would make a nice addition if included. Should account for the remaining ~20% stories
- Won't do. This feature will not be added in this iteration of the application development.
In addition, "story points" were assigned to each of the user stories. These points denoted how difficult each user story is and/or how long it should take to complete, relative to the other stories. The points ranged from 1-8 on a logarithmic scale (i.e. the points available were 1, 2, 4 or 8, each being approximately double the difficulty and/or time requirement of the previous).
User story issues on Github were assigned labels to keep track of which MoSCoW prioritisation and number of story points each story has.
As this project has both a backend and frontend component, each user story had associated frontend and backend tasks. Each repository, therefore, has its own github issue referencing each user story with the same user story and acceptance criteria, but with different tasks. The issue number for each user story is the same for both repositories and the corresponding user story to make tracking and review easy. Both sets of user stories can be found on the associated project board
All user stories can be found in the User Story grid
In the grid, each user story has details of it's EPIC, the user story number, the title, user story, acceptance criteria and both the backend and frontend tasks (with link to backend and frontend issues).
User stories (and bugs) were tracked using a Kanban board. This board has 3 columns - Todo, in progress and done. All user stories start life in the "to do" column and get moved, a maximum of five at a time, to the "in progress" column. When tasks are completed, they are moved to the "done" column and a new task(s) may be moved to the "in progress" column to be worked on.
An example of the kanban board during development and on completion of the application are shown below:
Kanban board in progress:
Kanban board with all tasks completed:
Prior to starting work on the project, wireframes were designed to plan the basic structure and layout of some of the pages on the site. This helped when designing components in React to see how the components fit together an what differences (if any) are present for different screen sizes.
Wireframes were made for three screen sizes - mobile, tablet and desktop - to help guide styling from a "mobile-first" perspective.
The wireframes for the project can be found in this toggle
The colour scheme for the project was kept extremely minimal as the focus of the site is user uploaded images and having bold colours throughout the site may detract or even clash with user uploaded image colours.
Colours were selected from the assets throughout the site to colour buttons and icons but otherwise most things were left with the default react-bootstrap colour scheme. This also improved accessibility by keeping contrast between backgrounds and text high.
DM-Sans was used as the typeface throughout the project as it is a sans-serif font designed to be readable at small text sizes and is compatible with FullCalendar. Reguls sans-serif is used as a backup font incase the google fonts typeface cannot be loaded.
A basic logo featuring a blue gemstone was used as a "home" button on the navbar and for the favicon.
This project was developed using React.
One of the main advantages of the React framework is the ability to create and use reusable components. This improves efficiency and readability of the code and allows global changes to be made with ease. This also reduces repetition in the code which is time consuming and liable to errors when a piece of code is updated and this must be correctly updated all areas where the original code was reused.
For this project, several reusable components were created and used throughout various pages. First I will detail the reusable components, then the pages in which some of these components were utilised.
click to expand
-
Navbar
The navbar is featured on every page and helps the user to effectively navigate through the site without having to enter routes into the url bar manually.
The navbar renders different content depending on whether the user is logged in or not and features an image of the Northern Lights which can be seen when the dropdown menu is opened. From here, logged in users can add posts and events, navigate to the main posts and events pages, calendar, user's own profile and friends page. They can also nagivate the the filtered versions of posts and events (watched events, liked posts, friend's event and friends posts). They can also sign out of the site.
Logged out users may only view the posts and events page, sign up and sign in.
-
Dropdown
The<MoreDropdown />
component is present on all editable and deletable components, including<Post />
,<Event />
,<Comment />
,<Memory />
and gives asset owners the option to edit and delete their assets. This component takes the handleEdit and handleShow (necessary for the confirm deletion modal) methods directly as props.The
<ProfileEditDropdown />
component is present on the<Profile />
component and handles redirects to the change password, change username and edit profile pages. -
Asset
The<Asset />
is a reusable component, useful for displaying a variety of, well... assets. This includes the image for the<NotFound />
page, the images for upload and no results, and the loading spinners used throughout the site. -
Avatar
The<Avatar />
component contains the profile image of users and is used in many other components. This includes each user's<Profile />
, the<Navbar />
component (as the dropdown menu toggle), part of the<Profile />
component for the<PopularProfiles />
sidebar, and at the top of each<Post />
and<Event />
asset. -
Event mini
The
<EventMini />
component takes the key details from each event (the title, image and start date) and makes a small component which is used in the calendar event modals and upcoming events sidebar. -
Event modal
In the<Calendar />
component, both thedateClick
andeventClick
functionalities from FullCalendar are used to determine user clicks on a whole day or on a specific event. When either of these is clicked, relevant information is passed to the<EventModal />
component to render the relevant event(s) in the modal.If a specific event is clicked, the name of that event becomes the modal title and the specific event is displayed in the body through the
<EventMini />
component. The footer of the modal contains a cancel or "view event" button to take the user to that specific event detail page (where it can be edited or deleted, if the user owns the event).If a whole day is clicked, "Events for
<date clicked>
" becomes the modal title and each of the events taking place that day are listed as<EventMini />
components. The footer of the modal contains a cancel or "add event" button to take the user to the "create new event" page so a user can create a new event. A future feature could automatically populate the new event form with the clicked date. -
Delete modal
The delete confirm modal is used in each of the places where assets can be deleted. This includes the<Post />
,<Event />
,<Comment />
and<Memory />
components. Each time the modal component is used, props in the form of a custom confirmation message and the specifichandleDelete
method are passed to the modal. This makes the modal completely interchangable for all delete instances. -
Selector switch
The selector switch was designed as there were a few places where multiple versions of a page could be displayed so I wanted a reusable component which could handle each of these instances. The switch has a left and right hand side and props are passed to it to determine the text rendered on each side, which side contains a link and the route for the link. This makes the component reusable on the profile page (for switching between a user's posts and events), on the main events page to switch between events in the past and those in the future and on individual events to switch between plans and memories.
These pages relate to the following user stories:
- As a visitor I can register for an account so that I can have a user profile with picture and have full access to the site, make, comment on and like posts and events
- As a registered user I can log in to my account so that I can have full access to the site, make, comment on and like posts and events
click to expand
-
Signup
The signup page was taken from the Code Institute Moments walkthrough project. The image was changed to a photo of lanterns but is otherwise unchanged from the walkthrough.
- Signin
The signin page was also taken from the Code Institute Moments walkthrough project. The image was changed to a photo of confetti at an event but is otherwise unchanged from the walkthrough.
click to expand
A '404 page not found' page replaces the default React 404 page. The <NotFound />
component contains the <Asset />
container with a custom "not found" image.
The 404 page will be rendered whenever a page not on the list of routes in <App />
is entered, for example https://organisation-app-frontend.herokuapp.com/nonexistantpage/
Custom routing has also been added for when the API returns a 400 or 404 error, for example when a resource does not exist. This means that if a non-existant resource id is entered (in an otherwise valid route), the 404 page will be returned. For example https://organisation-app-frontend.herokuapp.com/events/999.
The 404 page contains a button which links back to the homepage (post feed page).
These pages relate to the following user stories:
Posts:
- As a user I can view specific posts from another user in their profile so that I can see that user's post activity
- As a visitor I can view a list of posts so that I can view recent uploads and decide if I want to sign up
- As a visitor I can view individual posts so that I can read the post in more detail and see the associated comments
- As a user or visitor I can scroll through a list of posts so that I can browse the site more comfortably
- As a user I can create posts so that I can share information about events with other users
- As a user I can edit or delete my own posts so that I can fix incorrect information, add more information, or remove the post entirely
- As a user I can see posts made specifically by my friends so that I can easily access the posts most relevant to me
- As a user I can access a page containing posts I've liked so that I can easily find these posts again
- As a user I can choose an event from my event list when I post so that I can make a post about that specific event
Comments:
- As a user I can create comments on posts so that I can communicate with the poster and other users about the post content
- As a user I can edit and delete my own comments so that I can amend or remove the comment I wrote
Likes:
- As a user I can like other user's posts so that I can show that user I appreciated their content
- As a user I can access a page containing posts I've liked so that I can easily find these posts again
click to expand
The posts page can be accessed through the base route of the application and is in a "feed" style with <Post />
components from all users loaded on top of one another, starting from the most recent. 10 posts are loaded on page load, with another 10 being loaded when the user scrolls to the bottom, infinitely until the end of the post list is reached.
Each <Post />
component contains the poster's avatar, name and a link to their profile, the date of posting, the image (if present), title, post content and a link to the event (if added). Each post can be liked by all logged in users except the post owner. Any logged in user may comment on a post.
-
Posts can be liked and/or commented on by appropriately logged in users. Logged out users cannot like or comment on any posts, post owners can comment on but not like their own posts and logged in users who do not own the post may like/dislike and comment on any post they do not own.
The posts page also contains the
<PopularProfiles/>
component which displays the most followed profiles.
These pages relate to the following user stories:
Events:
- As a user I can view specific events from another user in their profile so that I can see that user's events
- As a user I can choose an event from my event list when I post so that I can make a post about that specific event
- As a visitor I can view public events so that I can see what events are planned and see if I would like to create an account to add the event(s) to my calendar
- As a visitor I can view individual events so that I can see more detail about the event and see any associated comments
- As a user or visitor I can scroll through a list of events so that I can browse the site more comfortably
- As a user I can create events so that I can share information about events with other users
- As a user I can edit or delete my own events so that I can fix incorrect information, add more information, or remove the event entirely
- As a user I can view my friend's events on a seperate page so that I can quickly browse events most relevant to me
- As a user I can see my upcoming events on a sidebar so that I can quickly see which of my events are coming up soon
Watches:
- As a user I can watch/unwatch other user's posts so that it is added to my watched events list
- As a user I can view my watched events on a seperate page so that I can keep an eye on the event and easily find it again
click to expand
-
Events can be watched and/or have a plan/memory added by appropriately logged in users. Logged out users cannot watch or make a plan/memory on any events or add an event to their calendar, event owners can leave a plan/memory on but not watch their own events or remove them from their calendar and logged in users who do not own the event may watch/unwatch and leave plans/memories on any event they do not own, plus add that event to their calendar.
-
watch event
Users can "watch" events if they do not own them. This adds them to their "watched events" page to make locating them again easier.
-
add event to calendar
Users can add and remove events they do not own to their calendar. This allows the event to be seen on the main Calendar page as well as the upcoming events sidepanel (if event is in the future)
-
upcoming events
Events in a user's calendar contain a boolean variable called "past" which indicates whether an event has already started or is upcoming. Upcoming events are displayed in a sidepanel on the "events" page and can be clicked to view more details of each individual event.
These pages relate to the following user stories:
-
As a user I can add memories to past events so that I can store my comments and images to look at later
-
As a user I can edit or delete my own memories so that I can fix incorrect information, add more information, or remove the memory entirely
-
As a user I can add plans to future events so that I can plan my event more effectively and store useful information together
-
As a user I can edit or delete my own plans so that I can fix incorrect information, add more information, or remove the plan entirely
-
As a user I can switch between plans and memories so that I can see all information associated with an event
click to expand
Plans and Memories are variants of the same component, depending on whether they were created before or after the start date of their associated event. "Plans" are created when the asset is created before the start of the event, otherwise the asset is a "Memory".The
<EventPage />
displays the detailed view of an event and also displays any plans that were created. The<EventPastPage />
also displays the detailed view of an event, but also displays the associated memories. The<SelectorSwtich />
component is reused here to switch between the two views.Placeholder text is rendered conditionally depending on whether the event's start date has passed ("The event is upcoming... add plans here!" if so, "This event has passed... add a memory here!" if not).
Users may add a plan or memory with text content and an image (optional). The
<MemoryCreateForm />
component is embedded inline and plans/memories are added to the top of the list without causing a full page refresh.The following shows the message displayed to the user when there are no plans or memories, depending on whether the event's start date is in the past or future and whether the user is logged in or not.
- As a user I am automatically assigned a calendar so that I can easily view my events
- As a user, the events I create are automatically added to my calendar so that I can immediately visualise them
- As a user I can add and remove other user's events to/from my calendar so that I can visually see when they will take place on my personal calendar
- As a user I can toggle the view of my calendar between year, month, week and day so that I can easily visualise my time and see when events are
- As a user I can navigate between days, weeks, months and years using directional arrows so that I can easily visualise my events in my calendar
- As a user I can click a day and see the events planned for that day so that I can quickly see which (if any) events are taking place on a day
- As a user I have the option to add an event from my calendar so that I can easily create new events
- As a user I can click an event in my calendar to see the event details so that I can easily visualise events in my calendar
- As a user I have a button to see the specific event when I click in in my calendar so that I can view further details, edit and delete it
- As a user I can syncronise my events with my google calendar so that I can keep one universal collection of events wherever I am
These pages relate to the following user stories:
click to expand
- CalendarThe calendar page makes heavy use of the FullCalendar component which generates the actual calendar grid. The project uses 3 plugins from FullCalendar to display different calendar views:
dayGridPlugin - provides the month and week views
timeGridPlugin - provides the day view (split into hours)
multiMonthPlugin - provides the year-at-a-glance view
initialView="dayGridMonth"
headerToolbar={{
start: "today prevYear,prev,next,nextYear",
center: "title",
end: "multiMonthYear,dayGridMonth,timeGridWeek,timeGridDay",
}}
The project also uses the interactionPlugin to allow targeting of the day or a specific event. This is used for the day and event modals which display detail of event(s) to the user. More detail about these modals can be found in the reusable component section above.
A custom pacman loading spinner makes this page a bit more fun as the API call can take a few seconds to complete
These pages relate to the following user stories:
-
As a user I can view other user's profiles so that I can see a specific user's posts and events
-
As a user I can have a profile created for me, add a profile picture and edit my profile so that I can have a custom profile picture and display information about myself
-
As a user I can add other users as friends so that I can preferentially see their posts and events
-
As a user I can view all the users I have added as a friend so that I can easily see them, access their profile or remove them
-
As a user I can see posts made specifically by my friends so that I can easily access the posts most relevant to me
-
As a user I can see popular profiles on the side panel on the posts page so that I can decide who to add as a friend
-
As a user I can view my friend's events on a seperate page so that I can quickly browse events most relevant to me
click to expand
-
The profile page is made up of several different components
<Avatar />
- profile details supplied in
<ProfilePage />
<ProfileEditDropdown />
<SelectorSwitch />
<Post />
or<Event />
component, depending on which view is chosen<PopularProfiles />
If it is another user's profile, the edit dropdown menu is not visible, but the button to add/remove friend is visible. The
<Asset />
component (the empty treasure chest here) is displayed if the user hasn't posted/added events yet.
The dropdown menu on a user's own profile allows the following actions:
Update profile details
Registered users can update their profile picture and profile details at any time with the profile edit form.
Form validation was used throughout the application to ensure only valid data can be submitted to the API. Although there is thorough validation in the backend too, it is important to prevent users from entering invalid data on the frontend too, to ensure that no invalid data slips through the net. It is also important for user experience to notify the user when they have entered invalid data and give hints how to make their data valid.
Users must enter a username and their password twice
Passwords must contain at least 8 characters and not be too common...
... and of course, they must match!
Login credentials must be entered in order to login
And the username and password must match an entry in the database, or else entry is denied.
Custom image validation prevents images larger than 4MB being uploaded. This helps to save space in the database and improve loading times.
Images must also not be too large. A limit of 4096 x 4096 pixels is the limit.
The title field is madatory for post creation and so frontend validation is in place to prevent this field from being blank.
The title, location and start and end time fields are madatory for event creation and so frontend validation is in place to prevent these fields from being blank. Privacy and event type are also mandatory, but these have default values and therefore are never blank and so do not cause validation errors.
There is also a custom validator to ensure that end time for an event is after the start time:
A custom <AlertMsg />
component was created for displaying success/error messages to the user in a bar under the Navbar. This could handle custom success and error messages, however due to page redirects following creation or editing of resources, the alert only shows briefly before redirect. Additionally, for event creation/editing, the message was shown at the top of the screen and so is not visible unless the user quickly scrolls to the top of the page. As it is obvious that a resource has been created, as a user is immediately redirected to the newly created resource, it was decided that this feature would not be included in the project.
This could be improved in the future by designing a more sophisticated message handling system that lives, for example, in the <NavBar />
component and receives props from other resources. This could then display the message at the top of the redirected page, removing both problems.
Alternatively, Websockets could be used to convey bi-directional (i.e. between the React client and the DRF server) notifications to users about changes in real time.
- Link to google calendar (through API). This would allow users to synchronise their EvntTrove calendar to their actual Google calendar and be able to keep track of and add to events wherever they are.
- Link to map service for location. This could Google maps or another map service provider. From here, a small interactive map could be rendered on each event to allow users to see exactly where the event will take place
- A weather widget to display the weather forecast for an event at the time and specific location the event will take palce
- Websockets for notifications. As mentioned above, the notification system could be improved by useing websockets.
- Improve interface. The general user interface is a bit plain and very similar to the Moments walkthrough guide. The focus of this project was on the features and calendar integration, but it would be nice to improve the aesthetics in the future too!
All testing can be found in a seperate md file here
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.
Head into the 'Deploy' tab select GitHub as the 'deployment method', find your project repository and click 'Connect'. Click 'Deploy branch' to trigger Heroku to start building the application. You can also enable automatic deployment if you wish. Once you see the message saying 'build succeeded' you can click 'Open App' to see your application in the browser.
In order to send and receive data to/from the API, the front and backend workspace need to be connected.
First, make sure that the API is successfully deployed to Heroku with the "CLIENT_ORIGIN" variable correctly set to the deployed URL of the frontend project so that it can recieve requests from the front-end (here https://organisation-app-frontend.herokuapp.com/). More details on API deployment may be found in the API respository for this project.
Then follow these steps to connect the front-end to the API:
- In the frontend workspace, install the Axios library using the command 'npm install axios'.
- Create a folder called 'API' and inside it create a file called 'axiosDefaults'.
- Import axios at the top of the file
- Define the baseURL which is the unique URL of the deployed API project (here https://organisation-app-api.herokuapp.com/).
- Set the content-type header to multi-part/form-data as the API will need to deal with images as well as text in it's requests.
- Import axiosDefaults into App.js (
import "./api/axiosDefaults";
) so that it may be accessed globally.
This project can be cloned or forked in order to make a local copy on your own system.
You can clone the repository by following these steps:
- Go to the GitHub repository
- Locate the Code button above the list of files and click it
- Select if you prefer to clone using HTTPS, SSH, or GitHub CLI and click the copy button to copy the URL to your clipboard
- Open Git Bash or Terminal
- Change the current working directory to the one where you want the cloned directory
- In your IDE Terminal, type the following command to clone my repository:
git clone https://github.com/dragon-fire-fly/organisation_app_frontend.git
- Press Enter to create your local clone.
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:
- Log in to GitHub and locate the GitHub Repository
- At the top of the Repository (not top of page) just above the "Settings" Button on the menu, locate the "Fork" Button.
- Once clicked, you should now have a copy of the original repository in your own GitHub account!
-
HTML used for the main site content.
-
CSS used for the main site design and layout.
-
JavaScript used to create the interactive elements of the website
-
React.js used as the frontend framework
-
React Bootstrap - A CSS framework that helps build solid, responsive, mobile-first sites
-
Balsamiq used to create the wireframes
-
Git used for version control. (
git add
,git commit
,git push
) -
GitHub used for secure online code storage.
-
Heroku used for hosting the deployed front-end site.
-
Visual Studio Code used as a local IDE for development.
-
Lighthouse used to test site performance.
-
Google Chrome DevTools used to debug and test responsiveness.
-
Cloudinary used to host image files for the project.
-
HTML Validation used to validate HTML code
-
CSS Validation used to validate CSS code
-
ESLint used to lint JavaScript code
-
FullCalendar used to generate the calendar component for the calendar page
Lantern photo https://www.pexels.com/photo/selective-focus-photography-of-lanterns-1313817/
Confetti photo https://unsplash.com/photos/ZODcBkEohk8
Navbar image https://images.pexels.com/photos/1933319/pexels-photo-1933319.jpeg
Images for resource not found, image upload placeholder and 404 page were created using dream.ai
jpg images were converted to webp using timy-img
https://react-bootstrap.github.io/components/modal/ - for creating modals https://www.npmjs.com/package/react-spinners - for custom spinner
https://stackoverflow.com/questions/72301355/how-to-populate-select-options-from-an-api-call-in-react-js-on-page-load - for event drop down in postcreateform
https://stackoverflow.com/questions/38049966/get-image-preview-before-uploading-in-react - for uploading images without using useRef() hook
- I would like to thank my Code Institute mentor, Martina Terlevic for her support throughout the development of this project.
- I would like to thank my previous Code Institute mentor, Tim Nelson. Although he isn't my mentor anymore, his previous support and guidance still helps me every day.
- I would like to thank the Code Institute tutor team for their assistance with troubleshooting and debugging some project issues.
- I would like to thank the Code Institute Slack community, particularly the class of May 2022, for the moral support; it kept me going during periods of self doubt and imposter syndrome.
- I would like to thank my husband (Christian Schmidt), for believing in me, and allowing me to make this transition into software development.