The aim of the repository is to solve a real world use case using relevant front end frameworks, libraries. The project is taken from PhotoGram | Dipesh Malvia
Understand how the project is created and how different lego blocks (vite, firebase, shadcn-ui) are assembled.
-
refer screenshots folder for helpful visuals to understand certain concepts
-
write from scratch pending: JSX of postCard, editProfile.tsx, profile/index.tsx, repository/user.service.ts, userList (suggest users to follow), deploy app
-
key events of regular components: onClick for Button, handleSubmit for form submit
-
tailwind styling layer: understand the layout and shadcn components made with tailwind
-
dependencies vs devDependencies in package.json and -D option in
npm install -D tailwindcss postcss autoprefixer
$ npm help install
• -D, --save-dev: Package will appear in your devDependencies.
-
npx vs npm an entry point:
NPM is a package manager used to install, delete, and update Javascript packages on your machine. NPX is a package executer, and it is used to execute javascript packages directly, without installing them
-
creating vite-react-typescript project again with
npm create vite@latestcreated starter withtsconfig.app.jsonalong withtsconfig.jsonandtsconfig.node.json. understanding the concept behind the two files and how to use them is not yet clear.the original project in github did not have
tsconfig.app.jsonandtsconfig.jsonreferenced the path oftsconfig.node.jsonthe entry point for this is probably related to project references in typescript
-
react-intro, ?: optional properties | property modifiers, ! non-null assertion operator
-
react hooks reference links>: useContext: overview , useEffect is a react hook that helps you synchronize your component with external system, useEffect w3schools, react hooks, useCallBack
-
react-router-dom reference links: react-router-dom navigate and useNavigate, Navigate, useLocation
-
what are side effects in React? and clear concept of onAuthStateChanged
-
"Top of component" in React can refer to a few different things, depending on the context:
-
Top-Level Component: This refers to the component at the very top of your component hierarchy. It's often the component rendered by the ReactDOM.render() method, acting as the entry point for your entire application.
-
Top Level of a Functional Component: Within a functional component, the "top level" refers to the code directly within the function body, before any return statement. This is where you typically declare variables, call hooks like useState and useEffect, and perform calculations. Example: JavaScript
-
Positioning with CSS: If you're talking about visually positioning something at the top of a component using CSS, you'd typically use properties like top: 0, align-items: flex-start (in flexbox), or justify-content: flex-start (in flexbox for vertical alignment).
-
// top level of functional component
import React, { useState } from 'react';
function MyComponent() {
const [count, setCount] = useState(0); // Top level
return (
<div>
<p>Count: {count}</p> // JSX returned
</div>
);
}- useEffect setup and clean-up:
Some components need to stay connected to the network, some browser API, or a third-party library, while they are displayed on the page.\
These systems aren’t controlled by React, so they are called external.
To connect your component to some external system, call useEffect at the top level of your component:
import { useEffect } from 'react';
import { createConnection } from './chat.js';
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, [serverUrl, roomId]);
// ...
} You need to pass two arguments to useEffect:
A setup function with setup code that connects to that system.
It should return a cleanup function with cleanup code that disconnects from that system.
A list of dependencies including every value from your component used inside of those functions.
React calls your setup and cleanup functions whenever it’s necessary, which may happen multiple times:
Your setup code runs when your component is added to the page (mounts).
After every re-render of your component where the dependencies have changed:
First, your cleanup code runs with the old props and state.
Then, your setup code runs with the new props and state.
Your cleanup code runs one final time after your component is removed from the page (unmounts).
Let’s illustrate this sequence for the example above.
When the ChatRoom component above gets added to the page, it will connect to the chat room with the initial serverUrl and roomId.
If either serverUrl or roomId change as a result of a re-render (say, if the user picks a different chat room in a dropdown),
your Effect will disconnect from the previous room, and connect to the next one. When the ChatRoom component is removed from the
page, your Effect will disconnect one last time.
-
note: copy the
app/index.cssgenerated withshadcn-uiinstallation tosrc/index.css -
firestore api:
// collection(db, COLLECTION_NAME) --> Table Name
//
// docRef = doc(db, COLLECTION_NAME, id)
// return getDoc(docRef) --> Matching Row / Record from given Table Name
//
// q = query(collection, orderBy/where)
// return getDocs(q) --> SELECT / READ WITH ORDER-BY AND WHERE
//
// addDoc/updateDoc/deleteDoc --> INSERT/UPDATE/DELETE-
configuring authentication and firestore database on firebase requires some minor settings and changes, refer screenshots folder and the project video for any errors with firebase services.
-
handy uploadcare transformation for previewing images selected for upload: ${file.cdnUrl}-/scale_crop/500x500/center/
-
read tailwind docs, with flow of topics and one layer at a time
-
terminology: destructuring an object (can be a parameter passed to function) to attibutes you need
-
styling: aspect-video, place-self-end, inset-0, tailwind grid: default grid has only one column, position: offsets on this page means top-2 left-0 etc, display when to use other values like inline-flex etc, z-index: overlaying divs / controlling stack order (3d positioning) of elements, flex: controlling how flex items grow and shrink, what is the purple dashed line area ?, inline-flex: create inline flex container that flows with text, style filter invert, how does one know all the attributes available and their usage on shadcn-component ? Textarea supports value, onChange, placeholder attributes?, useCallBack, cursor, overflow
-
is it required to add w-full in a div or block element :
The width of a block-level element, such as a <div> or <p> tag, in HTML is the length of the page by default. Block-level elements take up the full width available, stretching to the left and right as far as possible. They also automatically start on a new line and have some space (margin) added before and after them by browsers
-
styling idioms phrases:
- The ----OR----- separator (used in signup and login page)
<div className="relative"> <div className="absolute inset-0 flex items-center"> <span className="w-full border-t"></span> </div> <div className="relative flex justify-center text-xs uppercase"> <span className="bg-background px-2 text-muted-foreground"> Or </span> </div> </div>
-
Label and input to read email (used in signup and login page)
<div className="grid gap-2"> <Label htmlFor="email">Email Address</Label> <Input id="email" type="email" placeholder="john.doe@example.com" /> </div>
-
Grid of images (used in signup and login page):
<div className="bg-slate-800 w-full h-screen"> <div className="container mx-auto flex p-6 h-full"> <div className="flex justify-center items-center w-full"> <div className="p-6 w-2/3 hidden lg:block"> <div className="grid grid-cols-2 gap-2"> <img className="w-2/3 h-auto aspect-video rounded-3xl place-self-end" src={image2} /> <img className="w-2/4 h-auto aspect-auto rounded-3xl" src={image1} /> <img className="w-2/4 h-auto aspect-auto rounded-3xl place-self-end" src={image4} /> <img className="w-2/3 h-auto aspect-video rounded-3xl" src={image3} /> </div> </div> </div> </div> </div>
- used in src/layout/index.tsx: take screen height, display:hide element on smaller screens, display:block on large screens, fixed: position element relative to browser window and offsets w.r.t viewport
<aside classname="h-screen hidden lg:block fixed top-0 left-0 z-40 bg-gray-800 flex gap-x-4">
</aside>- gray overlay on myphotos with number of likes and heart icon:
<div key={item.photos[0].uuid} className="relative">
<div className="absolute inset-0
w-full h-full
group transition-all duration-200
bg-transparent
hover:bg-slate-950/75">
<div className="flex flex-col justify-center items-center w-full h-full">
<HeartIcon className="hidden group-hover:block fill-white" />
<div className="hidden group-hover:block text-white">{item.likes} likes</div>
</div>
</div>
<img src={`${item.photos[0].cdnUrl}/-/progressive/yes/-/scale_crop/300x300/center/`} />
</div>-
Refer getting started guide on uploadcare project portal and use the examples repository to update uploadcare to use latest version and understand the semantics / setting up for latest version
-
explore uploader-configurator by clicking FileUploader tab on upload care portal, to customize the upload popup
- make sure to import components / functions from right packages
- import { GoogleAuthProvider } from 'firebase/auth/web-extension'
+ import { GoogleAuthProvider } from 'firebase/auth'- import Label from radix-ui not the added shadcn-ui component
- import { Input } from '@/components/ui/input'
+ import { Label } from "@radix-ui/react-label";- on firebase project portal -> Authentication -> Sign-In method (tab) -> Native providers -> Email/Password -> Enable Email/Password
1. Project Setup Using Vite:
$ npm create vite@latest
Need to install the following packages:
create-vite@5.3.0
Ok to proceed? (y) y
✔ Project name: … PhotoGram
✔ Package name: … photogram
✔ Select a framework: › React
✔ Select a variant: › TypeScript
Scaffolding project in /home/adi/Downloads/github/github-setup/PhotoGram...
Done. Now run:
cd PhotoGram
npm install
npm run dev
$ npm install
$ npm run dev - add following code to vite.config.ts
// when we run app on local, it should start in browser
server: {
open: true,
port: 3000,
}- Firebase Project Setup
- Signup on console.firebase.google.com
- Create a new web app project with name
photogram - Skip Google Analytics Add-on
- Select npm for firebase SDK setup and configuration
- Install firebase
$ npm install firebase- Create
photogram/src/firebaseConfig.tsand copy paste firebase initialization code with configurations - Create
photogram/src/.envfile, copy firebase settings and reference them fromphotogram/src/firebaseConfig.ts - Setup
authanddbvariables from firestore
export const auth = getAuth(app);
export const db = getFirestore(app);
export default app;- Install Shadcn/ui & Tailwind CSS:
- Follow the steps 1 to 4 mentioned in shadcn-docs-installation-vite
- Install shadcn
$ npx shadcn-ui@latest init
✔ Would you like to use TypeScript (recommended)? yes
✔ Which style would you like to use? Default
✔ Which color would you like to use as base color? Gray
✔ Where is your global CSS file? app/index.css
✔ Would you like to use CSS variables for colors? yes
✔ Are you using a custom tailwind prefix eg. tw-? (Leave blank if not) › <enter> // leave blank
✔ Where is your tailwind.config.js located? tailwind.config.js
✔ Configure the import alias for components: @/components
✔ Configure the import alias for utils: @/lib/utils
✔ Are you using React Server Components? no
✔ Write configuration to components.json. Proceed? yes
✔ Writing components.json...
✔ Initializing project...
✔ Installing dependencies...
Success! Project initialization completed. You may now add components.- Install shadcn
components.jsonandlib/utils.tsis created with options that you have provided- Add button component and check
/components/ui/button.tsxis created
- Pages & Routes Setup:
npm i react-router-dom- Create
pages/home,error,myphotos,login,profile,post,signup/index.htmlfiles - Install Typescript React Code Snippets VSCode plugin
- In each of the above file use the snippet with shorthand
tsrsfcand replaceAppwith directory name - Create
routes.tsxand addCreateBrowserRouter
- Protecting Private Routes:
- Create
src/components/ui/ProtectedRoutes - Update
routes.tsxto protect all routes / pages save forloginandsignup
- User Auth Context Api Setup:
- Create
src/context/userAuthContext.tsx
- Build User Signup Feature
-
Setup
src/pages/signup.tsxusing create-account.tsx component from shadcn-ui github repo -
Setup card, input & label shadcn components required for create-account.tsx (signup)
$ npx shadcn-ui@latest add card input label
-
Add icons component from shadcn-ui-github/icons
-
From Build FullStack Social Media App take the code for
src/pages/signup.tsx,src/types/index.tsx,src/index.csscopied fromapp/index.css,src/assets/iconsandsrc/assets/images -
Note: the above repo has 3 branches for each episode, switch to relevant branch as you follow along
- Build User Login Feature:
- Setup
src/pages/login.tsx
- Resolve Firebase Issues:
- Add Email and Google Authentication providers on firebase portal
- Resolve Page Refresh Issue (react-firebase-hooks):
-
Problem: On signup and login, firebase provides user details to the app and home page is loaded. Refreshing the page reloads the login/signup despite having the user details.
-
Reason: In
src/context/userAuthContext.tsx, a page refresh firesonAuthStateChangeevent and before user information is processed, UI is rendered.The UI for protected routes will get rendered before we get the actual information of user. -
We need to hold the JSX
protectedRoutes/index.tsxuntil we get the user information -
Loading state is one way to handle this, we use
react-firebase-hooksto this end.
- Design App Layout:
-
Setup
src/layout/index.tsxto design app layout. -
Three sections form the layout: center for content (feed), sidebar for navigation and right side column for friends suggestion
-
Design Sidebar Navigation:
- Add JSX for navbar items
-
Adding Layout on all Pages:
- Wrap all page components in the created Layout component
-
Create Post Design:
-
Uploadcare walkthrough:
-
Setup uploadcare account
-
The project uses an older version of uploadcare, refer the getting started page on your upload-care project and *example repo to update the code to use latest version.
-
Follow project instructions for time being and use
"@uploadcare/blocks": "0.31.1"npm i @uploadcare/blocks --save --exact -
create a new upload-care project in your account and use the api key shown in getting started page for the JSX code
-
upload-care portal saves the uploaded files, generates id, optimizes images and provides a
CDN URL for image preview (you can change pixel resolution in this url) -
image operations are carried out by suffixing operations as path parameters in CDN URL of uploaded image to explore and use image optimization / transformations / operations go to
upload-care project page > files tab > modify > click learn more, read the docs to meet your use-case requirements. For ex: user profile pic should appear as a small circle on his post but image he posts should appear with a certain size, such image operations can specified as part of URL at fetch / load time to upload care -
you can customise uploader configuration (widget/popup) and get corresponding code which you can import into your project
-
-
Integrate Uploadcare to Project:
- Create
FileUploadercomponent insrc/components/fileUploader/index.ts - Add
FileUploadercomponent insrc/pages/posts/index.ts - Check preview to confirm upload-care setup is working
- Create
-
Create Interfaces & Handle Post Form:
-
Add Post, PhotoMeta and FileEntry types in
src/types/index.ts -
Add File
-
-
Create File Uploader Component:
- Uploadcare Image Optimisation & Transformation:
- Handle Create Post:
-
Firestore DB Setup & Post Service:
- Setup cloud firestore on firebase
- Add CRUD methods on
postresource - Refer https://firebase.google.com/docs/firestore/manage-data/add-data
- Complete Create Post Feature:
- Build My Photos - Fetch User Photos:
- Build My Photos - Display User Photos:
- Home Page Design:
- Fetch Feeds/Posts:
- User Stories Component :
- Post Card Component:
- Post Like/Dislike Feature:
- User Profile Component & Feature :
- Edit Profile Component:
- User Profile Collection & Service:
- FileUploader (Uploadcare) Profile Picture:
- Update & Create User Profile in Firestore DB:
- Sync User Profile With Firebase User:
- Create Post With User Info:
- Sync User Post with User Profile: