Skip to content

aditya-suripeddi/PhotoGram

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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

Chapters:

Understand how the project is created and how different lego blocks (vite, firebase, shadcn-ui) are assembled.

Code Understanding / Todos:

  • 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

    npx vs npm

  • creating vite-react-typescript project again with npm create vite@latest created starter with tsconfig.app.json along with tsconfig.json and tsconfig.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.json and tsconfig.json referenced the path of tsconfig.node.json

    the 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:

    1. 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.

    2. 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

    3. 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.css generated with shadcn-ui installation to src/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
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:

    1. 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>
    1. 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>
    2. 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>
            
  1. 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>
  1. 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>

Uploadcare

  • 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

Errors / bugs:

  • 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

Flow:



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,
       }


  1. 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.ts and copy paste firebase initialization code with configurations
  • Create photogram/src/.env file, copy firebase settings and reference them from photogram/src/firebaseConfig.ts
  • Setup auth and db variables from firestore
      export const auth = getAuth(app);
      export const db = getFirestore(app);

      export default app;


  1. Install Shadcn/ui & Tailwind CSS:
       $ 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.json and lib/utils.ts is created with options that you have provided
  • Add button component and check /components/ui/button.tsx is created


  1. Pages & Routes Setup:
  • npm i react-router-dom
  • Create pages/home,error,myphotos,login,profile,post,signup/index.html files
  • Install Typescript React Code Snippets VSCode plugin
  • In each of the above file use the snippet with shorthand tsrsfc and replace App with directory name
  • Create routes.tsx and add CreateBrowserRouter


  1. Protecting Private Routes:
  • Create src/components/ui/ProtectedRoutes
  • Update routes.tsx to protect all routes / pages save for login and signup


  1. User Auth Context Api Setup:
  • Create src/context/userAuthContext.tsx


  1. Build User Signup Feature
  • Setup src/pages/signup.tsx using 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.css copied from app/index.css, src/assets/icons and src/assets/images

  • Note: the above repo has 3 branches for each episode, switch to relevant branch as you follow along



  1. Build User Login Feature:
  • Setup src/pages/login.tsx


  1. Resolve Firebase Issues:
  • Add Email and Google Authentication providers on firebase portal


  1. 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 fires onAuthStateChange event 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.tsx until we get the user information

  • Loading state is one way to handle this, we use react-firebase-hooks to this end.



  1. Design App Layout:
  • Setup src/layout/index.tsx to design app layout.

  • Three sections form the layout: center for content (feed), sidebar for navigation and right side column for friends suggestion



  1. Design Sidebar Navigation:

    • Add JSX for navbar items


  1. Adding Layout on all Pages:

    • Wrap all page components in the created Layout component


  1. Create Post Design:



  1. 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



  1. Integrate Uploadcare to Project:

    • Create FileUploader component in src/components/fileUploader/index.ts
    • Add FileUploader component in src/pages/posts/index.ts
    • Check preview to confirm upload-care setup is working


  1. Create Interfaces & Handle Post Form:

    • Add Post, PhotoMeta and FileEntry types in src/types/index.ts

    • Add File



  1. Create File Uploader Component:



  1. Uploadcare Image Optimisation & Transformation:


  1. Handle Create Post:



  1. Firestore DB Setup & Post Service:



  1. Complete Create Post Feature:


  1. Build My Photos - Fetch User Photos:


  1. Build My Photos - Display User Photos:


  1. Home Page Design:


  1. Fetch Feeds/Posts:


  1. User Stories Component :


  1. Post Card Component:


  1. Post Like/Dislike Feature:


  1. User Profile Component & Feature :


  1. Edit Profile Component:


  1. User Profile Collection & Service:


  1. FileUploader (Uploadcare) Profile Picture:


  1. Update & Create User Profile in Firestore DB:


  1. Sync User Profile With Firebase User:


  1. Create Post With User Info:


  1. Sync User Post with User Profile:


About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors