From 9b2d327c0e55a58fce58807d243faa160fa05fd8 Mon Sep 17 00:00:00 2001 From: Aswanth Vc Date: Sat, 12 Oct 2024 21:49:06 +0530 Subject: [PATCH] feat: LC modifications --- src/App.tsx | 5 + .../pages/LcDashboard/LcDashboard.module.css | 221 ++++++++++- .../pages/LcDashboard/LcDashboard.tsx | 6 +- .../LcDashboard/components/LcHistory.tsx | 112 +++--- .../pages/LcDashboard/components/LcHome.tsx | 362 ++++++++++++++---- .../LcDashboard/components/LcMeetCreate.tsx | 257 +++++++++++++ .../LcDashboard/components/LcMeetups.tsx | 94 +++++ .../pages/LcDashboard/components/LcReport.tsx | 132 ++----- .../pages/LcDashboard/components/YourLc.tsx | 107 ++++++ .../pages/LearningCircle.module.css | 67 ++++ .../pages/LearningCircleLandingPage.tsx | 193 ++++------ .../pages/Meetup/LcMeetup.module.css | 0 .../LearningCircle/pages/Meetup/LcMeetup.tsx | 20 + .../services/LearningCircleAPIs.ts | 133 +++++++ .../services/LearningCircleInterface.d.ts | 37 +- src/services/endpoints.ts | 6 +- src/services/urls.ts | 6 + 17 files changed, 1408 insertions(+), 350 deletions(-) create mode 100644 src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcMeetCreate.tsx create mode 100644 src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcMeetups.tsx create mode 100644 src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/YourLc.tsx create mode 100644 src/modules/Dashboard/modules/LearningCircle/pages/Meetup/LcMeetup.module.css create mode 100644 src/modules/Dashboard/modules/LearningCircle/pages/Meetup/LcMeetup.tsx diff --git a/src/App.tsx b/src/App.tsx index 6828ce635..6d4228701 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -44,6 +44,7 @@ import Refund from "./modules/Public/Donation/pages/Refund"; import DonationSuccess from "./modules/Public/Donation/pages/DonationSuccess"; import OpenGrad from "./modules/Dashboard/modules/OpenGrad"; import UserInterest from "./modules/Common/Authentication/pages/Onboarding/UserInterest/UserInterest"; +import LcMeetupIfo from "./modules/Dashboard/modules/LearningCircle/pages/Meetup/LcMeetup"; const Profile = lazy( () => import("./modules/Dashboard/modules/Profile/pages/Profile") @@ -693,6 +694,10 @@ function App() { path: "learning-circle", element: }, + { + path: "learning-circle/meetup/:id", + element: + }, { path: "learning-circle/details/:id", element: diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/LcDashboard.module.css b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/LcDashboard.module.css index 732f9f094..07384052b 100644 --- a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/LcDashboard.module.css +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/LcDashboard.module.css @@ -191,6 +191,46 @@ font-size: 18px; font-weight: 600; } + +.input_switch { + width: calc(100% - 20px); + background: #fff; + padding: 20px; + border-radius: 10px; + display: flex; + justify-content: space-between; + align-items: end; + margin: 10px; + .label { + font-size: 15px; + } +} + +.input_field { + background: #fff; + padding: 20px; + border-radius: 10px; + margin: 10px; + label.label { + display: block; + width: 100%; + text-align: left; + margin: 0 0 10px 0; + } + textarea { + width: 100%; + background-color: rgba(238, 242, 255, 1); + min-height: 130px; + border-radius: 10px; + padding: 10px; + } + .error_message { + color: rgb(246, 45, 45); + font-size: 12px !important; + margin-top: 10px; + text-align: start; + } +} .ReportWrapper .DetailSection .SectionTwo textarea { width: 100%; background-color: rgba(238, 242, 255, 1); @@ -366,6 +406,7 @@ } .HistoryDataWrapper .Headings { width: 38%; + text-align: left; } .HistoryDataWrapper .detailedSection { width: 60%; @@ -703,6 +744,9 @@ input[type="time"]::-webkit-calendar-picker-indicator { .ScheduleOn { text-align: center; + margin-bottom: 10px; + padding-bottom: 10px; + border-bottom: 1px solid var(--grey); } .ScheduleOn b { @@ -744,7 +788,7 @@ input[type="time"]::-webkit-calendar-picker-indicator { flex-wrap: wrap; } -.dateandtime input[type="time"] { +.dateandtime input[type="datetime-local"] { padding: 0px 10px; border-radius: 6px; width: 47%; @@ -1125,3 +1169,178 @@ input[type="time"]::-webkit-calendar-picker-indicator { text-align: left; color: #1d1d1d; } + +.ContainerWrapper .ContentWrapper .TopContainer .sectionOne { + .meetups { + display: flex; + flex-direction: column; + gap: 10px; + .meetup { + background: #fff; + padding: 10px; + width: 100%; + border-radius: 10px; + .meetupStatusBar { + display: flex; + justify-content: space-between; + align-items: center; + gap: 10px; + width: 100%; + .date { + font-size: 15px; + font-weight: 800; + display: flex; + align-items: end; + gap: 5px; + justify-content: start; + + span { + width: 20px; + height: 20px; + display: inline-flex; + align-items: center; + justify-content: center; + svg { + width: 15px; + height: 15px; + } + } + } + .status { + font-size: 12px; + font-weight: 600; + &.ongoing { + color: var(--green); + } + &.upcoming { + color: var(--blue); + } + } + } + .meetupDetails { + display: flex; + justify-content: space-between; + align-items: start; + flex-direction: column; + gap: 10px; + background: #22222205; + padding: 20px; + margin: 20px 10px; + border-radius: 5px; + .title { + font-size: 18px; + font-weight: 800; + } + .agenda { + font-size: 15px; + font-weight: 600; + color: #1d1d1d; + } + .venue { + width: 100%; + display: flex; + flex-direction: column; + gap: 10px; + align-items: start; + .venueHead { + font-size: 15px; + font-weight: 800; + color: #1d1d1d; + } + .actions { + width: 100%; + display: flex; + align-items: center; + gap: 10px; + justify-content: end; + } + .meetupVenue { + margin: 10px 0; + padding: 10px 10px; + background: #fff; + border-radius: 5px; + display: flex; + align-items: center; + gap: 5px; + width: 100%; + flex-direction: column; + + .head { + font-size: 15px; + font-weight: 900; + border-bottom: 1px solid #1d1d1d; + color: #1d1d1d; + } + .venueLink { + font-size: 15px; + font-weight: 600; + color: var(--blue); + background: #dddddd90; + padding: 2px 10px; + border-radius: 5px; + width: 100%; + } + } + } + } + } + } +} + +.inputBox input, +.inputBox select { + border: none; + background: rgba(239, 241, 249, 0.6); + border-radius: 6px; + padding: 10px; + outline: none; + width: 100%; + margin-top: 10px; +} + +.imageBox { + position: relative; + + div { + color: #456ff6; + position: absolute; + top: 0; + display: flex; + align-items: center; + right: 5%; + height: 110%; + + &:active { + transform: scale(0.9); + } + } +} + +.imageBox input::file-selector-button { + background-color: rgb(69, 111, 246); + color: white; + border: none; + border-radius: 0.25rem; + padding: 0.25rem; +} + +.label { + font-weight: 600; + margin-top: 5px; + color: var(--black); + text-align: left; +} + +.powerfulButton:hover { + color: hsl(var(--primary-btn-color)); +} + +.powerfulButton { + height: 50px; +} + +/* @media (max-width: 1500px) { + .edit_profile_container { + left: unset; + } +} */ diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/LcDashboard.tsx b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/LcDashboard.tsx index 5d3a551a3..29b846bf5 100644 --- a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/LcDashboard.tsx +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/LcDashboard.tsx @@ -9,7 +9,6 @@ import MuLoader from "@/MuLearnComponents/MuLoader/MuLoader"; import { comingSoon } from "../../../../utils/common"; import LcTeam from "./components/LcTeam"; import LcHome from "./components/LcHome"; -import LcProgress from "./components/LcProgress"; const LcDashboard = () => { const [lc, setLc] = useState(); @@ -19,7 +18,8 @@ const LcDashboard = () => { isHistory: false, isTeam: false, isSchedule: false, - reRender: false + reRender: false, + isCreateMeeting: false }); const [tab, setTab] = useState<"Dashboard">("Dashboard"); @@ -39,7 +39,7 @@ const LcDashboard = () => { useEffect(() => { handleFetchDetails(); - }, [temp.isSchedule, temp.isTeam, temp.reRender]); + }, [temp.isTeam, temp.reRender]); return temp.loading ? ( diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcHistory.tsx b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcHistory.tsx index 6fa11b128..14d27edaa 100644 --- a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcHistory.tsx +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcHistory.tsx @@ -1,86 +1,106 @@ import styles from "../LcDashboard.module.css"; -import { LcAttendees } from "./LcAttendees"; -import { useEffect, useState } from "react"; -import { getLCMeetingReport } from "../../../services/LearningCircleAPIs"; -import { convertDateToDayAndMonthAndYear } from "../../../../../utils/common"; +import { + interestedMeetup, + joinMeetup +} from "../../../services/LearningCircleAPIs"; +import { convertToFormatedDate } from "../../../../../utils/common"; import { convert24to12, extract24hTimeFromDateTime, getDayOfWeek } from "../../../services/utils"; -import { useParams } from "react-router-dom"; import MuLoader from "@/MuLearnComponents/MuLoader/MuLoader"; +import { PowerfulButton } from "@/MuLearnComponents/MuButtons/MuButton"; type Props = { id: string | undefined; - lc: LcDetail | undefined; + lc: LcMeetupDetailInfo | undefined; }; const LcHistory = (props: Props) => { - const [data, setData] = useState(); - const { id } = useParams(); - - useEffect(() => { - getLCMeetingReport(props.id, id).then(res => { - setData(res); - }); - }, []); - + console.log(props.lc); + const handleInterested = (e: any) => { + e.preventDefault(); + if (props.lc?.is_lc_member) { + joinMeetup(props.lc?.id ?? ""); + return; + } + interestedMeetup(props.lc?.id ?? "", props.lc?.is_interested); + }; return (
- {data ? ( + {props.lc ? ( <>
-

- {convertDateToDayAndMonthAndYear( - data?.meet_time - )} -

-

{getDayOfWeek(data?.meet_time)}

+

{props.lc?.title}

+

{getDayOfWeek(props.lc?.meet_time)}

{

- Venuesdf:{" "} - {data.meet_place || + Venue:{" "} + {props.lc.meet_place || props.lc?.meet_place}

}

Time:{" "} - {convert24to12( - extract24hTimeFromDateTime( - data.meet_time - ) - )} + {convertToFormatedDate(props.lc.meet_time) + + " " + + convert24to12( + extract24hTimeFromDateTime( + props.lc.meet_time + ) + )}

+ {props.lc.is_lc_member && ( + <> +

Meet Code: {props.lc.meet_code}

+

+ Total interests: + {" " + props.lc.total_interested} +

+

+ Total joinees: + {" " + props.lc.total_joined} +

+ + )}

Agenda

-

{data.agenda}

+

{props.lc.agenda}

-
-

Attendees

- {Array.isArray(data.attendees_details) && - data.attendees_details.map(attendee => ( -
- -
- ))} -
-
- -
+ {props.lc.image ? ( +
+ +
+ ) : null}
+ + {props.lc.is_lc_member + ? props.lc.is_started + ? "Join" + : "Join & Start meetup" + : props.lc.joined_at + ? "Joined" + : props.lc.is_interested + ? "Undo Interest" + : "I'm Interested Join"} + ) : (
{ - const nextMeet = getNextMeetingDate( - props.lc?.day || [], - props.lc?.meet_time === null ? "00:00" : String(props.lc?.meet_time) - ); - - const [selectedMeeting, setSelectedMeeting] = useState(""); - + const [meetups, setMeetups] = useState([]); + const [pastMeetups, setPastMeetups] = useState([]); + const [selectedMeeting, setSelectedMeeting] = useState(""); + useEffect(() => { + getLcMeetups(props.id ?? "").then(res => { + if (res) { + if (res.hasError) { + toast.error(res.message.general[0]); + } else { + setMeetups(res.meetups); + setPastMeetups(res.past); + } + } + }); + }, [props.lc]); + const navigate = useNavigate(); return (
@@ -40,8 +47,8 @@ const LcHome = (props: Props) => { ...props.temp, isReport: false, isHistory: false, - isTeam: false, - isSchedule: false + isTeam: false + // isSchedule: false }) } > @@ -59,7 +66,245 @@ const LcHome = (props: Props) => { Team
- {props.temp.isReport ? ( +
+
+
+ {props.temp.isReport ? ( + + ) : props.temp.isCreateMeeting ? ( + + ) : ( + <> +
+ {meetups.length > 0 ? ( + meetups.map(meetup => ( +
+
+
+ + + + {convertToFormatedDate( + meetup.meet_time + )} +
+
+ {meetup.is_started + ? "Ongoing" + : "Upcoming"} +
+
+
+

+ {meetup.title} +

+

+ {meetup.agenda} +

+
+

+ Venue Details +

+
+
+ + { + meetup.meet_place + } + +
+ + { + meetup.location + } + +
+
+ { + props.setTemp( + prev => ({ + ...prev, + isReport: + true + }) + ); + setSelectedMeeting( + meetup.id + ); + }} + > + Submit Report + + { + navigate( + "/dashboard/learning-circle/meetup/" + + meetup.id + ); + }} + > + More Info + +
+
+
+
+ )) + ) : ( + <> +
+

+ Next meeting not scheduled. +
+ Kindly schedule a meeting. +

+
+ + + )} +
+ + {/*
+
+ {props.lc?.meet_place && ( +

Venue: {props.lc?.meet_place}

+ )} + {props.lc?.meet_time && ( +

Time: {nextMeet?.formattedTime}

+ )} +
+ {props.lc?.meet_time && ( + + )} +
*/} + + )} +
+
+ {props.lc?.previous_meetings && + props.lc?.previous_meetings.length > 0 && ( +

Your past meetings

+ )} +
+ {pastMeetups.map((report, index) => ( +
{ + navigate( + "/dashboard/learning-circle/meetup/" + + report.id + ); + }} + > +
+

{index + 1}.

+

+ {convertToFormatedDate( + report.meet_time + )} +

+
+
+

+ {convertToFormatedDate( + report.meet_time + )}{" "} + {convert24to12( + extract24hTimeFromDateTime( + report.meet_time + ) + )} +

+ +
+
+ ))} +
+
+
+
+ {/* {props.temp.isReport ? ( ) : props.temp.isHistory ? ( @@ -67,8 +312,8 @@ const LcHome = (props: Props) => {
- {props.temp.isSchedule ? ( - { <>
{nextMeet && - props.lc?.meet_place && - props.lc?.meet_time ? ( + props.lc?.meet_place && + props.lc?.meet_time ? (

Next meeting on

@@ -103,7 +348,7 @@ const LcHome = (props: Props) => { onClick={() => { props.setTemp(prev => ({ ...prev, - isSchedule: true + isCreateMeeting: true })); }} > @@ -125,16 +370,18 @@ const LcHome = (props: Props) => {

)}

- {props.lc?.meet_time && ()} + {props.lc?.meet_time && ( + + )}
)} @@ -151,52 +398,11 @@ const LcHome = (props: Props) => {

Your past meetings

)}
- {props.lc?.previous_meetings.map( - (report, index) => ( -
{ - props.setTemp({ - ...props.temp, - isReport: false, - isHistory: true - }); - setSelectedMeeting(report.id); - }} - > -
-

{index + 1}.

-

- {convertToFormatedDate( - report.meet_time - )} -

-
-
-

- {convert24to12( - extract24hTimeFromDateTime( - report.meet_time - ) - )} -

- -
-
- ) - )} +
- )} + )} */}
); }; diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcMeetCreate.tsx b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcMeetCreate.tsx new file mode 100644 index 000000000..22c341b8d --- /dev/null +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcMeetCreate.tsx @@ -0,0 +1,257 @@ +import { Dispatch, SetStateAction, useState } from "react"; +import styles from "../LcDashboard.module.css"; +import toast from "react-hot-toast"; +import { + createMeetup, + setLCMeetTime +} from "../../../services/LearningCircleAPIs"; +import { useFormik } from "formik"; +import { Switch } from "@chakra-ui/react"; + +type Props = { + setTemp: Dispatch>; + lc: LcDetail | undefined; + id: string | undefined; +}; + +const LcMeetCreate = (props: Props) => { + const formik = useFormik({ + initialValues: { + title: "", + location: "", + meet_time: "", + meet_place: "", + agenda: "", + need_pre_requirements: false, + pre_requirements: null, + is_public: true, + limit_attendees: false, + max_attendees: -1 + }, + onSubmit: values => { + createMeetup(values, props.id ?? "") + .then(res => { + console.log(res); + if (res) { + if (res.hasError) { + toast.error(res.message.general[0]); + } else { + toast.success(res.message.general[0]); + } + } + }) + .catch(err => { + toast.error("Failed to create meetup"); + }); + + props.setTemp(prev => ({ + ...prev, + isCreateMeeting: false + })); + }, + validate: values => { + if (values.location === "") { + return { location: "Location is required" }; + } else if (!values.location.startsWith("http")) { + return { + location: + "Location should be link to maps location or online meet link." + }; + } + } + }); + + return ( + <> +
+ Create a Meetup +

Enter details to schedule a meet

+
+ +
+
+
+ + + +
+
+ +
+ + {formik.touched.title && formik.errors.title ? ( +

+ {formik.errors.title} +

+ ) : null} +
+
+
+ +
+ + {formik.touched.agenda && formik.errors.agenda ? ( +

+ {formik.errors.agenda} +

+ ) : null} +
+
+
+ +
+ + {formik.touched.location && + formik.errors.location ? ( +

+ {formik.errors.location} +

+ ) : null} +
+
+
+ + { + formik.setFieldValue( + "is_public", + e.target.checked + ); + }} + /> +
+
+ + { + formik.setFieldValue( + "need_pre_requirements", + e.target.checked + ); + }} + /> +
+ {formik.values.need_pre_requirements && ( +
+ +
+ + {formik.touched.pre_requirements && + formik.errors.pre_requirements ? ( +

+ {formik.errors.pre_requirements} +

+ ) : null} +
+
+ )} +
+ + { + if (!e.target.checked) { + formik.setFieldValue("max_attendees", -1); + } else { + formik.setFieldValue("max_attendees", 100); + } + formik.setFieldValue( + "limit_attendees", + e.target.checked + ); + }} + /> +
+ {formik.values.limit_attendees && ( +
+ +
+ + {formik.touched.max_attendees && + formik.errors.max_attendees ? ( +

+ {formik.errors.max_attendees} +

+ ) : null} +
+
+ )} +
+ +
+
+
+ + ); +}; + +export default LcMeetCreate; diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcMeetups.tsx b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcMeetups.tsx new file mode 100644 index 000000000..22f9e582c --- /dev/null +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcMeetups.tsx @@ -0,0 +1,94 @@ +import styles from "../../LearningCircle.module.css"; +import imageBottom from "../../../assets/images/LC3.webp"; +import { PowerfulButton } from "@/MuLearnComponents/MuButtons/MuButton"; +import { useNavigate } from "react-router-dom"; +import { useEffect, useState } from "react"; +import { BsChevronRight } from "react-icons/bs"; +import { getMeetups } from "../../../services/LearningCircleAPIs"; +import toast from "react-hot-toast"; + +const LcMeetups = () => { + const navigate = useNavigate(); + const [meetups, setMeetups] = useState(); + useEffect(() => { + getMeetups(setMeetups) + .then(() => {}) + .catch(error => { + console.log(error); + toast.error("Failed to fetch meetups"); + }); + }, []); + + return ( +
+
+
    + {meetups && meetups.length > 0 ? ( + <> + Meetups +
    + {meetups.map((meetup, pos) => ( +
    +

    + {meetup.title} +

    +

    + Location: {meetup.location} +

    +

    + Time: {meetup.meet_time} +

    +

    + Place: {meetup.meet_place} +

    +

    + Agenda: {meetup.agenda} +

    +

    + Pre-requirements:{" "} + {meetup.pre_requirements || "None"} +

    +

    + + {meetup.location} + +

    + { + navigate( + `/dashboard/learning-circle/meetup/${meetup.id}` + ); + }} + > + More info + +
    + ))} +
    + + ) : ( +
    + No meetups + No Meetups! +

    No meetups are currently running now

    +
    + )} +
+
+
+ ); +}; + +export default LcMeetups; diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcReport.tsx b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcReport.tsx index 7a80f72e5..7d10a59d5 100644 --- a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcReport.tsx +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/LcReport.tsx @@ -12,28 +12,9 @@ type Props = { }; const LcReport = (props: Props) => { - const [formData, setFormData] = useState({ - day: "", - meet_time: "", - agenda: "", - attendees: [] - }); + const [reportText, setReportText] = useState(""); const [uploadedImage, setUploadedImage] = useState(null); - useEffect(() => { - const now = new Date(); - const hours = now.getHours().toString().padStart(2, "0"); - const minutes = now.getMinutes().toString().padStart(2, "0"); - const year = now.getFullYear().toString(); - const month = (now.getMonth() + 1).toString().padStart(2, "0"); - const day = now.getDate().toString().padStart(2, "0"); - setFormData(prevState => ({ - ...prevState, - day: `${year}-${month}-${day}`, - meet_time: `${hours}:${minutes}:00` - })); - }, []); - const handleImageUpload = (event: React.ChangeEvent) => { const file = event.target.files && event.target.files[0]; if (file) { @@ -41,61 +22,15 @@ const LcReport = (props: Props) => { } }; - const handleMemberClick = (memberId: string) => { - setFormData(prevState => { - // Check if the attendee is already in the list - const isAlreadySelected = prevState.attendees.includes(memberId); - - // If already selected, remove them; otherwise, add them - const updatedAttendees = isAlreadySelected - ? prevState.attendees.filter(id => id !== memberId) // Remove the attendee - : [...prevState.attendees, memberId]; // Add the attendee - - return { - ...prevState, - attendees: updatedAttendees - }; - }); - }; - - const validateForm = (state: LcReport) => { - let errors: { [key: string]: string } = {}; - if (!state.day) { - errors.day = "Date is required"; - } - if (!state.meet_time) { - errors.time = "Time is required"; - } - if (!state.agenda.trim()) { - errors.agenda = "Agenda is required"; - } - if (state.attendees.length === 0) { - errors.attendees = "At least one attendee is required"; - } - if (!uploadedImage) { - errors.image = "Image is required"; - } else { - const allowedTypes = ["image/jpeg", "image/png", "image/gif"]; - if (!allowedTypes.includes(uploadedImage.type)) { - errors.image = - "Invalid image type. Please upload a JPEG, PNG, or GIF."; - } - } - { - Object.keys(errors).length > 0 - ? toast.error(Object.values(errors).join("\n")) - : null; - } - return Object.keys(errors).length > 0 ? false : true; - }; - const handleSubmit = (event: any) => { event.preventDefault(); - if (validateForm(formData)) { + if (!uploadedImage) { + toast.error("Please upload an image"); + return; + } + if (reportText.length > 0) { const data = new FormData(); - data.append("agenda", formData.agenda); - data.append("attendees", formData.attendees.join(",")); - data.append("time", formData.meet_time); + data.append("report_text", reportText); if (uploadedImage) { data.append("images", uploadedImage); } @@ -122,10 +57,21 @@ const LcReport = (props: Props) => { } ); - - return Failed to report meeting!; + return error?.response?.data?.message ? ( + + { + (error?.response?.data?.message?.general ?? [ + "Failed to report meeting" + ])[0] + } + + ) : ( + Failed to report meeting! + ); } }); + } else { + toast.error("Please fill the notes"); } }; @@ -136,7 +82,7 @@ const LcReport = (props: Props) => { return (
-
+ {/*
{ } />
-
+
*/}
-

Agenda

+

What happened on the meet? *

-
-

Attendees

-
- {props.lc?.members.map(member => ( -
handleMemberClick(member.id)} - > - -
- ))} - {/* */} -
-
diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/YourLc.tsx b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/YourLc.tsx new file mode 100644 index 000000000..e1cca1351 --- /dev/null +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LcDashboard/components/YourLc.tsx @@ -0,0 +1,107 @@ +import styles from "../../LearningCircle.module.css"; +import imageBottom from "../../../assets/images/LC3.webp"; +import { PowerfulButton } from "@/MuLearnComponents/MuButtons/MuButton"; +import { useNavigate } from "react-router-dom"; +import { useEffect, useState } from "react"; +import { BsChevronRight } from "react-icons/bs"; +import { getUserLearningCircles } from "../../../services/LearningCircleAPIs"; + +const YourLc = ({ userCircleList }: { userCircleList: LcType[] }) => { + const navigate = useNavigate(); + + return ( +
+
+
    + {userCircleList && userCircleList.length > 0 ? ( + <> + Your learning circles + {userCircleList?.map((circle, pos) => ( +
    +
  • { + navigate( + `/dashboard/learning-circle/dashboard/${circle.id}` + ); + }} + > + + +
  • +
    + ))} + + ) : ( +
    + You haven't joined any circles yet + Nothing yet! +

    You haven't joined any learning circles yet.

    +
    + )} +
+
+
+ ); +}; + +export default YourLc; diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LearningCircle.module.css b/src/modules/Dashboard/modules/LearningCircle/pages/LearningCircle.module.css index 8d1abd845..8ae409cd5 100644 --- a/src/modules/Dashboard/modules/LearningCircle/pages/LearningCircle.module.css +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LearningCircle.module.css @@ -29,6 +29,7 @@ } .learningCircleLandingPageMiddle { + width: 100%; display: flex; flex-direction: column; justify-content: center; @@ -1264,3 +1265,69 @@ transform: scaleX(-1); } } +.SwitchNav { + display: flex; + gap: 5px; + align-items: center; + .items { + padding: 8px 20px; + background-color: #f3f3f4; + color: black; + font-weight: 600; + border-radius: 15px; + &.active { + background-color: white; + border-radius: 15px 15px 0px 0px; + } + } + .plusItem { + border-left: 2px solid #8b8e92; + color: black; + font-size: 25px; + padding: 0px; + height: fit-content; + padding-left: 10px; + line-height: 1; + } +} + +.ContentWrapper { + width: 100%; + padding: 30px; + background-color: white; + display: flex; + flex-direction: column; + gap: 15px; + align-items: start; +} +.inputBox { + background: #fff; + margin: 0px 10px; + input { + width: 100%; + background-color: rgba(238, 242, 255, 1); + border: none; + border-radius: 10px; + padding: 10px; + } +} +.modalinfo { + margin: 10px; + color: #22222290; + font-size: 15px; +} +.meetupGrid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 20px; + .meetupCard { + background: #fdfdfd; + color: #222; + padding: 20px; + box-shadow: 0px 0px 5px 1px rgba(0, 0, 0, 0.05); + border-radius: 10px; + } + @media screen and (max-width: 768px) { + grid-template-columns: 1fr; + } +} diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/LearningCircleLandingPage.tsx b/src/modules/Dashboard/modules/LearningCircle/pages/LearningCircleLandingPage.tsx index 59fd3de51..849402ff9 100644 --- a/src/modules/Dashboard/modules/LearningCircle/pages/LearningCircleLandingPage.tsx +++ b/src/modules/Dashboard/modules/LearningCircle/pages/LearningCircleLandingPage.tsx @@ -1,24 +1,30 @@ import styles from "./LearningCircle.module.css"; import imageTop from "../assets/images/LC2.webp"; -import imageBottom from "../assets/images/LC3.webp"; import { PowerfulButton } from "@/MuLearnComponents/MuButtons/MuButton"; import { useNavigate } from "react-router-dom"; import { useEffect, useState } from "react"; -import { BsChevronRight } from "react-icons/bs"; -import { getUserLearningCircles } from "../services/LearningCircleAPIs"; +import { + getUserLearningCircles, + joinMeetup +} from "../services/LearningCircleAPIs"; import MuLoader from "@/MuLearnComponents/MuLoader/MuLoader"; +import YourLc from "./LcDashboard/components/YourLc"; +import LcMeetups from "./LcDashboard/components/LcMeetups"; +import MuModal from "@/MuLearnComponents/MuModal/MuModal"; +import toast from "react-hot-toast"; const LearningCircleLandingPage = () => { const navigate = useNavigate(); const [userCircleList, setUserCircleList] = useState(); const [isLoading, setIsLoading] = useState(true); - + const [curpage, setCurPage] = useState(0); + const [meetingCodeModalOpen, setMeetingCodeModalOpen] = useState(false); useEffect(() => { getUserLearningCircles(setUserCircleList).then(() => { setIsLoading(false); }); }, []); - + const [meetupCode, setMeetupCode] = useState(""); const handleJoin = () => { navigate("/dashboard/learning-circle/find-circle"); }; @@ -27,8 +33,46 @@ const LearningCircleLandingPage = () => { navigate("/dashboard/learning-circle/create-circle"); }; + const joinMeet = () => { + if (meetupCode.length !== 6) { + toast.error("Invalid meetup code"); + return; + } + joinMeetup(meetupCode); + setMeetingCodeModalOpen(false); + }; + + const handleJoinMeetup = () => { + setMeetingCodeModalOpen(true); + }; return ( <> + { + setMeetingCodeModalOpen(false); + }} + title={"Enter Meeting Code"} + type={"success"} + onDone={joinMeet} + > +
+ { + setMeetupCode(e.target.value.toUpperCase()); + }} + /> +
+

+ Enter the 6 digit code provided by the meetup organizer to + join the meetup and earn karma points. +

+
{isLoading ? (
@@ -49,6 +93,11 @@ const LearningCircleLandingPage = () => { styles.learningCircleLandingPageButton } > + { onClick={handleJoin} />
- -
-
    - {userCircleList && userCircleList.length > 0 ? ( - <> - Your learning circles - {userCircleList?.map((circle, pos) => ( -
    -
  • { - navigate( - `/dashboard/learning-circle/dashboard/${circle.id}` - ); - }} - > - - -
  • -
    - ))} - - ) : ( -
    - You haven't joined any circles yet - Nothing yet! -

    - You haven't joined any learning circles - yet. -

    -
    - )} -
+
+
+ + +
+ {curpage === 0 ? ( + + ) : ( + + )}
)} diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/Meetup/LcMeetup.module.css b/src/modules/Dashboard/modules/LearningCircle/pages/Meetup/LcMeetup.module.css new file mode 100644 index 000000000..e69de29bb diff --git a/src/modules/Dashboard/modules/LearningCircle/pages/Meetup/LcMeetup.tsx b/src/modules/Dashboard/modules/LearningCircle/pages/Meetup/LcMeetup.tsx new file mode 100644 index 000000000..9fccd4a27 --- /dev/null +++ b/src/modules/Dashboard/modules/LearningCircle/pages/Meetup/LcMeetup.tsx @@ -0,0 +1,20 @@ +import { useParams } from "react-router-dom"; +import LcHistory from "../LcDashboard/components/LcHistory"; +import { useEffect, useState } from "react"; +import { getMeetupInfo } from "../../services/LearningCircleAPIs"; +import toast from "react-hot-toast"; + +export default function LcMeetupIfo() { + const params = useParams(); + const [data, setData] = useState(); + useEffect(() => { + getMeetupInfo(setData, params.id ?? "") + .then(res => { + console.log(res); + }) + .catch(() => { + toast.error("Failed to fetch data"); + }); + }, []); + return data ? : <>Loading; +} diff --git a/src/modules/Dashboard/modules/LearningCircle/services/LearningCircleAPIs.ts b/src/modules/Dashboard/modules/LearningCircle/services/LearningCircleAPIs.ts index c90d7b54d..4292b2925 100644 --- a/src/modules/Dashboard/modules/LearningCircle/services/LearningCircleAPIs.ts +++ b/src/modules/Dashboard/modules/LearningCircle/services/LearningCircleAPIs.ts @@ -24,6 +24,109 @@ export const getUserLearningCircles = async ( } }; +export const joinMeetup = async (meetId: string) => { + try { + const response = await privateGateway.post( + dynamicRoute(dashboardRoutes.joinMeetup, meetId) + ); + const message: any = response?.data; + toast.success(message.message?.general[0] ?? "Failed to join meetup"); + } catch (err: unknown) { + const error = err as AxiosError; + toast.error( + ((error?.response?.data as any).message?.general ?? [ + "Failed to join meetup" + ])[0] + ); + if (error?.response) { + throw error; + } + toast.error("Failed to join meetup"); + } +}; + +export const interestedMeetup = async ( + meetId: string, + undo: boolean = false +) => { + try { + if (undo) { + const response = await privateGateway.delete( + dynamicRoute(dashboardRoutes.interestedMeetup, meetId) + ); + const message: any = response?.data; + toast.success( + message.message?.general[0] ?? "Failed to undo interest" + ); + return; + } + const response = await privateGateway.post( + dynamicRoute(dashboardRoutes.interestedMeetup, meetId) + ); + const message: any = response?.data; + toast.success(message.message?.general[0] ?? "Failed to show interest"); + } catch (err: unknown) { + console.log(err); + const error = err as AxiosError; + toast.error( + ((error?.response?.data as any).message?.general ?? [ + "Failed to show interest" + ])[0] + ); + if (error?.response) { + throw error; + } + toast.error("Failed to show interest"); + } +}; + +export const getMeetupInfo = async ( + setMeetup: + | UseStateFunc + | UseStateFunc, + meetId: string +) => { + try { + console.log(meetId); + const response = await privateGateway.get( + dynamicRoute(dashboardRoutes.getMeetupInfo, meetId) + ); + console.log(response); + const message: any = response?.data; + setMeetup(message.response); + } catch (err: unknown) { + const error = err as AxiosError; + if (error?.response) { + throw error; + } + } +}; +export const getMeetups = async ( + setMeetup: + | UseStateFunc + | UseStateFunc, + meetId: string | undefined = undefined +) => { + try { + console.log(meetId); + const response = await privateGateway.get(dashboardRoutes.getMeetups, { + params: meetId + ? { + meet_id: meetId + } + : {} + }); + console.log(response); + const message: any = response?.data; + setMeetup(message.response); + } catch (err: unknown) { + const error = err as AxiosError; + if (error?.response) { + throw error; + } + } +}; + export const getUserOrg = (setOrg: { (value: SetStateAction): void; (arg0: any): void; @@ -235,6 +338,36 @@ export const updateLcNote = async (data: LcNote) => { } }; +export const getLcMeetups = async (id: string | undefined) => { + try { + const response = await privateGateway.get( + dynamicRoute(lcRoutes.getLcMeetups, id as string) + ); + const message: any = response?.data; + return message.response; + } catch (err) { + const error = err as AxiosError; + if (error?.response) { + throw error; + } + } +}; + +export const createMeetup = async (data: LcMeetup, id: string) => { + try { + const response = await privateGateway.post( + dynamicRoute(lcRoutes.createMeet, id as string), + data + ); + const message: any = response?.data; + return message; + } catch (err) { + const error = err as AxiosError; + if (error?.response) { + throw error; + } + } +}; export const setLCMeetTime = async ( data: LcMeetSchedule, id: string | undefined diff --git a/src/modules/Dashboard/modules/LearningCircle/services/LearningCircleInterface.d.ts b/src/modules/Dashboard/modules/LearningCircle/services/LearningCircleInterface.d.ts index ae9f183f7..8962d6ff9 100644 --- a/src/modules/Dashboard/modules/LearningCircle/services/LearningCircleInterface.d.ts +++ b/src/modules/Dashboard/modules/LearningCircle/services/LearningCircleInterface.d.ts @@ -45,6 +45,7 @@ interface LcDashboardTempData { isTeam: boolean; isSchedule: boolean; reRender: boolean; + isCreateMeeting: boolean; } interface LcMeetSchedule { @@ -53,6 +54,35 @@ interface LcMeetSchedule { day: string; } +interface LcMeetup { + title: string; + location: string; + meet_time: string; + meet_place: string; + agenda: string; + need_pre_requirements: boolean; + pre_requirements: string | null; + is_public: boolean; + limit_attendees: boolean; + max_attendees: number; +} + +type LcMeetupInfo = LcMeetup & { + id: string; + is_started: boolean; + is_report_submitted: boolean; + meet_code: string | null; + image: string | null; +}; + +type LcMeetupDetailInfo = LcMeetupInfo & { + is_interested: boolean; + joined_at: string | null; + total_interested: number; + total_joined: number; + lc_members: number; + is_lc_member: boolean; +}; interface LcNote { note: string; id: string | undefined; @@ -64,13 +94,6 @@ interface ChecklistItem { isChecked: boolean; } -interface LcReport { - agenda: string; - attendees: string[]; - day: string; - meet_time: string; -} - interface LcPastReports { id: string; meet_time: string; diff --git a/src/services/endpoints.ts b/src/services/endpoints.ts index 5b6f557f7..9dcc901ef 100644 --- a/src/services/endpoints.ts +++ b/src/services/endpoints.ts @@ -1,3 +1,5 @@ +import { createMeetup } from "src/modules/Dashboard/modules/LearningCircle/services/LearningCircleAPIs"; + export const dynamicRoute = (route: string, ...args: string[]) => { let replacedRoute = route; args.forEach(arg => { @@ -9,12 +11,14 @@ export const dynamicRoute = (route: string, ...args: string[]) => { }; export const lcRoutes = { - createReport: "/api/v1/dashboard/lc/${LcID}/report/create/", + createReport: "/api/v1/dashboard/lc//meets/report/${meetId}/", getReport: "/api/v1/dashboard/lc/${LcID}/report/${ReportID}/show/", transferLead: "/api/v1/dashboard/lc/${LcID}/lead-transfer/${MemberID}/", approveRejectRemoveUser: "/api/v1/dashboard/lc/${LcID}/user-accept-reject/${MemberID}/", scheduleMeet: "/api/v1/dashboard/lc/${LcID}/schedule-meet/", + createMeet: "/api/v1/dashboard/lc/${LcID}/meet/create/", + getLcMeetups: "/api/v1/dashboard/lc/${LcID}/meet/list/", getDetailsUpdateNote: "/api/v1/dashboard/lc/${LcID}/details/" }; diff --git a/src/services/urls.ts b/src/services/urls.ts index c7d6d4baf..2ef8e3021 100644 --- a/src/services/urls.ts +++ b/src/services/urls.ts @@ -1,3 +1,5 @@ +import { joinMeetup } from "src/modules/Dashboard/modules/LearningCircle/services/LearningCircleAPIs"; + export const onboardingRoutes = { countryList: "/api/v1/register/country/list/", stateList: "/api/v1/register/state/list/", @@ -126,6 +128,10 @@ export const dashboardRoutes = { lc: "/api/v1/dashboard/lc/", searchLearningCircleWithCircleCode: "/api/v1/dashboard/lc/list-all/", getCampusLearningCircles: "/api/v1/dashboard/lc/", + getMeetups: "/api/v1/dashboard/lc/meets/list/", + getMeetupInfo: "/api/v1/dashboard/lc/meets/info/${meetId}/", + joinMeetup: "/api/v1/dashboard/lc/meets/join/${meetId}/", + interestedMeetup: "/api/v1/dashboard/lc/meets/interested/${meetId}/", getLearningCirclesLead: "/api/v1/dashboard/lc/lead/", createLearningCircle: "/api/v1/dashboard/lc/create/", listLearningCircle: "/api/v1/dashboard/lc/list-all/",