Skip to content

Instantly share code, notes, and snippets.

@adrianhajdin
Created October 27, 2023 09:18
Show Gist options
  • Save adrianhajdin/4d2500bf5af601bbd9f4f596298d33ac to your computer and use it in GitHub Desktop.
Save adrianhajdin/4d2500bf5af601bbd9f4f596298d33ac to your computer and use it in GitHub Desktop.
Build and Deploy a Full Stack Social Media App | React JS, Appwrite, Tailwind CSS, React Query
export const sidebarLinks = [
{
imgURL: "/assets/icons/home.svg",
route: "/",
label: "Home",
},
{
imgURL: "/assets/icons/wallpaper.svg",
route: "/explore",
label: "Explore",
},
{
imgURL: "/assets/icons/people.svg",
route: "/all-users",
label: "People",
},
{
imgURL: "/assets/icons/bookmark.svg",
route: "/saved",
label: "Saved",
},
{
imgURL: "/assets/icons/gallery-add.svg",
route: "/create-post",
label: "Create Post",
},
];
export const bottombarLinks = [
{
imgURL: "/assets/icons/home.svg",
route: "/",
label: "Home",
},
{
imgURL: "/assets/icons/wallpaper.svg",
route: "/explore",
label: "Explore",
},
{
imgURL: "/assets/icons/bookmark.svg",
route: "/saved",
label: "Saved",
},
{
imgURL: "/assets/icons/gallery-add.svg",
route: "/create-post",
label: "Create",
},
];
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap");
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
* {
@apply box-border list-none p-0 m-0 scroll-smooth;
}
body {
@apply bg-dark-1 text-white min-h-screen font-inter;
}
}
@layer utilities {
/* TYPOGRAPHY */
.h1-bold {
@apply text-[36px] font-bold leading-[140%] tracking-tighter;
}
.h1-semibold {
@apply text-[36px] font-semibold leading-[140%] tracking-tighter;
}
.h2-bold {
@apply text-[30px] font-bold leading-[140%] tracking-tighter;
}
.h3-bold {
@apply text-[24px] font-bold leading-[140%] tracking-tighter;
}
.base-semibold {
@apply text-[16px] font-semibold leading-[140%] tracking-tighter;
}
.base-medium {
@apply text-[16px] font-medium leading-[140%];
}
.base-regular {
@apply text-[16px] font-normal leading-[140%];
}
.body-bold {
@apply text-[18px] font-bold leading-[140%];
}
.body-medium {
@apply text-[18px] font-medium leading-[140%];
}
.small-semibold {
@apply text-[14px] font-semibold leading-[140%] tracking-tighter;
}
.small-medium {
@apply text-[14px] font-medium leading-[140%];
}
.small-regular {
@apply text-[14px] font-normal leading-[140%];
}
.subtle-semibold {
@apply text-[12px] font-semibold leading-[140%];
}
.tiny-medium {
@apply text-[10px] font-medium leading-[140%];
}
/* UTILITIES */
.invert-white {
@apply invert brightness-0 transition;
}
.flex-center {
@apply flex justify-center items-center;
}
.flex-between {
@apply flex justify-between items-center;
}
.flex-start {
@apply flex justify-start items-center;
}
.custom-scrollbar::-webkit-scrollbar {
width: 3px;
height: 3px;
border-radius: 2px;
}
.custom-scrollbar::-webkit-scrollbar-track {
background: #09090a;
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background: #5c5c7b;
border-radius: 50px;
}
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
background: #7878a3;
}
.common-container {
@apply flex flex-col flex-1 items-center gap-10 overflow-scroll py-10 px-5 md:px-8 lg:p-14 custom-scrollbar;
}
/* All Users */
.user-container {
@apply max-w-5xl flex flex-col items-start w-full gap-6 md:gap-9;
}
.user-grid {
@apply w-full grid grid-cols-1 xs:grid-cols-2 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 gap-7 max-w-5xl;
}
/* Explore */
.explore-container {
@apply flex flex-col flex-1 items-center overflow-scroll py-10 px-5 md:p-14 custom-scrollbar;
}
.explore-inner_container {
@apply max-w-5xl flex flex-col items-center w-full gap-6 md:gap-9;
}
.explore-search {
@apply h-12 bg-dark-4 border-none placeholder:text-light-4 focus-visible:ring-0 focus-visible:ring-offset-0 ring-offset-0 !important;
}
/* Home */
.home-container {
@apply flex flex-col flex-1 items-center gap-10 overflow-scroll py-10 px-5 md:px-8 lg:p-14 custom-scrollbar;
}
.home-posts {
@apply max-w-screen-sm flex flex-col items-center w-full gap-6 md:gap-9;
}
.home-creators {
@apply hidden xl:flex flex-col w-72 2xl:w-465 px-6 py-10 gap-10 overflow-scroll custom-scrollbar;
}
/* Post Details */
.post_details-container {
@apply flex flex-col flex-1 gap-10 overflow-scroll py-10 px-5 md:p-14 custom-scrollbar items-center;
}
.post_details-card {
@apply bg-dark-2 w-full max-w-5xl rounded-[30px] flex-col flex xl:flex-row border border-dark-4 xl:rounded-l-[24px];
}
.post_details-img {
@apply h-80 lg:h-[480px] xl:w-[48%] rounded-t-[30px] xl:rounded-l-[24px] xl:rounded-tr-none object-cover p-5 bg-dark-1;
}
.post_details-info {
@apply bg-dark-2 flex flex-col gap-5 lg:gap-7 flex-1 items-start p-8 rounded-[30px];
}
.post_details-delete_btn {
@apply p-0 flex gap-3 hover:bg-transparent hover:text-light-1 text-light-1 small-medium lg:base-medium;
}
/* Profile */
.profile-container {
@apply flex flex-col items-center flex-1 gap-10 overflow-scroll py-10 px-5 md:p-14 custom-scrollbar;
}
.profile-inner_container {
@apply flex items-center md:mb-8 xl:items-start gap-8 flex-col xl:flex-row relative max-w-5xl w-full;
}
.profile-tab {
@apply flex-center gap-3 py-4 w-48 bg-dark-2 transition flex-1 xl:flex-initial;
}
/* Saved */
.saved-container {
@apply flex flex-col flex-1 items-center gap-10 overflow-scroll py-10 px-5 md:p-14 custom-scrollbar;
}
/* Bottom bar */
.bottom-bar {
@apply z-50 flex-between w-full sticky bottom-0 rounded-t-[20px] bg-dark-2 px-5 py-4 md:hidden;
}
/* File uploader */
.file_uploader-img {
@apply h-80 lg:h-[480px] w-full rounded-[24px] object-cover object-top;
}
.file_uploader-label {
@apply text-light-4 text-center small-regular w-full p-4 border-t border-t-dark-4;
}
.file_uploader-box {
@apply flex-center flex-col p-7 h-80 lg:h-[612px];
}
/* Grid Post List */
.grid-container {
@apply w-full grid grid-cols-1 sm:grid-cols-2 md:grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-7 max-w-5xl;
}
.grid-post_link {
@apply flex rounded-[24px] border border-dark-4 overflow-hidden cursor-pointer w-full h-full;
}
.grid-post_user {
@apply absolute bottom-0 p-5 flex-between w-full bg-gradient-to-t from-dark-3 to-transparent rounded-b-[24px] gap-2;
}
/* Left sidebar */
.leftsidebar {
@apply hidden md:flex px-6 py-10 flex-col justify-between min-w-[270px] bg-dark-2;
}
.leftsidebar-link {
@apply rounded-lg base-medium hover:bg-primary-500 transition;
}
/* Post Card */
.post-card {
@apply bg-dark-2 rounded-3xl border border-dark-4 p-5 lg:p-7 w-full max-w-screen-sm;
}
.post-card_img {
@apply h-64 xs:h-[400px] lg:h-[450px] w-full rounded-[24px] object-cover mb-5;
}
/* Topbar */
.topbar {
@apply sticky top-0 z-50 md:hidden bg-dark-2 w-full;
}
/* User card */
.user-card {
@apply flex-center flex-col gap-4 border border-dark-4 rounded-[20px] px-5 py-8;
}
}
@layer components {
/* SHADCN COMPONENTS */
/* Form */
.shad-form_label {
@apply text-white !important;
}
.shad-form_message {
@apply text-red !important;
}
.shad-input {
@apply h-12 bg-dark-4 border-none placeholder:text-light-4 focus-visible:ring-1 focus-visible:ring-offset-1 ring-offset-light-3 !important;
}
.shad-textarea {
@apply h-36 bg-dark-3 rounded-xl border-none focus-visible:ring-1 focus-visible:ring-offset-1 ring-offset-light-3 !important;
}
/* Button */
.shad-button_primary {
@apply bg-primary-500 hover:bg-primary-500 text-light-1 flex gap-2 !important;
}
.shad-button_dark_4 {
@apply h-12 bg-dark-4 px-5 text-light-1 flex gap-2 !important;
}
.shad-button_ghost {
@apply flex gap-4 items-center justify-start hover:bg-transparent hover:text-white !important;
}
}
https://drive.google.com/file/d/13_7FofRAC3wARqPtAVPi53QNJJRd5RH_/view?usp=sharing
export enum QUERY_KEYS {
// AUTH KEYS
CREATE_USER_ACCOUNT = "createUserAccount",
// USER KEYS
GET_CURRENT_USER = "getCurrentUser",
GET_USERS = "getUsers",
GET_USER_BY_ID = "getUserById",
// POST KEYS
GET_POSTS = "getPosts",
GET_INFINITE_POSTS = "getInfinitePosts",
GET_RECENT_POSTS = "getRecentPosts",
GET_POST_BY_ID = "getPostById",
GET_USER_POSTS = "getUserPosts",
GET_FILE_PREVIEW = "getFilePreview",
// SEARCH KEYS
SEARCH_POSTS = "getSearchPosts",
}
/** @type {import('tailwindcss').Config} */
const defaultTheme = require('tailwindcss/defaultTheme')
module.exports = {
darkMode: ['class'],
content: [
'./pages/**/*.{ts,tsx}',
'./components/**/*.{ts,tsx}',
'./app/**/*.{ts,tsx}',
'./src/**/*.{ts,tsx}',
],
theme: {
container: {
center: true,
padding: '2rem',
screens: {
'2xl': '1400px',
},
},
extend: {
colors: {
'primary-500': '#877EFF',
'primary-600': '#5D5FEF',
'secondary-500': '#FFB620',
'off-white': '#D0DFFF',
'red': '#FF5A5A',
'dark-1': '#000000',
'dark-2': '#09090A',
'dark-3': '#101012',
'dark-4': '#1F1F22',
'light-1': '#FFFFFF',
'light-2': '#EFEFEF',
'light-3': '#7878A3',
'light-4': '#5C5C7B',
},
screens: {
'xs': '480px',
},
width: {
'420': '420px',
'465': '465px',
},
fontFamily: {
inter: ['Inter', 'sans-serif'],
},
keyframes: {
'accordion-down': {
from: { height: 0 },
to: { height: 'var(--radix-accordion-content-height)' },
},
'accordion-up': {
from: { height: 'var(--radix-accordion-content-height)' },
to: { height: 0 },
},
},
animation: {
'accordion-down': 'accordion-down 0.2s ease-out',
'accordion-up': 'accordion-up 0.2s ease-out',
},
},
},
plugins: [require('tailwindcss-animate')],
};
export type INavLink = {
imgURL: string;
route: string;
label: string;
};
export type IUpdateUser = {
userId: string;
name: string;
bio: string;
imageId: string;
imageUrl: URL | string;
file: File[];
};
export type INewPost = {
userId: string;
caption: string;
file: File[];
location?: string;
tags?: string;
};
export type IUpdatePost = {
postId: string;
caption: string;
imageId: string;
imageUrl: URL;
file: File[];
location?: string;
tags?: string;
};
export type IUser = {
id: string;
name: string;
username: string;
email: string;
imageUrl: string;
bio: string;
};
export type INewUser = {
name: string;
email: string;
username: string;
password: string;
};
import { useEffect, useState } from "react";
// https://codesandbox.io/s/react-query-debounce-ted8o?file=/src/useDebounce.js
export default function useDebounce<T>(value: T, delay: number): T {
// State and setters for debounced value
const [debouncedValue, setDebouncedValue] = useState<T>(value);
useEffect(() => {
// Update debounced value after delay
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
// Cancel the timeout if value changes (also on delay change or unmount)
// This is how we prevent debounced value from updating if value is changed ...
// .. within the delay period. Timeout gets cleared and restarted.
return () => {
clearTimeout(handler);
};
}, [value, delay]); // Only re-call effect if value or delay changes
return debouncedValue;
}
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
export const convertFileToUrl = (file: File) => URL.createObjectURL(file);
export function formatDateString(dateString: string) {
const options: Intl.DateTimeFormatOptions = {
year: "numeric",
month: "short",
day: "numeric",
};
const date = new Date(dateString);
const formattedDate = date.toLocaleDateString("en-US", options);
const time = date.toLocaleTimeString([], {
hour: "numeric",
minute: "2-digit",
});
return `${formattedDate} at ${time}`;
}
//
export const multiFormatDateString = (timestamp: string = ""): string => {
const timestampNum = Math.round(new Date(timestamp).getTime() / 1000);
const date: Date = new Date(timestampNum * 1000);
const now: Date = new Date();
const diff: number = now.getTime() - date.getTime();
const diffInSeconds: number = diff / 1000;
const diffInMinutes: number = diffInSeconds / 60;
const diffInHours: number = diffInMinutes / 60;
const diffInDays: number = diffInHours / 24;
switch (true) {
case Math.floor(diffInDays) >= 30:
return formatDateString(timestamp);
case Math.floor(diffInDays) === 1:
return `${Math.floor(diffInDays)} day ago`;
case Math.floor(diffInDays) > 1 && diffInDays < 30:
return `${Math.floor(diffInDays)} days ago`;
case Math.floor(diffInHours) >= 1:
return `${Math.floor(diffInHours)} hours ago`;
case Math.floor(diffInMinutes) >= 1:
return `${Math.floor(diffInMinutes)} minutes ago`;
default:
return "Just now";
}
};
export const checkIsLiked = (likeList: string[], userId: string) => {
return likeList.includes(userId);
};
@Subashree-24
Copy link

I cloned the repo,,. and did everything he did on the appwrite,. but i couldnt create a post.. what to do???? Please somebody help me please

@Jstreetman
Copy link

Hey did you properly create the post collection within appwrite?

@Subashree-24
Copy link

Hey did you properly create the post collection within appwrite?

Thank You!!
Yep, I did, the issue is that Apprwrite provides 50Mb of storage only, so updated the permission once again. Everything works fine now☺

@Jstreetman
Copy link

Awesome :)

@Jstreetman
Copy link

Does anyway know of a way to use appwrite in a nextjs app with a middleware?

@gitwow369
Copy link

not working hi how can I fix this

Vite@latest not vite@latest./

vite@latest ./

hey you are not space them Write this with Spacing
vite@latest ./ ///// { ./ they have space
}

@maxixo
Copy link

maxixo commented Aug 3, 2024

can somebody help me with this error , i cannot seem to navigate to the homepage after signing up , It says database not found . ANy help will be appreciated

ppwriteException: Database not found
at Client. (http://localhost:5173/node_modules/.vite/deps/appwrite.js?v=ec80e568:419:17)
at Generator.next ()
at fulfilled (http://localhost:5173/node_modules/.vite/deps/appwrite.js?v=ec80e56

@maxixo
Copy link

maxixo commented Aug 3, 2024

Finally, lets try for your reference, the chat feature has just been created ( https://whistly.vercel.app ), i thinkthe most complicated one is this

Can you please guide me to its source code??, whistly is made very nicely.

Hello , Please can i reach out to you concerning an error i have with creating the database in appwrite , it dosent seem to work

@Jstreetman
Copy link

check your appwrite make sure you actually have exsisting database if yoou do, make sure you have included the right value for your databaseId

@maxixo
Copy link

maxixo commented Aug 3, 2024

Yes i have an existing database and the database value is also correct in the .env.local file for appwrite. I have doublechecked and even created a new database but it's still the same.

Alongside the database error , i am also getting this error :

AppwriteException: User (role: guests) missing scope (account)
at Client. (http://localhost:5174/node_modules/.vite/deps/appwrite.js?v=8f725b5c:850:17)
at Generator.next ()
at fulfilled (http://localhost:5174/node_modules/.vite/deps/appwrite.js?v=8f725b5c:488:24)

It seems the error is coming from the apprwrite endpoint but i don't know how to rectify it. Thank you

check your appwrite make sure you actually have exsisting database if yoou do, make sure you have included the right value for your databaseId

@Bennydavid10
Copy link

Screenshot 2024-08-10 201604
how to resolve this error!
Screenshot 2024-08-10 201604

@Kaushalendra-pandey-05
Copy link

Screenshot 2024-08-10 201813
can anyone help me
i am updating my document but like is not updating

@ahad324
Copy link

ahad324 commented Aug 10, 2024

``

Screenshot 2024-08-10 201604 how to resolve this error! Screenshot 2024-08-10 201604

change your vite.config.js to this

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      '@src': path.resolve(__dirname, "src"),
      '@components': path.resolve(__dirname, 'src/components'),
      '@contexts': path.resolve(__dirname, 'src/contexts'),
      '@utils': path.resolve(__dirname, 'src/utils'),
      // Add other aliases as needed
    },
  },
});

you can change the aliases as well

@Rahulhanje
Copy link

I am also getting an error: AppwriteException: User (role: guests) missing scope (account) at Client.<anonymous>. - Which means that the user session was not detected by Appwrite. appwrite/appwrite#1203

  • Does anyone run into this issue as well? How did you fix it?
    Thank you

bro how to solve this error

@cyberpunk-dot
Copy link

Screenshot 2024-09-03 180431
hey what to do here

@ahad324
Copy link

ahad324 commented Sep 3, 2024

Screenshot 2024-09-03 180431 hey what to do here

As you can see the imageurl has invalid format I think you are not sending the things in a way that they are defined in the database make sure to send the data in the same order as they are created in the database

@cyberpunk-dot
Copy link

so which file controls that

@cyberpunk-dot
Copy link

Screenshot 2024-09-07 150143
how to fix

@dhruvipatel14
Copy link

Screenshot 2024-09-07 150143 how to fix

Have you added localhost to the appwrite/project/overview? Hostname: localhost. It will throw CORS if the host is not mentioned.
image

@Kabir7283
Copy link

Screenshot 2024-09-24 193533
can somebody help me with this

@linuxtudor
Copy link

image
can somebody help me with this - after tailwind install

@ayesha1209
Copy link

AppwriteException: Invalid document structure: Missing required attribute "imageId"
at Client. (http://localhost:5173/node_modules/.vite/deps/appwrite.js?v=2f82bd5c:850:17)
at Generator.next ()
at fulfilled (http://localhost:5173/node_modules/.vite/deps/appwrite.js?v=2f82bd5c:488:24)

i am getting this errror in signup and been stuck since 2 days can anyone help me

@gitboi91
Copy link

Followed the tutorial and I'm getting this error when trying to upload a post.

error uploading file AppwriteException: Missing required parameter: "bucketId"

can someone help me?

@tausif7851
Copy link

tausif7851 commented Oct 30, 2024

image iam facing this problem while deploying while i have set the endpoint in the project correctly please if any one could help me to deploy the project

It is not reading the env file you need to move your .env.local file outiside of src folder.

@Jstreetman
Copy link

Jstreetman commented Oct 30, 2024

AppwriteException: Invalid document structure: Missing required attribute "imageId" at Client. (http://localhost:5173/node_modules/.vite/deps/appwrite.js?v=2f82bd5c:850:17) at Generator.next () at fulfilled (http://localhost:5173/node_modules/.vite/deps/appwrite.js?v=2f82bd5c:488:24)

i am getting this errror in signup and been stuck since 2 days can anyone help me

make sure that in your api when you are calling a function whether you are sending a POST request to appwrite or a GET request , when you pass your data into it make sure you are passing in the imageId which can come from the id of which your are trying to send to appwrite. check your backend functions @gitboi91

@gitboi91
Copy link

gitboi91 commented Nov 5, 2024

Screenshot 2024-09-24 193533 can somebody help me with this

Did you find a solution, I have the same problem

@jan-eberwein
Copy link

Hey did you properly create the post collection within appwrite?

Thank You!! Yep, I did, the issue is that Apprwrite provides 50Mb of storage only, so updated the permission once again. Everything works fine now☺

What exactly did you do to resolve this issue? I still get the Error 401 (Unauthorized) AppwriteException: User (role: guests) missing scope (account) :(

@Ritik2042000
Copy link

TypeError: Failed to construct 'URL': Invalid URL
at Account. (account.ts:26:21)
at Generator.next ()
at tslib.es6.js:76:71
at new Promise ()
at __awaiter (tslib.es6.js:72:12)
at Account.get (account.ts:23:14)
at getCurrentUser (api.ts:72:42)
at checkAuthUser (AuthContext.tsx:46:38)
at AuthContext.tsx:83:7
at commitHookEffectListMount (react-dom.development.js:23189:26)
i am facing this problem of type of image url when the time of user sign up
Screenshot 2024-11-21 192134

@patnaikt4
Copy link

Hi! I am having trouble finding the zipped public folder with the assets that Adrian has made. Can anybody help with this? (would be greatly appreciated)

@roro1128
Copy link

Hi! I am having trouble finding the zipped public folder with the assets that Adrian has made. Can anybody help with this? (would be greatly appreciated)

https://drive.google.com/file/d/13_7FofRAC3wARqPtAVPi53QNJJRd5RH_/view?usp=sharing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment