From 60d45e20e929f8d0d2d336b40aa068ec5779df28 Mon Sep 17 00:00:00 2001
From: BalajiD <cb.en.u4cse18008@cb.students.amrita.edu>
Date: Sat, 27 Mar 2021 10:53:08 +0530
Subject: [PATCH] FileInsert #38

---
 digital-course-file/src/hooks/useFolder.js |  25 +++-
 digital-course-file/src/user/AddFile.js    | 145 +++++++++++++++++++++
 digital-course-file/src/user/File.js       |  16 +++
 digital-course-file/src/user/FolderNav.js  |   1 -
 digital-course-file/src/user/Hero.js       | 119 ++++++++++++++++-
 5 files changed, 298 insertions(+), 8 deletions(-)
 create mode 100644 digital-course-file/src/user/AddFile.js
 create mode 100644 digital-course-file/src/user/File.js

diff --git a/digital-course-file/src/hooks/useFolder.js b/digital-course-file/src/hooks/useFolder.js
index b4c921b..2ec2265 100644
--- a/digital-course-file/src/hooks/useFolder.js
+++ b/digital-course-file/src/hooks/useFolder.js
@@ -8,11 +8,12 @@ export const ROOT_FOLDER = {name: 'Root', id : null , path : [] , parents : []};
 export function useFolder( folderId = null, folder= null) {
 
     // const {currentUser} = firebase.auth.currentUser;
-
+    
     const ACTIONS = {
         SELECT_FOLDER : 'select-folder',
         UPDATE_FOLDER : 'update-folder',
         SET_CHILD_FOLDERS : 'set_child_folders',
+        SET_CHILD_FILES: "set-child-files",
     }
 
     function reducer( state, { type,payload } ){
@@ -36,6 +37,11 @@ export function useFolder( folderId = null, folder= null) {
                 return{
                     ...state,
                     childFolders : payload.childFolders,
+                }; 
+            case ACTIONS.SET_CHILD_FILES:
+                return {
+                    ...state,
+                    childFiles: payload.childFiles,
                 };    
 
             default:
@@ -104,6 +110,23 @@ export function useFolder( folderId = null, folder= null) {
                 })
             })
     },[folderId])
+    useEffect(() => {
+        if(firebase.auth().currentUser)
+        {
+                return (
+          database.files
+            .where("folderId", "==", folderId)
+            .where("userId", "==", firebase.auth().currentUser.uid)
+            .onSnapshot(snapshot => {
+              dispatch({
+                type: ACTIONS.SET_CHILD_FILES,
+                payload: { childFiles: snapshot.docs.map(database.formatDoc) },
+              })
+            })
+        )
+        }
+        
+      }, [folderId])
 
     return state;
 }
\ No newline at end of file
diff --git a/digital-course-file/src/user/AddFile.js b/digital-course-file/src/user/AddFile.js
new file mode 100644
index 0000000..3de4ef2
--- /dev/null
+++ b/digital-course-file/src/user/AddFile.js
@@ -0,0 +1,145 @@
+import React, { useState } from "react"
+import ReactDOM from "react-dom"
+import { faFileUpload } from "@fortawesome/free-solid-svg-icons"
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
+import { storage, database } from '../fire.js'
+import { ROOT_FOLDER } from "../hooks/useFolder"
+import { v4 as uuidV4 } from "uuid"
+import { ProgressBar, Toast } from "react-bootstrap"
+import firebase from 'firebase'
+
+export default function AddFile({ currentFolder }) {
+  const [uploadingFiles, setUploadingFiles] = useState([])
+  
+
+  function handleUpload(e) {
+    const file = e.target.files[0]
+    if (currentFolder == null || file == null) return
+
+    const id = uuidV4()
+    setUploadingFiles(prevUploadingFiles => [
+      ...prevUploadingFiles,
+      { id: id, name: file.name, progress: 0, error: false },
+    ])
+    const filePath =
+      currentFolder === ROOT_FOLDER
+        ? `${currentFolder.path.join("/")}/${file.name}`
+        : `${currentFolder.path.join("/")}/${currentFolder.name}/${file.name}`
+
+    const uploadTask = storage
+      .ref(`/files/${firebase.auth().currentUser.uid}/${filePath}`)
+      .put(file)
+
+    uploadTask.on(
+      "state_changed",
+      snapshot => {
+        const progress = snapshot.bytesTransferred / snapshot.totalBytes
+        setUploadingFiles(prevUploadingFiles => {
+          return prevUploadingFiles.map(uploadFile => {
+            if (uploadFile.id === id) {
+              return { ...uploadFile, progress: progress }
+            }
+
+            return uploadFile
+          })
+        })
+      },
+      () => {
+        setUploadingFiles(prevUploadingFiles => {
+          return prevUploadingFiles.map(uploadFile => {
+            if (uploadFile.id === id) {
+              return { ...uploadFile, error: true }
+            }
+            return uploadFile
+          })
+        })
+      },
+      () => {
+        setUploadingFiles(prevUploadingFiles => {
+          return prevUploadingFiles.filter(uploadFile => {
+            return uploadFile.id !== id
+          })
+        })
+
+        uploadTask.snapshot.ref.getDownloadURL().then(url => {
+          database.files
+            .where("name", "==", file.name)
+            .where("userId", "==", firebase.auth().currentUser.uid)
+            .where("folderId", "==", currentFolder.id)
+            .get()
+            .then(existingFiles => {
+              const existingFile = existingFiles.docs[0]
+              if (existingFile) {
+                existingFile.ref.update({ url: url })
+              } else {
+                database.files.add({
+                  url: url,
+                  name: file.name,
+                  createdAt: database.getTime(),
+                  folderId: currentFolder.id,
+                  userId: firebase.auth().currentUser.uid,
+                })
+              }
+            })
+        })
+      }
+    )
+  }
+
+  return (
+    <>
+      <label className="btn btn-outline-success btn-sm m-0 mr-2">
+        <FontAwesomeIcon icon={faFileUpload} />
+        <input
+          type="file"
+          onChange={handleUpload}
+          style={{ opacity: 0, position: "absolute", left: "-9999px" }}
+        />
+      </label>
+      {uploadingFiles.length > 0 &&
+        ReactDOM.createPortal(
+          <div
+            style={{
+              position: "absolute",
+              bottom: "1rem",
+              right: "1rem",
+              maxWidth: "250px",
+            }}
+          >
+            {uploadingFiles.map(file => (
+              <Toast
+                key={file.id}
+                onClose={() => {
+                  setUploadingFiles(prevUploadingFiles => {
+                    return prevUploadingFiles.filter(uploadFile => {
+                      return uploadFile.id !== file.id
+                    })
+                  })
+                }}
+              >
+                <Toast.Header
+                  closeButton={file.error}
+                  className="text-truncate w-100 d-block"
+                >
+                  {file.name}
+                </Toast.Header>
+                <Toast.Body>
+                  <ProgressBar
+                    animated={!file.error}
+                    variant={file.error ? "danger" : "primary"}
+                    now={file.error ? 100 : file.progress * 100}
+                    label={
+                      file.error
+                        ? "Error"
+                        : `${Math.round(file.progress * 100)}%`
+                    }
+                  />
+                </Toast.Body>
+              </Toast>
+            ))}
+          </div>,
+          document.body
+        )}
+    </>
+  )
+}
\ No newline at end of file
diff --git a/digital-course-file/src/user/File.js b/digital-course-file/src/user/File.js
new file mode 100644
index 0000000..e157c4c
--- /dev/null
+++ b/digital-course-file/src/user/File.js
@@ -0,0 +1,16 @@
+import { faFile } from "@fortawesome/free-solid-svg-icons"
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
+import React from "react"
+
+export default function File({ file }) {
+  return (
+    <a
+      href={file.url}
+      target="_blank"
+      className="btn btn-outline-dark text-truncate w-100"
+    >
+      <FontAwesomeIcon icon={faFile} className="mr-2" />
+      {file.name}
+    </a>
+  )
+}
diff --git a/digital-course-file/src/user/FolderNav.js b/digital-course-file/src/user/FolderNav.js
index ca67384..fbfe064 100644
--- a/digital-course-file/src/user/FolderNav.js
+++ b/digital-course-file/src/user/FolderNav.js
@@ -10,7 +10,6 @@ export default function FolderNav( {currentFolder} ) {
         path = [...path,...currentFolder.path];
     }
 
-    
     return(
         <Breadcrumb
             className="flex-grow-1"
diff --git a/digital-course-file/src/user/Hero.js b/digital-course-file/src/user/Hero.js
index 0e9e903..8beb26b 100644
--- a/digital-course-file/src/user/Hero.js
+++ b/digital-course-file/src/user/Hero.js
@@ -1,20 +1,25 @@
-import React, { useEffect, useState } from 'react'
+import React, { useState, Component } from "react"
 import AddFolder from './AddFolder'
+import AddFile from './AddFile'
 import { Container, Button, Navbar, Nav } from 'react-bootstrap'
-import { ROOT_FOLDER, useFolder } from '.././hooks/useFolder'
+import { useFolder } from '.././hooks/useFolder'
 import Folder from './Folder'
 import FolderNav from './FolderNav'
 import Deffolders from './Deffolders'
-import Deletefolder from './Deletefolder'
 import Sharelink from './Sharelink'
-import { useParams } from 'react-router-dom'
-import copyright from './copyright'
+import Deletefolder from './Deletefolder'
+import { useParams,useLocation } from 'react-router-dom' 
 import { Link } from 'react-router-dom'
+import File from './File'
+import 'firebase/storage';
+import ReactDOM from "react-dom"
+import firebase from "../fire";
 import Loader from 'react-loader-spinner'
 
 const Hero = ({ handleLogout }) => {
   const { folderId } = useParams()
-  const { folder, childFolders } = useFolder(folderId)
+  const { state = {} } = useLocation()
+  const { folder, childFolders, childFiles } = useFolder(folderId, state.folder)
 
   if (!folder) {
     return (
@@ -44,6 +49,7 @@ const Hero = ({ handleLogout }) => {
           )}
           {folder.id!=null &&  ( <Sharelink currentFolder={folder} /> )}
           {folder.id!=null &&  ( <Deletefolder currentFolder={folder} /> )}
+          {folder.id!=null &&  ( <AddFile currentFolder={folder} /> )}
         </div>
 
         {childFolders.length > 0 && (
@@ -59,8 +65,109 @@ const Hero = ({ handleLogout }) => {
             ))}
           </div>
         )}
+
+        {childFolders.length > 0 && childFiles.length > 0 && <hr />}
+        {childFiles.length > 0 && (
+          <div className="d-flex flex-wrap">
+            {childFiles.map(childFile => (
+              <div
+                key={childFile.id}
+                style={{ maxWidth: "250px" }}
+                className="p-2"
+              >
+                <File file={childFile} />
+                <div id="root">
+                  
+                </div>
+              </div>
+            ))}
+          </div>
+        )}
+        
       </Container>
+      <Navbar fixed='bottom' variant='light' bg='light'>
+        <Container className='ml-sm-2'>
+          <Nav.Link eventKey={2} href='copyright'>
+            &copy; Digital Course File Group 2
+          </Nav.Link>
+        </Container>
+      </Navbar>
     </>
   )
 }
+class ContextMenu extends React.Component {
+  state = {
+      visible: false,
+  };
+  
+  componentDidMount() {
+      document.addEventListener('contextmenu', this._handleContextMenu);
+      document.addEventListener('click', this._handleClick);
+      document.addEventListener('scroll', this._handleScroll);
+  };
+
+  componentWillUnmount() {
+    document.removeEventListener('contextmenu', this._handleContextMenu);
+    document.removeEventListener('click', this._handleClick);
+    document.removeEventListener('scroll', this._handleScroll);
+  }
+  
+  _handleContextMenu = (event) => {
+      event.preventDefault();
+      
+      this.setState({ visible: true });
+      
+      const clickX = event.clientX;
+      const clickY = event.clientY;
+      const screenW = window.innerWidth;
+      const screenH = window.innerHeight;
+      const rootW = this.root.offsetWidth;
+      const rootH = this.root.offsetHeight;
+      
+      const right = (screenW - clickX) > rootW;
+      const left = !right;
+      const top = (screenH - clickY) > rootH;
+      const bottom = !top;
+      
+      if (right) {
+          this.root.style.left = `${clickX + 5}px`;
+      }
+      
+      if (left) {
+          this.root.style.left = `${clickX - rootW - 5}px`;
+      }
+      
+      if (top) {
+          this.root.style.top = `${clickY + 5}px`;
+      }
+      
+      if (bottom) {
+          this.root.style.top = `${clickY - rootH - 5}px`;
+      }
+  };
+
+  _handleClick = (event) => {
+      const { visible } = this.state;
+      const wasOutside = !(event.target.contains === this.root);
+      
+      if (wasOutside && visible) this.setState({ visible: false, });
+  };
+
+  _handleScroll = () => {
+      const { visible } = this.state;
+      
+      if (visible) this.setState({ visible: false, });
+  };
+  
+  render() {
+      const { visible } = this.state;
+      
+      return(visible || null) && 
+          <div ref={ref => {this.root = ref}} className="contextMenu">
+              <div className="contextMenu--option">Delete</div>
+              
+          </div>
+  };
+}
+ReactDOM.render(<ContextMenu/>, document.getElementById('root'));
 export default Hero
-- 
GitLab