HaulAway is a user-to-user service that helps alleviate the difficulties of moving haul from one destination to the next.
We all know the struggles of moving. It takes a considerable amount of time signing up for moving services and find out the right vehicle sizes and price plans. With HaulAway, we make that simpler.
In this fullstack application, every information is stored in our NoSQL
document-oriented Mongo
database. Express
is used for our backend routing to simplify the task of writing server code. React
is the tool used for creating dynamic and scalable views rendered in HTML
. Lastly with Node
, JavaScript
is able to be implemented in the backend used to handle server-side requests.
Joshua C. Sadsad: Lead
Lena Shin: Backend
Fabio R. Bortone: Frontend
Dmitrii An: Flex
Backend | Frontend |
---|---|
MongoDB | React |
Express | google-maps-react |
Node | react-google-autocomplete |
multer | react-geocode |
AWS S3 | geolib |
- User Auth
The HaulAway team implemented a User Authentication system to access the job form and display the respective job in an index. Users are required to upload a profile picture that stores into our AWS S3 bucket.
- Job Postings
Users have to submit a form with required fields such as pickup, destination, start date, and end date. These fields are required to pass validations in order to submit a job.
In the Job Index, only available jobs are shown through a selector
.
export const getAvailableJobs = (state) => {
return Object.values(state.entities.jobs).filter((job) => job.isAvailable)
}
- Google Maps
Googles Maps is dynamically supported to show where a destination or pickup can be depending on the route. A Circle
prop is included in the map to help visualize the location.
On the job form, there is a default location until the Destination is submitted. Using geolib
, distance is calculated from Pickup to Destination. Once distanced is obtained, a price is also able to be generated and stored within every new Job.
onDestinationSelected(place) {
const address = place.formatted_address,
latValue = place.geometry.location.lat(),
lngValue = place.geometry.location.lng()
this.setState({
destinationCoords: {
lat: latValue,
lng: lngValue,
},
destination: address ? address : '',
markerPosition: {
lat: latValue,
lng: lngValue,
},
mapPosition: {
lat: latValue,
lng: lngValue,
},
})
}
- AWS
Users have the ability to upload multiple photos at once and images are uniquely stored in the MongoDB Collection.
router.post('/uploads', upload.array('file', 12), (req, res) => {
const file = req.files
let s3bucket = new AWS.S3({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
region: process.env.AWS_REGION,
})
s3bucket.createBucket(function () {
let ResponseData = []
file.map((item) => {
let params = {
Bucket: process.env.AWS_BUCKET_NAME,
Key: item.originalname,
Body: item.buffer,
ACL: 'public-read',
}
s3bucket.upload(params, function (err, data) {
if (err) {
res.json({ error: true, Message: err })
} else {
ResponseData.push(data)
if (ResponseData.length == file.length) {
res.json({
Message: 'File Uploaded successfully',
Data: ResponseData,
})
}
}
})
})
})
})
- Reviews
Once 2 Users (1 Job Poster and 1 Job Taker) have interacted and closed a job, they now have the ability to review each other. Reviews are able to be updated or deleted.
reviewJobButtons() {
const job = this.props.job
if (!job.reviews.includes(this.props.currentUserId)) {
if (
(job.jobPoster._id === this.props.currentUserId ||
job.jobTaker === this.props.currentUserId) &&
job.isClosed
) {
return (
<div className="review-job-buttons">
<div className="review-buttons-title">
Would you like to review this transaction?
</div>
<div className="review-job-buttons-inner-wrap">
<Link to={`/jobs/${job._id}/review`} job={job}>
<button className="yes-review-button">YES</button>
</Link>
<button
className="no-review-button"
onClick={(e) => this.handleClick('noReviewJob', e)}
>
NO
</button>
</div>
</div>
)
}
}
}
- User Average Ratings
- Calculate Fees Depending on Distance
- User Private Messaging