Pacer: MERN Stack Social Platform
Full-stack MERN platform for finding exercise partners for your favorite sports
Table of Contents
- Table of Contents
- Idea
- Features
- Plan
- Tech Stack
- Notable Highlights
- Implementation
- Google Maps API Integration
- Express.js Routing
- React.js Components
- State Management with Redux
- Challenges
- Team
Idea
“I hate running alone but my friends run way too fast. I wish I had my own personal Pacer…”
In the world of running pacers play a crucial role by setting a consistent speed to help runners achieve their target times in a race.
The Pacer platform helps you connect with people playing your favorite sport at similar performance levels so you can train, bond, and celebrate together.
👉
Live Demo
👈
Features
- User Auth
- Events (CRUD) w/ Interactive Google Map
- Google Maps API Integration (Dynamic Map, Static Map, & Places API)
- User Profiles
- Discover Events Page
- Event Social Stats
- Event Comments (CRUD)
Plan
-
Audience Value Props
-
App Architecture & Data Flow
-
Design
Tech Stack
- MongoDB
- ExpressJS
- React.js
- Node.js
Notable Highlights
User Authentication Modals
Event Filter
Google Maps API Integration
Implementation
Data Architecture with Mongoose & MongoDB
Mongoose Models: Events
, Users
, Comments
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const commentSchema = new Schema({
owner: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
},
event: {
type: Schema.Types.ObjectId,
ref: 'Event',
required: true
},
body: {
type: String,
required: true
}
}, {
timestamps: true
});
module.exports = mongoose.model('Comment', commentSchema);
Validations to ensure data integrity:
const validateEventInput = [
check('owner')
.exists({ checkFalsy: true })
.withMessage('User must be logged in to create an event'),
check('eventName')
.exists({ checkFalsy: true })
.isLength({ min: 5, max: 100 })
.withMessage('Event must have a name between 5 and 100 characters'),
check('description')
.exists({ checkFalsy: true })
.isLength({ min: 5, max: 1000 })
.withMessage('Event must have a description between 5 and 1000 characters'),
check('locationName')
.exists({ checkFalsy: true })
.withMessage('Event location must have a name'),
...
Google Maps API Integration
Integrated three Google Maps API endpoints:
- Dynamic interactive map on
Events
page. - Static map preview on
Discover
page. - Places API autocomplete search results when selecting an
Event
location.
<GoogleMap
mapContainerStyle={mapStyles}
zoom={14}
center={{
lat: selectedEvent?.latitude,
lng: selectedEvent?.longitude,
}}
>
<Marker
position={{
lat: selectedEvent?.latitude,
lng: selectedEvent?.longitude,
}}
onClick={handleMarkerClick}
/>
{infoWindowVisible && (
<InfoWindow
position={{
lat: selectedEvent?.latitude,
lng: selectedEvent?.longitude,
}}
onCloseClick={() => setInfoWindowVisible(false)}
>
<div>
<p>Location: {selectedEvent?.locationName}</p>
<p>Time of Event: {formattedTime}</p>
</div>
</InfoWindow>
)}
</GoogleMap>
Express.js Routing
- Three RESTful Express routes for
Users
,Events
,Comments
- Full CRUD for
Events
andComments
router.post('/', requireUser, validateCommentInput, async (req, res, next) => {
try {
const newComment = new Comment({
owner: req.body.owner,
event: req.body.event,
body: req.body.body
});
let comment = await newComment.save();
comment = await Comment.findById(comment._id)
.populate('owner', '_id firstName lastName profilePhotoUrl')
.populate('event', '_id eventName locationName dateTime difficulty eventType maxGroupSize longitude latitude');
return res.json(comment);
} catch (err) {
next(err);
}
});
React.js Components
-
Discover
Page:- Primary user interface with comprehensive
Event
filtering feature. - Displays all
Events
available forUsers
. Event POST
feature to create newEvents
.- Session and
User
validation required to create newEvents
.
- Primary user interface with comprehensive
-
Event
Page- Displays
Event
details from Redux state. - Attending & Interested buttons with integration to update Redux and MongoDB.
Comments POST
feature to create newComments
.
- Displays
State Management with Redux
- Redux implemented for state management enhancing UI load times and reducing unnecessary API calls.
- Redux slices of state for
Users
,Events
,Comments
. Events
reducer:
const eventsReducer = (state = { all: {}, user: {}, new: undefined }, action) => {
switch (action.type) {
case RECEIVE_EVENTS:
const allEventsArray = action.events;
const allEventsObject = allEventsArray.reduce((accumulator, event) => {
accumulator[event._id] = event;
return accumulator;
}, {});
return { ...state, all: allEventsObject, new: undefined };
case RECEIVE_NEW_EVENT:
return { ...state, all: { ...state.all, [action.event._id]: action.event }, new: undefined };
case UPDATE_EVENT:
return { ...state, all: { ...state.all, [action.event._id]: action.event }, new: undefined };
case DELETE_EVENT:
const { [action.eventId]: deletedEvent, ...rest } = state.all;
return { ...state, all: rest, new: undefined };
case RECEIVE_EVENT:
return { ...state, all: { ...state.all, [action.event._id]: action.event }, new: undefined };
case RECEIVE_USER_LOGOUT:
return { ...state, user: {}, new: undefined }
default:
return state;
}
};
Challenges
-
Three days to learn the MERN stack
- Team was well-versed with React and Node.js however Mongoose, MongoDB, and Express were new technologies for the team.
- The minimalism of Mongoose, and Express created a forgiving and flexible application architecture.
- Primary learning challenges were Express for backend routes due to it’s flexible nature vs. the team’s more familiar Rails convention over configuration paradigm.
-
Google Maps and parsing location data
- Implementing three different Google Maps API end points proved to be challenging.
- (1) Dynamic Interactive Map, (2) Static map image, and (3) Places API search autocomplete suggestions
- Each React component required different location data parsing logic to ensure UI loading efficiency across the user experience.
-
Handling bugs
- Debugging helped us understand the stack better via tracing bugs throughout the application.
- Developed a three-tier approach to assess bugs efficiently across a full-stack application: (1) Backend logs (2) Frontend console logs (3) Middleware logic assessment
Team
Gary Jiang
Team & Frontend Lead
Github
Website
LinkedIn
Jason Jun
Flex Lead
Github
Website
LinkedIn
Francis Cawog
Backend Lead
Github
Website
LinkedIn