diff --git a/src/components/ImgUpload/index.css b/src/components/ImgUpload/index.css index bfb10027c..d09c2eca3 100644 --- a/src/components/ImgUpload/index.css +++ b/src/components/ImgUpload/index.css @@ -190,6 +190,22 @@ input { font-size: large; } +.shareBtnContainer { + width: 100%; + display: flex; + gap: 5px; +} + +.disable_post_btn { + background: grey; + cursor: not-allowed; +} + +.disable_post_btn:hover { + background: grey; + cursor: not-allowed; +} + @media only screen and (min-width: 800px) { .dialogStyle { width: 60vw; @@ -239,6 +255,7 @@ input { .small_post_view { display: none; + width: 100%; } } @@ -263,7 +280,7 @@ input { } .post__caption_section { - width: 48vw; + width: 100%; } .next_button { diff --git a/src/components/ImgUpload/index.jsx b/src/components/ImgUpload/index.jsx index 68ae1612d..071b5407d 100644 --- a/src/components/ImgUpload/index.jsx +++ b/src/components/ImgUpload/index.jsx @@ -25,6 +25,7 @@ export default function ImgUpload(props) { const [imagePreviews, setImagePreviews] = useState([]); const [isValidimage, setisValidimage] = useState(true); const [buttonPopup, setButtonPopup] = useState(false); + const [isStoryUploaded, setIsStoryUploaded] = useState(false); const [username, setUsername] = useState(""); const displayName = auth.currentUser.displayName; @@ -48,8 +49,10 @@ export default function ImgUpload(props) { const docRef = doc(db, "users", auth?.currentUser?.uid); const docSnap = await getDoc(docRef); setUsername(docSnap.data().username); + if (docSnap.data().storyTimestamp) { + setIsStoryUploaded(true); + } } - getUsername(); }, []); @@ -87,30 +90,51 @@ export default function ImgUpload(props) { setImagePreviews(images); }; - const savePost = async (imageUrl = "") => { + const savePost = async (imageUrl = "", type) => { try { - const postRef = await db.collection("posts").add({ - timestamp: firebase.firestore.FieldValue.serverTimestamp(), - caption: caption, - imageUrl, - username: username, - displayName: props.user.displayName, - avatar: props.user.photoURL, - likecount: [], - uid: auth?.currentUser?.uid, - }); + if (type === "Post") { + const postRef = await db.collection("posts").add({ + timestamp: firebase.firestore.FieldValue.serverTimestamp(), + caption: caption, + imageUrl, + username: username, + displayName: props.user.displayName, + avatar: props.user.photoURL, + likecount: [], + uid: auth?.currentUser?.uid, + }); - const postId = postRef.id; // Store post ID in a separate variable + const postId = postRef.id; // Store post ID in a separate variable - await db - .collection("users") - .doc(props.user.uid) - .update({ - posts: firebase.firestore.FieldValue.arrayUnion(postId), // Use postId instead of postRef.id + await db + .collection("users") + .doc(props.user.uid) + .update({ + posts: firebase.firestore.FieldValue.arrayUnion(postId), // Use postId instead of postRef.id + }); + } else { + await db.collection("story").add({ + caption: caption, + imageUrl, + username: username, + uid: auth?.currentUser?.uid, }); + const querySnapshot = await db + .collection("users") + .where("username", "==", username) + .get(); + if (!querySnapshot.empty) { + const userRef = querySnapshot.docs[0].ref; + // Update the 'storyTimestamp' field + await userRef.update({ + storyTimestamp: firebase.firestore.FieldValue.serverTimestamp(), + }); + } + } + playSuccessSound(); - enqueueSnackbar("Post was uploaded successfully!", { + enqueueSnackbar(`${type} uploaded successfully!`, { variant: "success", }); @@ -138,7 +162,7 @@ export default function ImgUpload(props) { } }; - function handleUpload() { + function handleUpload(type) { if ((!image && !caption) || !isValidimage) { enqueueSnackbar("Upload valid image and caption!", { variant: "error", @@ -152,7 +176,7 @@ export default function ImgUpload(props) { } if (!image) { - savePost(); + savePost("", type); return; } @@ -167,7 +191,7 @@ export default function ImgUpload(props) { }, }) .then((urls) => { - savePost(JSON.stringify(urls)); + savePost(JSON.stringify(urls), type); }) .catch((err) => { enqueueSnackbar(err.message, { @@ -311,13 +335,24 @@ export default function ImgUpload(props) { }} style={{ color: "var(--color) !important" }} /> - +
+ + +
@@ -430,6 +465,7 @@ export default function ImgUpload(props) { )}
setCaption(e.target.value)} value={caption} variant="filled" @@ -445,16 +481,29 @@ export default function ImgUpload(props) { }, "& .MuiFilledInput-root": { background: "transparent", + color: "var(--color)", }, }} + style={{ color: "var(--color) !important" }} /> - +
+ + +
)} diff --git a/src/components/Post/index.jsx b/src/components/Post/index.jsx index f1ff0ddb4..d56390e15 100644 --- a/src/components/Post/index.jsx +++ b/src/components/Post/index.jsx @@ -60,7 +60,7 @@ function Post(prop) { snapshot.docs.map((doc) => ({ id: doc.id, content: doc.data(), - })), + })) ); }); } @@ -138,13 +138,6 @@ function Post(prop) { const tempLikeCount = likecount ? [...likecount] : []; - const buttonStyle = { - ":hover": { - color: "#FF4D4D", - fontSize: "29px", - }, - }; - async function likesHandler() { if (user && likecount !== undefined) { let ind = tempLikeCount.indexOf(user.uid); diff --git a/src/components/SideBar/index.jsx b/src/components/SideBar/index.jsx index 2013fa5b2..edd3e8bfd 100644 --- a/src/components/SideBar/index.jsx +++ b/src/components/SideBar/index.jsx @@ -53,7 +53,8 @@ function SideBar({ anonymous }) { } >
- New Post + {" "} + New Post/Story
  • { + const [storyData, setStoryData] = useState({}); + const [storyImage, setStoryImage] = useState(""); + const { imageUrl, caption } = storyData; + + useEffect(() => { + async function getStory() { + const docRef = db + .collection("story") + .where("username", "==", username) + .limit(1); + + docRef.get().then((snapshot) => { + const doc = snapshot.docs[0]; + setStoryData({ + ...doc?.data(), + }); + try { + setStoryImage(JSON.parse(doc.data().imageUrl)); + } catch { + const img = doc + ?.data() + ?.imageUrl?.split(",") + .map((url) => ({ + imageUrl: url, + imageWidth: 0, + imageHeight: 0, + thumbnail: null, + })); + setStoryImage(img); + } + }); + } + + getStory(); + }, []); + + async function deleteStory() { + // Delete the story from story collection + const querySnapshot = await db + .collection("story") + .where("username", "==", username) + .get(); + + querySnapshot?.forEach((doc) => { + doc.ref.delete().catch((error) => { + console.error("Error deleting document: ", error); + }); + }); + + // Delete story timestamp from user Doc + const userDocSnapshot = await db + .collection("users") + .where("username", "==", username) + .get(); + + userDocSnapshot?.forEach((doc) => { + doc.ref + .update({ + storyTimestamp: deleteField(), + }) + .then(() => { + setUserData((prevData) => ({ + ...prevData, + storyTimestamp: null, + })); + }) + .catch((error) => { + console.error("Error deleting document: ", error); + }); + }); + } + + return ( +
    + setViewStory(false)} + /> + {storyData !== {} ? ( + <> + { + deleteStory(); + setViewStory(false); + }} + /> +
    + {imageUrl == "" ? ( +
    + {username} +

    {caption}

    +
    + ) : ( +
    + {username} +

    {caption}

    +
    + )} +
    + + ) : ( +

    Sorry😓 No story!

    + )} +
    + ); +}; + +export default StoryView; diff --git a/src/components/index.js b/src/components/index.js index e396062cf..f487fb6f8 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -13,6 +13,7 @@ import Post from "./Post"; import ReadMore from "./ReadMore"; import SearchBar from "./SearchBar"; import SideBar from "./SideBar"; +import StoryView from "./Story"; export { Caption, @@ -30,6 +31,7 @@ export { ReadMore, SearchBar, SideBar, + StoryView, }; export default Post; diff --git a/src/pages/Profile/index.css b/src/pages/Profile/index.css index ddca15671..715bac841 100644 --- a/src/pages/Profile/index.css +++ b/src/pages/Profile/index.css @@ -135,6 +135,10 @@ font-weight: 600; } +.story_available_border { + border: 6px solid rgba(2, 106, 242, 0.6); +} + .setting-logout { display: flex; flex-direction: row; diff --git a/src/pages/Profile/index.jsx b/src/pages/Profile/index.jsx index 0a6edd195..2186e12dd 100644 --- a/src/pages/Profile/index.jsx +++ b/src/pages/Profile/index.jsx @@ -9,8 +9,14 @@ import { Typography, useMediaQuery, } from "@mui/material"; -import { auth, db } from "../../lib/firebase"; -import { collection, onSnapshot, query, where } from "firebase/firestore"; +import { auth, db, storage } from "../../lib/firebase"; +import { + collection, + deleteField, + onSnapshot, + query, + where, +} from "firebase/firestore"; import { getModalStyle, useStyles } from "../../App"; import { lazy, useEffect, useState } from "react"; import { playErrorSound, playSuccessSound } from "../../js/sounds"; @@ -25,6 +31,7 @@ import LogoutIcon from "@mui/icons-material/Logout"; import Modal from "@mui/material/Modal"; import NotFound from "../NotFound"; import SettingsIcon from "@mui/icons-material/Settings"; +import { StoryView } from "../../components"; import ViewsCounter from "../../reusableComponents/views"; import firebase from "firebase/compat/app"; import logo from "../../assets/logo.webp"; @@ -48,6 +55,7 @@ function Profile() { const [userData, setUserData] = useState(null); const [isEditing, setIsEditing] = useState(false); const [userExists, setUserExists] = useState(true); + const [viewStory, setViewStory] = useState(false); const { username } = useParams(); let name = ""; @@ -55,6 +63,7 @@ function Profile() { let uid = ""; let bio = ""; let country = ""; + let storyTimestamp = null; if (userData) { name = userData.name; @@ -62,6 +71,7 @@ function Profile() { uid = userData.uid; bio = userData.bio; country = userData.country; + storyTimestamp = userData.storyTimestamp; } const handleClose = () => setOpen(false); @@ -77,14 +87,43 @@ function Profile() { .then((snapshot) => { if (snapshot.docs) { const doc = snapshot.docs[0]; + + const currTimestamp = firebase.firestore.Timestamp.now().seconds; + const storyTimestamp = doc.data().storyTimestamp?.seconds; + + //Check if story is expired or not + if (storyTimestamp && currTimestamp - storyTimestamp > 86400) { + async function deleteStory() { + const querySnapshot = await db + .collection("story") + .where("username", "==", username) + .get(); + + // Delete the story that are expired + querySnapshot?.forEach((doc) => { + doc.ref.delete().catch((error) => { + console.error("Error deleting document: ", error); + }); + }); + + const docRef = doc.ref; + docRef.update({ + storyTimestamp: deleteField(), + }); + } + deleteStory(); + } + + const data = doc.data(); setUserData({ - name: doc.data().name, - avatar: doc.data().photoURL, - uid: doc.data().uid, - bio: doc.data().bio - ? doc.data().bio + name: data.name, + avatar: data.photoURL, + uid: data.uid, + bio: data.bio + ? data.bio : "Lorem ipsum dolor sit amet consectetur", - country: doc.data().country ? doc.data().country : "Global", + country: data.country ? data.country : "Global", + storyTimestamp: data.storyTimestamp, }); } else { setUserExists(false); @@ -241,6 +280,13 @@ function Profile() { + {viewStory && ( + + )} {isEditing && ( {avatar ? ( setOpen((on) => !on)} + onClick={() => { + if (storyTimestamp) { + setViewStory(true); + } + }} alt={name} src={avatar} - className="profile-pic-container" + className={`profile-pic-container ${ + storyTimestamp ? "story_available_border" : null + }`} /> ) : ( diff --git a/src/reusableComponents/ImageSlider/index.jsx b/src/reusableComponents/ImageSlider/index.jsx index 5e6eb5c94..a9c532210 100644 --- a/src/reusableComponents/ImageSlider/index.jsx +++ b/src/reusableComponents/ImageSlider/index.jsx @@ -28,7 +28,7 @@ const ImageSlider = ({ slides, doubleClickHandler }) => { return slides.length ? (
    - {slides.map(({ imageUrl, imageWidth, imageHeight, thumbnail }, index) => ( + {slides.map(({ imageUrl, thumbnail }, index) => (