-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
notifications, other minor changes and version bump (v0.0.2-prealpha)
Showing
13 changed files
with
304 additions
and
49 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import { doc } from "firebase/firestore"; | ||
import React, { useEffect, useState } from "react"; | ||
import { useDocument } from "react-firebase-hooks/firestore"; | ||
import { Link } from "react-router-dom"; | ||
import { db } from "../api/firebase-config"; | ||
|
||
const Notification = ({ data, key }) => { | ||
const type = data.type; | ||
const senderUid = data.uid; | ||
const time = data.sentAt; | ||
const senderQ = doc(db, "users", data.from); | ||
const [value, loading] = useDocument(senderQ); | ||
|
||
useEffect(() => { | ||
console.log(data.type); | ||
}, [data]); | ||
|
||
function timeDiff(secs) { | ||
let str = ""; | ||
let ms = Date.now(); | ||
let s = Math.floor(ms / 1000); | ||
let sDiff = s - secs; | ||
if (sDiff >= 0 && sDiff < 60) { | ||
str += Math.round(sDiff) + "s ago"; | ||
} else if (sDiff >= 60 && sDiff < 3600) { | ||
sDiff /= 60; | ||
str += Math.round(sDiff) + "m ago"; | ||
} else if (sDiff >= 3600 && sDiff < 86400) { | ||
sDiff /= 60; | ||
sDiff /= 60; | ||
str += Math.round(sDiff) + "h ago"; | ||
} else if (sDiff >= 86400 && sDiff < 2.628e6) { | ||
sDiff /= 60; | ||
sDiff /= 60; | ||
sDiff /= 24; | ||
str += Math.round(sDiff) + "d ago"; | ||
} else if (sDiff >= 2.628e6 && sDiff < 3.154e7) { | ||
sDiff /= 60; | ||
sDiff /= 60; | ||
sDiff /= 24; | ||
sDiff /= 30; | ||
str += Math.round(sDiff) + "m ago"; | ||
} else { | ||
sDiff /= 60; | ||
sDiff /= 60; | ||
sDiff /= 24; | ||
sDiff /= 30; | ||
sDiff /= 12; | ||
str += Math.round(sDiff) + "y ago"; | ||
} | ||
return str; | ||
} | ||
|
||
return ( | ||
<div key={key} className="notification-panel"> | ||
<hr /> | ||
<p>{type}</p> | ||
<p> | ||
From: {loading ? <p>loading...</p> : <p>{value.data().displayName}</p>} | ||
</p> | ||
<p>{timeDiff(time)}</p> | ||
<hr /> | ||
</div> | ||
); | ||
}; | ||
|
||
export default Notification; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
import { auth, db } from "../api/firebase-config"; | ||
import { | ||
collection, | ||
orderBy, | ||
query, | ||
onSnapshot, | ||
limit, | ||
startAfter, | ||
} from "firebase/firestore"; | ||
import Notification from "./Notification"; | ||
import React, { useEffect, useState, useCallback } from "react"; | ||
|
||
function Notifications() { | ||
const user = auth.currentUser; | ||
/** | ||
* The state variable that stores an array of notifications fetched from the backend. | ||
* @type {Array} | ||
*/ | ||
const [notifications, setNotifications] = useState([]); | ||
|
||
/** | ||
* The state variable that stores the number of notifications to be fetched from the backend. | ||
* @type {number} | ||
*/ | ||
const [limite] = useState(5); | ||
|
||
/** | ||
* The state variable that stores a boolean flag to indicate whether notifications are currently being loaded. | ||
* @type {boolean} | ||
*/ | ||
const [loading, setLoading] = useState(false); | ||
|
||
/** | ||
* The state variable that stores a boolean flag to indicate whether the user has scrolled to the bottom of the page. | ||
* @type {boolean} | ||
*/ | ||
const [atBottom, setAtBottom] = useState(false); | ||
|
||
/** | ||
* The state variable that stores the last loaded post for cursor based pagination | ||
* @type {DocumentSnapshot} | ||
*/ | ||
const [cursor, setCursor] = useState(null); | ||
|
||
/** | ||
* Hook that fetches posts from the Firestore database when the component is mounted. | ||
* Sets cursor to the last post loaded for proper cursor pagination | ||
* | ||
* @function | ||
* @returns {function} A cleanup function to remove the Firestore listener. | ||
*/ | ||
useEffect(() => { | ||
const NotificationCollectionRef = collection( | ||
db, | ||
`users/${user.uid}/notifications` | ||
); | ||
const unsub = () => { | ||
const q = query( | ||
NotificationCollectionRef, | ||
orderBy("sentAt", "desc"), | ||
limit(limite) | ||
); | ||
onSnapshot(q, (snapshot) => { | ||
const data = snapshot.docs.map((doc) => ({ | ||
...doc.data(), | ||
id: doc.id, | ||
})); | ||
setCursor(snapshot.docs[4]); | ||
setNotifications(data); | ||
setLoading(false); | ||
}); | ||
}; | ||
|
||
unsub(); | ||
}, [limite]); | ||
|
||
/** | ||
* Handles loading more posts when the "load more" button is clicked. | ||
* Calls a onSnapshot listener for the next 5 posts after the cursor. | ||
* | ||
* @callback | ||
* @returns {void} | ||
*/ | ||
const handleLoadMore = useCallback(() => { | ||
setLoading(true); | ||
const NotificationCollectionRef = collection( | ||
db, | ||
`users/${user.uid}/notifications` | ||
); | ||
const unsub = () => { | ||
const q = query( | ||
NotificationCollectionRef, | ||
orderBy("sentAt", "desc"), | ||
limit(limite), | ||
startAfter(cursor) | ||
); | ||
onSnapshot(q, (snapshot) => { | ||
const data = snapshot.docs.map((doc) => ({ | ||
...doc.data(), | ||
id: doc.id, | ||
})); | ||
setCursor(snapshot.docs[4]); | ||
setNotifications((p) => p.concat(data)); | ||
setLoading(false); | ||
}); | ||
}; | ||
unsub(); | ||
setAtBottom(false); | ||
}, [limite, cursor]); | ||
|
||
/** | ||
* Registers a scroll event listener on the window object to detect when the user | ||
* has scrolled to the bottom of the page, triggering the `handleLoadMore` callback | ||
* function to load additional posts. | ||
* | ||
* @callback | ||
* @returns {void} | ||
*/ | ||
const handleScroll = useCallback(() => { | ||
if (loading || atBottom) return; | ||
|
||
// Check if the user has scrolled to the bottom of the page | ||
if ( | ||
window.innerHeight + document.documentElement.scrollTop >= | ||
document.documentElement.offsetHeight | ||
) { | ||
console.log("Scrolled to bottom!"); | ||
setAtBottom(true); | ||
if (!loading) handleLoadMore(); | ||
} | ||
}, [loading, atBottom, handleLoadMore]); | ||
|
||
/** | ||
* Registers a scroll event listener on the window object and removes it when the | ||
* component unmounts. | ||
* | ||
* @callback | ||
* @returns {void} | ||
*/ | ||
useEffect(() => { | ||
window.addEventListener("scroll", handleScroll); | ||
return () => { | ||
window.removeEventListener("scroll", handleScroll); | ||
}; | ||
}, [handleScroll]); | ||
|
||
/** | ||
* Clears the "atBottom" state if it's set to true and the component is not loading. | ||
* | ||
* @function | ||
* @returns {void} | ||
*/ | ||
useEffect(() => { | ||
if (!loading && atBottom) { | ||
setAtBottom(false); | ||
} | ||
}, [loading, atBottom]); | ||
return ( | ||
<div className="notification-feed text-center"> | ||
{notifications.map((doc) => { | ||
return <Notification data={doc} key={doc.id} />; | ||
})} | ||
{loading && <p>Loading...</p>} | ||
</div> | ||
); | ||
} | ||
|
||
export default Notifications; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.