diff --git a/src/components/TutorialPage/components/Commnets/Comment.jsx b/src/components/TutorialPage/components/Commnets/Comment.jsx index 3f18faa6..4af417d3 100644 --- a/src/components/TutorialPage/components/Commnets/Comment.jsx +++ b/src/components/TutorialPage/components/Commnets/Comment.jsx @@ -1,18 +1,11 @@ import { - Card, Grid, - Box, Typography, Avatar, - TextField, Button, IconButton, - InputAdornment, Paper } from "@mui/material"; -import EmojiPicker from "emoji-picker-react"; -import { InsertEmoticon, Send } from "@mui/icons-material"; -import AccountCircle from "@mui/icons-material/AccountCircle"; import { makeStyles } from "@mui/styles"; import CardActions from "@mui/material/CardActions"; import MoreVertOutlinedIcon from "@mui/icons-material/MoreVertOutlined"; @@ -20,9 +13,22 @@ import ToggleButton from "@mui/lab/ToggleButton"; import ToggleButtonGroup from "@mui/lab/ToggleButtonGroup"; import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp"; import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; -import React, { useState } from "react"; +import React, { + useState, + useEffect, + useCallback, + useMemo, + useRef +} from "react"; import Textbox from "./Textbox"; -import { divide } from "lodash"; +import User from "../UserDetails"; +import { useDispatch, useSelector } from "react-redux"; +import { useFirebase, useFirestore } from "react-redux-firebase"; +import { + getCommentData, + getCommentReply, + addComment +} from "../../../../store/actions/tutorialPageActions"; const useStyles = makeStyles(() => ({ container: { margin: "10px 0", @@ -33,6 +39,7 @@ const useStyles = makeStyles(() => ({ fontWeight: "600" }, comments: { + margin: "5px", padding: "10px 15px" }, settings: { @@ -45,17 +52,40 @@ const useStyles = makeStyles(() => ({ } })); -const Comment = () => { +const Comment = ({ id }) => { const classes = useStyles(); - const [commentText, setCommentText] = useState(""); - const [showEmojiPicker, setShowEmojiPicker] = useState(false); const [showReplyfield, setShowReplyfield] = useState(false); - const addEmoji = emoji => { - setCommentText(prev => prev + emoji.emoji); - setShowEmojiPicker(false); - }; const [alignment, setAlignment] = React.useState("left"); const [count, setCount] = useState(1); + const firestore = useFirestore(); + const firebase = useFirebase(); + const dispatch = useDispatch(); + useState(() => { + getCommentData(id)(firebase, firestore, dispatch); + }, [id]); + + const commentsArray = useSelector( + ({ + tutorialPage: { + comment: { data } + } + }) => data + ); + + const [data] = commentsArray.filter(comment => comment.comment_id == id); + + const repliesArray = useSelector( + ({ + tutorialPage: { + comment: { replies } + } + }) => replies + ); + + const [replies] = repliesArray.filter(replies => replies.comment_id == id); + + console.log(repliesArray); + const handleIncrement = () => { setCount(count + 1); }; @@ -68,82 +98,81 @@ const Comment = () => { setAlignment(newAlignment); }; + const handleSubmit = comment => { + const commentData = { + content: comment, + replyTo: data.comment_id, + tutorial_id: data.tutorial_id, + createdAt: firestore.FieldValue.serverTimestamp(), + userId: "codelabzuser" + }; + addComment(commentData)(firebase, firestore, dispatch); + }; + return ( - <> - - - Amazing content keep it up 😃 - - - - - A - - - - Abhishek - - - 19th March,2023 - - - - - {!showReplyfield && ( - - )} - - - - {count} - - + + + {data?.content} + + + + + {!showReplyfield && ( + + )} + - - - - - - - - - - {showReplyfield && ( -
- -
- )} - + + + {count} + + + + + + + + + + + + {showReplyfield && ( +
+ + {replies?.replies.map((id, index) => { + return ; + })} +
+ )} + + ) ); }; diff --git a/src/components/TutorialPage/components/Commnets/CommentBox.jsx b/src/components/TutorialPage/components/Commnets/CommentBox.jsx index 71ad2300..61a7baa0 100644 --- a/src/components/TutorialPage/components/Commnets/CommentBox.jsx +++ b/src/components/TutorialPage/components/Commnets/CommentBox.jsx @@ -1,28 +1,11 @@ -import { - Card, - Grid, - Box, - Typography, - Avatar, - TextField, - Button, - IconButton, - InputAdornment, - Paper -} from "@mui/material"; -import EmojiPicker from "emoji-picker-react"; -import { InsertEmoticon, Send } from "@mui/icons-material"; -import AccountCircle from "@mui/icons-material/AccountCircle"; +import { Card, Grid, Typography, Button } from "@mui/material"; import { makeStyles } from "@mui/styles"; -import CardActions from "@mui/material/CardActions"; -import MoreVertOutlinedIcon from "@mui/icons-material/MoreVertOutlined"; -import ToggleButton from "@mui/lab/ToggleButton"; -import ToggleButtonGroup from "@mui/lab/ToggleButtonGroup"; -import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp"; -import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; import React, { useState } from "react"; import Textbox from "./Textbox"; import Comment from "./Comment"; +import { addComment } from "../../../../store/actions/tutorialPageActions"; +import { useDispatch, useSelector } from "react-redux"; +import { useFirebase, useFirestore } from "react-redux-firebase"; const useStyles = makeStyles(() => ({ container: { margin: "10px 0", @@ -45,26 +28,36 @@ const useStyles = makeStyles(() => ({ } })); -const CommentBox = () => { +const CommentBox = ({ comments, tutorialId }) => { const classes = useStyles(); + const firestore = useFirestore(); + const firebase = useFirebase(); + const dispatch = useDispatch(); + const handleSubmit = comment => { + const commentData = { + content: comment, + replyTo: tutorialId, + tutorial_id: tutorialId, + createdAt: firestore.FieldValue.serverTimestamp(), + userId: "codelabzuser" + }; + addComment(commentData)(firebase, firestore, dispatch); + }; + return ( - Comments(34) + Comments({comments?.length}) - + - - - - - - - - - - - + {comments?.map((id, index) => { + return ( + + + + ); + })} diff --git a/src/components/TutorialPage/components/PostDetails.jsx b/src/components/TutorialPage/components/PostDetails.jsx index 3563fcc4..bbceb822 100644 --- a/src/components/TutorialPage/components/PostDetails.jsx +++ b/src/components/TutorialPage/components/PostDetails.jsx @@ -12,6 +12,7 @@ import ToggleButton from "@mui/lab/ToggleButton"; import ToggleButtonGroup from "@mui/lab/ToggleButtonGroup"; import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp"; import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; +import User from "./UserDetails"; import { useDispatch, useSelector } from "react-redux"; import { useFirebase, useFirestore } from "react-redux-firebase"; import { getUserProfileData } from "../../../store/actions"; @@ -96,52 +97,11 @@ const PostDetails = ({ details }) => { - - - - {user?.photoURL && user?.photoURL.length > 0 ? ( - - ) : ( - user?.displayName[0] - )} - - - - - {user?.displayName} - - - {details?.published_on - ? getTime(details?.published_on) - : ""} - - - - + diff --git a/src/components/TutorialPage/components/Tutorial.jsx b/src/components/TutorialPage/components/Tutorial.jsx index 2b8c3c63..35571091 100644 --- a/src/components/TutorialPage/components/Tutorial.jsx +++ b/src/components/TutorialPage/components/Tutorial.jsx @@ -1,6 +1,7 @@ import React, { useEffect, useRef } from "react"; import { Card, Box, Grid, Typography } from "@mui/material"; import { makeStyles } from "@mui/styles"; +import HtmlTextRenderer from "../../Tutorials/subComps/HtmlTextRenderer"; const useStyles = makeStyles(() => ({ container: { @@ -20,10 +21,9 @@ const Tutorial = ({ steps }) => { {i + 1 + ". " + step.title} - + + + ); })} diff --git a/src/components/TutorialPage/components/UserDetails.jsx b/src/components/TutorialPage/components/UserDetails.jsx new file mode 100644 index 00000000..88be6a3a --- /dev/null +++ b/src/components/TutorialPage/components/UserDetails.jsx @@ -0,0 +1,101 @@ +import React, { useEffect, useState } from "react"; +import { Typography, Button, Grid } from "@mui/material"; +import { makeStyles } from "@mui/styles"; +import Avatar from "@mui/material/Avatar"; +import { useDispatch, useSelector } from "react-redux"; +import { useFirebase, useFirestore } from "react-redux-firebase"; +import { getUserProfileData } from "../../../store/actions"; +const useStyles = makeStyles(() => ({ + container: { + padding: "20px", + boxSizing: "border-box" + }, + small: { + padding: "2px" + }, + bold: { + fontWeight: "600" + } +})); +const User = ({ id, timestamp, showFollowButton, size }) => { + const classes = useStyles(); + const dispatch = useDispatch(); + const firebase = useFirebase(); + const firestore = useFirestore(); + useEffect(() => { + getUserProfileData(id)(firebase, firestore, dispatch); + }, [id]); + + const user = useSelector( + ({ + profile: { + user: { data } + } + }) => data + ); + + const getTime = timestamp => { + return timestamp.toDate().toDateString(); + }; + return ( + <> + + + + {user?.photoURL && user?.photoURL.length > 0 ? ( + + ) : ( + user?.displayName[0] + )} + + + + + {user?.displayName} + + + {timestamp ? getTime(timestamp) : ""} + + {showFollowButton && ( + + )} + + + + ); +}; + +export default User; diff --git a/src/components/TutorialPage/index.jsx b/src/components/TutorialPage/index.jsx index f1d16f14..0bc59be3 100644 --- a/src/components/TutorialPage/index.jsx +++ b/src/components/TutorialPage/index.jsx @@ -9,7 +9,10 @@ import Grid from "@mui/material/Grid"; import useStyles from "./styles"; import StepsBar from "./StepBar"; import useWindowSize from "../../helpers/customHooks/useWindowSize"; -import { getTutorialData } from "../../store/actions/tutorialPageActions"; +import { + getTutorialData, + getTutorialSteps +} from "../../store/actions/tutorialPageActions"; import { getUserProfileData } from "../../store/actions"; import { useDispatch, useSelector } from "react-redux"; import { useFirebase, useFirestore } from "react-redux-firebase"; @@ -28,6 +31,7 @@ function TutorialPage({ background = "white", textColor = "black" }) { const firestore = useFirestore(); useEffect(() => { getTutorialData(id)(firebase, firestore, dispatch); + getTutorialSteps(id)(firebase, firestore, dispatch); }, []); const tutorial = useSelector( ({ @@ -38,15 +42,23 @@ function TutorialPage({ background = "white", textColor = "black" }) { ); const postDetails = { - title: tutorial?.tut_title, - org: tutorial?.org_handle, - user: tutorial?.user_handle, + title: tutorial?.title, + org: tutorial?.owner, + user: tutorial?.created_by, upVote: tutorial?.upVotes, downVote: tutorial?.downVotes, - published_on: tutorial?.published_on, + published_on: tutorial?.createdAt, tag: tutorial?.tut_tags }; + const steps = useSelector( + ({ + tutorialPage: { + post: { steps } + } + }) => steps + ); + return ( @@ -86,8 +98,11 @@ function TutorialPage({ background = "white", textColor = "black" }) { xs={6} > - - + + diff --git a/src/store/actions/actionTypes.js b/src/store/actions/actionTypes.js index 990aee45..e8f3e990 100644 --- a/src/store/actions/actionTypes.js +++ b/src/store/actions/actionTypes.js @@ -135,3 +135,19 @@ export const GET_LAUNCHED_ORGS_FAIL = "GET_LAUNCHED_ORGS_FAIL"; export const GET_POST_DATA_START = "GET_POST_DETAILS_START"; export const GET_POST_DATA_SUCCESS = "GET_POST_DETAILS_SUCCESS"; export const GET_POST_DATA_FAIL = "GET_POST_DETAILS_FAILED"; + +export const GET_COMMENT_DATA_START = "GET_COMMENT_DATA_START"; +export const GET_COMMENT_DATA_SUCCESS = "GET_COMMENT_DATA_SUCCESS"; +export const GET_COMMENT_DATA_FAIL = "GET_COMMENT_DATA_FAIL"; + +export const GET_REPLIES_START = "GET_REPLIES_START"; +export const GET_REPLIES_SUCCESS = "GET_REPLIES_SUCCESS"; +export const GET_REPLIES_FAIL = "GET_REPLIES_FAIL"; + +export const ADD_COMMENT_START = "ADD_COMMENT_START"; +export const ADD_COMMENT_SUCCESS = "ADD_COMMENT_SUCCESS"; +export const ADD_COMMENT_FAILED = "ADD_COMMENT_FAILED"; + +export const GET_STEPS_DATA_START = "GET_STEPS_DETAILS_START"; +export const GET_STEPS_DATA_SUCCESS = "GET_STEPS_DETAILS_SUCCESS"; +export const GET_STEPS_DATA_FAIL = "GET_STEPS_DETAILS_FAILED"; diff --git a/src/store/actions/profileActions.js b/src/store/actions/profileActions.js index 88ed3682..54866a15 100644 --- a/src/store/actions/profileActions.js +++ b/src/store/actions/profileActions.js @@ -3,34 +3,33 @@ import { checkOrgHandleExists, checkUserHandleExists } from "./authActions"; import { getOrgBasicData } from "./orgActions"; import _ from "lodash"; -export const clearProfileEditError = () => async (dispatch) => { +export const clearProfileEditError = () => async dispatch => { dispatch({ type: actions.CLEAR_PROFILE_EDIT_STATE }); }; -export const setCurrentOrgUserPermissions = (org_handle, permissions) => ( - dispatch -) => { - try { - dispatch({ - type: actions.SET_CURRENT_ORG_PERMISSIONS_START, - }); - dispatch({ - type: actions.SET_CURRENT_ORG_PERMISSIONS_SUCCESS, - payload: { org_handle, permissions }, - }); - } catch (e) { - dispatch({ - type: actions.SET_CURRENT_ORG_PERMISSIONS_FAIL, - }); - } -}; +export const setCurrentOrgUserPermissions = + (org_handle, permissions) => dispatch => { + try { + dispatch({ + type: actions.SET_CURRENT_ORG_PERMISSIONS_START + }); + dispatch({ + type: actions.SET_CURRENT_ORG_PERMISSIONS_SUCCESS, + payload: { org_handle, permissions } + }); + } catch (e) { + dispatch({ + type: actions.SET_CURRENT_ORG_PERMISSIONS_FAIL + }); + } + }; -export const getProfileData = (organizations) => async (firebase, dispatch) => { +export const getProfileData = organizations => async (firebase, dispatch) => { try { let orgs = []; if (organizations && organizations.length > 0) { dispatch({ type: actions.GET_PROFILE_DATA_START }); - const promises = organizations.map((org_handle) => + const promises = organizations.map(org_handle => getOrgBasicData(org_handle)(firebase) ); orgs = await Promise.all(promises); @@ -40,7 +39,7 @@ export const getProfileData = (organizations) => async (firebase, dispatch) => { )(dispatch); dispatch({ type: actions.GET_PROFILE_DATA_SUCCESS, - payload: { organizations: _.orderBy(orgs, ["org_handle"], ["asc"]) }, + payload: { organizations: _.orderBy(orgs, ["org_handle"], ["asc"]) } }); } else { dispatch({ type: actions.GET_PROFILE_DATA_END }); @@ -50,131 +49,124 @@ export const getProfileData = (organizations) => async (firebase, dispatch) => { } }; -export const createOrganization = (orgData) => async ( - firebase, - firestore, - dispatch -) => { - try { - dispatch({ type: actions.PROFILE_EDIT_START }); - const userData = firebase.auth().currentUser; - const { org_name, org_handle, org_country, org_website } = orgData; - const isOrgHandleExists = await checkOrgHandleExists(org_handle)(firebase); - - if (isOrgHandleExists) { - dispatch({ - type: actions.PROFILE_EDIT_FAIL, - payload: { message: `Handle [${org_handle}] is already taken` }, - }); - return; - } +export const createOrganization = + orgData => async (firebase, firestore, dispatch) => { + try { + dispatch({ type: actions.PROFILE_EDIT_START }); + const userData = firebase.auth().currentUser; + const { org_name, org_handle, org_country, org_website } = orgData; + const isOrgHandleExists = await checkOrgHandleExists(org_handle)( + firebase + ); - await firestore.set( - { collection: "cl_org_general", doc: org_handle }, - { - org_name, - org_handle, - org_website, - org_country, - org_email: userData.email, - org_created_date: firestore.FieldValue.serverTimestamp(), - createdAt: firestore.FieldValue.serverTimestamp(), - updatedAt: firestore.FieldValue.serverTimestamp(), + if (isOrgHandleExists) { + dispatch({ + type: actions.PROFILE_EDIT_FAIL, + payload: { message: `Handle [${org_handle}] is already taken` } + }); + return; } - ); - const timeOutID = setTimeout(() => { - firestore - .collection("cl_user") - .doc(userData.uid) - .update({ organizations: firestore.FieldValue.arrayUnion(org_handle) }) - .then(() => { - clearTimeout(timeOutID); - dispatch({ type: actions.PROFILE_EDIT_SUCCESS }); - window.location.reload(); - }); - }, 7000); - } catch (e) { - dispatch({ type: actions.PROFILE_EDIT_FAIL, payload: e.message }); - } -}; + await firestore.set( + { collection: "cl_org_general", doc: org_handle }, + { + org_name, + org_handle, + org_website, + org_country, + org_email: userData.email, + org_created_date: firestore.FieldValue.serverTimestamp(), + createdAt: firestore.FieldValue.serverTimestamp(), + updatedAt: firestore.FieldValue.serverTimestamp() + } + ); -export const updateUserProfile = ({ - displayName, - website, - link_facebook, - link_github, - link_linkedin, - link_twitter, - description, - country, -}) => async (firebase, firestore, dispatch) => { - try { - dispatch({ type: actions.PROFILE_EDIT_START }); - await firebase.updateProfile( - { - displayName, - website, - link_facebook, - link_github, - link_linkedin, - link_twitter, - description, - country, - updatedAt: firestore.FieldValue.serverTimestamp(), - }, - { useSet: false, merge: true } - ); - dispatch({ type: actions.PROFILE_EDIT_SUCCESS }); - dispatch({ type: actions.CLEAR_PROFILE_EDIT_STATE }); - } catch (e) { - dispatch({ type: actions.PROFILE_EDIT_FAIL, payload: e.message }); - } -}; + const timeOutID = setTimeout(() => { + firestore + .collection("cl_user") + .doc(userData.uid) + .update({ + organizations: firestore.FieldValue.arrayUnion(org_handle) + }) + .then(() => { + clearTimeout(timeOutID); + dispatch({ type: actions.PROFILE_EDIT_SUCCESS }); + window.location.reload(); + }); + }, 7000); + } catch (e) { + dispatch({ type: actions.PROFILE_EDIT_FAIL, payload: e.message }); + } + }; -export const uploadProfileImage = (file, user_handle) => async ( - firebase, - dispatch -) => { - try { - const userData = firebase.auth().currentUser; - const storagePath = `user/${user_handle}/images`; - const dbPath = "cl_user"; - await firebase.uploadFile(storagePath, file, dbPath, { - metadataFactory: (uploadRes, firebase, metadata, downloadURL) => { - return { photoURL: downloadURL }; - }, - documentId: userData.uid, - }); - } catch (e) { - dispatch({ type: actions.PROFILE_EDIT_FAIL, payload: e.message }); - } -}; +export const updateUserProfile = + ({ + displayName, + website, + link_facebook, + link_github, + link_linkedin, + link_twitter, + description, + country + }) => + async (firebase, firestore, dispatch) => { + try { + dispatch({ type: actions.PROFILE_EDIT_START }); + await firebase.updateProfile( + { + displayName, + website, + link_facebook, + link_github, + link_linkedin, + link_twitter, + description, + country, + updatedAt: firestore.FieldValue.serverTimestamp() + }, + { useSet: false, merge: true } + ); + dispatch({ type: actions.PROFILE_EDIT_SUCCESS }); + dispatch({ type: actions.CLEAR_PROFILE_EDIT_STATE }); + } catch (e) { + dispatch({ type: actions.PROFILE_EDIT_FAIL, payload: e.message }); + } + }; -export const getUserProfileData = (handle) => async ( - firebase, - firestore, - dispatch -) => { - try { - dispatch({ type: actions.GET_USER_DATA_START }); - const isUserExists = await checkUserHandleExists(handle)(firebase); - if (isUserExists) { +export const uploadProfileImage = + (file, user_handle) => async (firebase, dispatch) => { + try { + const userData = firebase.auth().currentUser; + const storagePath = `user/${user_handle}/images`; + const dbPath = "cl_user"; + await firebase.uploadFile(storagePath, file, dbPath, { + metadataFactory: (uploadRes, firebase, metadata, downloadURL) => { + return { photoURL: downloadURL }; + }, + documentId: userData.uid + }); + } catch (e) { + dispatch({ type: actions.PROFILE_EDIT_FAIL, payload: e.message }); + } + }; + +export const getUserProfileData = + handle => async (firebase, firestore, dispatch) => { + try { + dispatch({ type: actions.GET_USER_DATA_START }); const docs = await firestore .collection("cl_user") .where("handle", "==", handle) .get(); const doc = docs.docs[0].data(); dispatch({ type: actions.GET_USER_DATA_SUCCESS, payload: doc }); - } else { - dispatch({ type: actions.GET_USER_DATA_SUCCESS, payload: false }); + } catch (e) { + dispatch({ type: actions.GET_USER_DATA_FAIL, payload: e.message }); } - } catch (e) { - dispatch({ type: actions.GET_USER_DATA_FAIL, payload: e.message }); - } -}; + }; -export const clearUserProfile = () => (dispatch) => { +export const clearUserProfile = () => dispatch => { dispatch({ type: actions.CLEAR_USER_PROFILE_DATA_STATE }); }; @@ -192,27 +184,27 @@ export const addUserFollower = ( const arr = [...followers]; arr.push(currentProfileData.handle); firestore.collection("cl_user").doc(profileData.uid).update({ - followers: arr, + followers: arr }); var arr2 = []; if (following) arr2 = [...following]; arr2.push(profileData.handle); firestore.collection("cl_user").doc(currentProfileData.uid).update({ - following: arr2, + following: arr2 }); } else { firestore .collection("cl_user") .doc(currentProfileData.uid) .update({ - following: [profileData.handle], + following: [profileData.handle] }); firestore .collection("cl_user") .doc(profileData.uid) .update({ - followers: [currentProfileData.handle], + followers: [currentProfileData.handle] }); } } catch (e) { @@ -233,13 +225,13 @@ export const removeUserFollower = ( return value !== currentProfileData.handle; }); firestore.collection("cl_user").doc(profileData.uid).update({ - followers: filteredFollowers, + followers: filteredFollowers }); var currFollowing = following.filter(function (value, index, arr) { return profileData.handle !== value; }); firestore.collection("cl_user").doc(currentProfileData.uid).update({ - following: currFollowing, + following: currFollowing }); } catch (e) {} }; diff --git a/src/store/actions/tutorialPageActions.js b/src/store/actions/tutorialPageActions.js index 986806c3..8940e939 100644 --- a/src/store/actions/tutorialPageActions.js +++ b/src/store/actions/tutorialPageActions.js @@ -1,15 +1,101 @@ import * as actions from "./actionTypes"; + export const getTutorialData = tutorialID => async (firebase, firestore, dispatch) => { try { dispatch({ type: actions.GET_POST_DATA_START }); const data = await firestore - .collection("cl_tutorials") + .collection("tutorials") .doc(tutorialID) .get(); const tutorial = data.data(); dispatch({ type: actions.GET_POST_DATA_SUCCESS, payload: tutorial }); } catch (e) { + dispatch({ type: actions.GET_POST_DATA_FAIL }); console.log(e); } }; + +export const getTutorialSteps = + tutorialID => async (firebase, firestore, dispatch) => { + try { + dispatch({ type: actions.GET_STEPS_DATA_START }); + const data = await firestore + .collection("tutorials") + .doc(tutorialID) + .collection("steps") + .get() + .then(querySnapshot => { + let steps = []; + querySnapshot.forEach(doc => { + steps.push(doc.data()); + }); + return steps; + }); + dispatch({ type: actions.GET_STEPS_DATA_SUCCESS, payload: data }); + } catch (e) { + dispatch({ type: actions.GET_STEPS_DATA_FAIL, payload: e }); + console.log(e); + } + }; + +export const getCommentData = + commentId => async (firebase, firestore, dispatch) => { + try { + dispatch({ type: actions.GET_COMMENT_DATA_START }); + const data = await firestore + .collection("cl_comments") + .doc(commentId) + .get(); + const comment = data.data(); + dispatch({ type: actions.GET_COMMENT_DATA_SUCCESS, payload: comment }); + } catch (e) { + dispatch({ type: actions.GET_COMMENT_DATA_FAIL }); + console.log(e); + } + }; + +export const getCommentReply = + commentId => async (firebase, firestore, dispatch) => { + try { + console.log("commentId", commentId); + dispatch({ type: actions.GET_REPLIES_START }); + console.log("Get replies"); + const replies = await firestore + .collection("cl_comments") + .where("replyTo", "==", commentId) + .get() + .then(querySnapshot => { + let data = []; + querySnapshot.forEach(doc => { + data.push(doc.data().comment_id); + }); + return data; + }); + dispatch({ + type: actions.GET_REPLIES_SUCCESS, + payload: { replies, comment_id: commentId } + }); + } catch (e) { + console.log(e); + } + }; + +export const addComment = comment => async (firebase, firestore, dispatch) => { + try { + dispatch({ type: actions.ADD_COMMENT_START }); + await firestore + .collection("cl_comments") + .add(comment) + .then(docref => { + firestore.collection("cl_comments").doc(docref.id).update({ + comment_id: docref.id + }); + }) + .then(() => { + dispatch({ type: actions.ADD_COMMENT_SUCCESS }); + }); + } catch (e) { + dispatch({ type: actions.ADD_COMMENT_FAILED, payload: e.message }); + } +}; diff --git a/src/store/reducers/tutorialPageReducers/commentReducer.js b/src/store/reducers/tutorialPageReducers/commentReducer.js new file mode 100644 index 00000000..7d1780ac --- /dev/null +++ b/src/store/reducers/tutorialPageReducers/commentReducer.js @@ -0,0 +1,70 @@ +import * as actions from "../../actions/actionTypes"; + +const initialState = { + loading: false, + error: null, + data: [], + replies: [] +}; + +const CommentReducer = (state = initialState, { type, payload }) => { + switch (type) { + case actions.GET_COMMENT_DATA_START: + return { + ...state, + loading: true + }; + + case actions.GET_COMMENT_DATA_SUCCESS: + return { + ...state, + loading: false, + error: false, + data: [...state.data, payload] + }; + + case actions.GET_COMMENT_DATA_FAIL: + return { + ...state, + loading: false, + error: payload + }; + + case actions.GET_REPLIES_START: + return { + ...state, + loading: true + }; + + case actions.GET_REPLIES_SUCCESS: + return { + ...state, + loading: false, + replies: [...state.replies, payload] + }; + + case actions.ADD_COMMENT_START: + return { + ...state, + loading: true + }; + + case actions.ADD_COMMENT_SUCCESS: + return { + ...state, + loading: false + }; + + case actions.ADD_COMMENT_FAILED: + return { + ...state, + loading: false, + error: payload + }; + + default: + return state; + } +}; + +export default CommentReducer; diff --git a/src/store/reducers/tutorialPageReducers/index.js b/src/store/reducers/tutorialPageReducers/index.js index 1c7a7aed..9199a3a9 100644 --- a/src/store/reducers/tutorialPageReducers/index.js +++ b/src/store/reducers/tutorialPageReducers/index.js @@ -1,6 +1,8 @@ import { combineReducers } from "redux"; import PostReducer from "./postReducer"; +import CommentReducer from "./commentReducer"; export default combineReducers({ - post: PostReducer + post: PostReducer, + comment: CommentReducer }); diff --git a/src/store/reducers/tutorialPageReducers/postReducer.js b/src/store/reducers/tutorialPageReducers/postReducer.js index c8e85d0c..ea297570 100644 --- a/src/store/reducers/tutorialPageReducers/postReducer.js +++ b/src/store/reducers/tutorialPageReducers/postReducer.js @@ -3,7 +3,8 @@ import * as actions from "../../actions/actionTypes"; const initialState = { loading: false, error: null, - data: null + data: null, + steps: [] }; const PostReducer = (state = initialState, { type, payload }) => { @@ -32,6 +33,27 @@ const PostReducer = (state = initialState, { type, payload }) => { error: payload }; + case actions.GET_STEPS_DATA_START: + return { + ...state, + loading: true + }; + + case actions.GET_STEPS_DATA_SUCCESS: + return { + ...state, + loading: false, + error: false, + steps: payload + }; + + case actions.GET_STEPS_DATA_FAIL: + return { + ...state, + loading: false, + error: payload + }; + default: return state; }