MeetPup is an inspired clone of the site: Meet-UP. This project is an effort to display the work for the utilization of React, Redux, Express, Sequelize, PostgreSQL, and Render.
Live site: https://meetpup.onrender.com
- Download and unzip
- Use the command
npm start
in both frontend and backend folders to run both servers - Browser should automatically open at localhost:3000 to the Splash page.
All endpoints that require a current user to be logged in.
- Request: endpoints that require authentication
- Error Response: Require authentication
-
Status Code: 401
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Authentication required" }
-
All endpoints that require authentication and the current user does not have the correct role(s) or permission(s).
- Request: endpoints that require proper authorization
- Error Response: Require proper authorization
-
Status Code: 403
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Forbidden" }
-
Returns the information about the current user that is logged in.
-
Require Authentication: true
-
Request
- Method: GET
- URL: /session
- Body: none
-
Successful Response when there is a logged in user
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "user": { "id": 1, "firstName": "John", "lastName": "Smith", "email": "[email protected]", "username": "JohnSmith" } }
-
-
Successful Response when there is no logged in user
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "user": null }
-
Logs in a current user with valid credentials and returns the current user's information.
-
Require Authentication: false
-
Request
-
Method: POST
-
URL: /session
-
Headers:
- Content-Type: application/json
-
Body:
{ "credential": "[email protected]", "password": "secret password" }
-
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "user": { "id": 1, "firstName": "John", "lastName": "Smith", "email": "[email protected]", "username": "JohnSmith" } }
-
-
Error Response: Invalid credentials
-
Status Code: 401
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Invalid credentials" }
-
-
Error response: Body validation errors
-
Status Code: 400
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Bad Request", // (or "Validation error" if generated by Sequelize), "errors": { "email": "Email is required", "password": "Password is required" } }
-
Creates a new user, logs them in as the current user, and returns the current user's information.
-
Require Authentication: false
-
Request
-
Method: POST
-
URL: /users
-
Headers:
- Content-Type: application/json
-
Body:
{ "firstName": "John", "lastName": "Smith", "email": "[email protected]", "username": "JohnSmith", "password": "secret password" }
-
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "user": { "id": 1, "firstName": "John", "lastName": "Smith", "email": "[email protected]", "username": "JohnSmith" } }
-
-
Error response: User already exists with the specified email
-
Status Code: 500
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "User already exists", "errors": { "email": "User with that email already exists" } }
-
-
Error response: User already exists with the specified username
-
Status Code: 500
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "User already exists", "errors": { "username": "User with that username already exists" } }
-
-
Error response: Body validation errors
-
Status Code: 400
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Bad Request", // (or "Validation error" if generated by Sequelize), "errors": { "email": "Invalid email", "firstName": "First Name is required", "lastName": "Last Name is required" } }
-
Returns all the groups.
-
Require Authentication: false
-
Request
- Method: GET
- URL: /groups
- Body: none
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "Groups": [ { "id": 1, "organizerId": 1, "name": "Evening Tennis on the Water", "about": "Enjoy rounds of tennis with a tight-nit group of people on the water facing the Brooklyn Bridge. Singles or doubles.", "type": "In person", "private": true, "city": "New York", "state": "NY", "createdAt": "2021-11-19 20:39:36", "updatedAt": "2021-11-19 20:39:36", "numMembers": 10, "previewImage": "image url" } ] }
-
Returns all the groups.
-
Require Authentication: true
-
Request
- Method: GET
- URL: /groups/current
- Body: none
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "Groups": [ { "id": 1, "organizerId": 1, "name": "Evening Tennis on the Water", "about": "Enjoy rounds of tennis with a tight-nit group of people on the water facing the Brooklyn Bridge. Singles or doubles.", "type": "In person", "private": true, "city": "New York", "state": "NY", "createdAt": "2021-11-19 20:39:36", "updatedAt": "2021-11-19 20:39:36", "numMembers": 10, "previewImage": "image url" } ] }
-
Returns the details of a group specified by its id.
-
Require Authentication: false
-
Request
- Method: GET
- URL: /groups/:groupId
- Body: none
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "id": 1, "organizerId": 1, "name": "Evening Tennis on the Water", "about": "Enjoy rounds of tennis with a tight-nit group of people on the water facing the Brooklyn Bridge. Singles or doubles.", "type": "In person", "private": true, "city": "New York", "state": "NY", "createdAt": "2021-11-19 20:39:36", "updatedAt": "2021-11-19 20:39:36", "numMembers": 10, "GroupImages": [ { "id": 1, "url": "image url", "preview": true }, { "id": 2, "url": "image url", "preview": false } ], "Organizer": { "id": 1, "firstName": "John", "lastName": "Smith" }, "Venues": [ { "id": 1, "groupId": 1, "address": "123 Disney Lane", "city": "New York", "state": "NY", "lat": 37.7645358, "lng": -122.4730327 } ] }
-
-
Error response: Couldn't find a Group with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Group couldn't be found" }
-
Creates and returns a new group.
-
Require Authentication: true
-
Request
-
Method: POST
-
URL: /groups
-
Headers:
- Content-Type: application/json
-
Body:
{ "name": "Beau's Secret Helpers", "about": "It takes a village to raise a wolf puppy. Especially one as spoiled as Beau.", "type": "In person", "private": false, "city": "San Diego", "state": "CA" }
-
-
Successful Response
-
Status Code: 201
-
Headers:
- Content-Type: application/json
-
Body:
{ "id": 1, "organizerId": 1, "name": "Beau's Secret Helpers", "about": "It takes a village to raise a wolf puppy. Especially one as spoiled as Beau.", "type": "In person", "private": false, "city": "San Diego", "state": "CA", "createdAt": "2023-06-15T22:45:07.267Z", "updatedAt": "2023-06-15T22:45:07.267Z" }
-
-
Error Response: Body validation error
-
Status Code: 400
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Bad Request", // (or "Validation error" if generated by Sequelize), "errors": { "name": "Name must be 60 characters or less", "about": "About must be 50 characters or more", "type": "Type must be 'Online' or 'In person'", "private": "Private must be a boolean", "city": "City is required", "state": "State is required" } }
-
Create and return a new image for a group specified by id.
-
Require Authentication: true
-
Require proper authorization: Current User must be the organizer for the group
-
Request
-
Method: POST
-
URL: /groups/:groupId/images
-
Headers:
- Content-Type: application/json
-
Body:
{ "url": "a really cute dog image url", "preview": true }
-
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "id": 1, "url": "a really cute dog image url", "preview": true }
-
-
Error response: Couldn't find a Group with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Group couldn't be found" }
-
Updates and returns an existing group.
-
Require Authentication: true
-
Require proper authorization: Group must belong to the current user
-
Request
-
Method: PUT
-
URL: /groups/:groupId
-
Headers:
- Content-Type: application/json
-
Body:
{ "name": "NEW DOG RELATED NAME IN ALL CAPS", "about": "Probably something related to running around Fiesta Island together, but we can settle for PB Dog Park", "type": "In person", "private": true, "city": "San Diego", "state": "CA" }
-
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "id": 8, "organizerId": 6, "name": "NEW DOG RELATED NAME IN ALL CAPS", "about": "Probably something related to running around Fiesta Island together, but we can settle for PB Dog Park", "type": "In person", "private": true, "city": "San Diego", "state": "CA", "createdAt": "2023-06-15T22:45:07.267Z", "updatedAt": "2023-06-15T22:49:44.038Z" }
-
-
Error Response: Body validation error
-
Status Code: 400
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Bad Request", // (or "Validation error" if generated by Sequelize), "errors": { "name": "Name must be 60 characters or less", "about": "About must be 50 characters or more", "type": "Type must be 'Online' or 'In person'", "private": "Private must be a boolean", "city": "City is required", "state": "State is required", } }
-
-
Error response: Couldn't find a Group with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Group couldn't be found" }
-
Deletes an existing group.
-
Require Authentication: true
-
Require proper authorization: Group must belong to the current user
-
Request
- Method: DELETE
- URL: /groups/:groupId
- Body: none
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Successfully deleted" }
-
-
Error response: Couldn't find a Group with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Group couldn't be found" }
-
Returns all venues for a group specified by its id
-
Require Authentication: true
-
Require Authentication: Current User must be the organizer of the group or a member of the group with a status of "co-host"
-
Request
- Method: GET
- URL: /groups/:groupId/venues
- Headers:
- Content-Type: application/json
- Body: none
-
Successful Response
- Status Code: 200
- Headers:
- Content-Type: application/json
- Body:
{ "Venues": [ { "id": 1, "groupId": 1, "address": "123 Disney Lane", "city": "New York", "state": "NY", "lat": 37.7645358, "lng": -122.4730327 } ] }
-
Error response: Couldn't find a Group with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Group couldn't be found" }
-
Creates and returns a new venue for a group specified by its id
-
Require Authentication: true
-
Require Authentication: Current User must be the organizer of the group or a member of the group with a status of "co-host"
-
Request
- Method: POST
- URL: /groups/:groupId/venues
- Headers:
- Content-Type: application/json
- Body:
{ "address": "1998 28th St", "city": "San Diego", "state": "CA", "lat": 32.72621, "lng": 32.72621 }
-
Successful Response
- Status Code: 200
- Headers:
- Content-Type: application/json
- Body:
{ "id": 8, "groupId": 6, "address": "1998 28th St", "city": "San Diego", "state": "CA", "lat": "32.7262100", "lng": "32.7262100" }
-
Error response: Couldn't find a Group with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Group couldn't be found" }
-
-
Error Response: Body validation errors
-
Status Code: 400
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Bad Request", // (or "Validation error" if generated by Sequelize), "errors": { "address": "Street address is required", "city": "City is required", "state": "State is required", "lat": "Latitude is not valid", "lng": "Longitude is not valid" } }
-
Edit a new venue specified by its id
-
Require Authentication: true
-
Require Authentication: Current User must be the organizer of the group or a member of the group with a status of "co-host"
-
Request
- Method: /venues/:venueId
- URL: PUT
- Headers:
- Content-Type: application/json
- Body:
{ "address": "AWESOME NEW DOG FRIENDLY ADDRESS", "city": "Dog Island", "state": "CA", "lat": 37.7645358, "lng": -122.4730327 }
-
Successful Response
- Status Code: 200
- Headers:
- Content-Type: application/json
- Body:
{ "id": "6", "groupId": 6, "address": "AWESOME NEW DOG FRIENDLY ADDRESS", "city": "Dog Island", "state": "CA", "lat": 37.7645358, "lng": -122.4730327 }
-
Error response: Couldn't find a Venue with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Venue couldn't be found" }
-
-
Error Response: Body validation errors
-
Status Code: 400
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Bad Request", // (or "Validation error" if generated by Sequelize), "errors": { "address": "Street address is required", "city": "City is required", "state": "State is required", "lat": "Latitude is not valid", "lng": "Longitude is not valid" } }
-
Returns all the events.
-
Require Authentication: false
-
Request
- Method: GET
- URL: /events
- Body: none
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "Events": [ { "id": 1, "groupId": 1, "venueId": null, "name": "Tennis Group First Meet and Greet", "type": "Online", "startDate": "2021-11-19 20:00:00", "endDate": "2021-11-19 22:00:00", "numAttending": 8, "previewImage": "image url", "Group": { "id": 1, "name": "Evening Tennis on the Water", "city": "New York", "state": "NY" }, "Venue": null, }, { "id": 1, "groupId": 1, "venueId": 1, "name": "Tennis Singles", "type": "In Person", "startDate": "2021-11-20 20:00:00", "endDate": "2021-11-19 22:00:00", "numAttending": 4, "previewImage": "image url", "Group": { "id": 1, "name": "Evening Tennis on the Water", "city": "New York", "state": "NY" }, "Venue": { "id": 1, "city": "New York", "state": "NY" }, }, ] }
-
Returns all the events of a group specified by its id
-
Require Authentication: false
-
Request
- Method: GET
- URL: /groups/:groupId/events
- Body: none
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "Events": [ { "id": 1, "groupId": 1, "venueId": null, "name": "Tennis Group First Meet and Greet", "type": "Online", "startDate": "2021-11-19 20:00:00", "endDate": "2021-11-19 22:00:00", "numAttending": 8, "previewImage": "image url", "Group": { "id": 1, "name": "Evening Tennis on the Water", "city": "New York", "state": "NY" }, "Venue": null, }, { "id": 1, "groupId": 1, "venueId": 1, "name": "Tennis Singles", "type": "In Person", "startDate": "2021-11-20 20:00:00", "endDate": "2021-11-19 22:00:00", "numAttending": 4, "previewImage": "image url", "Group": { "id": 1, "name": "Evening Tennis on the Water", "city": "New York", "state": "NY" }, "Venue": { "id": 1, "city": "New York", "state": "NY" }, }, ] }
-
-
Error response: Couldn't find a Group with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Group couldn't be found" }
-
Returns the details of an event specified by its id.
-
Require Authentication: false
-
Request
- Method: GET
- URL: /events/:eventId
- Body: none
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "id": 1, "groupId": 1, "venueId": 1, "name": "Tennis Group First Meet and Greet", "description": "First meet and greet event for the evening tennis on the water group! Join us online for happy times!", "type": "Online", "capacity": 10, "price": 18.50, "startDate": "2021-11-19 20:00:00", "endDate": "2021-11-19 22:00:00", "numAttending": 8, "Group": { "id": 1, "name": "Evening Tennis on the Water", "private": true, "city": "New York", "state": "NY" }, "Venue": { "id": 1, "address": "123 Disney Lane", "city": "New York", "state": "NY", "lat": 37.7645358, "lng": -122.4730327, }, "EventImages": [ { "id": 1, "url": "image url", "preview": true }, { "id": 2, "url": "image url", "preview": false } ], }
-
-
Error response: Couldn't find a Event with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Event couldn't be found" }
-
Creates and returns a new event for a group specified by its id
-
Require Authentication: true
-
Require Authorization: Current User must be the organizer of the group or a member of the group with a status of "co-host"
-
Request
-
Method: POST
-
URL: /groups/:groupId/events
-
Headers:
- Content-Type: application/json
-
Body:
{ "venueId": 1, "name": "Scooby Doo's Marathon", "type": "Online", "capacity": 1000, "price": 69.95, "description": "Likely a Mario Kart Tournament", "startDate": "2024-11-19 20:00:00", "endDate": "2024-11-19 22:00:00" }
-
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "id": 7, "groupId": 6, "venueId": 1, "name": "Scooby Doo's Marathon", "type": "Online", "capacity": 1000, "price": 69.95, "description": "Likely a Mario Kart Tournament", "startDate": "2024-11-19T20:00:00.000Z", "endDate": "2024-11-19T22:00:00.000Z" }
-
-
Error Response: Body validation errors
-
Status Code: 400
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Bad Request", // (or "Validation error" if generated by Sequelize), "errors": { "venueId": "Venue does not exist", "name": "Name must be at least 5 characters", "type": "Type must be Online or In person", "capacity": "Capacity must be an integer", "price": "Price is invalid", "description": "Description is required", "startDate": "Start date must be in the future", "endDate": "End date is less than start date" } }
-
-
Error response: Couldn't find a Group with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Group couldn't be found" }
-
Create and return a new image for an event specified by id.
-
Require Authentication: true
-
Require proper authorization: Current User must be an attendee, host, or co-host of the event
-
Request
-
Method: POST
-
URL: /events/:eventId/images
-
Headers:
- Content-Type: application/json
-
Body:
{ "url": "image url", "preview": false }
-
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "id": 1, "url": "image url", "preview": false }
-
-
Error response: Couldn't find an Event with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Event couldn't be found" }
-
Edit and returns an event specified by its id
-
Require Authentication: true
-
Require Authorization: Current User must be the organizer of the group or a member of the group with a status of "co-host"
-
Request
-
Method: PUT
-
URL: /events/:eventId
-
Headers:
- Content-Type: application/json
-
Body:
{ "venueId": 6, "name": "NEW BETTER NAME", "type": "Online", "capacity": 50, "price": 3.99, "description": "New and better name. We picked the best name, no one has better names than us.", "startDate": "2024-11-19 20:00:00", "endDate": "2024-11-19 21:00:00" }
-
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "id": 7, "groupId": 6, "venueId": 6, "name": "NEW BETTER NAME", "capacity": 50, "price": 3.99, "description": "New and better name. We picked the best name, no one has better names than us.", "startDate": "2024-11-19T20:00:00.000Z", "endDate": "2024-11-19T21:00:00.000Z" }
-
-
Error Response: Body validation errors
-
Status Code: 400
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Bad Request", // (or "Validation error" if generated by Sequelize), "errors": { "venueId": "Venue does not exist", "name": "Name must be at least 5 characters", "type": "Type must be Online or In person", "capacity": "Capacity must be an integer", "price": "Price is invalid", "description": "Description is required", "startDate": "Start date must be in the future", "endDate": "End date is less than start date" } }
-
-
Error response: Couldn't find a Venue with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Venue couldn't be found" }
-
-
Error response: Couldn't find an Event with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Event couldn't be found" }
-
Delete an event specified by its id
-
Require Authentication: true
-
Require Authorization: Current User must be the organizer of the group or a member of the group with a status of "co-host"
-
Request
- Method: DELETE
- URL: /events/:eventId
- Body: none
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Successfully deleted" }
-
-
Error response: Couldn't find an Event with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Event couldn't be found" }
-
Returns the members of a group specified by its id.
-
Require Authentication: false
-
Request
- Method: GET
- URL: /groups/:groupId/members
- Body: none
-
Successful Response: If you ARE the organizer or a co-host of the group. Shows all members and their statuses.
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "Members": [ { "id": 2, "firstName": "Clark", "lastName": "Adams", "Membership": { "status": "co-host" }, }, { "id": 3, "firstName": "John", "lastName": "Smith", "Membership": { "status": "member" }, }, { "id": 4, "firstName": "Jane", "lastName": "Doe", "Membership": { "status": "pending" }, }, ] }
-
-
Successful Response: If you ARE NOT the organizer of the group. Shows only members that don't have a status of "pending".
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "Members": [ { "id": 2, "firstName": "Clark", "lastName": "Adams", "Membership": { "status": "co-host" }, }, { "id": 3, "firstName": "John", "lastName": "Smith", "Membership": { "status": "member" }, }, ] }
-
-
Error response: Couldn't find a Group with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Group couldn't be found" }
-
Request a new membership for a group specified by id.
-
Require Authentication: true
-
Request
- Method: POST
- URL: /groups/:groupId/membership
- Headers:
- Content-Type: application/json
- Body: none
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "memberId": 2, "status": "pending" }
-
-
Error response: Couldn't find a Group with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Group couldn't be found" }
-
-
Error response: Current User already has a pending membership for the group
-
Status Code: 400
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Membership has already been requested" }
-
-
Error response: Current User is already an accepted member of the group
-
Status Code: 400
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "User is already a member of the group" }
-
Change the status of a membership for a group specified by id.
-
Require Authentication: true
-
Require proper authorization:
- To change the status from "pending" to "member":
- Current User must already be the organizer or have a membership to the group with the status of "co-host"
- To change the status from "member" to "co-host":
- Current User must already be the organizer
- To change the status from "pending" to "member":
-
Request
-
Method: PUT
-
URL: /groups/:groupId/membership
-
Headers:
- Content-Type: application/json
-
Body:
{ "memberId": 2, "status": "member" }
-
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "id": 1, "groupId": 1, "memberId": 2, "status": "member" }
-
-
Error response: If changing the membership status to "pending".
-
Status Code: 400
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Validations Error", "errors": { "status" : "Cannot change a membership status to pending" } }
-
-
Error response: Couldn't find a User with the specified memberId
-
Status Code: 400
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Validation Error", "errors": { "memberId": "User couldn't be found" } }
-
-
Error response: Couldn't find a Group with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Group couldn't be found" }
-
-
Error response: If membership does not exist
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Membership between the user and the group does not exist" }
-
Delete a membership to a group specified by id.
-
Require Authentication: true
-
Require proper authorization: Current User must be the host of the group, or the user whose membership is being deleted
-
Request
-
Method: DELETE
-
URL: /groups/:groupId/membership
-
Headers:
- Content-Type: application/json
-
Body:
{ "memberId": 1 }
-
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Successfully deleted membership from group" }
-
-
Error response: Couldn't find a User with the specified memberId
-
Status Code: 400
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Validation Error", "errors": { "memberId": "User couldn't be found" } }
-
-
Error response: Couldn't find a Group with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Group couldn't be found" }
-
-
Error response: Membership does not exist for this User
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Membership does not exist for this User" }
-
Returns the attendees of an event specified by its id.
-
Require Authentication: false
-
Request
- Method: GET
- URL: /events/:eventId/attendees
- Body: none
-
Successful Response: If you ARE the organizer of the group or a member of the group with a status of "co-host". Shows all attendees including those with a status of "pending".
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "Attendees": [ { "id": 2, "firstName": "Clark", "lastName": "Adams", "Attendance": { "status": "attending" }, }, { "id": 3, "firstName": "John", "lastName": "Smith", "Attendance": { "status": "waitlist" }, }, { "id": 4, "firstName": "Jane", "lastName": "Doe", "Attendance": { "status": "pending" }, }, ] }
-
-
Successful Response: If you ARE NOT the organizer of the group or a member of the group with a status of "co-host". Shows all members that don't have a status of "pending".
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "Attendees": [ { "id": 2, "firstName": "Clark", "lastName": "Adams", "Attendance": { "status": "attending" }, }, { "id": 3, "firstName": "John", "lastName": "Smith", "Attendance": { "status": "waitlist" }, }, ] }
-
-
Error response: Couldn't find an Event with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Event couldn't be found" }
-
Request attendance for an event specified by id.
-
Require Authentication: true
-
Require Authorization: Current User must be a member of the group
-
Request
- Method: POST
- URL: /events/:eventId/attendance
- Headers:
- Content-Type: application/json
- Body: none
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "userId": 2, "status": "pending" }
-
-
Error response: Couldn't find an Event with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Event couldn't be found" }
-
-
Error response: Current User already has a pending attendance for the event
-
Status Code: 400
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Attendance has already been requested" }
-
-
Error response: Current User is already an accepted attendee of the event
-
Status Code: 400
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "User is already an attendee of the event" }
-
Change the status of an attendance for an event specified by id.
-
Require Authentication: true
-
Require proper authorization: Current User must already be the organizer or have a membership to the group with the status of "co-host"
-
Request
-
Method: PUT
-
URL: /events/:eventId/attendance
-
Headers:
- Content-Type: application/json
-
Body:
{ "userId": 2, "status": "attending" }
-
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "id": 1, "eventId": 1, "userId": 2, "status": "attending" }
-
-
Error response: Couldn't find an Event with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Event couldn't be found" }
-
-
Error response: If changing the attendance status to "pending".
-
Status Code: 400
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Cannot change an attendance status to pending" }
-
-
Error response: If attendance does not exist
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Attendance between the user and the event does not exist" }
-
Delete an attendance to an event specified by id.
-
Require Authentication: true
-
Require proper authorization: Current User must be the host of the group, or the user whose attendance is being deleted
-
Request
-
Method: DELETE
-
URL: /events/:eventId/attendance
-
Headers:
- Content-Type: application/json
-
Body:
{ "userId": 1 }
-
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Successfully deleted attendance from event" }
-
-
Error response: Couldn't find an Event with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Event couldn't be found" }
-
-
Error response: Attendance does not exist for this User
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Attendance does not exist for this User" }
-
-
Error response: Only the User or organizer may delete an Attendance
-
Status Code: 403
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Only the User or organizer may delete an Attendance" }
-
Delete an existing image for a Group.
-
Require Authentication: true
-
Require proper authorization: Current user must be the organizer or "co-host" of the Group
-
Request
- Method: DELETE
- URL: /images/group-images/:imageId
- Body: none
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Successfully deleted" }
-
-
Error response: Couldn't find an Image with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Group Image couldn't be found" }
-
Delete an existing image for an Event.
-
Require Authentication: true
-
Require proper authorization: Current user must be the organizer or "co-host" of the Group that the Event belongs to
-
Request
- Method: DELETE
- URL: /images/event-images/:imageId
- Body: none
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Successfully deleted" }
-
-
Error response: Couldn't find an Image with the specified id
-
Status Code: 404
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Event Image couldn't be found" }
-
Return events filtered by query parameters.
-
Require Authentication: false
-
Request
- Method: GET
- URL: /events
- Query Parameters
- page: integer, minimum: 1, maximum: 10, default: 1
- size: integer, minimum: 1, maximum: 20, default: 20
- name: string, optional
- type: string, optional
- startDate: string, optional
- Body: none
-
Successful Response
-
Status Code: 200
-
Headers:
- Content-Type: application/json
-
Body:
{ "Events": [ { "id": 1, "groupId": 1, "venueId": null, "name": "Tennis Group First Meet and Greet", "type": "Online", "startDate": "2021-11-19 20:00:00", "endDate": "2021-11-19 22:00:00", "numAttending": 8, "previewImage": "image url", "Group": { "id": 1, "name": "Evening Tennis on the Water", "city": "New York", "state": "NY" }, "Venue": null, }, { "id": 1, "groupId": 1, "venueId": 1, "name": "Tennis Singles", "type": "In Person", "startDate": "2021-11-20 20:00:00", "endDate": "2021-11-19 22:00:00", "numAttending": 4, "previewImage": "image url", "Group": { "id": 1, "name": "Evening Tennis on the Water", "city": "New York", "state": "NY" }, "Venue": { "id": 1, "city": "New York", "state": "NY", }, }, ] }
-
-
Error Response: Query parameter validation errors
-
Status Code: 400
-
Headers:
- Content-Type: application/json
-
Body:
{ "message": "Bad Request", // (or "Validation error" if generated by Sequelize), "errors": { "page": "Page must be greater than or equal to 1", "size": "Size must be greater than or equal to 1", "name": "Name must be a string", "type": "Type must be 'Online' or 'In Person'", "startDate": "Start date must be a valid datetime", } }
-
##Navigation Our Navigation component is hosted at the top of ever page to allow for easy site maneuverability
Upon attempting to Sign Up for MeetPup, the SignUp form Modal opens and displays our Sign Up Form Page
Creates a new User to navigate site.
If a new user already has a log-in, they may browse their groups and events via the Login Form Modal
the login modal hosts the Login Form Page for all users
From our landing page, Users may create a group via this form component
Groups component allows us to view all Groups, which loads our Single Card component
Creates an individual card for each group within our database
Upon clicking any card, user is redirected to our Group Cards component which hosts group details our group can be updated here via the Edit Group Form component and deleted.
upon attempt to delete a group, a modal component was created to verify desire to delete a group.
Within our group details component, we host our Single Event Card which redirects to our Single Event Detail component for each of our upcoming and past events for each group
##Single Event Detail Hosts our detailed Event component which allows us to read single events and methods for deleting. Upon completion of the update Event component, it will also be available through Single Event Detail
Events component allows us to view all Events, both upcoming at the top and past events at the bottom
Below is our Front End paths
<> {isLoaded && (
<Route exact path='/groups/new'>
<CreateGroupForm />
</Route>
<Route exact path='/groups/:groupId/events/new'>
<CreateEventForm />
</Route>
<Route path="/login">
<LoginFormPage />
</Route>
<Route path="/signup">
<SignupFormPage />
</Route>
<Route exact path="/">
<Splash />
</Route>
<Route path='/groups/:groupId/edit'>
<EditGroupForm groups={groups}/>
</Route>
<Route exact path='/groups/:groupId'>
<SingleCard />
</Route>
<Route path='/events/:eventId/edit'>
<EditEventForm />
</Route>
<Route exact path='/events/:eventId'>
<SingleEventDetail />
</Route>
<Route exact path='/groups'>
<Groups />
</Route>
<Route path='/events'>
<Events />
</Route>
</Switch>
)}
export const rootReducer = combineReducers({ session: sessionReducer, group: groupReducer, events: eventReducer });
We will soon implement Memberships, Attendance, Venues full CRUDS and Update CRUD for our Events component
A few of the greatest challenges faced during this project composition includes conditional loading, proper utilization and construction of state, and breaking down each step within project construction. I would frequently find I had tangentially moved to another component or task while coding this project
Another challenge and accomplished feat involved solving how to best format our Date and Time information to meet the requirements within each component. These were the helper functions composed to complete this task:
//date and time helper functions
function splitDateTime(dateTimeString) {
const [date, fullTime] = dateTimeString.split('T');
const time = fullTime ? fullTime.split('.')[0] : '';
return { date, time } ;
}
function splitEndTime(dateTimeString) {
const [endDate, fullTime] = dateTimeString.split('T');
const endTime = fullTime ? fullTime.split('.')[0] : '';
return { endDate, endTime } ;
}
function convertToAMPM(timeString) {
if (!timeString) return '';
const [hour, minute] = timeString.split(':');
let amOrPm = 'AM';
let adjustedHour = parseInt(hour, 10);
if (adjustedHour >= 12) {
amOrPm = 'PM';
if (adjustedHour > 12) {
adjustedHour -= 12;
}
}
return `${adjustedHour}:${minute} ${amOrPm}`;
}
A section of code I wish to revise in the future for efficiency includes my Group Detail component which also hosts all upcoming events and past events. Rewriting my store to hold this information in state without having to make multiple calls to the backend would drastically increase the functioning speed of my application:
{showModal && (
<Modal onClose={() => setShowModal(false)}>
{modalContent === 'joinGroup' && (
<div className='feature-coming-soon'>
<div>Feature coming soon...</div>
</div>
)}
{modalContent === 'deleteConfirmation' && (
<div className="confirm-modal-content">
<div className="confirm-modal-title">
Confirm Delete
</div>
<div className="confirm-modal-text">
Are you sure you want to delete this group?
</div>
<div className="confirm-modal-option-1">
<button className='single-card-crud-event-red' onClick={handleConfirmDelete}>Confirm (Delete Group)</button>
</div>
<div className="confirm-modal-option-2">
<button className='single-card-crud-event' onClick={() => setShowModal(false)}>Cancel (Keep Group)</button>
</div>
</div>
)}
</Modal>
)}
{( loading || groupLoading) ? (
<div className="loading-container">
Loading...
</div>
) : (
<div className="single-eventDetail-container">
<div className="event-header-container">
<div className='redirect-to-allCards'>
<div className='single-link-arrow'><</div>
<Link className='single-event-link' to='/groups'>Groups </Link>
</div>
</div>
<div className='single-card-container'>
<div className='single-card-top'>
<img className='single-card-image' src={preview} alt="No Image"/>
<div className='single-card-top-info'>
<div className='single-card-top-name'>
{group.name}
</div>
<div className='single-card-top-location'>
{group.city}, {group.state}
</div>
<div className='single-card-top-privacy-status'>
{uniqueEvents.length} events · {group.private ? 'Private' : 'Public'}
</div>
<div className='single-card-top-organizer-fullname'>
Organized by: {group.Organizer?.firstName} {group.Organizer?.lastName}
</div>
<div className='single-card-top-buttons'>
{buttons}
</div>
</div>
</div>
<div className='single-event-body-container'>
<div className='single-group-body-container'>
<div className='single-card-bottom-top-container'>
<div className='single-card-top-name'>Organizer</div>
<div className='single-card-top-location'> {group.Organizer?.firstName} </div>
</div>
<div className='single-card-bottom-mid-container'>
<div className='single-card-top-name'>What we're about</div>
<div className='single-card-about'>{group.about}</div>
</div>
<div className='single-card-events-container'>
<div className='single-card-top-name'>
Upcoming Events({futureEventsCount})
</div>
{loading ? (
<div className='loading-notification'>Loading events...</div>
): uniqueEvents.length === 0 ? (
<div className='no-upcoming-events-text'>No upcoming events</div>
) : (
uniqueEvents.map(event => (
<SingleEventCard key={event.id} event={event} />
))
)}
</div>
<div className='single-card-events-container'>
<div className='single-card-top-name'>
Past Events({uniquePastEventsCount})
</div>
<div>
{loading ? (
<div className='loading-notification'>Loading events...</div>
): uniquePastEvents.length === 0 ? (
<div className='no-upcoming-events-text'>No upcoming events</div>
) : (
uniquePastEvents.map(event => (
<SingleEventCard key={event.id} event={event} />
))
)}
</div>
</div>
</div>
</div>
</div>
</div>)}
Chris Gomez: [email protected]