Linkr is a professional networking application that allows users to connect in a simplified manner. Users are presented with several users in their city that they can choose to connect with or reject. The idea is centered around users forming connections based on whether or not they find someones business interests or occupation attractive. Users can connect or reject potential associates with a swipe. Users can swipe right to form a connection with another user or swipe left if they don't want to form a connection with a user. Forming a connection allows both users to view more intimate details about their professional lives like their linkedIn profile link, professional networking sites, or portfolios. Skipping or rejecting a user means they will not appear as a potential suggestion in the future.
Since networking has taken a turn for the digital, Linkr strives to be the intuitive go-to application for meeting new associates.
Explore our app! Linkr
- clone this repository
- run
npm install
inside root directory and frontend directory - run
npm run dev
in root directory - navigate to
localhost:3000
in your browser
- React.js
- Node.js
- MongoDB
- Express.js
- AWS S3
- Faker
- socket.io
Linkr is centered around user interaction so we implemented a schema allows our backend to keep track of users' relationships. When users interact with another profile, the user tags the other profile as either blocked, pending, or connected and stores this information as arrays in the user's document. Swiping is how the user interacts other profiles. Swiping left will skip the other profile and adds their profile to the user's blocked list. Swiping right adds the other profile to the user's pending list or if the other profile has swiped right on the user's profile to the user's connected user's list. Getting a mutual swipe right results in a successful connection adding the users to each others connected array.
User profiles are rendered to a user depending on their location, we filter through all the users in the database to only show users near their area. In the future we plan to not only render users within the area, but give users the option to filter through other parameters.
router.get('/query/:filter/:value', (req, res) => {
User.find({[req.params.filter]: req.params.value})
.sort({ date: -1 })
.then(users => res.json(users))
.catch( err =>
res.status(404).json({ nousersfound: 'No users found'})
);
});
To keep track of what users are connected, we used a Connection Schema where we stored arrays of connected, pending, or blocked. The connected
array stored user id's of other users that had reciprocated. connection request. The pending
array stored the ids of the users that have sent a connection request to the current user already, and the blocked
array stores the ids of the users that did not request to connect with the current user. When a user swipes left or right it dispatch a connection action with a status of "add"
or "block"
. The add
status goes through a series of conditionals where we reference both users' connection instances to check if the users have a pending connection, if they do, then they both get reinstated into the connected array. If a user is new, their connection instance is generated on their first swipe. The conditional statement handling the "add" status was very complicated and one of our biggest challenges. We had to aacount for new users without a schema, users that had already requested to connect and also blocked users. Although we have a fully functional feature, we plan to refactor so that we can optimize the space and time.
} else if (status === "block") {
User.findOne({ _id: currUser_id }).then(user => {
if (user.connection) {
user.connection.blocked.push(nextUser_id);
user.save()
return res.json('block')
} else {
let connection = new Connection({ connected: [], pending: [], blocked: [nextUser_id] })
user.connection = connection;
user.save();
return res.json('block')
}
})
When users are connected, they are automatically added to their connections page, where the current user can browse through their established connections giving them access to full profiles. In the connections page the profile cards display all information related to the user selected.
Users can communicate through a chat feature. Our feature was implemented using socket.io
to update the chat in real-time whenever a new message has been posted. We incorporated a third server to be able to implement our feature. We made it accessible in every page so that the user can easily respond to messages as they browse through he application. This is a global chat that will ideally be used for job postings or networking opportunities for all our users to access and post on.
io.on('connection', (socket) => {
Message.find().sort({createdAt: -1}).limit(10).exec((err, messages) => {
if (err) return console.error(err);
socket.emit('init', messages);
});
socket.on('message', (msg) => {
const message = new Message({
content: msg.content,
name: msg.name,
});
message.save((err) => {
if (err) return console.error(err);
});
socket.broadcast.emit('push', msg);
});
});
http.listen(port, () => {
console.log('listening on *:' + port);
});
Since this app was meant to be used as a social networking application, we decided to optimize so that it is mobile friendly. Our app can be easily accessible on your phone so that i can be readily available on whatever device you use.
#friend-index{
background-color: rgba(255, 255, 255, 0.294);
-webkit-box-shadow: -1px 1px 3px 4px rgba(37, 92, 122, 0.459), 1px 2px 3px 5px rgba(67, 122, 152, 0.452), 0px 5px 0px 3px rgba(198,147,177,0.79), inset 0px 0px 11px 1px rgba(192,186,148,0.76), inset 0px 0px 8px 1px rgba(192,186,148,0.76);
box-shadow: -1px 1px 3px 4px rgba(37, 92, 122, 0.459), 1px 2px 3px 5px rgba(67, 122, 152, 0.452), 0px 5px 0px 3px rgba(198,147,177,0.79), inset 0px 0px 11px 1px rgba(192,186,148,0.76), inset 0px 0px 8px 1px rgba(192,186,148,0.76);
@media screen and (min-width: 1259px){
overflow-y:scroll;
position: absolute;
width: 370px;
height: 390px;
max-height: 60%;
display: grid;
grid-template-columns: 33% 33% 33%;
grid-auto-rows: 31%;
margin: auto;
right: 25px;
top: 35%;
justify-content: center;
justify-items: center;
align-content: center;
}
@media screen and (max-width: 1259px){
transform:translateY(95px);
height: fit-content;
min-width: 50%;
margin-bottom: 100px;
display: flex;
flex-direction: row;
overflow-x:scroll;
width: 100%;
height: min-content;
}
@media screen and (min-width: 1500px){
width: 440px;
height: 470px;
top: 30%;
}
}
- Swipe Event
- Peer to Peer private messaging
- Job board