From 17a17ae055853c353f4c18b9b5dcc1584df33794 Mon Sep 17 00:00:00 2001 From: karivarkey Date: Sat, 25 May 2024 18:00:10 +0530 Subject: [PATCH 1/2] feat(dashboard): Added display of courses Added card format for courses in dashboard (wadhwani section) with wokring coourse links --- .../modules/Wadhwani/index.module.css | 88 ++++++++++--- .../Dashboard/modules/Wadhwani/index.tsx | 116 ++++++++++++++---- 2 files changed, 163 insertions(+), 41 deletions(-) diff --git a/src/modules/Dashboard/modules/Wadhwani/index.module.css b/src/modules/Dashboard/modules/Wadhwani/index.module.css index bcc7b7a09..456268457 100644 --- a/src/modules/Dashboard/modules/Wadhwani/index.module.css +++ b/src/modules/Dashboard/modules/Wadhwani/index.module.css @@ -3,31 +3,35 @@ font-size: 3rem; } +.course { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); + gap: 1rem; /* Combines row-gap and column-gap */ + justify-items: center; +} + + + + +.cardHeading{ + font-size: bold; + size: 10rem; +} + .container { display: flex; flex-wrap: wrap; justify-content: center; width: 100%; + max-height: 20v; } -.card { - width: 20vw; - margin: 1rem; - padding: 1rem; - border: 1px solid var(--Primary); - border-radius: 5px; - background-color: var(--White); - color: black; - cursor: pointer; -} -.card:hover { - background-color: aliceblue; -} @media screen and (max-width: 1300px) { - .card { + .container { width: 30vw; + height: 45vw; /* Adjust height to maintain aspect ratio */ } } @@ -35,13 +39,65 @@ .wrapper h1 { font-size: 2rem; } - .card { + .container { width: 70vw; + height: 105vw; /* Adjust height to maintain aspect ratio */ } } @media screen and (max-width: 500px) { - .card { + .container { width: 85vw; + height: 127.5vw; /* Adjust height to maintain aspect ratio */ } +} + + +.second_view_container { + margin-top: 3rem; + padding: 2rem; + background-color: #ffffff; +} + + + +.containercard { + font-family: Poppins, sans-serif; + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-between; + padding: 2rem; + border-radius: 10px; + gap: 1.5rem; + + box-shadow: 1px 1px 45px -5px rgb(0 0 0 / 8%); + -webkit-box-shadow: 1px 1px 45px -5px rgb(0 0 0 / 8%); + -moz-box-shadow: 1px 1px 45px -5px rgba(0, 0, 0, 0.08); +} + +.title { + font-weight: 500; + font-size: 30px; + margin-bottom: 0.5rem; +} + +.desc { + color: #404d61; + font-size: 0.9rem; +} + +.duration { + color: #404d61; + opacity: 0.5; + font-weight: 500; + margin-top: 0.5rem; + font-size: 0.9rem; +} + +.cta { + background: #456ff6; + color: white; + padding: 0.5rem 1rem; + border-radius: 5px; } \ No newline at end of file diff --git a/src/modules/Dashboard/modules/Wadhwani/index.tsx b/src/modules/Dashboard/modules/Wadhwani/index.tsx index 7196b6d71..59c9b1755 100644 --- a/src/modules/Dashboard/modules/Wadhwani/index.tsx +++ b/src/modules/Dashboard/modules/Wadhwani/index.tsx @@ -1,18 +1,44 @@ -import { useEffect, useState } from "react"; +import React, { useEffect, useState } from "react"; +import toast from "react-hot-toast"; +import styles from "./index.module.css"; +import MuLoader from "@/MuLearnComponents/MuLoader/MuLoader"; +import axios from "axios"; import { getWadhwaniClientToken, getWadhwaniCourseLink, getWadhwaniCourses -} from "./services/api"; -import toast from "react-hot-toast"; -import styles from "./index.module.css"; -import MuLoader from "@/MuLearnComponents/MuLoader/MuLoader"; +} from './services/api' + +interface CourseCardProps { + title: string; + desc: string; + duration: string; + rootId: string; +} + +interface WadhwaniCourseResponse { + courseId: string; + courseRootId: string; + courseName: string; + thumbnail: string; + description: string; +} +interface WadhwaniSheetResponse { + courseId: string; + courseRootId: string; + courseName: string; + thumbnail: string; + description: string; + CourseDuration: string; +} -const Wadhwani = () => { - const [data, setData] = useState([]); +const Wadhwani: React.FC = () => { + const [data, setData] = useState([]); const [clientToken, setClientToken] = useState(""); - const [isLoading,setIsLoading]=useState(true) + const [isLoading, setIsLoading] = useState(true); + const [sheet, setSheet] = useState([]); + useEffect(() => { fetchData(); @@ -30,41 +56,81 @@ const Wadhwani = () => { if (error) { toast.error(error); } else if (courses) { + try { + setIsLoading(true); + const response = await axios.get( + "https://opensheet.elk.sh/1LEvZozIVVquXjSvtptQcjiU0_WFaxVuEYBCYyCdsCtY/sheet" + ); + setSheet(response.data); + } catch (error) { + console.log(error); + } finally { + setIsLoading(false); + } setData(courses); } setIsLoading(false) } }; - const handleCourseSelection = async (course: wadhwaniCourseResponse) => { - const { response, error } = await getWadhwaniCourseLink( - clientToken, - course.courseRootId - ); + const handleCourseSelection = async (courseRootId: string) => { + const { response, error } = await getWadhwaniCourseLink(clientToken, courseRootId); if (error) { toast.error(error); + return null; } else if (response) { - window.open(response.data, "_blank", "noopener,noreferrer"); + console.log(response.data) + window.open(response.data, "_blank"); } }; + +function getRootIdByTitle(titleToSearch: string): string { + const course = data.find(course => course.courseName === titleToSearch); + console.log(course?.courseName + titleToSearch) + return course ? course.courseRootId : "null"; +} + + function stringSlice(inputString: string): string { + return inputString.substring(3, 200); + } + const CourseCard: React.FC = ({ title, desc, duration, rootId }) => { + return ( +
+
+

{title}

+

{desc}

+

{duration}hrs

+
+
handleCourseSelection(rootId)} className={styles.cta}> + Checkout Courses +
+
+ ); + }; + return (

Wadhwani Foundation Courses

-
- {isLoading?: - data.map(course => ( -
handleCourseSelection(course)} - > -

{course.courseName}

+
+
+
+
+ {sheet.map((sheet) => ( + + ))} +
- ))} +
); }; -export default Wadhwani; +export default Wadhwani; \ No newline at end of file From 9ea8ca65f2bf66752d53ab5a6d2f727112d73557 Mon Sep 17 00:00:00 2001 From: George Emmanuel Thomas Date: Fri, 31 May 2024 11:54:33 +0530 Subject: [PATCH 2/2] feat(DonationSuccess): success page added --- src/App.tsx | 5 + src/modules/Public/Donation/Donation.tsx | 32 ++- .../Donation/pages/DonationSuccess.module.css | 209 ++++++++++++++++++ .../Public/Donation/pages/DonationSuccess.tsx | 108 +++++++++ src/modules/Public/Donation/services/api.ts | 179 ++++++++------- 5 files changed, 449 insertions(+), 84 deletions(-) create mode 100644 src/modules/Public/Donation/pages/DonationSuccess.module.css create mode 100644 src/modules/Public/Donation/pages/DonationSuccess.tsx diff --git a/src/App.tsx b/src/App.tsx index 0a9ee81e8..2b58bc896 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -45,6 +45,7 @@ import Test from "./modules/Dashboard/modules/Test/Test"; import Analytics from "./modules/Dashboard/modules/UrlShortener/Pages/Analytics"; import Donation from "./modules/Public/Donation/Donation"; import Refund from "./modules/Public/Donation/pages/Refund"; +import DonationSuccess from "./modules/Public/Donation/pages/DonationSuccess"; const Profile = lazy( () => import("./modules/Dashboard/modules/Profile/pages/Profile") @@ -268,6 +269,10 @@ function App() { path: "donation", element: }, + { + path: "donation/success", + element: + }, { path: "donation/refund", element: diff --git a/src/modules/Public/Donation/Donation.tsx b/src/modules/Public/Donation/Donation.tsx index cb73d64e8..ff489502f 100644 --- a/src/modules/Public/Donation/Donation.tsx +++ b/src/modules/Public/Donation/Donation.tsx @@ -255,13 +255,31 @@ const Donation = () => {
diff --git a/src/modules/Public/Donation/pages/DonationSuccess.module.css b/src/modules/Public/Donation/pages/DonationSuccess.module.css new file mode 100644 index 000000000..d07430fe2 --- /dev/null +++ b/src/modules/Public/Donation/pages/DonationSuccess.module.css @@ -0,0 +1,209 @@ +.LClandingPage { + position: relative; + overflow-x: hidden; +} + +.backgroundImage { + top: 0; + position: absolute; + z-index: -2; +} + +.backgroundImage img { + width: 100vw; + height: 110vh; +} + +.LClandingPageHero { + position: relative; + height: 100vh; + width: 100%; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + text-align: center; + gap: 1rem; + padding-top: 5rem; +} + +.LClandingPageHero span { + display: flex; + align-items: center; + justify-content: center; + gap: 1rem; + font-size: 3.5rem; + color: #000; +} + +.LClandingPageHero span img { + position: relative; + top: 0.75rem; + height: 3rem; +} + +.LClandingPageHero .dash { + position: absolute; + top: -50%; + width: 120%; + height: 100%; + border: 5px solid #accaf6; + border-style: dashed; + border-radius: 45%; +} + +.LClandingPageHero .heroTitle b:nth-child(2) { + font-size: 4rem; + color: var(--blue); + position: relative; + top: -1rem; + background-image: linear-gradient(to right, #ddecff, #eaf3ff); + border-radius: 10%; + height: -1rem; + padding: 0rem 0.5rem; +} + +.LClandingPageHero p { + width: 75%; + font-weight: 600; + font-size: 1.1rem; +} + +.DonationSection { + display: flex; + justify-content: center; + margin-bottom: 6rem; +} + +.DonationFormElement { + background: #fff; + box-shadow: -1.6px 6.4px 32px 3.2px rgba(0, 0, 0, 0.15); + width: 80%; + padding: 2rem; + text-align: center; + border-radius: 1rem; +} + +.SuccessMessage { + margin-bottom: 2rem; +} + +.SuccessMessage h1 { + font-size: 2rem; + margin-bottom: 0.5rem; +} + +.SuccessMessage p { + font-size: 1.2rem; + color: #666; +} + +.ButtonContainer { + display: flex; + justify-content: center; + gap: 1rem; /* Added gap between buttons */ +} + +.homeButton { + background-color: var(--blue); + color: #fff; + border: none; + border-radius: 0.5rem; + padding: 0.9rem 1.4rem; + font-size: 1.2rem; + cursor: pointer; + transition: background-color 0.3s ease; +} + +.homeButton:hover { + background-color: #004aad; +} + +.downloadButton { + background-color: #fff; + width: auto; + color: var(--blue); + border: 2px solid var(--blue); + border-radius: 0.5rem; + padding: 0.9rem 1.4rem; + margin-bottom: 1rem; +} + +.downloadButton:hover { + background-color: var(--blue); + color: #fff; +} + +@media (max-width: 820px) { + .LClandingPageHero span { + font-size: 1.7rem; + gap: 0.5rem; + } + + .LClandingPageHero span img { + top: 0.5rem; + height: 2.2rem; + } + + .LClandingPageHero .heroTitle b:nth-child(2) { + font-size: 2.5rem; + top: 0rem; + } + + .LClandingPageHero p { + width: 90%; + font-size: 0.8rem; + } + + .DonationFormElement { + width: 90%; + } + + .homeButton, + .downloadButton { + font-size: 1rem; + padding: 0.7rem 1.2rem; + } +} + +@media (max-width: 550px) { + .LClandingPageHero span { + font-size: 1.5rem; + } + + .LClandingPageHero span img { + top: 0.3rem; + height: 2rem; + } + + .DonationFormElement { + padding: 1.5rem; + } + + .homeButton, + .downloadButton { + font-size: 0.9rem; + padding: 0.5rem 1rem; + } +} + +@media (max-width: 380px) { + .LClandingPageHero span { + font-size: 1.2rem; + } + + .LClandingPageHero span img { + top: 0.1rem; + height: 1.5rem; + } + + .DonationFormElement { + padding: 1rem; + } + + .homeButton, + .downloadButton { + font-size: 0.8rem; + padding: 0.4rem 0.8rem; + } +} diff --git a/src/modules/Public/Donation/pages/DonationSuccess.tsx b/src/modules/Public/Donation/pages/DonationSuccess.tsx new file mode 100644 index 000000000..d26d1bd67 --- /dev/null +++ b/src/modules/Public/Donation/pages/DonationSuccess.tsx @@ -0,0 +1,108 @@ +import { Link } from "react-router-dom"; +import { useEffect } from "react"; +import Footer from "../components/Footer"; +import Navbar from "../components/Navbar"; +import styles from "./DonationSuccess.module.css"; +import NotFound from "../../../../components/NotFound"; + +const DonationSuccess = () => { + const pdfData = localStorage.getItem("pdfData"); + + const base64toBlob = (base64data: any) => { + const byteString = atob(base64data.split(",")[1]); + const mimeType = base64data.split(",")[0].split(":")[1].split(";")[0]; + const arrayBuffer = new ArrayBuffer(byteString.length); + const uint8Array = new Uint8Array(arrayBuffer); + for (let i = 0; i < byteString.length; i++) { + uint8Array[i] = byteString.charCodeAt(i); + } + return new Blob([arrayBuffer], { type: mimeType }); + }; + + const downloadReceipt = () => { + const base64data = localStorage.getItem("pdfData"); + + if (base64data) { + const pdfBlob = base64toBlob(base64data); + const pdfUrl = URL.createObjectURL(pdfBlob); + const link = document.createElement("a"); + link.href = pdfUrl; + link.download = "downloaded-file.pdf"; + + document.body.appendChild(link); + link.click(); + + document.body.removeChild(link); + } else { + console.error("No PDF data found in localStorage."); + } + }; + + const handleUnload = () => { + localStorage.removeItem("pdfData"); + }; + + useEffect(() => { + window.addEventListener("beforeunload", handleUnload); + return () => { + window.removeEventListener("beforeunload", handleUnload); + }; + }, []); + + return pdfData ? ( +
+ + +
+
+ textured background +
+
+
+ + Thank You!{" "} + + We appreciate your support +
+

+ Your donation was successful. A confirmation email has been + sent. +

+
+ +
+
+
+

Success!

+

+ Thank you for your donation. Your support means a + lot to us. +

+
+
+ + + + +
+
+
+ +
+
+ ) : ( +
+ +
+ ); +}; + +export default DonationSuccess; diff --git a/src/modules/Public/Donation/services/api.ts b/src/modules/Public/Donation/services/api.ts index 49c52d3d0..aa967f9ae 100644 --- a/src/modules/Public/Donation/services/api.ts +++ b/src/modules/Public/Donation/services/api.ts @@ -3,10 +3,10 @@ import { publicGateway } from "@/MuLearnServices/apiGateways"; import { donationRoutes } from "@/MuLearnServices/urls"; declare global { - interface Window { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - Razorpay: any; - } + interface Window { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + Razorpay: any; + } } export const submitForm = async ({ @@ -15,88 +15,113 @@ export const submitForm = async ({ company, email, mobile, - pan + pan }: { - amount: number; - name: string; - company?: string; - email: string; - mobile: number; - pan: string; - + amount: number; + name: string; + company?: string; + email: string; + mobile: number; + pan: string; }) => { + const script = document.createElement("script"); + script.src = "https://checkout.razorpay.com/v1/checkout.js"; + document.body.appendChild(script); + + publicGateway + .post(donationRoutes.order, { + amount, + name, + company, + email, + mobile + }) + .then(response => { + const paymentId: string = response.data.response.id; + const paymentAmount: string = response.data.response.amount; - const script = document.createElement('script'); - script.src = 'https://checkout.razorpay.com/v1/checkout.js'; - document.body.appendChild(script); + const options = { + key_id: import.meta.env.VITE_RAZORPAY_KEY_ID, + amount: paymentAmount, + currency: response.data.response.currency, + name: "Mulearn Foundation", + description: "Donation", + image: "/assets/µLearn.png", + order_id: paymentId, + handler: function (response: any) { + console.log(response); - publicGateway - .post(donationRoutes.order, { - amount, - name, - company, - email, - mobile - }) - .then((response) => { - const paymentId: string = response.data.response.id; - const paymentAmount: string = response.data.response.amount; + publicGateway + .post(donationRoutes.verify, { + razorpay_order_id: response.razorpay_order_id, + razorpay_payment_id: response.razorpay_payment_id, + razorpay_signature: response.razorpay_signature + }) + .then(res => { + console.log(res?.data); + toast.success( + res?.data?.message?.general[0] || + "Payment Successful" + ); + // Assuming response.data contains the PDF data - const options = { - key_id: import.meta.env.VITE_RAZORPAY_KEY_ID, - amount: paymentAmount, - currency: response.data.response.currency, - name: 'Mulearn Foundation', - description: 'Donation', - image: '/assets/µLearn.png', - order_id: paymentId, - handler: function (response: any) { - console.log(response); + const pdfData = res?.data; - publicGateway - .post(donationRoutes.verify, { - razorpay_order_id: response.razorpay_order_id, - razorpay_payment_id: response.razorpay_payment_id, - razorpay_signature: response.razorpay_signature, - }) - .then((res) => { - console.log(res?.data); - toast.success(res?.data?.message?.general[0] || 'Payment Successful'); - // Assuming response.data contains the PDF data + // Create a new blob from the PDF data + const pdfBlob = new Blob([pdfData], { + type: "application/pdf" + }); - const pdfData = res?.data; + // // Create a URL for the blob + // const pdfUrl = URL.createObjectURL(pdfBlob); - // Create a new blob from the PDF data - const pdfBlob = new Blob([pdfData], { type: 'application/pdf' }); + // // Open the PDF in a new window or tab + // // window.open(pdfUrl, '_blank'); + // const link = document.createElement("a"); + // link.href = pdfUrl; + // link.download = "downloaded-file.pdf"; // Provide a filename here + // document.body.appendChild(link); + // link.click(); + // document.body.removeChild(link); + // window.location.href = "/donation/success"; - // Create a URL for the blob - const pdfUrl = URL.createObjectURL(pdfBlob); + // Convert blob data to a base64 string + const reader = new FileReader(); + reader.onloadend = function () { + const base64data = reader.result; + if (base64data) { + localStorage.setItem( + "pdfData", + base64data as string + ); - // Open the PDF in a new window or tab - // window.open(pdfUrl, '_blank'); - const link = document.createElement('a'); - link.href = pdfUrl; - link.download = 'downloaded-file.pdf'; // Provide a filename here - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - }) - .catch((error) => { - console.log(error); - toast.error( - JSON.stringify(error) || 'Error in Validating Payment', - ); - }); - }, - theme: { - color: '#456ff6', - }, - }; + window.location.href = "/donation/success"; + } else { + console.error("Failed to read PDF data."); + } + }; + reader.readAsDataURL(pdfBlob); + }) + .catch(error => { + console.log(error); + toast.error( + JSON.stringify(error) || + "Error in Validating Payment" + ); + }); + }, + theme: { + color: "#456ff6" + } + }; - const rzp1 = new window.Razorpay(options); - rzp1.open(); - }) - .catch((error) => { - toast.error(error?.response?.data?.message?.general[0] || 'Error in Registering Event'); - }); + const rzp1 = new window.Razorpay(options); + rzp1.open(); + }) + .catch(error => { + toast.error( + error?.response?.data?.message?.general[0] || + "Error in Registering Event" + ); + }); };