Skip to content
/ Chirpy Public

Chirpy: Redesigning Threads App: Chirpy's Approach for Addressing the Gaps Left by Threads

License

Notifications You must be signed in to change notification settings

LeinahI/Chirpy

Repository files navigation

NEXT.js 13.5.6 Chirpy

Thumbnail

Leinah License Top Language deployment Known Vulnerabilities

πŸ“– Table of Contents

Table of Contents

🌐 Live Demo

Look at the project's live demonstration: Chirpy web application

πŸ“ Description

Users can share their thoughts with other users on the social media platform named Chirpy by using this application. Chirpy is a server-side rendering, full-stack web application written in TypeScript and Next.js 13. It makes use of Clerk as the provider of authentication and MongoDB as the database. It uploads pictures to the cloud via UploadThing as well. Tailwind CSS and Shadcn components are utilized for styling the application.

🏁 Purpose

Our objective is to develop "Chirpy," an application that addresses accessibility concerns and goes above and beyond to make sure that all users, regardless of their abilities or impairments, feel not only accommodated but also genuinely welcomed. We are committed to developing a platform where inclusion is the norm and understand how crucial it is to make it user-friendly for everyone.

πŸ— Application Structure

Folder Structure
chirpy
β”œβ”€ app
β”‚  β”œβ”€ (auth)
β”‚  β”‚  β”œβ”€ layout.tsx
β”‚  β”‚  β”œβ”€ onboarding
β”‚  β”‚  β”‚  └─ page.tsx
β”‚  β”‚  β”œβ”€ sign-in
β”‚  β”‚  β”‚  └─ [[...sign-in]]
β”‚  β”‚  β”‚     └─ page.tsx
β”‚  β”‚  └─ sign-up
β”‚  β”‚     └─ [[...sign-up]]
β”‚  β”‚        └─ page.tsx
β”‚  β”œβ”€ (root)
β”‚  β”‚  β”œβ”€ activity
β”‚  β”‚  β”‚  └─ page.tsx
β”‚  β”‚  β”œβ”€ chirp
β”‚  β”‚  β”‚  β”œβ”€ reactions
β”‚  β”‚  β”‚  β”‚  └─ [id]
β”‚  β”‚  β”‚  β”‚     └─ page.tsx
β”‚  β”‚  β”‚  └─ [id]
β”‚  β”‚  β”‚     └─ page.tsx
β”‚  β”‚  β”œβ”€ circles
β”‚  β”‚  β”‚  β”œβ”€ page.tsx
β”‚  β”‚  β”‚  └─ [id]
β”‚  β”‚  β”‚     └─ page.tsx
β”‚  β”‚  β”œβ”€ create-chirp
β”‚  β”‚  β”‚  └─ page.tsx
β”‚  β”‚  β”œβ”€ edit-chirp
β”‚  β”‚  β”‚  └─ [id]
β”‚  β”‚  β”‚     └─ page.tsx
β”‚  β”‚  β”œβ”€ layout.tsx
β”‚  β”‚  β”œβ”€ page.tsx
β”‚  β”‚  β”œβ”€ profile
β”‚  β”‚  β”‚  β”œβ”€ edit
β”‚  β”‚  β”‚  β”‚  └─ page.tsx
β”‚  β”‚  β”‚  └─ [id]
β”‚  β”‚  β”‚     └─ page.tsx
β”‚  β”‚  └─ search
β”‚  β”‚     └─ page.tsx
β”‚  β”œβ”€ api
β”‚  β”‚  β”œβ”€ uploadthing
β”‚  β”‚  β”‚  β”œβ”€ core.ts
β”‚  β”‚  β”‚  └─ route.ts
β”‚  β”‚  └─ webhook
β”‚  β”‚     └─ clerk
β”‚  β”‚        └─ route.ts
β”‚  β”œβ”€ favicon_io.zip
β”‚  β”œβ”€ globals.css
β”‚  └─ icon.ico
β”œβ”€ components
β”‚  β”œβ”€ atoms
β”‚  β”‚  β”œβ”€ EditChirp.tsx
β”‚  β”‚  β”œβ”€ FollowUser.tsx
β”‚  β”‚  └─ ReactChirp.tsx
β”‚  β”œβ”€ cards
β”‚  β”‚  β”œβ”€ ChirpCard.tsx
β”‚  β”‚  β”œβ”€ CircleCard.tsx
β”‚  β”‚  └─ UserCard.tsx
β”‚  β”œβ”€ forms
β”‚  β”‚  β”œβ”€ AccountProfile.tsx
β”‚  β”‚  β”œβ”€ Comment.tsx
β”‚  β”‚  β”œβ”€ DeleteChirp.tsx
β”‚  β”‚  └─ PostChirp.tsx
β”‚  β”œβ”€ shared
β”‚  β”‚  β”œβ”€ Bottombar.tsx
β”‚  β”‚  β”œβ”€ ChirpsTab.tsx
β”‚  β”‚  β”œβ”€ LeftSidebar.tsx
β”‚  β”‚  β”œβ”€ Pagination.tsx
β”‚  β”‚  β”œβ”€ ProfileHeader.tsx
β”‚  β”‚  β”œβ”€ RightSidebar.tsx
β”‚  β”‚  β”œβ”€ Searchbar.tsx
β”‚  β”‚  β”œβ”€ SearchBarCircles.tsx
β”‚  β”‚  └─ Topbar.tsx
β”‚  └─ ui
β”‚     β”œβ”€ button.tsx
β”‚     β”œβ”€ form.tsx
β”‚     β”œβ”€ input.tsx
β”‚     β”œβ”€ label.tsx
β”‚     β”œβ”€ tabs.tsx
β”‚     └─ textarea.tsx
β”œβ”€ components.json
β”œβ”€ constants
β”‚  └─ index.js
β”œβ”€ lib
β”‚  β”œβ”€ actions
β”‚  β”‚  β”œβ”€ chirp.actions.ts
β”‚  β”‚  β”œβ”€ circle.actions.ts
β”‚  β”‚  └─ user.actions.ts
β”‚  β”œβ”€ models
β”‚  β”‚  β”œβ”€ chirp.model.ts
β”‚  β”‚  β”œβ”€ circle.model.ts
β”‚  β”‚  └─ user.model.ts
β”‚  β”œβ”€ mongoose.ts
β”‚  β”œβ”€ uploadthing.ts
β”‚  β”œβ”€ utils.ts
β”‚  └─ validations
β”‚     β”œβ”€ chirp.ts
β”‚     └─ user.ts
β”œβ”€ middleware.ts
β”œβ”€ next.config.js
β”œβ”€ package-lock.json
β”œβ”€ package.json
β”œβ”€ postcss.config.js
β”œβ”€ public
β”‚  β”œβ”€ assets
β”‚  β”‚  └─ user.svg
β”‚  β”œβ”€ next.svg
β”‚  └─ vercel.svg
β”œβ”€ README.md
β”œβ”€ tailwind.config.js
└─ tsconfig.json

Look at each folder cautiously to see what they contain

app/

(auth)/ - (root)/ - (api)/

In the app directory, nested folders are normally mapped to URL paths. However, you can mark a folder as a Route Group to prevent the folder from being included in the route's URL path.

This allows you to organize your route segments and project files into logical groups without affecting the URL path structure.

For example,

components/

atoms/ - cards/ - forms/ - shared/ - ui/

The components directory contains all the components used in the application. The components are grouped into atoms, cards, forms, shared and ui. the ui folder generated by shadcn/ui package and contains all the required shadcn components that used in the application.

constants/

index.js

This is a JavaScript code contains all the constants used in the application, specifically the Sidebar Navigation (sidebarLinks), Profile Tabs (profileTabs) and Circle Tabs (circleTabs) constants.

lib/

actions/ - models/ - validations/ - mongoose.ts - uploadthing.ts - utils.ts

The lib folder holds crucial components for Chirpy App:

  • actions: Manage actions for Circle, Chirp, and User entities using Mongoose for database interaction.
  • models: Define mongoose schemas for Circle, Chirp, and User entities.
  • validations: Provide validation schemas with Zod for Chirp and User data.
  • mongoose.ts: Establishes and manages MongoDB connections for the application.
  • uploadthing.ts: Offers a React utility for simplified file uploads to UploadThing.
  • utils.ts: Contains various reusable utility functions.

public/

assets/ - next.svg - vercel.svg

The public directory contains the media used in the application. The assets folder contains all the images used in the application.

✨ Technologies Used

Chirpy is built using the following technologies:
  • TypeScript: TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.
  • Next.js 13: Next.js is a React framework for building server-side rendered and statically generated web applications.
  • Tailwind CSS: Tailwind CSS is a utility-first CSS framework for rapidly building custom user interfaces.
  • Shadcn: Shadcn is a collection of Tailwind CSS components.
  • Clerk: Clerk is a developer-first authentication API that handles all the logic for user sign up, sign in, and more.
  • UploadThing: UploadThing is a simple, fast, and reliable file uploader for your website.
  • MongoDB: MongoDB is a general purpose, document-based, distributed database built for modern application developers and for the cloud era.
  • Mongoose: Mongoose is a MongoDB object modeling tool designed to work in an asynchronous environment.
  • Zod: Zod is a TypeScript-first schema declaration and validation library.
  • svix: Svix is a webhook proxy that allows you to receive webhooks locally.
  • emoji-mart: Emoji Mart is a customizable. emoji picker HTML component for the web.
  • Vercel: Vercel is a cloud platform for frontend developers, providing the frameworks, workflows, and infrastructure to build a faster, more personalized Web.

Technologies Used

🧰 Get Started

To get this project up and running in your development environment, follow these step-by-step instructions.

πŸ“‹ Prerequisites

In order to install and run this project locally, you would need to have the following installed on your local machine.

βš™οΈ Installation and Run Locally

Step 0:

Create ‼️ .env.local file and it should be located alongside with .gitignore, next.config.js & etc.
image

Note ‼️ the application uses Clerk for Authentication and User Management, therefore, you need to create Clerk account here and sets the CLERK_PUBLISHABLE_KEY and CLERK_SECRET_KEY environment variables in .env.local file. Also, the different URLs for the Clerk sign-in, sign-up, after sign-in and after sign-up pages.

Note ‼️ the application uses a MongoDB database, therefore, you need to create a database and connect it to the application, for this, change the MONGODB_URL environment variable in .env.local file located in server folder.

Note ‼️ the application uses a UploadThing Cloud, therefore, you need to create UploadThing account here and sets the UPLOADTHING_SECRET and UPLOADTHING_APP_ID environment variables in .env.local file.

After following all the instructions above, we'll want to create a new webhook on Clerk. To do this, go to the Clerk Dashboard, click on the "Webhooks" tab, and then click "Add Endpoint". For the Endpoint URL, enter http://<PASTE-YOUR-LINK-HERE>/api/webhook/clerk. For the evetnts, select the "organization", "organizationDomain", "organizationInvitation" and "organizationMembership". Then click "Create" to create the webhook. get the signing secret and set it as CLERK_WEBHOOK_SECRET environment variable in .env.local file.

Step 1:

Download or clone this repo by using the link below:

git clone https://github.com/LeinahI/Chirpy.git

Step 2:

Execute the following command in the root directory of the downloaded repo in order to install dependencies:

npm install

Step 3:

Execute the following command in order to run the development server locally:

npm run dev

Step 4:

Open http://localhost:3000 with your browser to see the result.

πŸ“œ Scripts

All scripts are defined in the package.json file. Here is a list of all scripts:

Script Action
npm install Installs dependencies
npm run dev Starts local dev server at localhost:3000
npm run build Build your production site to ./dist/
npm run start Start your production site locally
npm run lint Run ESLint

πŸ”’ Environment Variables

Environment variables[^10] can be used for configuration. They must be set before running the app.

Environment variables are variables that are set in the operating system or shell, typically used to configure programs.

Chirpy uses Clerk, UploadThing, and MongoDB as external services. You need to create an account on each of these services and get the required credentials to run the app.

Create a .env.local file in the root directory of the project and add the following environment variables:

//MongoDB
MONGODB_URL=<MONGODB_URL>

//ClerkApi
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=<CLERK_PUBLISHABLE_KEY>
CLERK_SECRET_KEY=<CLERK_SECRET_KEY>
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/onboarding
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/
//ClerkApi_Signing-Secret
NEXT_CLERK_WEBHOOK_SECRET=<CLERK_WEBHOOK_SECRET>

//UploadThing
UPLOADTHING_SECRET=<UPLOADTHING_SECRET>
UPLOADTHING_APP_ID=<UPLOADTHING_APP_ID>

πŸš€ Deployment

Deploy to production (manual)

You can create an optimized production build with the following command:

npm run build

Deploy on Vercel (recommended)

The easiest way to deploy this Next.js app is to use the Vercel Platform.

Deploy with Vercel

πŸ’‘ Features

Chirpy web application comes with the following features:

  • CRUD Chirps, Communities and Profiles
  • Like Chirps
  • Multi-level Comment Chirps
  • Follow Profiles
  • Search Profiles and Circles
  • Activity Feed (Likes, Comments, Follows)
  • Explore Feed (Chirps of Followed Profiles)
  • Profile Tabs (Chirps, Followers, Following)
  • Community Tabs (Chirps, Members)
  • Chirp Likes Page (Profiles that liked a Chirp)
  • Post and Comment Emoji via emoji-mart

In terms of technical features, Chirpy web application comes with the following features:

  • TypeScripted Codebase with Next.js
  • Authentication with Clerk
  • User Management with Clerk
  • Organization Management with Clerk
  • File Upload with UploadThing
  • Server Side Rendering with Next.js
  • MongoDB Database
  • Mongoose ODM
  • Zod Validation
  • Shadcn Components
  • Tailwind CSS
  • Svix Webhook Proxy
  • Vercel Deployment

🀳 Screenshots

Sign In

Screen Shot 2023-12-09 at 16 47 13

Sign Up

Screen Shot 2023-12-09 at 16 47 43

Onboarding

Screen Shot 2023-12-09 at 16 49 46

Home

Screen Shot 2023-12-09 at 16 51 40

Search

Screen Shot 2023-12-09 at 16 52 22

Activity

Screen Shot 2023-12-09 at 16 52 55

Create Chirp

Screen Shot 2023-12-09 at 16 53 17

Circles

Screen Shot 2023-12-09 at 16 53 50

Profile

Screen Shot 2023-12-09 at 16 54 17 Screen Shot 2023-12-09 at 16 56 32 Screen Shot 2023-12-09 at 16 56 35

Edit Profile

Screen Shot 2023-12-09 at 16 55 36

User Profile

Screen Shot 2023-12-09 at 16 57 17

Create Organization/Circle

Screen Shot 2023-12-09 at 16 58 20

Circle Profile

Screen Shot 2023-12-09 at 16 58 43 Screen Shot 2023-12-09 at 16 58 46

Chirp Page

Screen Shot 2023-12-09 at 16 59 37

Chirp Likes Page

Screen Shot 2023-12-09 at 17 00 03

πŸ› Errors & Bugs that I fixed from References

  1. Not implementing utfs.io on next.config.js
//Solution
remotePatterns: [
      ...
      ,{
        protocol: "https",
        hostname: "utfs.io",
      },
    ],
  1. Activity Tab = Hydration errors due to interactive content of <Link>... <Link>...<Link/>...</Link> this occurence.
//This error occurs on app/(root)/activity/page.tsx because of href={`/profile/${author.id}`} is undefined
//Solution
import dynamic from "next/dynamic";
const DynamicLink = dynamic(() => import("next/link"), { ssr: false });

// all <Link> tag from next/link should change into DynamicLink
<DynamicLink
   key={activity._id}
   href={`${
   (activity.parentId && `/chirp/${activity.parentId}`) ||
   `/profile/${activity.author.id}`
   }`}>
...
<DynamicLink key={author._id} href={`/profile/${author.id}`}>
   <span className="text-primary-500">{author.name}</span>
</DynamicLink>
  1. Activity Tab = When the same person liked your 2 different post but it only shows a same single link.
//at user.actions.ts getActivity()

const reactionsData = reactions.map(
      (reaction: {
        user: { toString: () => any };
        _id: any; /* NEW */
        createdAt: any;
      }) => {
        const reactingUser = reactionsUsers.find(
          (user) => user._id.toString() === reaction.user.toString()
        );

        if (reactingUser._id.equals(userId)) return null;

        const parentChirp = userChirps.find((chirp) => /* NEW */
          chirp.reactions.some((r: { equals: (arg0: any) => any }) =>
            r.equals(reaction._id)
          )
        );

        if (!parentChirp) return null; /* NEW */

        return {
          author: {
            name: reactingUser.name,
            username: reactingUser.username,
            image: reactingUser.image,
            _id: reactingUser._id,
            id: reactingUser.id,
          },
          createdAt: reaction.createdAt,
          parentId: parentChirp._id.toString(), /* Modified */
          activityType: "reaction",
        };
      }
    );

    const replies = await Chirp.find({ /* Modified and reaction to concat follow removed */
      _id: { $in: childChirpIds },
      author: { $ne: userId },
    }).populate({
      path: "author",
      model: User,
      select: "name username image id _id",
    });

    const activity = [...replies, ...reactionsData, ...followersData]
      .filter((item) => item !== null)
      .sort((a, b) => b.createdAt - a.createdAt);

πŸ“‹ License

Chirpy is open source software licensed as MIT and is free to use β€” See LICENSE for more details.

πŸ’Ž Acknowledgements

The following people assisted me throughout this project and made it possible, for which I am grateful.:

πŸ“š References

β€’ JavaScript Mastery. (2023, August 4). Build and deploy a full stack MERN Next.js 14 threads app | React, Next JS, TypeScript, MongoDB. Retrieved from https://www.youtube.com/watch?v=O5cmLDVTgAs
β€’ Ladunjexa. (2023). GitHub - ladunjexa/nextjs13-threads: Threads, Next.js 13 app that skyrocketed to 100 million sign-ups in less than 5 days. Retrieved from https://github.com/ladunjexa/nextjs13-threads