{"id":26218242,"url":"https://github.com/sudhansuuranjan/multimedia-app","last_synced_at":"2026-04-12T03:04:36.282Z","repository":{"id":175576630,"uuid":"654142750","full_name":"SudhansuuRanjan/multimedia-app","owner":"SudhansuuRanjan","description":"A multimedia app using React + firebase.","archived":false,"fork":false,"pushed_at":"2023-07-06T17:55:41.000Z","size":4454,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-31T21:12:41.290Z","etag":null,"topics":["firebase","google-auth","reactjs"],"latest_commit_sha":null,"homepage":"https://spectre-7-featuresection.web.app","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SudhansuuRanjan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-06-15T13:26:24.000Z","updated_at":"2023-06-21T16:40:02.000Z","dependencies_parsed_at":"2023-06-26T08:45:30.148Z","dependency_job_id":null,"html_url":"https://github.com/SudhansuuRanjan/multimedia-app","commit_stats":null,"previous_names":["sudhansuuranjan/multimedia-app"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/SudhansuuRanjan/multimedia-app","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SudhansuuRanjan%2Fmultimedia-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SudhansuuRanjan%2Fmultimedia-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SudhansuuRanjan%2Fmultimedia-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SudhansuuRanjan%2Fmultimedia-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SudhansuuRanjan","download_url":"https://codeload.github.com/SudhansuuRanjan/multimedia-app/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SudhansuuRanjan%2Fmultimedia-app/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31702582,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-11T21:17:31.016Z","status":"online","status_checked_at":"2026-04-12T02:00:06.763Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["firebase","google-auth","reactjs"],"created_at":"2025-03-12T13:15:56.489Z","updated_at":"2026-04-12T03:04:36.276Z","avatar_url":"https://github.com/SudhansuuRanjan.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Multimedia App\n[Live Site Url](https://spectre-7-featuresection.web.app/)\n\n## Description\nThis is a multimedia app that allows users to upload files. Users can create an account and login to upload their own images and videos. Users can also view other users' images, files, docs and videos.\n\n## Project Layout\n\u003cbr/\u003e\n\n\u003cimg src=\"https://i.ibb.co/nMtnfdt/Group-33737.png\" alt=\"Group-33737\"\u003e\u003cbr/\u003e\n\n## Which features I am trying to add and why?\n\n- ### Added Google Authentication using Firebase\n  - I added Google Authentication using Firebase because it is easy to implement and it is secure. It also allows users to login using their Google account which is convenient for users. And users can store and retrive their files from Firebase Storage and other users can't see thier files, also it protects the platform from spam and abuse.\n  - Implemented Protected Routes using React Router. So, users can't access the dashboard without login.\n  - Modified dashboard Navbar to show user's profile picture and also placed a logout button.\n\n- ### Added a feature to upload files using Firebase Cloud Storage\n  - I added a feature to upload files using Firebase Cloud Storage because it is easy to implement and it is secure. It allows users to create folders and upload files to their folders. And users can store and retrive their files from Firebase Storage.\n  - Implemented File icons so users can easily identify the file type.\n\n## My Work and How It works?\n\n### 1. Added Google Authentication using Firebase\n\n- The `App.js` sets up routes for a React application using React Router. It imports the two pages `Login` and `Dashboard`, defines routes for public and protected pages, and wraps them in a router component.\n\n    ```jsx\n    // App.js\n\n    import Home from './pages/Home'\n    import Login from './pages/Login'\n    import PrivateRoute from './components/PrivateRoute'\n    import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'\n\n    const App = () =\u003e {\n    return (\n        \u003cRouter\u003e\n        \u003cRoutes\u003e\n            {/* Public Route */}\n            \u003cRoute path=\"/login\" element={\u003cLogin /\u003e} /\u003e\n\n            {/* Protected Route */}\n            \u003cRoute path='/' element={\u003cPrivateRoute /\u003e}\u003e\n            \u003cRoute path=\"/\" element={\u003cHome /\u003e} /\u003e\n            \u003c/Route\u003e\n\n        \u003c/Routes\u003e\n        \u003c/Router\u003e\n    )\n    }\n\n    export default App\n    ```\n\n- The `PrivateRoute.js` component defines a PrivateRoute component that is used to protect certain routes in the React app. It imports Navigate and Outlet components from react-router-dom for routing functionality and `useAuthStatus` custom hook for authentication status.\n\n    ```jsx\n    // useAuthStatus.js\n\n    import { getAuth, onAuthStateChanged } from 'firebase/auth'\n    import { useEffect, useState, useRef } from 'react'\n\n    export const useAuthStatus = () =\u003e {\n        const [loggedIn, setLoggedIn] = useState(false);\n        const [checkingStatus, setCheckingStatus] = useState(true);\n        const isMounted = useRef(true);\n\n        useEffect(() =\u003e {\n            if (isMounted) {\n                const auth = getAuth();\n                onAuthStateChanged(auth, (user) =\u003e {\n                    if (user) {\n                        setLoggedIn(true);\n                    } else {\n                        setLoggedIn(false);\n                    }\n                    setCheckingStatus(false);\n                })\n            }\n\n            return () =\u003e {\n                isMounted.current = false;\n            }\n        }, [isMounted])\n\n\n        return { loggedIn, checkingStatus }\n    }\n    ```\n\n- The component first checks the `checkingStatus` variable to display a loading spinner while the authentication status is being checked. Once the status is determined, if the user is logged in (loggedIn is true), it renders the child components using the Outlet component. Otherwise, it redirects the user to the login page using the Navigate component.\n\n    ```jsx\n    // PrivateRoute.js\n\n    import { Navigate, Outlet } from \"react-router-dom\"\n    import { useAuthStatus } from \"../hooks/useAuthStatus\"\n    import Loader from \"./Loader\"\n\n\n    const PrivateRoute = () =\u003e {\n        const { loggedIn, checkingStatus } = useAuthStatus();\n\n        if (checkingStatus) {\n            return \u003cdiv style={{height:\"100vh\", display:\"flex\",alignItems:\"center\",justifyContent:\"center\"}}\u003e\n                \u003cLoader/\u003e\n            \u003c/div\u003e\n        }\n\n        return loggedIn ? \u003cOutlet /\u003e : \u003cNavigate to=\"/login\" /\u003e\n    }\n\n    export default PrivateRoute\n    ```\n\n- The `Login.js` component defines a Login component that is used to login to the React app. It imports the `useAuth` custom hook for authentication functionality and `useNavigate` hook for navigation functionality.\n\n    ```jsx\n    import React from 'react'\n    import OAuth from '../components/OAuth'\n\n    const Login = ({ setUser }) =\u003e {\n    return (\n        \u003cdiv style={styles.container}\u003e\n        \u003cdiv style={styles.box}\u003e\n            \u003cdiv style={styles.logoCont}\u003e\n            \u003cimg style={styles.logoFirebase} src=\"./icons/firebase.png\" alt=\"logo\" /\u003e\n            \u003cdiv style={styles.plus}\u003e\n                +\n            \u003c/div\u003e\n            \u003cimg style={styles.logoStackup} src=\"./icons/stackup.svg\" alt=\"logo\" /\u003e\n            \u003c/div\u003e\n            \u003cdiv style={styles.appname}\u003e\n            Multimedia Application\n            \u003c/div\u003e\n            \u003cOAuth setUser={setUser} /\u003e\n        \u003c/div\u003e\n        \u003c/div\u003e\n    )\n    }\n    ```\n\n- In `OAuth.js` component, `handleOauth` function handles the Google Authentication and also checks if the user exists in firestore. If user does not exist in firestore, it creates a new document in firestore.\n\n    ```jsx\n    const navigate = useNavigate()\n        const handleOAuth = async () =\u003e {\n            try {\n                const auth = getAuth()\n                const provider = new GoogleAuthProvider();\n                const result = await signInWithPopup(auth, provider)\n                const user = result.user\n\n                // Check if user exists in firestore\n                const userRef = doc(db, 'users', user.uid)\n                const userDoc = await getDoc(userRef)\n\n                // If user does not exist in firestore, create a new document\n                if (!userDoc.exists()) {\n                    await setDoc(userRef, {\n                        name: user.displayName,\n                        email: user.email,\n                        timestamp: serverTimestamp(),\n                        id: shortid.generate().toUpperCase(),\n                        photoURL: user.photoURL\n                    })\n                }\n                navigate('/');\n            } catch (error) {\n                // toast.error('Bad User Credentials')\n                console.log(error);\n            }\n        }\n    ```\n\n- The `Home.js` Component, First we importing all the required components and firebase and ChartJs libraries,, hooks and functions.\n\n    ```jsx\n    import React, { useState, useEffect } from 'react';\n    import { db } from '../firebase.config';\n    import { getAuth } from 'firebase/auth';\n    import { collection, getDocs, query, where, updateDoc, doc, deleteDoc } from 'firebase/firestore';\n    import { Pie, Bar } from 'react-chartjs-2';\n    import { AudioPlayer, ImageViewer, Loader, DocumentViewer, VideoPlayer, NewFolder, Folder, FileUploadPopup, Header } from '../components';\n    import { Chart as ChartJS, CategoryScale, LinearScale, BarElement, Title, ArcElement, Tooltip, Legend\n    } from 'chart.js';\n    ChartJS.register( CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend, ArcElement );\n    ```\n\n    Define the state variables and functions to Fetch all the files and folders from firestore and store them in state variables. Also define the state variables and functions to open and close modals and also delete and edit Files.\n\n    ```jsx\n  const auth = getAuth();\n  const [myFiles, setMyFiles] = useState(null)\n  const [selectedFile, setSelectedFile] = useState(null)\n  const [showChartModal, setShowChartModal] = useState(false);\n  const [showFileModal, setShowFileModal] = useState(false);\n  const [currentFolder, setCurrentFolder] = useState(null) // All Files, [folder name\n  const [folders, setFolders] = useState([]);\n  const [showFolderModal, setShowFolderModal] = useState(false);\n  const [selectedFolderName, setSelectedFolderName] = useState(\"All Files\");\n\n      // Get all files and Folders on page load\n  useEffect(() =\u003e {\n    getFolders();\n    getFiles();\n  }, [])\n\n\n  var barChartOptions = {\n    responsive: true,\n    plugins: {\n      legend: {\n        position: 'top',\n      },\n      title: {\n        display: true,\n        text: 'Files Breakdown',\n      },\n    },\n  };\n\n  // Get all files created by the user and sort them by date created in descending order (newest first) from firestore\n  const getFiles = async () =\u003e {\n    const q = query(collection(db, \"files\"), where(\"createdBy\", \"==\", auth.currentUser.email));\n    const querySnapshot = await getDocs(q);\n    const files = [];\n    querySnapshot.forEach((doc) =\u003e {\n      const data = doc.data();\n      data.uid = doc.id;\n      files.push(data);\n    });\n    files.sort((a, b) =\u003e b.createdAt - a.createdAt);\n    // console.log(files);\n    setMyFiles(files);\n    setCurrentFolder(files);\n  }\n\n  // Get all folders created by the user and sort them by date created in descending order (newest first) from firestore\n  const getFolders = async () =\u003e {\n    const q = query(collection(db, \"folders\"), where(\"createdBy\", \"==\", auth.currentUser.email));\n    const querySnapshot = await getDocs(q);\n    const folders = [];\n    querySnapshot.forEach((doc) =\u003e {\n      const data = doc.data();\n      data.uid = doc.id;\n      folders.push(data);\n    });\n    folders.sort((a, b) =\u003e b.createdAt - a.createdAt);\n    // console.log(folders);\n    setFolders(folders);\n  }\n\n  // Rename a File in firestore\n  const renameFile = async (id, fileName) =\u003e {\n    try {\n      const fileRef = doc(db, \"files\", id);\n      await updateDoc(fileRef, { fileName });\n    } catch (error) {\n      console.log(error);\n    }\n  }\n\n    // Delete a File in firestore\n    const deleteFile = async (id) =\u003e {\n        try {\n        const fileRef = doc(db, \"files\", id);\n        await deleteDoc(fileRef);\n        } catch (error) {\n        console.log(error);\n        }\n    }\n    ```\n    \n    Popups to Create a new folder and upload a new file\n\n    ```jsx\n    {\n        showFolderModal \u0026\u0026 (\n          \u003cNewFolder folders={folders} setShowFolderModal={setShowFolderModal} getFolders={getFolders} /\u003e\n        )\n    }\n    {\n        showFileModal \u0026\u0026 (\n          \u003cFileUploadPopup getFiles={getFiles} folders={folders} setShowFileModal={setShowFileModal} /\u003e\n        )\n    }\n    ```\n     Mapping Folders and Create Folder button\n\n     ```jsx\n     \u003cdiv style={styles.controlTools}\u003e\n            {\n              folders.map((folder) =\u003e (\n                \u003cFolder setSelectedFile={setSelectedFile} setSelectedFolderName={setSelectedFolderName} selected={folder.folderName === selectedFolderName} files={myFiles} setCurrentFolder={setCurrentFolder} key={folder.id} folder={folder} /\u003e\n              ))\n            }\n\n            \u003cdiv onClick={() =\u003e setShowFolderModal(true)} style={styles.Folder}\u003e\n              \u003cimg style={styles.folderImG} src=\"./icons/newfolder.png\" alt=\"folder\" /\u003e\n              \u003cdiv style={styles.name}\u003e\n                Create Folder\n              \u003c/div\u003e\n            \u003c/div\u003e\n    \u003c/div\u003e\n     ```\n\n     Adding Loader and Icons to the files based on the file type\n\n     ```\n     {!currentFolder ? \u003cLoader /\u003e : currentFolder.map((file) =\u003e\n                \u003cdiv style={selectedFile?.fileUrl === file.fileUrl ? styles.fileSelected : styles.file} className=\"files\" key={file.id} onClick={() =\u003e {\n                  if (selectedFile \u0026\u0026 selectedFile.id === file.id) {\n                    setSelectedFile(null)\n                    return\n                  }\n                  setSelectedFile(file)\n                }}\u003e\n                  {\n                    file.fileType === 'video' \u0026\u0026 (\n                      \u003cimg alt='video' src=\"./icons/youtube.png\" style={{ width: 40, height: 40 }} /\u003e)\n                  }\n                  {\n                    file.fileType === 'audio' \u0026\u0026 (\n                      \u003cimg alt='audio' src=\"./icons/audio.png\" style={{ width: 40, height: 40 }} /\u003e)\n                  }\n                  {\n                    file.fileType === 'document' \u0026\u0026 (\n                      \u003cimg alt='doc' src=\"./icons/doc.png\" style={{ width: 40, height: 40 }} /\u003e)\n                  }\n                  {\n                    file.fileType === 'image' \u0026\u0026 (\n                      \u003cimg alt='pic' src=\"./icons/image.png\" style={{ width: 40, height: 40 }} /\u003e)\n                  }\n                  \u003cp\u003e{file.fileName}\u003c/p\u003e\n                \u003c/div\u003e\n              )\n            }\n     ```\n\n    Create Folder Popup is opened when we click new folder button. In `NewFolder` component we are handing folder creation using function `handleFolderCreate`, If the folder with the name exists or it is empty we reject, else we are creating the folder in firestore in `folders` collection.\n\n     ```jsx\n     const handleFolderCreate = async (e) =\u003e {\n        e.preventDefault();\n        setFolderCreating(true);\n        if (newFolderName === \"\") {\n            alert(\"Folder name cannot be empty\");\n            setFolderCreating(false);\n            return;\n        }\n        if (folders.find(folder =\u003e folder.folderName === newFolderName)) {\n            alert(\"Folder with same name already exists\");\n            setFolderCreating(false);\n            return;\n        }\n        try {\n            const folderRef = collection(db, \"folders\");\n            const payload = {\n                id: shortid.generate(),\n                folderName: newFolderName,\n                createdAt: new Date(),\n                createdBy: auth.currentUser.email,\n            }\n            await addDoc(folderRef, payload);\n            setShowFolderModal(false);\n            alert(\"Folder created successfully\");\n            setNewFolderName(\"\");\n            setFolderCreating(false);\n            await getFolders();\n        } catch (error) {\n            console.log(error);\n            setFolderCreating(false);\n        }\n    }\n    ```\n    Create File Popup is opened when we click Upload File button. In `FileUploadPopup` component we are handing folder creation using function `handleFolderCreate`, If the formdata is valid we are uploading file, getting its url and creating a new doc in firestore in `files` collection.\n\n    ```jsx\n    // Upload file to Firebase Storage and getting url\n    const storeFile = async (file) =\u003e {\n        const storage = getStorage();\n        const filename = `${file.name}-${shortid.generate()}`\n        console.log(filename);\n        const storageRef = ref(storage, 'files/' + filename);\n        await uploadBytesResumable(storageRef, file);\n        const url = await getDownloadURL(storageRef);\n        return url;\n    }\n\n   // Creating a new doc in files collection with filedata\n    const handleSubmit = async (e) =\u003e {\n    e.preventDefault();\n    setFileUploading(true);\n    try {\n      if (!fileToUpload) return;\n      if (\n        formData.fileName === \"\" || formData.fileType === \"\" || formData.folder === \"\"\n      ) return alert(\"Please fill all the fields\");\n      const fileUrl = await storeFile(fileToUpload);\n      const fileRef = collection(db, \"files\");\n      const payload = {\n        id: shortid.generate(),\n        fileName: formData.fileName,\n        fileType: formData.fileType,\n        folder: formData.folder,\n        fileUrl,\n        createdAt: new Date(),\n        createdBy: auth.currentUser.email,\n      }\n      await addDoc(fileRef, payload);\n      setShowFileModal(false);\n      alert(\"File uploaded successfully\");\n      setFormData({\n        fileName: \"\",\n        fileType: \"\",\n        folder: \"\",\n        fileUrl: \"\",\n      })\n      setFileToUpload(null);\n      await getFiles();\n      setFileUploading(false);\n    } catch (error) {\n      console.log(error);\n      setFileUploading(false);\n    }\n  }\n    ```\n\n### Working of the features\n\nLogin Screen\n![Multimedia App](https://i.ibb.co/ykLd4Qj/Screenshot-1409.png \"a title\")\n\n1. First Sigin with Google, the Dashboard Appears\n![Screenshot (1410)](https://github.com/SudhansuuRanjan/multimedia-app/assets/77230416/ad963b80-bb2d-4f08-98eb-ea20e995576f)\n\n2. Create A folder\n![Dashboard](https://i.ibb.co/gPd7cjY/Screenshot-1411.png)\n\n3. Create Files in that folder\n![Dashboard](https://i.ibb.co/z7Y7yJT/Screenshot-1412.png)\n\n4. Now you can view all the files in the folders or you could view files from a particular folder.\n![Screenshot (1410)](https://github.com/SudhansuuRanjan/multimedia-app/assets/77230416/ad963b80-bb2d-4f08-98eb-ea20e995576f)\n\n5. Now we can upload more files, create folders, preview files, edit filenames, see filebreakdown, download and also delete files, or you could just logout.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsudhansuuranjan%2Fmultimedia-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsudhansuuranjan%2Fmultimedia-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsudhansuuranjan%2Fmultimedia-app/lists"}