From ba9973bc2167f8d3fad47d27fed48d3b591715da Mon Sep 17 00:00:00 2001 From: faisalEsMagico Date: Mon, 20 Nov 2023 12:20:45 +0530 Subject: [PATCH 01/28] feat(3cp): settlement ui --- public/images/group-profile-users.png | Bin 0 -> 9097 bytes src/app/3cp/layout.tsx | 14 ++ src/app/3cp/settlements/page.tsx | 28 +++ src/app/setup-new-configuration/page.tsx | 38 ++-- src/app/wpcas/page.tsx | 2 +- src/components/navbar/SideNavbar.tsx | 84 +++++++- .../settlements/SettlementsTable.tsx | 194 ++++++++++++++++++ src/components/wpcasOverView/SearchUser.tsx | 5 +- src/components/wpcasOverView/UserTable.tsx | 1 + src/components/wpcasOverView/WpcasNavbar.tsx | 4 +- src/services/configurationServices.ts | 12 +- 11 files changed, 344 insertions(+), 38 deletions(-) create mode 100644 public/images/group-profile-users.png create mode 100644 src/app/3cp/layout.tsx create mode 100644 src/app/3cp/settlements/page.tsx create mode 100644 src/components/settlements/SettlementsTable.tsx diff --git a/public/images/group-profile-users.png b/public/images/group-profile-users.png new file mode 100644 index 0000000000000000000000000000000000000000..af0e1a4bba22a271ba6a36d99c0eecc3b7202438 GIT binary patch literal 9097 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 + + {children} + + ); +} diff --git a/src/app/3cp/settlements/page.tsx b/src/app/3cp/settlements/page.tsx new file mode 100644 index 0000000..14e82da --- /dev/null +++ b/src/app/3cp/settlements/page.tsx @@ -0,0 +1,28 @@ +'use client'; +import React from 'react'; + +import SettlementsTable from '@/components/settlements/SettlementsTable'; + +const Settlesments = () => { + // const [filterUserData, setFilterUserData] = useState([]) + // const [loading,setLoading]=useState(false) + // const [error,setError]=useState(false) + + return ( + <> + {/* {loading &&
Loading...
} */} + {/* {error &&
Error...
} */} + {/* {!loading && !error && ( */} +
+ value} + /> +
+ {/* // )} */} + + ); +}; + +export default Settlesments; diff --git a/src/app/setup-new-configuration/page.tsx b/src/app/setup-new-configuration/page.tsx index 2b738e9..7e0394f 100644 --- a/src/app/setup-new-configuration/page.tsx +++ b/src/app/setup-new-configuration/page.tsx @@ -1,7 +1,6 @@ 'use client'; import exportFromJSON from 'export-from-json'; import React, { useState } from 'react'; -import { toast } from 'react-toastify'; import { outfit } from '@/components/FontFamily'; import SubNavbar from '@/components/navbar/SubNavbar'; @@ -12,7 +11,10 @@ import CommonModal from '@/components/uiComponents/CommonModal'; import SetupConfigurationForm from '@/components/wpcasOverView/SetupConfigurationForm'; import SurveyTable from '@/components/wpcasOverView/SurveyTable'; -import { downloadAssessesList } from '@/services/configurationServices'; +import { + downloadAssessesList, + downloadUserList, +} from '@/services/configurationServices'; const assessmentGuidelines = [ 'Duis 2 aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat', @@ -41,12 +43,11 @@ const SetupNewSurvey = ({ visible }: { visible: boolean }) => { const handleAssessesFileDownload = () => { (async () => { - const response = await downloadAssessesList(); - const data = response?.data; + const data = await downloadAssessesList(); const fileName = 'assesses-file-template'; const exportType = exportFromJSON.types.csv; exportFromJSON({ data, fileName, exportType }); - toast.success(response?.message); + // toast.success(response?.message); })(); }; @@ -57,20 +58,19 @@ const SetupNewSurvey = ({ visible }: { visible: boolean }) => { // for download userList const handleUserListDownload = () => { - return null; - // (async () => { - // const response = await downloadUserList(); - // const data = response?.map((item: DownloadUserListType) => { - // return { - // ...item, - // Level: item?.Level?.levelNumber, - // Department: item?.Department?.name, - // }; - // }); - // const fileName = 'user-list'; - // const exportType = exportFromJSON.types.csv; - // exportFromJSON({ data, fileName, exportType }); - // })(); + (async () => { + const data = await downloadUserList(); + // const data = response?.map((item: DownloadUserListType) => { + // return { + // ...item, + // Level: item?.Level?.levelNumber, + // Department: item?.Department?.name, + // }; + // }); + const fileName = 'user-list'; + const exportType = exportFromJSON.types.csv; + exportFromJSON({ data, fileName, exportType }); + })(); }; return ( diff --git a/src/app/wpcas/page.tsx b/src/app/wpcas/page.tsx index 0ae936b..a6fe060 100644 --- a/src/app/wpcas/page.tsx +++ b/src/app/wpcas/page.tsx @@ -62,7 +62,7 @@ const Wpcas = () => { return (
- + {loading &&
Loading...
} {error &&
Error...
} {!loading && !error && ( diff --git a/src/components/navbar/SideNavbar.tsx b/src/components/navbar/SideNavbar.tsx index 657acdf..e91947b 100644 --- a/src/components/navbar/SideNavbar.tsx +++ b/src/components/navbar/SideNavbar.tsx @@ -8,9 +8,7 @@ import { outfit, oxanium } from '../../components/FontFamily'; import ListIcon from '~/svg/admin.svg'; import DashboardIcon from '~/svg/dashboardIcon.svg'; -import MarketPlaceIcon from '~/svg/marketplaceIcon.svg'; import UserIcon from '~/svg/userIcon.svg'; -import WalletIcon from '~/svg/walletIcon.svg'; import WpcasIcon from '~/svg/wpcasIcon.svg'; const SideNavbar = () => { @@ -27,9 +25,56 @@ const SideNavbar = () => { Dashboard{' '} - - Market Place{' '} - +
  • +
    + + 3CP +
    +
  • +
  • +
      + +
    • + + Marketplace +
    • + + +
    • + + Settlements +
    • + + +
    • + + Account Verification +
    • + +
    +
  • {
  • - +
  • +
    + + User Management +
    +
  • +
  • +
      + +
    • + + User Wallet +
    • + +
    +
  • + {/* User Information Payment - +
    */}
    diff --git a/src/components/settlements/SettlementsTable.tsx b/src/components/settlements/SettlementsTable.tsx new file mode 100644 index 0000000..f88a575 --- /dev/null +++ b/src/components/settlements/SettlementsTable.tsx @@ -0,0 +1,194 @@ +'use client'; + +import Image from 'next/image'; +import React, { useState } from 'react'; + +import { outfit } from '@/components/FontFamily'; +import ButtonFill from '@/components/uiComponents/ButtonFill'; +import Pagination from '@/components/wpcasOverView/Pagination'; +import SearchUser from '@/components/wpcasOverView/SearchUser'; + +import groupProfileImage from '~/images/group-profile-users.png'; +export type UserListType = { + userId: string; + userName: string; + wpcasScore: string; + surveysFilled: number; + surveysToBeFilled: number; + dateOfJoining: Date; + isNewEmployee: boolean; + designation: string; + isAdmin: boolean; + profilePicture: string; +}; + +type PropType = { + userData: UserListType[]; + filterUserData: UserListType[]; + setFilterUserData: (arg: UserListType[]) => void; +}; + +const SettlementsTable = ({ + userData, + setFilterUserData, + filterUserData, +}: PropType) => { + const [currentPage, setCurrentPage] = useState(1); + const [pageSize, setPageSize] = useState(5); + const [searchInput, setSearchInput] = useState(''); + + const totalPages = Math.ceil(filterUserData?.length / pageSize); + const startIndex = (currentPage - 1) * pageSize; + const endIndex = startIndex + pageSize; + const currentData = filterUserData?.slice(startIndex, endIndex); + + const handleSearch = (value: string) => { + const newData = userData?.filter((item) => { + const nameMatch = item?.userName + ?.toLowerCase() + .includes(value.toLowerCase()); + return nameMatch; + }); + setSearchInput(value); + setFilterUserData(newData); + if (currentPage != 1) setCurrentPage(1); + }; + + return ( + <> + handleSearch(value)} + // handleSearch={() => null} + placeholder='Search Course Provider' + /> +
    + + + + + + + + + + + + + {currentData.length == 0 && ( + + + + )} + {currentData.length > 0 && + currentData?.map((user: UserListType) => { + return ( + + + + + + + + + + ); + })} + + + + + + + + + + + +
    + Sr No + + Third Party Course Providers + + Total Courses + + Active Users + + Total Credits +
    + No Result Found +
    + {user?.userId} + + {user?.userName} + + {user?.wpcasScore ? user?.wpcasScore : '--'} + + {user?.surveysFilled} + + {user?.surveysToBeFilled} + + {new Date(user?.dateOfJoining).toLocaleDateString( + 'en-GB' + )} +
    + 1 + +
    + img + Unacademy +
    +
    + 16 + + 45 + + 4500 + + null} classes='bg-[#26292D]'> + Settle + +
    + setPageSize(value)} + pageSize={pageSize} + totalPages={totalPages} + currentPage={currentPage} + handlePage={(value: number) => setCurrentPage(value)} + /> +
    + + ); +}; + +export default SettlementsTable; diff --git a/src/components/wpcasOverView/SearchUser.tsx b/src/components/wpcasOverView/SearchUser.tsx index 28a46d5..2aa3a21 100644 --- a/src/components/wpcasOverView/SearchUser.tsx +++ b/src/components/wpcasOverView/SearchUser.tsx @@ -7,19 +7,20 @@ type PropType = { value: string; onChange: (arg: string) => void; // handleSearch: () => void; + placeholder: string; }; // import ButtonFill from '@/components/uiComponents/ButtonFill'; // import SearchIcon from '~/svg/searchIcon.svg'; -const SearchUser = ({ value, onChange }: PropType) => { +const SearchUser = ({ value, onChange, placeholder }: PropType) => { return (
    onChange(updatedValue)} - placeholder='Search User' + placeholder={placeholder} /> {/*
    diff --git a/src/components/wpcasOverView/UserTable.tsx b/src/components/wpcasOverView/UserTable.tsx index 8bed0d3..e2e1ce5 100644 --- a/src/components/wpcasOverView/UserTable.tsx +++ b/src/components/wpcasOverView/UserTable.tsx @@ -55,6 +55,7 @@ const UserTable = ({ <> handleSearch(value)} // handleSearch={() => null} /> diff --git a/src/components/wpcasOverView/WpcasNavbar.tsx b/src/components/wpcasOverView/WpcasNavbar.tsx index 3785685..a8b3432 100644 --- a/src/components/wpcasOverView/WpcasNavbar.tsx +++ b/src/components/wpcasOverView/WpcasNavbar.tsx @@ -7,11 +7,11 @@ import AdminSelect from '@/components/uiComponents/AdminSelect'; import BellLogo from '~/svg/bellLogo.svg'; -const WpcasNavbar = () => { +const WpcasNavbar = ({ heading }: { heading: string }) => { return (
    From b3de4eed5d70186bdbefa9e7f2e7c7755015dc4d Mon Sep 17 00:00:00 2001 From: Ankitml Date: Fri, 24 Nov 2023 08:13:35 +0530 Subject: [PATCH 06/28] feat(account section): final touchup --- src/components/3cp/SingleAccount.tsx | 77 +++++++++++++--------------- 1 file changed, 36 insertions(+), 41 deletions(-) diff --git a/src/components/3cp/SingleAccount.tsx b/src/components/3cp/SingleAccount.tsx index 1eed620..3af42db 100644 --- a/src/components/3cp/SingleAccount.tsx +++ b/src/components/3cp/SingleAccount.tsx @@ -1,5 +1,5 @@ import Image from 'next/image'; -import { useState } from 'react'; +import React, { useState } from 'react'; import RejectedReason from '@/components/3cp/RejectedReason'; import RejectSummary from '@/components/3cp/RejectSummary'; @@ -37,6 +37,7 @@ const SingleAccount = ({ heading='Account Rejection Reason' /> + {/* head line */}
    -
    -

    - Name of moderator -

    -

    {account?.name}

    -
    -
    -

    Email Id

    -

    {account?.email}

    -
    -
    -

    Phone

    -

    {account?.Phone}

    -
    + + {account?.name} + + {account?.email} + {account?.Phone}
    -
    -

    Bank

    -

    {account?.bank}

    -
    -
    -

    Branch

    -

    {account?.branch}

    -
    -
    -

    - Account Number -

    -

    {account?.accountNumber}

    -
    + {account?.bank} + {account?.branch} + + {account?.accountNumber} +
    -
    -

    IFSC Code

    -

    {account?.ifscCode}

    -
    -
    -

    PAN Number

    -

    {account?.panNumber}

    -
    -
    -

    GST Number

    -

    {account?.gstNumber}

    -
    + + {account?.ifscCode} + + + {account?.panNumber} + + + {account?.gstNumber} +
    @@ -138,4 +118,19 @@ const SingleAccount = ({
    ); }; + +const SingleDetail = ({ + children, + subHeading, +}: { + children: React.ReactNode; + subHeading: string; +}) => { + return ( +
    +

    {subHeading}

    +

    {children}

    +
    + ); +}; export default SingleAccount; From 913e824209c6c5e654ac1e3b96f0de51e1e5bc8a Mon Sep 17 00:00:00 2001 From: Ankitml Date: Sat, 25 Nov 2023 13:16:25 +0530 Subject: [PATCH 07/28] feat(marketplace admin): integration --- src/app/marketplace/page.tsx | 117 ++++++-------------- src/components/3cp/Competency.tsx | 39 ++----- src/components/3cp/CourseItems.tsx | 5 +- src/components/3cp/CourseSection.tsx | 61 +++++++++- src/components/3cp/RejectSummary.tsx | 10 +- src/components/3cp/RejectedReason.tsx | 40 +++++-- src/components/3cp/ReviewCourse.tsx | 81 ++++++++------ src/components/3cp/SearchCourse.tsx | 17 ++- src/components/3cp/SingleCompetency.tsx | 13 +-- src/components/3cp/SingleCourse.tsx | 52 +++++---- src/components/navbar/MarketPlaceNavbar.tsx | 34 ++---- src/services/marketPlaceServices.ts | 20 ++++ 12 files changed, 266 insertions(+), 223 deletions(-) create mode 100644 src/services/marketPlaceServices.ts diff --git a/src/app/marketplace/page.tsx b/src/app/marketplace/page.tsx index be43d3b..cd46533 100644 --- a/src/app/marketplace/page.tsx +++ b/src/app/marketplace/page.tsx @@ -1,111 +1,59 @@ 'use client'; -import axios from 'axios'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; +import { toast } from 'react-toastify'; import CourseSection from '@/components/3cp/CourseSection'; import MarketPlaceNavbar from '@/components/navbar/MarketPlaceNavbar'; import WpcasNavbar from '@/components/wpcasOverView/WpcasNavbar'; +import { getAllCourses } from '@/services/marketPlaceServices'; + +type competencyType = { + [key: string]: string[]; +}; + export type CourseType = { - courseId: number; - course_name: string; - competency_list: string[]; - course_provider: string; + id: number; + title: string; + competency: competencyType; + CourseProvider: string; author: string; language: string[]; - rating: number; - credit: number; - status: string; -}; -const getinitialValule = () => { - return [ - { - courseId: 1, - course_name: 'Mastering Data Structures with Advanced Python Programming', - competency_list: [ - 'Advanced Data Structures for Efficient Algorithms', - 'Algorithmic Problem Solving with Python', - 'Data Manipulation and Analysis Techniques', - 'Optimizing Code Performance', - 'Python Programming Best Practices', - ], - course_provider: 'Coursera', - author: 'Smith', - language: ['English', 'Spanish'], - rating: 4.5, - credit: 75, - status: 'approved', - }, - { - courseId: 2, - course_name: - 'Building Scalable and Responsive Applications in Full Stack Web Development', - competency_list: [ - 'Fundamentals of HTML5 Markup', - 'CSS3 Styling Techniques', - 'Modern JavaScript Development', - 'Server-Side Development with Node.js', - 'Client-Server Communication', - ], - course_provider: 'edX', - author: 'Johnson', - language: ['English', 'French'], - rating: 4.2, - credit: 60, - status: 'pending', - }, - { - courseId: 3, - course_name: - 'Financial Management: Strategic Budgeting, Investing, and Retirement Planning', - competency_list: [ - 'Effective Budgeting Strategies', - 'Strategic Investment Planning', - 'Retirement Income Optimization', - 'Financial Decision-Making Skills', - ], - course_provider: 'Udemy', - author: 'Miller', - language: ['English', 'Chinese'], - rating: 4.8, - credit: 90, - status: 'rejected', - }, - ]; + avgRating: number; + credits: number; + verificationStatus: string; + imgLink: string; + description: string; + rejectionReason?: string; }; const MarketPlace = () => { - const [activeSection, setActiveSection] = useState('pendingSection'); - const [currentCourseList, setCurrentCourseList] = useState( - getinitialValule() - ); - const [courseList, setCourseList] = useState( - getinitialValule() - ); + const [activeSection, setActiveSection] = useState('PENDING'); + const [currentCourseList, setCurrentCourseList] = useState([]); + const [courseList, setCourseList] = useState([]); const fetchData = async () => { try { - const response = await axios.get('http://127.0.0.1:3001/courses'); - - const pendingCourses = response.data.filter( - (course: CourseType) => course.status === 'pending' - ); - setCurrentCourseList(pendingCourses); - setCourseList(response.data); + const response = await getAllCourses(); + const filterResult = response.filter((course: CourseType) => { + return course.verificationStatus === activeSection; + }); + setCurrentCourseList(filterResult); + setCourseList(response); } catch (error) { - // console.error('Error fetching data:', error); + toast.error('something went wrong'); } }; const filterCourse = (courseType: string) => { const filteredResult = courseList.filter((course: CourseType) => { - return course.status === courseType; + return course.verificationStatus === courseType; }); setCurrentCourseList(filteredResult); }; - useEffect(() => { - fetchData(); - }, []); + // useEffect(() => { + // fetchData(); + // }, []); return (
    @@ -119,6 +67,7 @@ const MarketPlace = () => {
    diff --git a/src/components/3cp/Competency.tsx b/src/components/3cp/Competency.tsx index ebc0d83..14db58a 100644 --- a/src/components/3cp/Competency.tsx +++ b/src/components/3cp/Competency.tsx @@ -1,38 +1,19 @@ import SingleCompetency from '@/components/3cp/SingleCompetency'; -const competencies = [ - { - key: 1, - name: 'Pregnancy Identification', - levels: [ - 'Understands health of males and females and initial assessment protocols', - 'Identifies pregnancy using Nischaya Kit', - ], - }, - { - key: 3, - name: 'Pregnancy Identification', - levels: [ - 'Understands health of males and females and initial assessment protocols', - 'Identifies pregnancy using Nischaya Kit', - ], - }, - { - key: 2, - name: 'Pregnancy Identification', - levels: [ - 'Understands health of males and females and initial assessment protocols', - 'Identifies pregnancy using Nischaya Kit', - ], - }, -]; +import { CourseType } from '@/app/marketplace/page'; -const Competencies = () => { +const Competencies = ({ courseDetails }: { courseDetails: CourseType }) => { return (
    - {competencies.map((competency) => { + {Object.keys(courseDetails?.competency).map((key, index) => { return ( - + ); })}
    diff --git a/src/components/3cp/CourseItems.tsx b/src/components/3cp/CourseItems.tsx index 6fec411..5d74405 100644 --- a/src/components/3cp/CourseItems.tsx +++ b/src/components/3cp/CourseItems.tsx @@ -5,18 +5,21 @@ import SingleCourse from './SingleCourse'; const CourseItems = ({ activeSection, courseList, + fetchData, }: { activeSection: string; courseList: CourseType[]; + fetchData: () => void; }) => { return (
    {courseList.map((course) => { return ( ); })} diff --git a/src/components/3cp/CourseSection.tsx b/src/components/3cp/CourseSection.tsx index 346593f..b9abac2 100644 --- a/src/components/3cp/CourseSection.tsx +++ b/src/components/3cp/CourseSection.tsx @@ -5,6 +5,7 @@ import SearchCourse from '@/components/3cp/SearchCourse'; import { outfit } from '@/components/FontFamily'; import { CourseType } from '@/app/marketplace/page'; +import { OptionType } from '@/app/propTypes'; import EmptyBox from '~/svg/emptyBox.svg'; @@ -20,38 +21,86 @@ const getEmptyValue = () => { const CourseSection = ({ activeSection, courseList, + fetchData, }: { activeSection: string; courseList: CourseType[]; + fetchData: () => void; }) => { const [input, setInput] = useState(getEmptyValue()); + const [competencyOption, setCompetencyOption] = useState([]); + const [languageOption, setLanguageOption] = useState([]); const [filterCourse, setFilterCourse] = useState([]); const handleSearch = () => { - // // filter based on the input - // //filter from above courseList and set in present course list - // // console.log(input); - // // setFilterCourse([]); + const filteredCourses = courseList.filter((course) => { + const courseTitleLower = course.title.toLowerCase(); + const inputCourseLower = input.course.toLowerCase(); + const competencyMatch = + input.competency === '' || + course.competency[input.competency]?.length > 0; + + const languageMatch = + input.language === '' || course.language.includes(input.language); + + return ( + courseTitleLower.includes(inputCourseLower) && + competencyMatch && + languageMatch + ); + }); + + setFilterCourse(filteredCourses); }; useEffect(() => { + const allCompetencies: string[] = courseList.reduce( + (competencies, course) => + competencies.concat(Object.keys(course.competency)), + [] + ); + const uniqueCompetencies: string[] = Array.from(new Set(allCompetencies)); + + const competencyOptions: OptionType[] = uniqueCompetencies.map( + (competency) => ({ + label: competency, + value: competency, + }) + ); + const allLanguages: string[] = courseList.reduce( + (languages, course) => languages.concat(course.language), + [] + ); + + const uniqueLanguages: string[] = Array.from(new Set(allLanguages)); + + const languageOptions: OptionType[] = uniqueLanguages.map((language) => ({ + label: language, + value: language, + })); + + setLanguageOption(languageOptions); + setCompetencyOption(competencyOptions); setFilterCourse(courseList); }, [courseList]); return (
    - {filterCourse.length !== 0 ? ( + {courseList?.length !== 0 ? (

    - {courseList.length} Courses + {filterCourse?.length} Courses

    ) : ( diff --git a/src/components/3cp/RejectSummary.tsx b/src/components/3cp/RejectSummary.tsx index 6a12243..a2e43ca 100644 --- a/src/components/3cp/RejectSummary.tsx +++ b/src/components/3cp/RejectSummary.tsx @@ -1,6 +1,6 @@ import { outfit } from '@/components/FontFamily'; -const RejectSummary = () => { +const RejectSummary = ({ summary }: { summary?: string | undefined }) => { return (
    { Rejection Reason:
    -
    - Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi - ut aliquip ex ea commodo con Lorem ipsum dolor sit amet, consectetur - adipiscing elit, sed do eiusmod tempor incididunt ut labore Lorem ipsum - dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor - incididunt ut labore{' '} -
    +
    {summary ? summary : '==='}
    ); }; diff --git a/src/components/3cp/RejectedReason.tsx b/src/components/3cp/RejectedReason.tsx index ab2966f..b74147b 100644 --- a/src/components/3cp/RejectedReason.tsx +++ b/src/components/3cp/RejectedReason.tsx @@ -1,21 +1,39 @@ import { useState } from 'react'; +import { toast } from 'react-toastify'; import { outfit } from '@/components/FontFamily'; import ButtonFill from '@/components/uiComponents/ButtonFill'; import ButtonOutline from '@/components/uiComponents/ButtonOutline'; +import { rejectCourse } from '@/services/marketPlaceServices'; + const RejectedReason = ({ setShowReviewReasonPopUp, heading, + id, + fetchData, }: { setShowReviewReasonPopUp: (value: boolean) => void; heading?: string; + id?: number; + fetchData?: () => void; }) => { const [text, setText] = useState(''); + const [error, setError] = useState(false); - const handleProceedButton = () => { + const handleProceedButton = async () => { //call api to handle the proceed button - setShowReviewReasonPopUp(false); + if (text === '' || !id || !fetchData) { + setError(true); + return; + } + try { + await rejectCourse(id, text); + await fetchData(); + setShowReviewReasonPopUp(false); + } catch (error) { + toast.error('somethings went wrong'); + } }; return (
    @@ -30,15 +48,23 @@ const RejectedReason = ({ Rejection Reason + {error && ( +
    + Rejection Reason should not be Empty +
    + )}
    void; setShowReviewReasonPopUp: (value: boolean) => void; + fetchData: () => void; }) => { - const handleApprovedButton = () => { - setShowPreviewPopUp(false); + const handleApprovedButton = async () => { + try { + await approveCourse(courseDetails.id); + fetchData(); + setShowPreviewPopUp(false); + } catch (error) { + toast.error('something went wrong'); + } }; const handleRejectButton = () => { setShowReviewReasonPopUp(true); @@ -37,7 +47,7 @@ const ReviewCourse = ({ return (

    - {courseDetails?.course_provider} + {courseDetails?.CourseProvider || '===='}

    @@ -58,7 +68,7 @@ const ReviewCourse = ({ {/* centeritem */}

    - {courseDetails?.course_name} + {courseDetails?.title}

    @@ -69,15 +79,21 @@ const ReviewCourse = ({
    - - + {courseDetails?.language?.map((item, index) => ( + + ))}

    - Cr. {courseDetails?.credit} + Cr. {courseDetails?.credits}

    @@ -89,12 +105,7 @@ const ReviewCourse = ({ About Course

    - Duis aute irure dolor in reprehenderit in voluptate velit esse cillum - dolore eu fugiat nulla pariatuNemo enim ipsam voluptatem quia voluptas - sit aspernatur aut odit aut fugit, sunt in culpa qui officia deserunt - mollit anim id essed quia consequuntur maExcepteur sint occaecat - cupidatat non proident, sunt in culpa qui officia deserunt mollit anim - id es + {courseDetails?.description}

    {/* compitency */} @@ -103,29 +114,31 @@ const ReviewCourse = ({ Competencies

    - +
    {/* button */} - {activeSection === 'rejectedSection' ? ( + {activeSection === 'REJECTED' ? (
    - +
    ) : ( -
    - - Reject - - - Confirm Approval - -
    + activeSection === 'PENDING' && ( +
    + + Reject + + + Confirm Approval + +
    + ) )}
    ); diff --git a/src/components/3cp/SearchCourse.tsx b/src/components/3cp/SearchCourse.tsx index 6b44a53..591d4f6 100644 --- a/src/components/3cp/SearchCourse.tsx +++ b/src/components/3cp/SearchCourse.tsx @@ -3,17 +3,26 @@ import { SearchIcon } from 'lucide-react'; import React from 'react'; import { SearchInputType } from '@/components/3cp/CourseSection'; -import { DEPARTMENT_OPTIONS } from '@/components/SelectOptions'; import ButtonFill from '@/components/uiComponents/ButtonFill'; import SearchInput from '@/components/uiComponents/SearchInput'; import SelectTag from '@/components/uiComponents/SelectTag'; +import { OptionType } from '@/app/propTypes'; + type PropType = { value: SearchInputType; onChange: (arg: SearchInputType) => void; handleSearch: () => void; + competencyOption: OptionType[]; + languageOption: OptionType[]; }; -const SearchCourse = ({ value, onChange, handleSearch }: PropType) => { +const SearchCourse = ({ + value, + onChange, + handleSearch, + competencyOption, + languageOption, +}: PropType) => { return (
    { placeholder='Search Course by title' /> { if (typeof updatedValue == 'string') { @@ -36,7 +45,7 @@ const SearchCourse = ({ value, onChange, handleSearch }: PropType) => { paddingY='2px' /> { if (typeof updatedValue == 'string') { diff --git a/src/components/3cp/SingleCompetency.tsx b/src/components/3cp/SingleCompetency.tsx index 4101338..b0c062f 100644 --- a/src/components/3cp/SingleCompetency.tsx +++ b/src/components/3cp/SingleCompetency.tsx @@ -4,20 +4,19 @@ import { MdKeyboardArrowDown, MdKeyboardArrowUp } from 'react-icons/md'; import { outfit, poppins } from '@/components/FontFamily'; -type propType = { - key: number; +type CompetencyType = { name: string; levels: string[]; }; - -const SingleCompetency = ({ competency }: { competency: propType }) => { +const SingleCompetency = ({ competency }: { competency: CompetencyType }) => { const [open, setOpen] = useState(false); - const { name, levels } = competency; return (
    -

    {name}

    +

    + {competency?.name} +

    setOpen(!open)}> {open ? ( @@ -35,7 +34,7 @@ const SingleCompetency = ({ competency }: { competency: propType }) => {

      - {levels.map((level, index) => { + {competency?.levels?.map((level, index) => { return (
    • • {level} diff --git a/src/components/3cp/SingleCourse.tsx b/src/components/3cp/SingleCourse.tsx index 455c10d..257a313 100644 --- a/src/components/3cp/SingleCourse.tsx +++ b/src/components/3cp/SingleCourse.tsx @@ -17,11 +17,12 @@ import CourseProvider from '~/images/courseProviderImage.png'; const SingleCourse = ({ activeSection, course, + fetchData, }: { activeSection: string; course: CourseType; + fetchData: () => void; }) => { - const { course_name, rating, author, credit } = course; const [showReviewPopUp, setShowPreviewPopUp] = useState(false); const [showReviewReasonPopUp, setShowReviewReasonPopUp] = useState(false); @@ -39,6 +40,7 @@ const SingleCourse = ({ setShowPreviewPopUp={setShowPreviewPopUp} activeSection={activeSection} setShowReviewReasonPopUp={setShowReviewReasonPopUp} + fetchData={fetchData} /> {/* */} @@ -46,7 +48,11 @@ const SingleCourse = ({ isOpen={showReviewReasonPopUp} onClose={() => setShowReviewReasonPopUp(false)} > - +
      @@ -58,17 +64,17 @@ const SingleCourse = ({

      - {course_name} + {course?.title}

        -
      1. Pregnancy Identification (L1,L2)
      2. -
      3. - Vaginal Examination and plotting on partograph - (L1,L2,L3,L4,L5) -
      4. -
      5. lorem ipsum dolps kihdkkf for PW(L1,L2,L3)
      6. -
      7. Birth Planning and preparedness for PW(L1,L2,L3)
      8. + {Object.keys(course?.competency)?.map((key) => { + return ( +
      9. + {key} ( {course.competency[key].join(', ')} ) +
      10. + ); + })}
      @@ -83,27 +89,35 @@ const SingleCourse = ({

      Unacademy

      - {author} + {course?.author}

      - - + + {course?.language?.map((item, index) => ( + + ))}
    {/* three dot */}
    - {activeSection === 'approvedSection' && ( + {activeSection === 'ACCEPTED' && (

    - {rating} + {course?.avgRating ? course?.avgRating : '--'}{' '} +

    )}

    - Cr.{credit} + Cr.{course?.credits}

    diff --git a/src/components/navbar/MarketPlaceNavbar.tsx b/src/components/navbar/MarketPlaceNavbar.tsx index 86e1f77..062f7b3 100644 --- a/src/components/navbar/MarketPlaceNavbar.tsx +++ b/src/components/navbar/MarketPlaceNavbar.tsx @@ -14,13 +14,7 @@ const MarketPlaceNavbar = ({ }) => { const handleClick = (type: string) => { setActiveSection(type); - if (type === 'approvedSection') { - filterCourse('approved'); - } else if (type === 'pendingSection') { - filterCourse('pending'); - } else if (type === 'rejectedSection') { - filterCourse('rejected'); - } + filterCourse(type); }; const pathname = usePathname(); const isAccountVerificationPage = pathname?.includes('/account-verification'); @@ -32,52 +26,44 @@ const MarketPlaceNavbar = ({
    {' '}
    {' '} diff --git a/src/services/marketPlaceServices.ts b/src/services/marketPlaceServices.ts new file mode 100644 index 0000000..e5c839b --- /dev/null +++ b/src/services/marketPlaceServices.ts @@ -0,0 +1,20 @@ +import axios from 'axios'; + +export const getAllCourses = async () => { + const data = await axios.get('http://localhost:4005/api/admin/courses'); + return data.data.data; +}; +export const approveCourse = async (courseId: number) => { + const data = await axios.patch( + `http://localhost:4005/api/admin/courses/${courseId}/accept`, + { cqf_score: 20 } + ); + return data.data.data; +}; +export const rejectCourse = async (courseId: number, reason: string) => { + const data = await axios.patch( + `http://localhost:4005/api/admin/courses/${courseId}/reject`, + { rejectionReason: reason } + ); + return data.data.data; +}; From a04b3d2aee01d3e6fb451c6750f910f6094fbdd5 Mon Sep 17 00:00:00 2001 From: Ankitml Date: Sat, 25 Nov 2023 16:23:04 +0530 Subject: [PATCH 08/28] feat(marketplace admin): integration --- src/app/account-verification/page.tsx | 109 +++++++------------- src/app/marketplace/page.tsx | 13 +-- src/components/3cp/AccountItems.tsx | 5 +- src/components/3cp/AccountSection.tsx | 7 +- src/components/3cp/RejectedReason.tsx | 6 +- src/components/3cp/SingleAccount.tsx | 49 ++++++--- src/components/navbar/MarketPlaceNavbar.tsx | 10 +- src/services/accountVerficationServices.tsx | 16 +++ 8 files changed, 111 insertions(+), 104 deletions(-) create mode 100644 src/services/accountVerficationServices.tsx diff --git a/src/app/account-verification/page.tsx b/src/app/account-verification/page.tsx index 908a145..32b2f53 100644 --- a/src/app/account-verification/page.tsx +++ b/src/app/account-verification/page.tsx @@ -1,73 +1,31 @@ 'use client'; -import axios from 'axios'; -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; +import { toast } from 'react-toastify'; import AccountSection from '@/components/3cp/AccountSection'; import MarketPlaceNavbar from '@/components/navbar/MarketPlaceNavbar'; import WpcasNavbar from '@/components/wpcasOverView/WpcasNavbar'; -const getinitialValue = () => { - return [ - { - userId: 1, - name: 'Lakshmi Narayana a', - organization: 'Unacademy', - Phone: '9876543210', - email: 'sampletest@gmail.com', - bank: 'SBI', - branch: 'Allahabad', - accountNumber: '56156156456421562165', - ifscCode: 'SBI0000456', - status: 'approved', - logo: '../../../public/images/courseProvider.png', - panNumber: 'SABCA456116P', - gstNumber: '62651616262162', - date: '22 Oct 2023', - }, - { - userId: 2, - name: 'Lakshmi Narayana p', - organization: 'Unacademy', - Phone: '9876543210', - email: 'sampletest@gmail.com', - bank: 'SBI', - branch: 'Allahabad', - accountNumber: '56156156456421562165', - ifscCode: 'SBI0000456', - status: 'pending', - logo: '../../../public/images/courseProvider.png', - panNumber: 'SABCA456116P', - gstNumber: '62651616262162', - date: '22 Oct 2023', - }, - { - userId: 3, - name: 'Lakshmi Narayana r', - organization: 'Unacademy', - Phone: '9876543210', - email: 'sampletest@gmail.com', - bank: 'SBI', - branch: 'Allahabad', - accountNumber: '56156156456421562165', - ifscCode: 'SBI0000456', - status: 'rejected', - logo: '../../../public/images/courseProvider.png', - panNumber: 'SABCA456116P', - gstNumber: '62651616262162', - date: '22 Oct 2023', - }, - ]; -}; +import { getAllProviders } from '@/services/accountVerficationServices'; +// { +// "IFSC": "HDFC0000009", +// "accNo": "8483654687", +// "bankName": "HDFC", +// "branchName": "HSR Layout" +// } + export type accountType = { - userId: number; + id: string; name: string; + email: string; organization: string; Phone: string; - email: string; - bank: string; - branch: string; - accountNumber: string; - ifscCode: string; + paymentInfo: { + IFSC: string; + accNo: string; + bankName: string; + branchName: string; + }; status: string; logo?: string; panNumber: string; @@ -76,22 +34,24 @@ export type accountType = { }; const AccountVefication = () => { - const [activeSection, setActiveSection] = useState('pendingSection'); + const [activeSection, setActiveSection] = useState('PENDING'); const [currentAccountList, setCurrentAccountList] = useState( - getinitialValue() - ); - const [AccountList, setAccountList] = useState( - getinitialValue() + [] ); - const fetchData = async () => { - const response = await axios.get('http://127.0.0.1:3001/accounts'); + const [AccountList, setAccountList] = useState([]); + const fetchData = useCallback(async () => { + try { + const response = await getAllProviders(); + const pendingCourses = response?.filter( + (account: accountType) => account.status === activeSection + ); - const pendingCourses = response.data.filter( - (course: accountType) => course.status === 'pending' - ); - setCurrentAccountList(pendingCourses); - setAccountList(response.data); - }; + setCurrentAccountList(pendingCourses); + setAccountList(response); + } catch (error) { + toast.error('something went wrong'); + } + }, [activeSection]); const filterCourse = (courseType: string) => { const filteredResult = AccountList.filter((course: accountType) => { return course.status === courseType; @@ -101,7 +61,7 @@ const AccountVefication = () => { useEffect(() => { fetchData(); - }, []); + }, [fetchData]); return (
    @@ -114,6 +74,7 @@ const AccountVefication = () => {
    ); diff --git a/src/app/marketplace/page.tsx b/src/app/marketplace/page.tsx index cd46533..5dbd469 100644 --- a/src/app/marketplace/page.tsx +++ b/src/app/marketplace/page.tsx @@ -1,5 +1,5 @@ 'use client'; -import { useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { toast } from 'react-toastify'; import CourseSection from '@/components/3cp/CourseSection'; @@ -32,7 +32,7 @@ const MarketPlace = () => { const [currentCourseList, setCurrentCourseList] = useState([]); const [courseList, setCourseList] = useState([]); - const fetchData = async () => { + const fetchData = useCallback(async () => { try { const response = await getAllCourses(); const filterResult = response.filter((course: CourseType) => { @@ -43,7 +43,8 @@ const MarketPlace = () => { } catch (error) { toast.error('something went wrong'); } - }; + }, [activeSection]); + const filterCourse = (courseType: string) => { const filteredResult = courseList.filter((course: CourseType) => { return course.verificationStatus === courseType; @@ -51,9 +52,9 @@ const MarketPlace = () => { setCurrentCourseList(filteredResult); }; - // useEffect(() => { - // fetchData(); - // }, []); + useEffect(() => { + fetchData(); + }, [fetchData]); return (
    diff --git a/src/components/3cp/AccountItems.tsx b/src/components/3cp/AccountItems.tsx index 2b593f1..365ae55 100644 --- a/src/components/3cp/AccountItems.tsx +++ b/src/components/3cp/AccountItems.tsx @@ -5,18 +5,21 @@ import { accountType } from '@/app/account-verification/page'; const AccountItems = ({ activeSection, accountList, + fetchData, }: { activeSection: string; accountList: accountType[]; + fetchData: () => void; }) => { return (
    {accountList.map((account) => { return ( ); })} diff --git a/src/components/3cp/AccountSection.tsx b/src/components/3cp/AccountSection.tsx index 965a9e3..5dde476 100644 --- a/src/components/3cp/AccountSection.tsx +++ b/src/components/3cp/AccountSection.tsx @@ -11,9 +11,11 @@ import EmptyBox from '~/svg/emptyBox.svg'; const AccountSection = ({ activeSection, accountList, + fetchData, }: { activeSection: string; accountList: accountType[]; + fetchData: () => void; }) => { const [input, setInput] = useState(''); @@ -36,7 +38,7 @@ const AccountSection = ({
    {filterAccounts.length !== 0 ? (
    - {activeSection !== 'pendingSection' && ( + {activeSection !== 'PENDING' && ( setInput(value)} @@ -46,13 +48,14 @@ const AccountSection = ({

    {accountList.length}{' '} - {activeSection === 'pendingSection' + {activeSection === 'PENDING' ? 'Onboard request' : 'Third Party Course Providers'}

    ) : ( diff --git a/src/components/3cp/RejectedReason.tsx b/src/components/3cp/RejectedReason.tsx index b74147b..2b59e34 100644 --- a/src/components/3cp/RejectedReason.tsx +++ b/src/components/3cp/RejectedReason.tsx @@ -5,6 +5,7 @@ import { outfit } from '@/components/FontFamily'; import ButtonFill from '@/components/uiComponents/ButtonFill'; import ButtonOutline from '@/components/uiComponents/ButtonOutline'; +import { rejectAccount } from '@/services/accountVerficationServices'; import { rejectCourse } from '@/services/marketPlaceServices'; const RejectedReason = ({ @@ -15,7 +16,7 @@ const RejectedReason = ({ }: { setShowReviewReasonPopUp: (value: boolean) => void; heading?: string; - id?: number; + id?: number | string; fetchData?: () => void; }) => { const [text, setText] = useState(''); @@ -28,7 +29,8 @@ const RejectedReason = ({ return; } try { - await rejectCourse(id, text); + if (typeof id === 'number') await rejectCourse(id, text); + else await rejectAccount(id); await fetchData(); setShowReviewReasonPopUp(false); } catch (error) { diff --git a/src/components/3cp/SingleAccount.tsx b/src/components/3cp/SingleAccount.tsx index 3af42db..3632bea 100644 --- a/src/components/3cp/SingleAccount.tsx +++ b/src/components/3cp/SingleAccount.tsx @@ -1,5 +1,6 @@ import Image from 'next/image'; import React, { useState } from 'react'; +import { toast } from 'react-toastify'; import RejectedReason from '@/components/3cp/RejectedReason'; import RejectSummary from '@/components/3cp/RejectSummary'; @@ -9,20 +10,28 @@ import ButtonOutline from '@/components/uiComponents/ButtonOutline'; import CommonModal from '@/components/uiComponents/CommonModal'; import { accountType } from '@/app/account-verification/page'; +import { approvedAccount } from '@/services/accountVerficationServices'; import CourseProviderImage from '~/images/courseProviderImage.png'; const SingleAccount = ({ activeSection, account, + fetchData, }: { activeSection: string; account: accountType; + fetchData: () => void; }) => { const [showReviewReasonPopUp, setShowReviewReasonPopUp] = useState(false); - const handleApprovedButton = () => { - //call api and handle approve accout here + const handleApprovedButton = async () => { + try { + await approvedAccount(account?.id); + await fetchData(); + } catch (error) { + toast.error('something went wrong'); + } }; return (
    {/* head line */} @@ -50,9 +61,11 @@ const SingleAccount = ({ {account?.date}

    - {activeSection === 'pendingSection' ? ( + {activeSection === 'PENDING' ? (
    -

    On {account?.date}

    +

    + On {account?.date || '--'} +

    setShowReviewReasonPopUp(true)} classes='bg-[#FFE4E4] text-[#ED2B2B] w-[170px]' @@ -70,13 +83,13 @@ const SingleAccount = ({

    - {activeSection === 'rejectedSection' ? 'Rejected' : 'Onboard'} On - 22 Oct 2023 + {activeSection === 'REJECTED' ? 'Rejected' : 'Onboard'} On{' '} + {account?.date || '--'}

    )} @@ -88,29 +101,35 @@ const SingleAccount = ({ {account?.name} {account?.email} - {account?.Phone} + + {account?.Phone || '--'} +
    - {account?.bank} - {account?.branch} + + {account?.paymentInfo?.bankName || '--'} + + + {account?.paymentInfo?.branchName || '--'} + - {account?.accountNumber} + {account?.paymentInfo?.accNo || '--'}
    - {account?.ifscCode} + {account?.paymentInfo?.IFSC || '--'} - {account?.panNumber} + {account?.panNumber || '--'} - {account?.gstNumber} + {account?.gstNumber || '--'}
    - {activeSection === 'rejectedSection' && ( + {activeSection === 'REJECTED' && (
    diff --git a/src/components/navbar/MarketPlaceNavbar.tsx b/src/components/navbar/MarketPlaceNavbar.tsx index 062f7b3..2e6fa64 100644 --- a/src/components/navbar/MarketPlaceNavbar.tsx +++ b/src/components/navbar/MarketPlaceNavbar.tsx @@ -12,13 +12,15 @@ const MarketPlaceNavbar = ({ setActiveSection: (value: string) => void; filterCourse: (value: string) => void; }) => { - const handleClick = (type: string) => { - setActiveSection(type); - filterCourse(type); - }; const pathname = usePathname(); const isAccountVerificationPage = pathname?.includes('/account-verification'); + const handleClick = (type: string) => { + setActiveSection(type); + if (isAccountVerificationPage && type === 'ACCEPTED') { + filterCourse('VERIFIED'); + } else filterCourse(type); + }; return (
    { + const data = await axios.get('http://localhost:4005/api/admin/providers'); + return data.data.data; +}; +export const approvedAccount = async (providerId: string) => { + await axios.patch( + `http://localhost:4005/api/admin/providers/${providerId}/verify` + ); +}; +export const rejectAccount = async (providerId: string) => { + await axios.get( + `http://localhost:4005/api/admin/providers/${providerId}/reject` + ); +}; From e75765fd845f708974795218536153243a9aec8f Mon Sep 17 00:00:00 2001 From: Ankitml Date: Sat, 25 Nov 2023 16:35:17 +0530 Subject: [PATCH 09/28] feat(question bank): changed type --- src/components/wpcasOverView/LevelAndQuestion.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/wpcasOverView/LevelAndQuestion.tsx b/src/components/wpcasOverView/LevelAndQuestion.tsx index 5ed863b..d546e15 100644 --- a/src/components/wpcasOverView/LevelAndQuestion.tsx +++ b/src/components/wpcasOverView/LevelAndQuestion.tsx @@ -29,7 +29,11 @@ const LevelAndQuestion = ({ setLevel(option)} + onChange={(option) => { + if (typeof option === 'string') { + setLevel(option); + } + }} width='710px' placeholder='Department' paddingY='2px' From 566cf47e2c140de5b559d8e5c98d5f800232fa77 Mon Sep 17 00:00:00 2001 From: Aman Agarwal Date: Tue, 28 Nov 2023 12:13:18 +0530 Subject: [PATCH 10/28] feat(docker): changing docker in two stages --- Dockerfile | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2032755..f0757ef 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,8 @@ -# Use the official Node.js 14 image as a base -FROM node:18-alpine +# Stage 1: Build Stage +FROM node:18-alpine AS build # Set the working directory inside the container -WORKDIR /usr/src/app +WORKDIR /app # Copy package.json and package-lock.json to the working directory COPY package*.json ./ @@ -16,7 +16,20 @@ COPY . . # Build the Next.js app RUN npm run build -COPY /.next/standalone ./ +# Stage 2: Runtime Stage +FROM node:18-alpine + +# Set the working directory inside the container +WORKDIR /app + +# Copy only necessary files from the build stage +ENV NODE_ENV production + +COPY --from=build /app/next.config.js ./next.config.js +COPY --from=build /app/public ./public +COPY --from=build /app/package.json ./package.json +COPY --from=build /app/.next/standalone ./ +COPY --from=build /app/.next/static ./.next/static # Expose the desired port EXPOSE 3000 From 0540d6b7252c8ee7afd8b949f7a6d2ca1b5cc862 Mon Sep 17 00:00:00 2001 From: Ankitml Date: Tue, 28 Nov 2023 16:51:25 +0530 Subject: [PATCH 11/28] feat(userWallet): transectionIntegration --- src/app/3cp/settlements/page.tsx | 7 +- src/app/account-verification/page.tsx | 6 - src/app/context/UserWalletContext.tsx | 74 +++++++++++ src/app/marketplace/page.tsx | 19 ++- src/app/propTypes/index.tsx | 2 +- .../user-management/user-wallet/[id]/page.tsx | 122 +++++++++++++----- .../user-management/user-wallet/layout.tsx | 20 +-- src/app/user-management/user-wallet/page.tsx | 37 ++---- src/components/3cp/AccountSection.tsx | 2 +- src/components/3cp/CourseSection.tsx | 2 +- src/components/navbar/MarketPlaceNavbar.tsx | 2 +- .../settlements/ConfirmSettlement.tsx | 19 ++- .../settlements/SettlementsTable.tsx | 20 ++- src/components/uiComponents/SelectTag.tsx | 2 +- .../userManagement/ConfirmTransaction.tsx | 38 +++++- .../userManagement/UserWalletTable.tsx | 33 +++-- src/components/wpcasOverView/WpcasNavbar.tsx | 2 +- src/services/configurationServices.ts | 53 +++++++- 18 files changed, 329 insertions(+), 131 deletions(-) create mode 100644 src/app/context/UserWalletContext.tsx diff --git a/src/app/3cp/settlements/page.tsx b/src/app/3cp/settlements/page.tsx index 7662702..a521205 100644 --- a/src/app/3cp/settlements/page.tsx +++ b/src/app/3cp/settlements/page.tsx @@ -8,8 +8,9 @@ import { getSettlementsData } from '@/services/configurationServices'; export type SettlementDataType = { id: string; - thirdPartyCourseProvide: string; - totalCourse: number; + imgLink: string; + name: string; + totalCourses: number; activeUsers: number; totalCredits: number; }; @@ -48,7 +49,7 @@ const Settlements = () => { )} {error &&
    Error...
    } {!loading && !error && ( -
    +
    void; + filterUserData: UserWalletDataType[]; + userData: UserWalletDataType[]; + loading: boolean; + error: boolean; + setFetchData: (value: boolean) => void; + adminId: string; +} + +const UserWalletProvider = createContext({ + setFilterUserData: () => null, + filterUserData: [], + userData: [], + loading: true, + error: false, + setFetchData: () => null, + adminId: '', +}); + +const UserWalletContext = ({ children }: { children: React.ReactElement }) => { + const adminId = localStorage.getItem('adminId') ?? ''; + const [filterUserData, setFilterUserData] = useState( + [] + ); + const [userData, setUserData] = useState([]); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(false); + const [fetchData, setFetchData] = useState(true); + + useEffect(() => { + if (fetchData) { + (async () => { + try { + const data = await getUserWalletDetails(adminId); + setLoading(false); + setFetchData(false); + setUserData(data?.consumers); + setFilterUserData(data?.consumers); + } catch (error) { + // Handle any errors that occur during the API call + // eslint-disable-next-line no-console + console.error('API call error:', error); + setLoading(false); + setError(true); + } + })(); + } + }, [fetchData, adminId]); + return ( + + {children} + + ); +}; + +export const useUserWalletContext = () => useContext(UserWalletProvider); +export default UserWalletContext; diff --git a/src/app/marketplace/page.tsx b/src/app/marketplace/page.tsx index 5dbd469..7dd3a14 100644 --- a/src/app/marketplace/page.tsx +++ b/src/app/marketplace/page.tsx @@ -29,21 +29,20 @@ export type CourseType = { const MarketPlace = () => { const [activeSection, setActiveSection] = useState('PENDING'); - const [currentCourseList, setCurrentCourseList] = useState([]); const [courseList, setCourseList] = useState([]); + const [currentCourseList, setCurrentCourseList] = useState([]); + const fetchData = useCallback(async () => { try { const response = await getAllCourses(); - const filterResult = response.filter((course: CourseType) => { - return course.verificationStatus === activeSection; - }); - setCurrentCourseList(filterResult); + + // setCurrentCourseList(filterResult); setCourseList(response); } catch (error) { toast.error('something went wrong'); } - }, [activeSection]); + }, []); const filterCourse = (courseType: string) => { const filteredResult = courseList.filter((course: CourseType) => { @@ -55,6 +54,12 @@ const MarketPlace = () => { useEffect(() => { fetchData(); }, [fetchData]); + useEffect(() => { + const filterResult = courseList.filter((course: CourseType) => { + return course.verificationStatus === activeSection; + }); + setCurrentCourseList(filterResult); + }, [activeSection, courseList]); return (
    @@ -64,7 +69,7 @@ const MarketPlace = () => { setActiveSection={setActiveSection} filterCourse={filterCourse} /> -
    +
    void) => { @@ -21,22 +32,50 @@ const isValid = (value: string, setError: (arg: string) => void) => { return true; }; -const AddToWallet = () => { +const AddToWallet = ({ params }: { params: { id: string } }) => { + const { userData, setFetchData, adminId } = useUserWalletContext(); + const [credit, setCredit] = useState(''); const [error, setError] = useState(''); const [isOpen, setIsOpen] = useState(false); + const [isAddWallet, setIsAddWallet] = useState(false); + const [transections, setTransections] = useState([]); + const [fetchTransectionData, setFetchTransectionData] = useState(true); const handleAddWallet = () => { if (isValid(credit, setError)) { + setIsAddWallet(true); setIsOpen(true); } }; + const handleRemoveWallet = () => { + if (isValid(credit, setError)) { + setIsAddWallet(false); + setIsOpen(true); + } + }; + + const data = userData?.find((item) => item.consumerId === params.id); const handleCreditChange = (value: string) => { if (error) setError(''); setCredit(value); }; + useEffect(() => { + if (fetchTransectionData) { + (async () => { + try { + const data = await getTransectionHistory(adminId, params?.id); + setTransections(data); + setFetchTransectionData(false); + } catch (error) { + toast.error('something went wrong'); + } + })(); + } + }, [adminId, fetchTransectionData, params?.id]); + return (
    { onClose={() => setIsOpen(false)} isCrossShow={false} > - setIsOpen(false)} /> + setIsOpen(false)} + isAddWallet={isAddWallet} + setFetchData={setFetchData} + adminId={adminId} + consumerId={params?.id} + setFetchTransectionData={setFetchTransectionData} + />
    @@ -61,15 +108,19 @@ const AddToWallet = () => {

    - Sushama Kumari + {data?.userName ?? 'DUMMY NAME'} +

    +

    + {data?.role ?? 'DUMMY ROLE'}

    -

    Head Nurse

    Wallet Balance

    -

    Cr 200

    +

    + Cr {data?.credits ?? '--'} +

    null} + onClick={handleRemoveWallet} classes='border-[#385B8B] text-[#385B8B] w-[200px]' > Remove from Wallet @@ -101,33 +152,38 @@ const AddToWallet = () => {
    Transaction History
    -
    -
    Purchased Course ABC
    -
    -
    - -Cr 200 -
    -
    20 Sep 2023
    -
    -
    -
    -
    Purchased Course ABC
    -
    -
    - -Cr 200 -
    -
    20 Sep 2023
    -
    -
    -
    -
    Purchased Course ABC
    -
    -
    - +Cr 200 + {transections.map((transection: transectionType) => { + const createdAtDate = new Date(transection?.createdAt); + + const formattedDate = new Intl.DateTimeFormat('en-US', { + day: 'numeric', + month: 'short', + year: 'numeric', + }).format(createdAtDate); + return ( +
    +
    + {transection?.description} +
    +
    + {transection?.type !== 'ADD_CREDITS' ? ( +
    + -Cr {transection?.credits} +
    + ) : ( +
    + +Cr {transection?.credits} +
    + )} + +
    {formattedDate}
    +
    -
    20 Sep 2023
    -
    -
    + ); + })}
    ); diff --git a/src/app/user-management/user-wallet/layout.tsx b/src/app/user-management/user-wallet/layout.tsx index bb0bbbe..ff43957 100644 --- a/src/app/user-management/user-wallet/layout.tsx +++ b/src/app/user-management/user-wallet/layout.tsx @@ -4,19 +4,23 @@ import * as React from 'react'; import WpcasNavbar from '@/components/wpcasOverView/WpcasNavbar'; +import UserWalletContext from '@/app/context/UserWalletContext'; + export default function Layout({ children }: { children: React.ReactNode }) { const heading = 'Payments'; const pathname = usePathname(); return (
    - {pathname?.includes('/user-wallet/') ? ( - <>{children} - ) : ( - <> - - {children} - - )} + + {pathname?.includes('/user-wallet/') ? ( + <>{children} + ) : ( + <> + + {children} + + )} +
    ); } diff --git a/src/app/user-management/user-wallet/page.tsx b/src/app/user-management/user-wallet/page.tsx index 83fef26..659c466 100644 --- a/src/app/user-management/user-wallet/page.tsx +++ b/src/app/user-management/user-wallet/page.tsx @@ -1,43 +1,22 @@ 'use client'; -import React, { useEffect, useState } from 'react'; +import React from 'react'; import Spinner from '@/components/Spinner'; import UserWalletTable from '@/components/userManagement/UserWalletTable'; -import { getUserWalletDetails } from '@/services/configurationServices'; +import { useUserWalletContext } from '@/app/context/UserWalletContext'; export type UserWalletDataType = { - userId: string; + consumerId: string; userName: string; role: string; - coursePurchased: number; - walletBalance: string; + numCoursesPurchased: number; + credits: string; }; const Wallet = () => { - const [filterUserData, setFilterUserData] = useState( - [] - ); - const [userData, setUserData] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(false); - - useEffect(() => { - (async () => { - try { - const data = await getUserWalletDetails(); - setLoading(false); - setUserData(data); - setFilterUserData(data); - } catch (error) { - // Handle any errors that occur during the API call - // eslint-disable-next-line no-console - console.error('API call error:', error); - setLoading(false); - setError(true); - } - })(); - }, []); + const { userData, filterUserData, setFilterUserData, loading, error } = + useUserWalletContext(); return ( <> @@ -48,7 +27,7 @@ const Wallet = () => { )} {error &&
    Error...
    } {!loading && !error && ( -
    +
    +
    {filterAccounts.length !== 0 ? (
    {activeSection !== 'PENDING' && ( diff --git a/src/components/3cp/CourseSection.tsx b/src/components/3cp/CourseSection.tsx index b9abac2..4e4cfb6 100644 --- a/src/components/3cp/CourseSection.tsx +++ b/src/components/3cp/CourseSection.tsx @@ -83,7 +83,7 @@ const CourseSection = ({ setFilterCourse(courseList); }, [courseList]); return ( -
    +
    {courseList?.length !== 0 ? (
    void }) => { - const handleConfirmSettlement = () => { +import { handleSettlement } from '@/services/configurationServices'; + +const ConfirmSettlement = ({ + onClose, + id, +}: { + onClose: () => void; + id: string; +}) => { + const handleConfirmSettlement = async () => { + try { + await handleSettlement(id); + toast.success('Settlement done successfully'); + } catch (error) { + toast.error('something went wrong'); + } onClose(); }; diff --git a/src/components/settlements/SettlementsTable.tsx b/src/components/settlements/SettlementsTable.tsx index 6a41651..b5529ae 100644 --- a/src/components/settlements/SettlementsTable.tsx +++ b/src/components/settlements/SettlementsTable.tsx @@ -12,8 +12,6 @@ import SearchUser from '@/components/wpcasOverView/SearchUser'; import { SettlementDataType } from '@/app/3cp/settlements/page'; -import groupProfileImage from '~/images/group-profile-users.png'; - type PropType = { userData: SettlementDataType[]; filterUserData: SettlementDataType[]; @@ -26,6 +24,7 @@ const SettlementsTable = ({ filterUserData, }: PropType) => { const [isOpen, setIsOpen] = useState(false); + const [userId, setUserId] = useState(''); const [currentPage, setCurrentPage] = useState(1); const [pageSize, setPageSize] = useState(5); @@ -38,9 +37,7 @@ const SettlementsTable = ({ const handleSearch = (value: string) => { const newData = userData?.filter((item) => { - const nameMatch = item?.thirdPartyCourseProvide - ?.toLowerCase() - .includes(value.toLowerCase()); + const nameMatch = item?.name?.toLowerCase().includes(value.toLowerCase()); return nameMatch; }); setSearchInput(value); @@ -48,7 +45,8 @@ const SettlementsTable = ({ if (currentPage != 1) setCurrentPage(1); }; - const handleSettlement = () => { + const handleSettlement = (id: string) => { + setUserId(id); setIsOpen(true); }; @@ -59,7 +57,7 @@ const SettlementsTable = ({ onClose={() => setIsOpen(false)} isCrossShow={false} > - setIsOpen(false)} /> + setIsOpen(false)} id={userId} />
    img - {user?.thirdPartyCourseProvide} + {user?.name}
    - {user?.totalCourse} + {user?.totalCourses} @@ -134,7 +132,7 @@ const SettlementsTable = ({ handleSettlement(user?.id)} classes='bg-[#26292D]' > Settle diff --git a/src/components/uiComponents/SelectTag.tsx b/src/components/uiComponents/SelectTag.tsx index 19b4118..92187da 100644 --- a/src/components/uiComponents/SelectTag.tsx +++ b/src/components/uiComponents/SelectTag.tsx @@ -30,7 +30,7 @@ const SelectTag = ({ item.value === value)} +// placeholder={placeholder} +// onChange={(e: SingleValue) => { +// if (e) { +// onChange(e?.value); +// } +// }} +// styles={{ +// input: (base) => ({ +// ...base, +// 'input:focus': { +// boxShadow: 'none', +// }, +// width: '150px', +// }), +// control: (baseStyles) => ({ +// ...baseStyles, +// border: 'none', +// outline: 'none', +// boxShadow: 'none', +// }), +// }} +// /> +//
    +//
    +// ); +// }; + +// export default AdminSelect; + 'use client'; import Image from 'next/image'; import React from 'react'; import Select, { SingleValue } from 'react-select'; -import { OptionType, PropsType } from '@/components/uiComponents/SelectTag'; +export type OptionType = { + label: string; + value: string; +}; + +export type PropsType = { + onChange: (value: string) => void; + value: string; + width?: string; + options: OptionType[]; + placeholder: string; + errorMessage?: string; + paddingY?: string; + isDisabled?: boolean; + logo: string; +}; -import Profile from '~/images/profile.png'; +// import CourseProvider from '~/images/courseProvider.png'; -const AdminSelect = ({ options, onChange, placeholder, value }: PropsType) => { +const AdminSelect = ({ + options, + onChange, + placeholder, + value, + logo, +}: PropsType) => { return ( -
    +
    - profile +
    + profile +
    +
    + + {value && typeof value !== 'string' + ? value?.name + : 'choose file to upload'} + + + Browse Files + +
    + {errorMessage && ( +

    + {errorMessage} +

    + )} +
    + ); +}; + +export default FileInput; diff --git a/src/components/uiComponents/PasswordInput.tsx b/src/components/uiComponents/PasswordInput.tsx new file mode 100644 index 0000000..b78f7c1 --- /dev/null +++ b/src/components/uiComponents/PasswordInput.tsx @@ -0,0 +1,78 @@ +import React, { useState } from 'react'; +import { AiOutlineEye, AiOutlineEyeInvisible } from 'react-icons/ai'; +import { TiLockClosed } from 'react-icons/ti'; + +type PropType = { + width: string; + placeholder: string; + required?: boolean; + onChange: (arg: string) => void; + value: string; + isConfirmPassword?: boolean; + errorMessage?: string; +}; + +const PasswordInput = ({ + width, + placeholder, + required = false, + onChange, + value, + isConfirmPassword = false, + errorMessage = '', +}: PropType) => { + const [isPassword, setIsPassword] = useState(true); + + return ( + <> +
    + onChange(e?.target?.value)} + /> +
    !isConfirmPassword && setIsPassword((pre) => !pre)} + > + {isConfirmPassword ? ( + + ) : isPassword ? ( +
    + +
    + ) : ( +
    + +
    + )} +
    +
    + {errorMessage && ( +

    + {errorMessage} +

    + )} + + ); +}; + +export default PasswordInput; diff --git a/src/components/uiComponents/SearchInput.tsx b/src/components/uiComponents/SearchInput.tsx index 1e0384d..6518664 100644 --- a/src/components/uiComponents/SearchInput.tsx +++ b/src/components/uiComponents/SearchInput.tsx @@ -26,9 +26,9 @@ const SearchInput = ({ > diff --git a/src/components/wpcasOverView/ProfileNavbar.tsx b/src/components/wpcasOverView/ProfileNavbar.tsx new file mode 100644 index 0000000..a33301f --- /dev/null +++ b/src/components/wpcasOverView/ProfileNavbar.tsx @@ -0,0 +1,43 @@ +'use client'; +import { useRouter } from 'next/navigation'; +import React from 'react'; + +import { outfit } from '@/components/FontFamily'; +import { ADMIN_OPTIONS } from '@/components/SelectOptions'; +import AdminSelect from '@/components/uiComponents/AdminSelect'; + +import { useAuthContext } from '@/app/context/AuthContext'; + +import BellLogo from '~/svg/bellLogo.svg'; + +const ProfileNavbar = ({ heading }: { heading?: string }) => { + const { adminData } = useAuthContext(); + const router = useRouter(); + + const handleLogout = (value: string) => { + if (value == 'logout') { + localStorage.removeItem('adminData'); + router.push('/login'); + } + }; + + return ( + + ); +}; + +export default ProfileNavbar; diff --git a/src/components/wpcasOverView/WpcasNavbar.tsx b/src/components/wpcasOverView/WpcasNavbar.tsx deleted file mode 100644 index 751a8b0..0000000 --- a/src/components/wpcasOverView/WpcasNavbar.tsx +++ /dev/null @@ -1,29 +0,0 @@ -'use client'; -import React from 'react'; - -import { outfit } from '@/components/FontFamily'; -import { DEPARTMENT_OPTIONS } from '@/components/SelectOptions'; -import AdminSelect from '@/components/uiComponents/AdminSelect'; - -import BellLogo from '~/svg/bellLogo.svg'; - -const WpcasNavbar = ({ heading }: { heading?: string }) => { - return ( - - ); -}; - -export default WpcasNavbar; diff --git a/src/lib/helper.ts b/src/lib/helper.ts index d0d6477..53c09d9 100644 --- a/src/lib/helper.ts +++ b/src/lib/helper.ts @@ -1,5 +1,8 @@ import { SurveyDataType } from '@/components/wpcasOverView/SetupConfigurationForm'; +import { LoginDataType } from '@/app/login/page'; +import { SignupDataType } from '@/app/sign-up/page'; + export function getFromLocalStorage(key: string): string | null { if (typeof window !== 'undefined') { return window.localStorage.getItem(key); @@ -39,3 +42,100 @@ export const isValidConfigFormData = ( } return flag; }; + +export const isValidPassword = (password: string) => { + return ( + password.length >= 8 && + /[A-Z]/.test(password) && + /[a-z]/.test(password) && + /\d/.test(password) && + /[!@#$%^&*]/.test(password) + ); +}; + +const isEmailValid = (email: string) => { + const regex = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i; + return regex.test(email); +}; + +// will check for valid email +export const validateLoginData = ( + data: LoginDataType, + handleError: (key: string, value: string) => void +) => { + let flag = true; + if (!data.email || !isEmailValid(data.email)) { + const ErrorMessage = data?.email + ? 'email is not valid' + : 'please enter email!'; + handleError('email', ErrorMessage); + flag = false; + } + if (!data.password || !isValidPassword(data?.password)) { + const ErrorMessage = data?.password + ? 'Password must be 8 characters or longer with at least one uppercase, one lowercase,one number, and one special character' + : 'please enter password'; + handleError('password', ErrorMessage); + flag = false; + } + return flag; +}; + +export const isValidSignupData = ( + data: SignupDataType, + handleError: (key: string, value: string) => void +) => { + let flag = true; + if (!data.name) { + handleError('name', 'name is required!'); + flag = false; + } + if (!data.email || !isEmailValid(data.email)) { + const ErrorMessage = data?.email + ? 'email is not valid' + : 'please enter email!'; + handleError('email', ErrorMessage); + flag = false; + } + if (!data.profile) { + handleError('profile', 'Profile is required!'); + flag = false; + } + if (!data?.password || !isValidPassword(data?.password)) { + const errorMessage = !data?.password + ? 'password is required!' + : 'Password must be 8 characters or longer with at least one uppercase, one lowercase,one number, and one special character'; + handleError('password', errorMessage); + flag = false; + } + if (!data?.confirmPassword || data.password !== data.confirmPassword) { + const errorMessage = !data?.confirmPassword + ? 'confirm password is required!' + : 'password and confirm password must be same'; + handleError('confirmPassword', errorMessage); + flag = false; + } + return flag; +}; + +export const capitalizeName = (inputString: string) => { + // Replace numbers with empty strings + const stringWithoutNumbers = inputString.replace(/\d/g, ''); + + // Split the modified string into words using space as a separator + const words = stringWithoutNumbers.split(' '); + + // Capitalize the first letter of each word + const transformedWords = words.map((word) => { + if (word.match(/[a-zA-Z]/)) { + // If the word contains alphabetic characters, capitalize the first letter + return word.charAt(0).toUpperCase() + word.slice(1); + } + return word; // Keep the word as is if it contains non-alphabetic characters + }); + + // Join the transformed words with spaces to form the final string + const result = transformedWords.join(' '); + // Trim spaces from the left and right + return result.trimStart(); +}; diff --git a/src/services/accountVerficationServices.tsx b/src/services/accountVerficationServices.tsx index 6bee2ec..92450af 100644 --- a/src/services/accountVerficationServices.tsx +++ b/src/services/accountVerficationServices.tsx @@ -2,21 +2,21 @@ import axios from 'axios'; // course manager export const getAllProviders = async () => { - const data = await axios.get('http://localhost:3000/api/admin/providers'); + const data = await axios.get('http://localhost:4005/api/admin/providers'); return data.data.data; }; // course manager export const approvedAccount = async (providerId: string) => { await axios.patch( - `http://localhost:3000/api/admin/providers/${providerId}/verify` + `http://localhost:4005/api/admin/providers/${providerId}/verify` ); }; // course manager export const rejectAccount = async (providerId: string, reasone: string) => { await axios.patch( - `http://localhost:3000/api/admin/providers/${providerId}/reject`, + `http://localhost:4005/api/admin/providers/${providerId}/reject`, { rejectionReason: reasone } ); }; diff --git a/src/services/authService.ts b/src/services/authService.ts new file mode 100644 index 0000000..da2f24b --- /dev/null +++ b/src/services/authService.ts @@ -0,0 +1,20 @@ +import axios from 'axios'; + +import { LoginDataType } from '@/app/login/page'; + +// course manager +export const loginAdmin = async (userData: LoginDataType) => { + const data = await axios.post( + 'http://localhost:4005/api/admin/login', + userData + ); + return data.data.data; +}; + +export const signupAdmin = async (userData: FormData) => { + const data = await axios.post( + 'http://localhost:4005/api/admin/signup', + userData + ); + return data.data.data; +}; diff --git a/src/services/configurationServices.ts b/src/services/configurationServices.ts index 49c2fa3..08b8854 100644 --- a/src/services/configurationServices.ts +++ b/src/services/configurationServices.ts @@ -45,7 +45,7 @@ export const getUserList = async () => { // course manager export const getSettlementsData = async (adminId: string) => { const data = await axios.get( - `http://localhost:3000/api/admin/${adminId}/providers/settlements` + `http://localhost:4005/api/admin/${adminId}/providers/settlements` ); return data.data.data; }; @@ -54,7 +54,7 @@ export const getSettlementsData = async (adminId: string) => { export const handleSettlement = async (userId: string, adminId: string) => { const payload = { id: userId }; const data = await axios.post( - `http://localhost:3000/api/admin/${adminId}/providers/settlements`, + `http://localhost:4005/api/admin/${adminId}/providers/settlements`, payload ); return data.data.data; @@ -62,7 +62,7 @@ export const handleSettlement = async (userId: string, adminId: string) => { export const getUserWalletDetails = async (adminId: string) => { const data = await axios.get( - `http://localhost:4000/api/admin/${adminId}/consumers` + `http://localhost:4005/api/admin/${adminId}/consumers` ); return data.data.data; }; @@ -75,7 +75,7 @@ export const addCreditToUser = async ( adminId: string ) => { const data = await axios.post( - `http://localhost:4000/api/admin/${adminId}/addCredits`, + `http://localhost:4005/api/admin/${adminId}/addCredits`, payload ); return data.data.data; @@ -85,7 +85,7 @@ export const removeCreditFromUser = async ( adminId: string ) => { const data = await axios.post( - `http://localhost:4000/api/admin/${adminId}/reduceCredits`, + `http://localhost:4005/api/admin/${adminId}/reduceCredits`, payload ); return data.data.data; @@ -95,7 +95,7 @@ export const getTransectionHistory = async ( consumerId: string ) => { const data = await axios.get( - `http://localhost:4000/api/admin/${adminId}/userWallets/transactions/${consumerId}` + `http://localhost:4005/api/admin/${adminId}/userWallets/transactions/${consumerId}` ); return data.data.data; }; diff --git a/src/services/marketPlaceServices.ts b/src/services/marketPlaceServices.ts index 649ee77..adf4a50 100644 --- a/src/services/marketPlaceServices.ts +++ b/src/services/marketPlaceServices.ts @@ -2,14 +2,14 @@ import axios from 'axios'; // course manager api export const getAllCourses = async () => { - const data = await axios.get('http://localhost:3000/api/admin/courses'); + const data = await axios.get('http://localhost:4005/api/admin/courses'); return data.data.data; }; // course manager api export const approveCourse = async (courseId: number) => { const data = await axios.patch( - `http://localhost:3/api/admin/courses/${courseId}/accept` + `http://localhost:4005/api/admin/courses/${courseId}/accept` ); return data.data.data; }; @@ -17,7 +17,7 @@ export const approveCourse = async (courseId: number) => { // course manager api export const rejectCourse = async (courseId: number, reason: string) => { const data = await axios.patch( - `http://localhost:3000/api/admin/courses/${courseId}/reject`, + `http://localhost:4005/api/admin/courses/${courseId}/reject`, { rejectionReason: reason } ); return data.data.data; From 9d4ece1f45572ac69e3d66fe5d429e89be9b004e Mon Sep 17 00:00:00 2001 From: faisalEsMagico Date: Fri, 8 Dec 2023 19:22:31 +0530 Subject: [PATCH 16/28] feat(integration): integration done --- public/svg/bellLogo.svg | 4 +- src/app/3cp/marketplace/page.tsx | 3 +- src/app/page.tsx | 2 +- src/components/3cp/CourseItems.tsx | 4 +- src/components/3cp/RejectedReason.tsx | 25 ++++++---- src/components/3cp/ReviewCourse.tsx | 7 +-- src/components/3cp/SingleAccount.tsx | 2 - src/components/3cp/SingleCourse.tsx | 18 +++---- src/components/uiComponents/AdminSelect.tsx | 50 +------------------ src/components/wpcasOverView/Pagination.tsx | 1 - src/components/wpcasOverView/SearchUser.tsx | 11 ---- .../wpcasOverView/SingleQuestion.tsx | 0 src/components/wpcasOverView/UserTable.tsx | 1 - src/services/accountVerficationServices.tsx | 4 +- src/services/configurationServices.ts | 8 +-- src/services/marketPlaceServices.ts | 4 +- 16 files changed, 40 insertions(+), 104 deletions(-) delete mode 100644 src/components/wpcasOverView/SingleQuestion.tsx diff --git a/public/svg/bellLogo.svg b/public/svg/bellLogo.svg index a0558ea..6ab6b6b 100644 --- a/public/svg/bellLogo.svg +++ b/public/svg/bellLogo.svg @@ -1,5 +1,5 @@ - + - + \ No newline at end of file diff --git a/src/app/3cp/marketplace/page.tsx b/src/app/3cp/marketplace/page.tsx index 8b15ff3..3f88dac 100644 --- a/src/app/3cp/marketplace/page.tsx +++ b/src/app/3cp/marketplace/page.tsx @@ -14,8 +14,9 @@ type competencyType = { }; export type CourseType = { - id: number; + courseId: string; title: string; + providerLogo: string; competency: competencyType; providerName: string; author: string; diff --git a/src/app/page.tsx b/src/app/page.tsx index aeeb68c..e9e7348 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -27,7 +27,7 @@ export default function HomePage() {
    -
    +

    diff --git a/src/components/3cp/CourseItems.tsx b/src/components/3cp/CourseItems.tsx index e1f8493..28b6c33 100644 --- a/src/components/3cp/CourseItems.tsx +++ b/src/components/3cp/CourseItems.tsx @@ -13,10 +13,10 @@ const CourseItems = ({ }) => { return (

    - {courseList.map((course) => { + {courseList?.map((course) => { return ( void; heading?: string; - id?: number | string; + id: string; fetchData: () => void; + isCourse?: boolean; }) => { const [text, setText] = useState(''); const [error, setError] = useState(false); const handleProceedButton = async () => { //call api to handle the proceed button - if (text === '' || !id) { + if (!text) { setError(true); return; } try { - if (typeof id === 'number') { - await rejectCourse(id, text); - toast.success('course reject successfully'); - } else { - await rejectAccount(id, text); - toast.success('Provider account rejected successfully'); + if (id) { + if (isCourse) { + await rejectCourse(id, text); + toast.success('course reject successfully'); + } else { + await rejectAccount(id, text); + toast.success('Provider account rejected successfully'); + } + + await fetchData(); + setShowReviewReasonPopUp(false); } - await fetchData(); - setShowReviewReasonPopUp(false); } catch (error) { toast.error('somethings went wrong'); } diff --git a/src/components/3cp/ReviewCourse.tsx b/src/components/3cp/ReviewCourse.tsx index f332311..103ac7a 100644 --- a/src/components/3cp/ReviewCourse.tsx +++ b/src/components/3cp/ReviewCourse.tsx @@ -13,11 +13,6 @@ import ButtonOutline from '@/components/uiComponents/ButtonOutline'; import { CourseType } from '@/app/3cp/marketplace/page'; import { approveCourse } from '@/services/marketPlaceServices'; -// import CourseFullImage from '~/images/course.png'; -// import CourseProvider from '~/images/courseProviderImage.png'; - -// import { EditIcon, Star } from '~/svg'; - const ReviewCourse = ({ activeSection, courseDetails, @@ -33,7 +28,7 @@ const ReviewCourse = ({ }) => { const handleApprovedButton = async () => { try { - await approveCourse(courseDetails.id); + await approveCourse(courseDetails?.courseId); fetchData(); toast.success('course approved successfully'); setShowPreviewPopUp(false); diff --git a/src/components/3cp/SingleAccount.tsx b/src/components/3cp/SingleAccount.tsx index 75626b7..3d5222a 100644 --- a/src/components/3cp/SingleAccount.tsx +++ b/src/components/3cp/SingleAccount.tsx @@ -12,8 +12,6 @@ import CommonModal from '@/components/uiComponents/CommonModal'; import { accountType } from '@/app/3cp/account-verification/page'; import { approvedAccount } from '@/services/accountVerficationServices'; -// import CourseProviderImage from '~/images/courseProviderImage.png'; - // will format date export const formatDate = (inputDate: string | Date) => { const date = typeof inputDate == 'string' ? new Date(inputDate) : inputDate; diff --git a/src/components/3cp/SingleCourse.tsx b/src/components/3cp/SingleCourse.tsx index 7d50855..6f42d3a 100644 --- a/src/components/3cp/SingleCourse.tsx +++ b/src/components/3cp/SingleCourse.tsx @@ -11,9 +11,6 @@ import CommonModal from '@/components/uiComponents/CommonModal'; import { CourseType } from '@/app/3cp/marketplace/page'; -// import CourseImage from '~/images/course.png'; -// import CourseProvider from '~/images/courseProviderImage.png'; - const SingleCourse = ({ activeSection, course, @@ -50,8 +47,9 @@ const SingleCourse = ({ > @@ -59,7 +57,7 @@ const SingleCourse = ({ {/* image */}
    course-image
      - {Object.keys(course?.competency)?.map((key) => { + {Object.keys(course?.competency ?? {})?.map((key) => { return (
    1. - {key} ( {course.competency[key].join(', ')} ) + {key} ( {course?.competency[key]?.join(', ')} )
    2. ); })} @@ -88,10 +86,10 @@ const SingleCourse = ({
      course provide image

      diff --git a/src/components/uiComponents/AdminSelect.tsx b/src/components/uiComponents/AdminSelect.tsx index ad7b7ba..130644a 100644 --- a/src/components/uiComponents/AdminSelect.tsx +++ b/src/components/uiComponents/AdminSelect.tsx @@ -1,49 +1,3 @@ -// 'use client'; -// import Image from 'next/image'; -// import React from 'react'; -// import Select, { SingleValue } from 'react-select'; - -// import { OptionType, PropsType } from '@/components/uiComponents/SelectTag'; - -// import Profile from '~/images/profile.png'; - -// const AdminSelect = ({ options, onChange, placeholder, value }: PropsType) => { -// return ( -//

      -//
      -// profile -//