diff --git a/index.html b/index.html index 275b444d..5d34024f 100644 --- a/index.html +++ b/index.html @@ -2,11 +2,9 @@ - Codelabz -
diff --git a/less.config.js b/less.config.js index 5b997099..2faad74d 100644 --- a/less.config.js +++ b/less.config.js @@ -1,4 +1,4 @@ -const lessOptions = { +export const lessOptions = { lessOptions: { javascriptEnabled: true, modifyVars: { @@ -10,7 +10,3 @@ const lessOptions = { } } }; - -module.exports = { - lessOptions -}; diff --git a/src/components/AuthPage/smButton/smButtons.jsx b/src/components/AuthPage/smButton/smButtons.jsx index 226c31f4..2f904102 100644 --- a/src/components/AuthPage/smButton/smButtons.jsx +++ b/src/components/AuthPage/smButton/smButtons.jsx @@ -26,11 +26,11 @@ const SmButtons = () => { }} > - - signInWithGoogle()(firebase, dispatch)} - className={classes.google} - > + signInWithGoogle()(firebase, dispatch)} + > + google diff --git a/src/components/CardTabs/Events/index.jsx b/src/components/CardTabs/Events/index.jsx index 2605b29b..c3042e55 100644 --- a/src/components/CardTabs/Events/index.jsx +++ b/src/components/CardTabs/Events/index.jsx @@ -37,14 +37,14 @@ const EventsCard = props => {
- + {props.title} {props.events.map(function (event, index) { @@ -54,23 +54,23 @@ const EventsCard = props => { container direction="row" spacing={2} - data-testId={index == 0 ? "upEventBox" : ""} + data-testid={index == 0 ? "upEventBox" : ""} > - + {event.name} {event.date} diff --git a/src/components/CardTabs/Tags/index.jsx b/src/components/CardTabs/Tags/index.jsx index 8a566662..4bbd14d2 100644 --- a/src/components/CardTabs/Tags/index.jsx +++ b/src/components/CardTabs/Tags/index.jsx @@ -41,14 +41,14 @@ const TagCard = props => { const classes = useStyles(); return ( -
+
Popular Tags @@ -61,7 +61,7 @@ const TagCard = props => { label={tag} id={index} className={classes.chip} - data-testId={index === 0 ? "TagsChip" : ""} + data-testid={index === 0 ? "TagsChip" : ""} /> ); })} diff --git a/src/components/CardTabs/Users/UserElement.jsx b/src/components/CardTabs/Users/UserElement.jsx index 2a6c2a9c..05fcebe5 100644 --- a/src/components/CardTabs/Users/UserElement.jsx +++ b/src/components/CardTabs/Users/UserElement.jsx @@ -15,7 +15,7 @@ const UserElement = ({ user, index, useStyles }) => { key: "user" + { index }, mb: 1.5 }} - gutterBottom + gutterbottom="true" > - + {/* 750 ? true : undefined} xs={2} className={classes.sideBody}> */} + 750 ? true : undefined} + xs={windowSize.width > 750 ? 2 : undefined} + className={classes.sideBody} + > {windowSize.width > 750 && ( 750 ? true : undefined} className={classes.leftSideCard} direction="column" style={{ @@ -216,17 +222,22 @@ function HomePage({ background = "white", textColor = "black" }) { boxShadow: "none" }} > - + 750 ? true : undefined} + className={classes.outerSideBar} + > )} 750 ? true : undefined} className={classes.mainBody} - data-testId="homepageMainBody" - xs={6} + data-testid="homepageMainBody" + xs={windowSize.width > 750 ? 6 : undefined} > - + 750 ? true : undefined} + sx={{ display: { md: "none" } }} + > {tutorials.map(tutorial => { @@ -257,7 +272,7 @@ function HomePage({ background = "white", textColor = "black" }) { - + 750 ? true : undefined} + className={classes.sideBody} + xs={windowSize.width > 750 ? 3 : undefined} + > 750 ? true : undefined} alignContent="center" direction="column" style={{ width: "100%" }} - data-testId="homepageTagSidebar" + data-testid="homepageTagSidebar" > - + 750 ? true : undefined} + style={{ minWidth: "100%" }} + > @@ -325,9 +349,13 @@ function HomePage({ background = "white", textColor = "black" }) { style={{ width: "100%" }} - data-testId="homepageUpcomingEvents" + data-testid="homepageUpcomingEvents" > - + 750 ? true : undefined} + style={{ minWidth: "100%" }} + > @@ -338,9 +366,13 @@ function HomePage({ background = "white", textColor = "black" }) { style={{ width: "100%" }} - data-testId="homepageUsersToFollow" + data-testid="homepageUsersToFollow" > - + 750 ? true : undefined} + style={{ minWidth: "100%" }} + > @@ -356,9 +388,13 @@ function HomePage({ background = "white", textColor = "black" }) { border: "none", boxShadow: "none" }} - data-testId="homepageContributors" + data-testid="homepageContributors" > - + 750 ? true : undefined} + style={{ minWidth: "100%" }} + > @@ -370,9 +406,13 @@ function HomePage({ background = "white", textColor = "black" }) { style={{ width: "100%" }} - data-testId="homepagePopularEventSidebar" + data-testid="homepagePopularEventSidebar" > - + 750 ? true : undefined} + style={{ minWidth: "100%" }} + > diff --git a/src/components/NavBar/new/MiniNavbar/index.jsx b/src/components/NavBar/new/MiniNavbar/index.jsx index 596e4e5b..ae9579a9 100644 --- a/src/components/NavBar/new/MiniNavbar/index.jsx +++ b/src/components/NavBar/new/MiniNavbar/index.jsx @@ -131,13 +131,12 @@ function MiniNavbar() { - - {window.innerWidth > 960 && ( - toggleDrawer(true)} /> - )} - {window.innerWidth <= 960 && ( - toggleSlider()} /> - )} + + window.innerWidth > 960 ? toggleDrawer(true) : toggleSlider() + } + > + diff --git a/src/components/SideBar/sidelist.jsx b/src/components/SideBar/sidelist.jsx index abc8d879..8d8edd7a 100644 --- a/src/components/SideBar/sidelist.jsx +++ b/src/components/SideBar/sidelist.jsx @@ -91,7 +91,7 @@ const SideList = ({ {menuItems.map(function (item, index) { return (
- +
Activity diff --git a/src/components/Topbar/NewCodelabz/index.jsx b/src/components/Topbar/NewCodelabz/index.jsx index 392d030f..659777b9 100644 --- a/src/components/Topbar/NewCodelabz/index.jsx +++ b/src/components/Topbar/NewCodelabz/index.jsx @@ -34,9 +34,9 @@ function NewCodelabz({ setVisibleModal }) { return ( - + setVisibleModal(true)} > diff --git a/src/components/Tutorials/MyTutorials/BaseTutorialsComponent/TutorialCard.jsx b/src/components/Tutorials/MyTutorials/BaseTutorialsComponent/TutorialCard.jsx index 6ba03913..deddb642 100644 --- a/src/components/Tutorials/MyTutorials/BaseTutorialsComponent/TutorialCard.jsx +++ b/src/components/Tutorials/MyTutorials/BaseTutorialsComponent/TutorialCard.jsx @@ -12,7 +12,7 @@ import React from "react"; import { Link } from "react-router-dom"; const TutorialCard = ({ - tutorialData: { tutorial_id, title, summary, icon, owner }, + tutorialData: { tutorial_id, title, summary, featured_image, owner }, loading }) => { return ( @@ -22,7 +22,7 @@ const TutorialCard = ({ component="img" alt="Tutorial icon" height="140" - image={icon ? icon : TutorialImg} + image={featured_image ? featured_image : TutorialImg} title="Tutorial icon" /> diff --git a/src/components/Tutorials/NewTutorial/index.jsx b/src/components/Tutorials/NewTutorial/index.jsx index ac826889..16b90076 100644 --- a/src/components/Tutorials/NewTutorial/index.jsx +++ b/src/components/Tutorials/NewTutorial/index.jsx @@ -14,11 +14,12 @@ import Avatar from "@mui/material/Avatar"; import { makeStyles } from "@mui/styles"; import { deepPurple } from "@mui/material/colors"; import { Typography } from "@mui/material"; -import ImageIcon from "@mui/icons-material/Image"; import DescriptionIcon from "@mui/icons-material/Description"; import MovieIcon from "@mui/icons-material/Movie"; import Select from "react-select"; import { common } from "@mui/material/colors"; +import ImageUploadButton from "../../ui-helpers/buttons/ImageUploadButton"; +import { set } from "lodash"; const useStyles = makeStyles(theme => ({ root: { @@ -43,10 +44,12 @@ const NewTutorial = ({ viewModal, onSidebarClick, viewCallback, active }) => { const [visible, setVisible] = useState(false); const [loading, setLoading] = useState(false); const [error, setError] = useState(false); + const [isUploading, setIsUploading] = useState(false); const [formValue, setformValue] = useState({ title: "", summary: "", - owner: "" + owner: "", + featured_image: "" }); const loadingProp = useSelector( @@ -117,7 +120,7 @@ const NewTutorial = ({ viewModal, onSidebarClick, viewCallback, active }) => { setVisible(viewModal); }, [viewModal]); - const onSubmit = formData => { + const onSubmit = async formData => { formData.preventDefault(); const tutorialData = { ...formValue, @@ -125,8 +128,19 @@ const NewTutorial = ({ viewModal, onSidebarClick, viewCallback, active }) => { is_org: userHandle !== formValue.owner, completed: false }; - console.log(tutorialData); - createTutorial(tutorialData)(firebase, firestore, dispatch, history); + console.log( + `formValue is ${formValue} and tutorialData is ${tutorialData}` + ); + try { + await createTutorial(tutorialData)( + firebase, + firestore, + dispatch, + history + ); + } catch (error) { + console.error("Error creating tutorial:", error); + } }; const onOwnerChange = value => { @@ -145,6 +159,15 @@ const NewTutorial = ({ viewModal, onSidebarClick, viewCallback, active }) => { })); }; + const handleImageChange = url => { + console.log("URL is ", url); + setformValue(prev => ({ + ...prev, + featured_image: url + })); + setIsUploading(false); + }; + const classes = useStyles(); return ( { onChange={e => handleChange(e)} style={{ marginBottom: "2rem" }} /> - - - - + @@ -263,6 +287,7 @@ const NewTutorial = ({ viewModal, onSidebarClick, viewCallback, active }) => { } }} disabled={ + isUploading || formValue.title === "" || formValue.summary === "" || formValue.owner === "" diff --git a/src/components/ui-helpers/buttons/ImageUploadButton.jsx b/src/components/ui-helpers/buttons/ImageUploadButton.jsx new file mode 100644 index 00000000..c43effc7 --- /dev/null +++ b/src/components/ui-helpers/buttons/ImageUploadButton.jsx @@ -0,0 +1,118 @@ +import React, { useState, useRef } from "react"; +import ImageIcon from "@mui/icons-material/Image"; +import { IconButton, LinearProgress } from "@mui/material"; +import firebase from "../../../config"; +import PropTypes from "prop-types"; + +function ImageUploadButton({ isUploading, setIsUploading, onImageUpload }) { + const [uploadProgress, setUploadProgress] = useState(0); + const [selectedImage, setSelectedImage] = useState(null); + const fileInputRef = useRef(null); + + async function handleImageUpload(event) { + setIsUploading(true); + const file = event.target.files[0]; + + const uniqueId = new Date().getTime(); + const storage = firebase.storage(); + const storageRef = storage.ref(); + const imageRef = storageRef.child( + `tutorial_images/${uniqueId}_${file.name}` + ); + + try { + const uploadTask = imageRef.put(file); + + // Update progress + uploadTask.on("state_changed", snapshot => { + const progress = Math.round( + (snapshot.bytesTransferred / snapshot.totalBytes) * 100 + ); + setUploadProgress(progress); + }); + + // Get download URL when upload is complete + uploadTask.then(async snapshot => { + const downloadURL = await snapshot.ref.getDownloadURL(); + console.log(downloadURL) + setSelectedImage(downloadURL); // Set selected image to display + onImageUpload(downloadURL); + setIsUploading(false); + setUploadProgress(0); // Reset upload progress after upload + }); + } catch (error) { + setIsUploading(false); + console.error("Error uploading file:", error); + } + } + + const handleClick = () => { + fileInputRef.current.click(); + }; + + return ( + <> + {/* Hidden file input to trigger file selection */} + + + {/* Display upload progress */} + {isUploading && ( + + )} + + {/* Display uploaded image */} + {!isUploading && selectedImage && ( +
+ Uploaded +
+ )} + + {/* Display image icon always, but disabled during upload */} + + + + + ); +} + +ImageUploadButton.propTypes = { + onImageUpload: PropTypes.func.isRequired, + isUploading: PropTypes.bool.isRequired, + setIsUploading: PropTypes.func.isRequired, +}; + +export default ImageUploadButton; diff --git a/src/helpers/appBar.jsx b/src/helpers/appBar.jsx index 6db7a627..dd0c7364 100644 --- a/src/helpers/appBar.jsx +++ b/src/helpers/appBar.jsx @@ -109,13 +109,13 @@ const CodeLabzAppBar = () => { if (authed) { return ( -
+
); } else { return ( -
+
); diff --git a/src/store/actions/tutorialsActions.js b/src/store/actions/tutorialsActions.js index 7d273c1d..edae9656 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, featured_image } = tutorialData; const setData = async () => { const document = firestore.collection("tutorials").doc(); @@ -138,7 +138,7 @@ export const createTutorial = summary, title, tutorial_id: documentID, - featured_image: "", + featured_image: featured_image || "", icon: "", url: "", background_color: "#ffffff",