Creating the LinkTree page of a user | LinkTree Project

• Updated May 5, 2023

This tutorial is a part of the Series ‘Complete FullStack LinkTree Project with MERN‘. This Project covers beginner to Intermediate level implementation of MongoDB, Express, ReactJS, NodeJS, and NextJS.

Project Walkthrough

Users can signup on the LinkTree website and start creating their LinkTree immediately. They get a user profile editing page, an edit or customize links page, a Dashboard to edit and track the links, and many more.

I’ve created a YouTube series on this Project in 6 parts. This Code snippet is from the 5th part where we create a LinkTree page itself for a single user.

Frontend

import React from 'react'
import LinkTreeCard from './LinkTreeCard'
import {AnimatePresence, motion} from 'framer-motion';

const LinkTree = ({data}) => {
    const {name, avatar, bio, links} = data;
  return (
    <>
        <section className='relative'>
            <img className='w-20 absolute rounded-full left-1/2 -translate-x-1/2 mt-2' src={avatar} alt="" />
            <h2 className='text-center text-lg font-bold pt-28'>{name ? name: 'No Username'}</h2>
            <p className='text-center pb-5'>{bio}</p>
            <div className='flex flex-col justify-center max-w-7xl m-auto md:my-5 w-full md:w-2/5'>
                <AnimatePresence>
                    {links.map((link, index)=>(
                        <motion.div
                            key={index}
                            initial={{ opacity: 0, y:40 }}
                            animate={{ opacity: 1, y: 0, transition: {delay: index * 0.1 + 0.5} }}
                        >
                            <LinkTreeCard title={link.title} url={link.url} image={link.icon}/>
                        </motion.div>
                    ))}
                </AnimatePresence>
            </div>
        </section>
    </>
  )
}

export default LinkTree
import Link from 'next/link'
import React from 'react'

const LinkTreeCard = ({title, url, image}) => {
  return (
    <>
        <span className='w-full'>
            <Link className='flex flex-row items-center p-2 rounded-xl text-white bg-indigo-400 hover:bg-indigo-300 mb-3 mx-2 hover:translate-x-1 hover:translate-y-1 transition-all duration-500' target="_blank" href={`https://${url}`}>
                <img className='bg-white rounded-md p-1 w-11 mr-5' src={image} alt="" />
                <h4 className='md:text-lg'>{title}</h4>
            </Link>
        </span>
    </>
  )
}

export default LinkTreeCard
import Link from 'next/link';
import React from 'react'

const SocialTree = ({social}) => {
    const {
        facebook,
        twitter,
        instagram,
        youtube,
        linkedin,
        github
    } = social;
    return (
        <>
            <div className="social flex flex-row justify-center my-4">
                <Link className='bg-white rounded-full p-2 hover:bg-zinc-100 transition-all duration-500 hover:scale-110 shadow border border-gray-70 mx-1 select-none' target='_blank' href={`https://facebook.com/${facebook}`}>
                    <img className='w-6' src="/svg/facebook.svg"/>
                </Link>
                <Link className='bg-white rounded-full p-2 hover:bg-zinc-100 transition-all duration-500 hover:scale-110 shadow border border-gray-70 mx-1 select-none' target='_blank' href={`https://instagram.com/${facebook}`}>
                    <img className='w-6' src="/svg/instagram.svg"/>
                </Link>
                <Link className='bg-white rounded-full p-2 hover:bg-zinc-100 transition-all duration-500 hover:scale-110 shadow border border-gray-70 mx-1 select-none' target='_blank' href={`https://youtube.com/${facebook}`}>
                    <img className='w-6' src="/svg/yt.svg"/>
                </Link>
                <Link className='bg-white rounded-full p-2 hover:bg-zinc-100 transition-all duration-500 hover:scale-110 shadow border border-gray-70 mx-1 select-none' target='_blank' href={`https://linkedin.com/${facebook}`}>
                    <img className='w-6' src="/svg/lnkdn.svg"/>
                </Link>
                <Link className='bg-white rounded-full p-2 hover:bg-zinc-100 transition-all duration-500 hover:scale-110 shadow border border-gray-70 mx-1 select-none' target='_blank' href={`https://github.com/${facebook}`}>
                    <img className='w-6' src="/svg/github.svg"/>
                </Link>
                <Link className='bg-white rounded-full p-2 hover:bg-zinc-100 transition-all duration-500 hover:scale-110 shadow border border-gray-70 mx-1 select-none' target='_blank' href={`https://twitter.com/${facebook}`}>
                    <img className='w-6' src="/svg/twt.svg"/>
                </Link>
            </div>
        </>
    )
}

export default SocialTree
import React, { useState, useEffect } from 'react'
import {useRouter} from 'next/router';
import LinkTree from '../components/LinkTree'
import Link from 'next/link';
import SocialTree from '../components/SocialTree'
import ShareButton from '../components/ShareButton'

const Handle = () => {

    const router = useRouter();
    const [data, setData] = useState({});
    const [userFound, setUserFound] = useState(false);

    const [social, setSocial] = useState({
        facebook: '',
        twitter: '',
        instagram: '',
        youtube: '',
        linkedin: '',
        github: ''
    })

    useEffect(()=>{
        if(router.query?.handle){
            fetch(`http://localhost:8080/get/${router.query.handle}`)
            .then(res=>res.json())
            .then(data=>{
                if(data.status==='error') return toast.error(data.error);
                if(data.status==='success'){
                    setData(data.userData);
                    setSocial(data.socials);
                    setUserFound(true);
                }
            }).catch(err=>{
                console.log(err);
            })
        }
    }, [router.query])

    if(!userFound){
        return(
            <div className='flex justify-center items-center h-screen'>
                <div className="not-found px-3 ">
                    <h1 className='font-bold text-lg'>User Not found 🙁</h1>                    
                    <p>If you're looking for a page, double check the spelling.</p>
                    Create your own<Link className='bg-indigo-600 px-2 ml-2 text-white hover:bg-indigo-400 transition-all duration-500' href="/apply"> LinkTree</Link>
                </div>
            </div>
        )
    }

    return (
        <div>
            <ShareButton/>
            <LinkTree data={data}/>
            <SocialTree social={social} />
        </div>
    )
}

export default Handle

Backend

// Added user data grabbing to previous code in index.js

app.get('/get/:handle', getUserData);
const User = require('../models/user')

const getUserData = async(req, res)=>{
    const handle = req.params.handle;
    try {
        const user = await User.findOne({handle: handle});
        console.log(user);
        const userData = {
            name: user.name,
            avatar: user.avatar,
            bio: user.bio,
            links: user.links
        }
        const socials = user.socialMedia;
        return res.json({ message: 'found', userData, socials, status: 'success'})
    } catch (err) {
        console.log(err);
        return res.json({ status: 'error', error: err.message});
    }
}

const getUserSocials = async(req, res)=>{
    const handle = req.params.handle;
    try {
        console.log(handle);
        const user = await User.findOne({handle: handle});
        const socials = user.socialMedia;
        return res.json({ message: 'found', socials, status: 'success'})
    } catch (err) {
        return res.json({ status: 'error', error : err.message});
    }
}

module.exports = {getUserData, getUserSocials}

Summing up

I hope this part of the tutorial on the Fullstack LinkTree Project was helpful to you. If you faced any problems while following the video or the source code snippets, comment below and I’ll reply as soon as possible. See you soon.

Sharing Is Caring:

An aspiring BTech Electronics and Communication student, obsessed with Coding, Gadgets, and Blogging.

Leave a Comment