From d6b4d415ced692b602c87689999e63c588957a4c Mon Sep 17 00:00:00 2001 From: rohitPandey469 Date: Sun, 18 Feb 2024 22:28:52 +0530 Subject: [PATCH] Select and Display Tags Options --- src/components/Card/CardWithPicture.jsx | 18 +- src/components/Card/CardWithoutPicture.jsx | 18 +- .../Tutorials/NewTutorial/index.jsx | 36 +- .../Tutorials/subComps/EditControls.jsx | 20 ++ .../Tutorials/subComps/TagSelectorModal.jsx | 100 ++++++ src/store/actions/tutorialPageActions.js | 1 + src/store/actions/tutorialsActions.js | 334 ++++++++++-------- 7 files changed, 362 insertions(+), 165 deletions(-) create mode 100644 src/components/Tutorials/subComps/TagSelectorModal.jsx diff --git a/src/components/Card/CardWithPicture.jsx b/src/components/Card/CardWithPicture.jsx index e8cd65c2..a477288a 100644 --- a/src/components/Card/CardWithPicture.jsx +++ b/src/components/Card/CardWithPicture.jsx @@ -172,14 +172,16 @@ export default function CardWithPicture({ tutorial }) { - + {tutorial?.tags.map(tag => ( + + ))} - + {tutorial?.tags.map(tag => ( + + ))} ({ root: { @@ -32,6 +33,9 @@ const useStyles = makeStyles(theme => ({ purple: { color: deepPurple[700], backgroundColor: deepPurple[500] + }, + chip: { + marginRight: "5px" } })); @@ -46,7 +50,8 @@ const NewTutorial = ({ viewModal, onSidebarClick, viewCallback, active }) => { const [formValue, setformValue] = useState({ title: "", summary: "", - owner: "" + owner: "", + tags: [] }); const loadingProp = useSelector( @@ -145,6 +150,23 @@ const NewTutorial = ({ viewModal, onSidebarClick, viewCallback, active }) => { })); }; + const tagOptions = ["HTML", "Css", "JavaScript", "React", "Python", "Java"]; + + const handleTagClick = tag => { + const isSelected = formValue.tags.includes(tag); + if (isSelected) { + setformValue(prev => ({ + ...prev, + tags: prev.tags.filter(t => t !== tag) + })); + } else { + setformValue(prev => ({ + ...prev, + tags: [...prev.tags, tag] + })); + } + }; + const classes = useStyles(); return ( { onChange={e => handleChange(e)} style={{ marginBottom: "2rem" }} /> +
+ {tagOptions.map(tag => ( + handleTagClick(tag)} + color={formValue.tags.includes(tag) ? "primary" : undefined} + className={classes.chip} + /> + ))} +
diff --git a/src/components/Tutorials/subComps/EditControls.jsx b/src/components/Tutorials/subComps/EditControls.jsx index f3e9083c..8d1d0b0d 100644 --- a/src/components/Tutorials/subComps/EditControls.jsx +++ b/src/components/Tutorials/subComps/EditControls.jsx @@ -22,6 +22,7 @@ import { useDispatch } from "react-redux"; import RemoveStepModal from "./RemoveStepModal"; import ColorPickerModal from "./ColorPickerModal"; import { Box, Stack } from "@mui/system"; +import TagSelectorModal from "./TagSelectorModal"; const EditControls = ({ isPublished, @@ -43,6 +44,7 @@ const EditControls = ({ const dispatch = useDispatch(); const [viewRemoveStepModal, setViewRemoveStepModal] = useState(false); const [viewColorPickerModal, setViewColorPickerModal] = useState(false); + const [viewTagSelectorModal, setViewTagSelectorModal] = useState(false); const [publishLoad, setPublishLoad] = useState(false); const DropdownMenu = () => { const [anchorEl, setAnchorEl] = React.useState(null); @@ -160,6 +162,18 @@ const EditControls = ({ step_length={step_length} /> + + setViewTagSelectorModal(e)} + tutorial_id={tutorial_id} + owner={owner} + /> ); }; diff --git a/src/components/Tutorials/subComps/TagSelectorModal.jsx b/src/components/Tutorials/subComps/TagSelectorModal.jsx new file mode 100644 index 00000000..0d322447 --- /dev/null +++ b/src/components/Tutorials/subComps/TagSelectorModal.jsx @@ -0,0 +1,100 @@ +import React, { useState, useEffect } from "react"; +import Modal from "@mui/material/Modal"; +import Box from "@mui/material/Box"; +import Typography from "@mui/material/Typography"; +import TextField from "@mui/material/TextField"; +import Button from "@mui/material/Button"; +import { + fetchTutorialTags, + updateTutorialTags +} from "../../../store/actions/tutorialsActions"; +import { useFirebase, useFirestore } from "react-redux-firebase"; +import { useDispatch } from "react-redux"; +import Chip from "@mui/material/Chip" + +const TagSelectorModal = ({ visible, visibleCallback, tutorial_id, owner }) => { + const firebase = useFirebase(); + const firestore = useFirestore(); + const dispatch = useDispatch(); + const [selectedTags, setSelectedTags] = useState([]); + + const tagOptions = ["HTML", "Css", "JavaScript", "React", "Python", "Java"]; + + useEffect(() => { + const fetchTags = async () => { + try { + const tags = await fetchTutorialTags(tutorial_id)(firebase, firestore, dispatch); + setSelectedTags(tags); + } catch (error) { + console.error("Error fetching tags:", error); + } + }; + if (visible) { + fetchTags(); + } + }, [visible, tutorial_id, firebase, firestore, dispatch]); + + const handleTagSelection = (tag) => { + setSelectedTags((prevTags) => { + if (prevTags.includes(tag)) { + return prevTags.filter((selectedTag) => selectedTag !== tag); + } else { + return [...prevTags, tag]; + } + }); + }; + + const handleSaveTags = async () => { + try { + await updateTutorialTags(tutorial_id, selectedTags)(firebase, firestore, dispatch); + visibleCallback(false); + } catch (error) { + console.error("Error updating tags:", error); + } + }; + + return ( + visibleCallback(false)} + aria-labelledby="modal-modal-title" + aria-describedby="modal-modal-description" + > + + + Select Tags + + + {tagOptions.map(tag => ( + handleTagSelection(tag)} + color={selectedTags.includes(tag) ? "primary" : undefined} + sx={{ mr: 1, mb: 1 }} + /> + ))} + + + + + + + ); +}; + +export default TagSelectorModal; diff --git a/src/store/actions/tutorialPageActions.js b/src/store/actions/tutorialPageActions.js index c716765a..b9e3b8b2 100644 --- a/src/store/actions/tutorialPageActions.js +++ b/src/store/actions/tutorialPageActions.js @@ -98,6 +98,7 @@ export const getTutorialFeedData = title: tutorial?.title, summary: tutorial?.summary, owner: tutorial?.owner, + tags:tutorial?.tags, created_by: tutorial?.created_by, createdAt: tutorial?.createdAt, featured_image: tutorial?.featured_image diff --git a/src/store/actions/tutorialsActions.js b/src/store/actions/tutorialsActions.js index 7d273c1d..96689e05 100644 --- a/src/store/actions/tutorialsActions.js +++ b/src/store/actions/tutorialsActions.js @@ -122,7 +122,7 @@ export const createTutorial = tutorialData => async (firebase, firestore, dispatch, history) => { try { dispatch({ type: actions.CREATE_TUTORIAL_START }); - const { title, summary, owner, created_by, is_org } = tutorialData; + const { title, summary, owner, created_by, is_org, tags } = tutorialData; const setData = async () => { const document = firestore.collection("tutorials").doc(); @@ -135,6 +135,7 @@ export const createTutorial = editors: [created_by], isPublished: false, owner, + tags, summary, title, tutorial_id: documentID, @@ -230,36 +231,36 @@ export const getCurrentTutorialData = export const addNewTutorialStep = ({ owner, tutorial_id, title, time, id }) => - async (firebase, firestore, dispatch) => { - try { - dispatch({ type: actions.CREATE_TUTORIAL_STEP_START }); + async (firebase, firestore, dispatch) => { + try { + dispatch({ type: actions.CREATE_TUTORIAL_STEP_START }); - await firestore - .collection("tutorials") - .doc(tutorial_id) - .collection("steps") - .doc(id) - .set({ - content: `Switch to editor mode to begin ${title} step`, - id, - time, - title, - visibility: true, - deleted: false - }); + await firestore + .collection("tutorials") + .doc(tutorial_id) + .collection("steps") + .doc(id) + .set({ + content: `Switch to editor mode to begin ${title} step`, + id, + time, + title, + visibility: true, + deleted: false + }); - await getCurrentTutorialData(owner, tutorial_id)( - firebase, - firestore, - dispatch - ); + await getCurrentTutorialData(owner, tutorial_id)( + firebase, + firestore, + dispatch + ); - dispatch({ type: actions.CREATE_TUTORIAL_STEP_SUCCESS }); - } catch (e) { - console.log("CREATE_TUTORIAL_STEP_FAIL", e.message); - dispatch({ type: actions.CREATE_TUTORIAL_STEP_FAIL, payload: e.message }); - } - }; + dispatch({ type: actions.CREATE_TUTORIAL_STEP_SUCCESS }); + } catch (e) { + console.log("CREATE_TUTORIAL_STEP_FAIL", e.message); + dispatch({ type: actions.CREATE_TUTORIAL_STEP_FAIL, payload: e.message }); + } + }; export const clearCreateTutorials = () => dispatch => dispatch({ type: actions.CLEAR_CREATE_TUTORIALS_STATE }); @@ -305,78 +306,78 @@ export const setCurrentStepContent = export const hideUnHideStep = (owner, tutorial_id, step_id, visibility) => - async (firebase, firestore, dispatch) => { - try { - /* not being used */ - // const type = await checkUserOrOrgHandle(owner)(firebase); - await firestore - .collection("tutorials") - .doc(tutorial_id) - .collection("steps") - .doc(step_id) - .update({ - [`visibility`]: !visibility, - updatedAt: firestore.FieldValue.serverTimestamp() - }); + async (firebase, firestore, dispatch) => { + try { + /* not being used */ + // const type = await checkUserOrOrgHandle(owner)(firebase); + await firestore + .collection("tutorials") + .doc(tutorial_id) + .collection("steps") + .doc(step_id) + .update({ + [`visibility`]: !visibility, + updatedAt: firestore.FieldValue.serverTimestamp() + }); - await getCurrentTutorialData(owner, tutorial_id)( - firebase, - firestore, - dispatch - ); - } catch (e) { - console.log(e.message); - } - }; + await getCurrentTutorialData(owner, tutorial_id)( + firebase, + firestore, + dispatch + ); + } catch (e) { + console.log(e.message); + } + }; export const publishUnpublishTutorial = (owner, tutorial_id, isPublished) => - async (firebase, firestore, dispatch) => { - try { - await firestore - .collection("tutorials") - .doc(tutorial_id) - .update({ - ["isPublished"]: !isPublished - }); + async (firebase, firestore, dispatch) => { + try { + await firestore + .collection("tutorials") + .doc(tutorial_id) + .update({ + ["isPublished"]: !isPublished + }); - getCurrentTutorialData(owner, tutorial_id)(firebase, firestore, dispatch); - } catch (e) { - console.log(e.message); - } - }; + getCurrentTutorialData(owner, tutorial_id)(firebase, firestore, dispatch); + } catch (e) { + console.log(e.message); + } + }; export const removeStep = (owner, tutorial_id, step_id, current_step_no) => - async (firebase, firestore, dispatch) => { - try { - await firestore - .collection("tutorials") - .doc(tutorial_id) - .collection("steps") - .doc(step_id) - .delete() - - // const data = await firestore - // .collection("tutorials") - // .doc(tutorial_id) - // .collection("steps") - // .doc(step_id) - // .get(); - - await setCurrentStepNo( - current_step_no > 0 ? current_step_no - 1 : current_step_no - )(dispatch); - - await getCurrentTutorialData(owner, tutorial_id)( - firebase, - firestore, - dispatch - ); - } catch (e) { - console.log(e.message); - } - }; + async (firebase, firestore, dispatch) => { + try { + await firestore + .collection("tutorials") + .doc(tutorial_id) + .collection("steps") + .doc(step_id) + .delete(); + + // const data = await firestore + // .collection("tutorials") + // .doc(tutorial_id) + // .collection("steps") + // .doc(step_id) + // .get(); + + await setCurrentStepNo( + current_step_no > 0 ? current_step_no - 1 : current_step_no + )(dispatch); + + await getCurrentTutorialData(owner, tutorial_id)( + firebase, + firestore, + dispatch + ); + } catch (e) { + console.log(e.message); + } + }; export const setCurrentStep = data => async dispatch => dispatch({ type: actions.SET_EDITOR_DATA, payload: data }); @@ -465,69 +466,106 @@ export const remoteTutorialImages = export const updateStepTitle = (owner, tutorial_id, step_id, step_title) => - async (firebase, firestore, dispatch) => { - try { - const dbPath = `tutorials/${tutorial_id}/steps`; - await firestore - .collection(dbPath) - .doc(step_id) - .update({ - [`title`]: step_title, - updatedAt: firestore.FieldValue.serverTimestamp() - }); + async (firebase, firestore, dispatch) => { + try { + const dbPath = `tutorials/${tutorial_id}/steps`; + await firestore + .collection(dbPath) + .doc(step_id) + .update({ + [`title`]: step_title, + updatedAt: firestore.FieldValue.serverTimestamp() + }); - await getCurrentTutorialData(owner, tutorial_id)( - firebase, - firestore, - dispatch - ); - } catch (e) { - console.log(e); - } - }; + await getCurrentTutorialData(owner, tutorial_id)( + firebase, + firestore, + dispatch + ); + } catch (e) { + console.log(e); + } + }; export const updateStepTime = (owner, tutorial_id, step_id, step_time) => - async (firebase, firestore, dispatch) => { - try { - const dbPath = `tutorials/${tutorial_id}/steps`; - - await firestore - .collection(dbPath) - .doc(step_id) - .update({ - [`time`]: step_time, - updatedAt: firestore.FieldValue.serverTimestamp() - }); + async (firebase, firestore, dispatch) => { + try { + const dbPath = `tutorials/${tutorial_id}/steps`; - await getCurrentTutorialData(owner, tutorial_id)( - firebase, - firestore, - dispatch - ); - } catch (e) { - console.log(e.message); - } - }; + await firestore + .collection(dbPath) + .doc(step_id) + .update({ + [`time`]: step_time, + updatedAt: firestore.FieldValue.serverTimestamp() + }); + + await getCurrentTutorialData(owner, tutorial_id)( + firebase, + firestore, + dispatch + ); + } catch (e) { + console.log(e.message); + } + }; export const setTutorialTheme = ({ tutorial_id, owner, bgColor, textColor }) => - async (firebase, firestore, dispatch) => { - try { - const dbPath = `tutorials`; + async (firebase, firestore, dispatch) => { + try { + const dbPath = `tutorials`; - await firestore.collection(dbPath).doc(tutorial_id).update({ - text_color: textColor, - background_color: bgColor, - updatedAt: firestore.FieldValue.serverTimestamp() - }); + await firestore.collection(dbPath).doc(tutorial_id).update({ + text_color: textColor, + background_color: bgColor, + updatedAt: firestore.FieldValue.serverTimestamp() + }); - await getCurrentTutorialData(owner, tutorial_id)( - firebase, - firestore, - dispatch - ); - } catch (e) { - console.log(e.message); - } - }; + await getCurrentTutorialData(owner, tutorial_id)( + firebase, + firestore, + dispatch + ); + } catch (e) { + console.log(e.message); + } + }; + +export const fetchTutorialTags = + tutorialId => async (firebase, firestore, dispatch) => { + try { + const tutorialDoc = await firestore + .collection("tutorials") + .doc(tutorialId) + .get(); + const tags = tutorialDoc.data().tags || []; + return tags; + } catch (error) { + console.log(error); + return []; + } + }; + +export const updateTutorialTags = + (tutorialId, newTags) => async (firebase, firestore, dispatch) => { + try { + // dispatch({ type: actions.UPDATE_TUTORIAL_TAGS_START }); + await firestore.collection("tutorials").doc(tutorialId).update({ + tags: newTags, + updatedAt: firestore.FieldValue.serverTimestamp() + }); + + // dispatch({ + // type: actions.UPDATE_TUTORIAL_TAGS_SUCCESS, + // payload: { tutorialId, newTags } + // }); + } catch (error) { + // dispatch({ + // type: actions.UPDATE_TUTORIAL_TAGS_FAIL, + // payload: error.message + // }); + console.log(error); + } + };