diff --git a/apps/quick-learn-frontend/src/app/(Auth)/forgot-password/ForgotPassword.tsx b/apps/quick-learn-frontend/src/app/(Auth)/forgot-password/ForgotPassword.tsx index 6554306e..61639196 100644 --- a/apps/quick-learn-frontend/src/app/(Auth)/forgot-password/ForgotPassword.tsx +++ b/apps/quick-learn-frontend/src/app/(Auth)/forgot-password/ForgotPassword.tsx @@ -1,6 +1,5 @@ 'use client'; import { z } from 'zod'; -import Link from 'next/link'; import React, { useState } from 'react'; import { useRouter } from 'next/navigation'; import { forgotPasswordSchema } from './forgotPasswordSchema'; @@ -11,6 +10,7 @@ import { forgotPasswordApiCall } from '@src/apiServices/authService'; import { toast } from 'react-toastify'; import { showApiErrorInToast } from '@src/utils/toastUtils'; import { en } from '@src/constants/lang/en'; +import { SuperLink } from '@src/utils/HiLink'; const ForgotPassword = () => { const router = useRouter(); @@ -49,12 +49,12 @@ const ForgotPassword = () => { />

{en.Auth.Login}   - {en.Auth.SignIn} - +

); diff --git a/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/approvals/approvalList.tsx b/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/approvals/approvalList.tsx index 8e330078..68bd9192 100644 --- a/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/approvals/approvalList.tsx +++ b/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/approvals/approvalList.tsx @@ -3,13 +3,13 @@ import { DateFormats } from '@src/constants/dateFormats'; import { en } from '@src/constants/lang/en'; import { RouteEnum } from '@src/constants/route.enum'; import { format } from 'date-fns'; -import Link from 'next/link'; import { useEffect } from 'react'; import ApprovalListSkeleton from './ApprovalListSkeleton'; import { RootState } from '@src/store/store'; import { fetchUnapprovedLessons } from '@src/store/features/approvalSlice'; import { useAppDispatch, useAppSelector } from '@src/store/hooks'; import { updateSystemPreferencesData } from '@src/store/features/systemPreferenceSlice'; +import { SuperLink } from '@src/utils/HiLink'; const columns = [ en.common.lesson, @@ -83,12 +83,12 @@ const ApprovalList = () => { className="px-4 py-2 font-medium text-gray-900 whitespace-nowrap dark:text-white" >
- {lesson.name} - +
diff --git a/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/content/[roadmap]/[course]/view/[lesson]/lessonDetails.tsx b/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/content/[roadmap]/[course]/view/[lesson]/lessonDetails.tsx index 72217ca2..92a70b89 100644 --- a/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/content/[roadmap]/[course]/view/[lesson]/lessonDetails.tsx +++ b/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/content/[roadmap]/[course]/view/[lesson]/lessonDetails.tsx @@ -9,9 +9,9 @@ import ViewLesson from '@src/shared/components/ViewLesson'; import { TBreadcrumb } from '@src/shared/types/breadcrumbType'; import { TLesson, TRoadmap } from '@src/shared/types/contentRepository'; import { selectUser } from '@src/store/features/userSlice'; +import { SuperLink } from '@src/utils/HiLink'; import { showApiErrorInToast } from '@src/utils/toastUtils'; import { UserTypeIdEnum } from 'lib/shared/src'; -import Link from 'next/link'; import { useParams, useRouter } from 'next/navigation'; import { useEffect, useMemo, useState } from 'react'; import { useSelector } from 'react-redux'; @@ -87,13 +87,13 @@ const LessonDetails = () => { <> {canEdit && ( - | Edit - + )} ); diff --git a/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/layout.tsx b/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/layout.tsx index e57e4d81..15d3b021 100644 --- a/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/layout.tsx +++ b/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/layout.tsx @@ -3,11 +3,16 @@ import { getUser } from '@src/apiServices/authService'; import { RouteEnum } from '@src/constants/route.enum'; import { useFetchContentRepositoryMetadata } from '@src/context/contextHelperService'; import Navbar from '@src/shared/components/Navbar'; +import { TUser } from '@src/shared/types/userTypes'; import { selectHideNavbar } from '@src/store/features/uiSlice'; import { setUser } from '@src/store/features/userSlice'; import { useAppDispatch, useAppSelector } from '@src/store/hooks'; import { usePathname } from 'next/navigation'; -import { useEffect } from 'react'; +import { useEffect, useRef } from 'react'; + +// Create a module-level flag for the entire session +let hasInitialFetchStarted = false; +let currentFetchPromise: Promise | null = null; export default function Layout({ children, @@ -19,26 +24,38 @@ export default function Layout({ const pathname = usePathname(); const { fetchMetadata, fetchApprovalData } = useFetchContentRepositoryMetadata(); + const isFetching = useRef(false); useEffect(() => { - const fetchData = async () => { - getUser() - .then((res) => { + if (hasInitialFetchStarted || isFetching.current || currentFetchPromise) { + return; + } + + isFetching.current = true; + + currentFetchPromise = getUser() + .then(async (res) => { + if (!hasInitialFetchStarted) { + hasInitialFetchStarted = true; dispatch(setUser(res.data)); - fetchMetadata(res?.data.user_type_id); - fetchApprovalData(res?.data.user_type_id); - }) - .catch((err) => console.log(err)); - }; - fetchData(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - // Add paths that should be full width - const fullWidthPaths = [RouteEnum.MY_LEARNING_PATH]; - const isFullWidth = fullWidthPaths.some((path) => pathname?.startsWith(path)); + await fetchMetadata(res?.data.user_type_id); + await fetchApprovalData(res?.data.user_type_id); + } + return res.data; + }) + .catch((err) => { + hasInitialFetchStarted = false; + currentFetchPromise = null; + console.log(err); + }) + .finally(() => { + isFetching.current = false; + }); + }, [dispatch, fetchMetadata, fetchApprovalData]); + const fullWidthPaths = [RouteEnum.MY_LEARNING_PATH]; + const isFullWidth = fullWidthPaths.some((path) => pathname?.startsWith(path)); const mainClasses = isFullWidth ? 'mt-16 w-full' : 'max-w-screen-2xl mx-auto mt-16 py-3 px-4 sm:py-5 lg:px-8'; diff --git a/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/teams/TeamMemberListing.tsx b/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/teams/TeamMemberListing.tsx index 7a47b906..bbdf29b7 100644 --- a/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/teams/TeamMemberListing.tsx +++ b/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/teams/TeamMemberListing.tsx @@ -1,6 +1,5 @@ 'use client'; import { RouteEnum } from '@src/constants/route.enum'; -import Link from 'next/link'; import { useMemo, useState } from 'react'; import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/24/outline'; import { TUserType } from '@src/shared/types/userTypes'; @@ -15,6 +14,7 @@ import { } from '@src/store/features/teamSlice'; import { useAppDispatch, useAppSelector } from '@src/store/hooks'; import { en } from '@src/constants/lang/en'; +import { SuperLink } from '@src/utils/HiLink'; const TeamMemberListing = () => { const dispatch = useAppDispatch(); const [searchInputValue, setSearchInputValue] = useState(''); // Local state for input value @@ -60,6 +60,12 @@ const TeamMemberListing = () => { debouncedSearch(value); // Debounce the Redux update and API call }; + function showRange() { + const initial = filteredTotal === 0 ? 0 : (currentPage - 1) * 10 + 1; + const end = Math.min(currentPage * 10, filteredTotal); + return `${initial} ${en.teams.to} ${end} ${en.teams.of} ${filteredTotal}`; + } + return ( <>
@@ -81,13 +87,13 @@ const TeamMemberListing = () => { onChange={handleSearchChange} id="search" /> - {en.teams.addNewMember} - +
@@ -131,22 +137,7 @@ const TeamMemberListing = () => {

{en.teams.showing}{' '} - - {currentPage > 1 - ? (currentPage - 1) * 10 + 1 - : filteredTotal === 0 - ? 0 - : 1} - {' '} - {en.teams.to}{' '} - - {currentPage * 10 <= filteredTotal - ? currentPage * 10 - : filteredTotal} - {' '} - {en.teams.to} - - {filteredTotal}{' '} + {showRange()}{' '} {en.teams.results}

diff --git a/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/teams/TeamTable.tsx b/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/teams/TeamTable.tsx index 37367369..2b36519b 100644 --- a/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/teams/TeamTable.tsx +++ b/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/teams/TeamTable.tsx @@ -1,7 +1,6 @@ // components/TeamTable.tsx import { useEffect } from 'react'; import { format } from 'date-fns'; -import Link from 'next/link'; import { toast } from 'react-toastify'; import { DateFormats } from '@src/constants/dateFormats'; import { CustomClipBoardIcon } from '@src/shared/components/UIElements'; @@ -11,7 +10,7 @@ import TeamMemberListingSkeleton from './TeamMemberListingSkeleton'; import { RootState } from '@src/store/store'; import { fetchTeamMembers } from '@src/store/features/teamSlice'; import { useAppDispatch, useAppSelector } from '@src/store/hooks'; - +import { SuperLink } from '@src/utils/HiLink'; const TeamTable = () => { const dispatch = useAppDispatch(); const { @@ -94,10 +93,10 @@ const TeamTable = () => { key={user.uuid} className="border-b border-gray-200 hover:bg-gray-100" > - - + + {user.first_name} {user.last_name} - +
diff --git a/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/teams/[member]/teamMemberDetails.tsx b/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/teams/[member]/teamMemberDetails.tsx index 1c414dca..09ac23cf 100644 --- a/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/teams/[member]/teamMemberDetails.tsx +++ b/apps/quick-learn-frontend/src/app/(Dashboard)/dashboard/teams/[member]/teamMemberDetails.tsx @@ -1,6 +1,5 @@ 'use client'; -import Link from 'next/link'; -import { useParams } from 'next/navigation'; +import { useParams, useRouter } from 'next/navigation'; import { useCallback, useEffect, useState } from 'react'; import { CursorArrowRippleIcon, @@ -31,7 +30,6 @@ import { showApiMessageInToast, } from '@src/utils/toastUtils'; import { Tooltip } from 'flowbite-react'; -import { useRouter } from 'next/navigation'; import EmptyState from '@src/shared/components/EmptyStatePlaceholder'; import TeamMemberDetailsSkeleton from './TeamMemberDetailsSkeleton'; import { @@ -47,6 +45,7 @@ import { import ActivityGraph, { Course } from '@src/shared/modals/ActivityGraph'; import { useDispatch } from 'react-redux'; import { decrementTotalUsers } from '@src/store/features/teamSlice'; +import { SuperLink } from '@src/utils/HiLink'; const defaultlinks: TBreadcrumb[] = [{ name: 'Team', link: RouteEnum.TEAM }]; @@ -65,9 +64,8 @@ const TeamMemberDetails = () => { TRoadmapCategories[] >([]); const [userProgress, setUserProgress] = useState([]); - const [userDailyLessonProgressData, setUserDalyLessonProgressData] = useState< - TUserDailyProgress[] - >([]); + const [userDailyLessonProgressData, setUserDailyLessonProgressData] = + useState([]); const [allCourses, setAllCourses] = useState([]); const [userActivityModal, setUserActivityModal] = useState(false); @@ -101,7 +99,7 @@ const TeamMemberDetails = () => { // Set the user's daily lesson progress data getUserDailyLessonProgress(Number(userId)) - .then((res) => setUserDalyLessonProgressData(res.data)) + .then((res) => setUserDailyLessonProgressData(res.data)) .catch((e) => showApiErrorInToast(e)); setLinks([ @@ -217,19 +215,19 @@ const TeamMemberDetails = () => { {member?.first_name} {member?.last_name}

- ({member?.assigned_roadmaps?.length || 0} {en.common.roadmaps},{' '} + ({member?.assigned_roadmaps?.length ?? 0} {en.common.roadmaps},{' '} {allCourses.length} {en.common.courses})

{/* Action Buttons */}
- - + diff --git a/apps/quick-learn-frontend/src/app/layout.tsx b/apps/quick-learn-frontend/src/app/layout.tsx index 3f79b7c6..ee0f0556 100644 --- a/apps/quick-learn-frontend/src/app/layout.tsx +++ b/apps/quick-learn-frontend/src/app/layout.tsx @@ -1,8 +1,6 @@ -'use client'; import 'flowbite/dist/flowbite.css'; import './global.css'; import { ToastContainer } from 'react-toastify'; -import 'react-toastify/dist/ReactToastify.css'; import { ReduxProvider } from '@src/store/provider'; import { getClientIp } from '@src/apiServices/ipService'; diff --git a/apps/quick-learn-frontend/src/context/contextHelperService.ts b/apps/quick-learn-frontend/src/context/contextHelperService.ts index 46965145..052770f0 100644 --- a/apps/quick-learn-frontend/src/context/contextHelperService.ts +++ b/apps/quick-learn-frontend/src/context/contextHelperService.ts @@ -1,11 +1,14 @@ 'use client'; -import { getContentRepositoryMetadata } from '@src/apiServices/contentRepositoryService'; +import { + getContentRepositoryMetadata, + getSystemPreferences, +} from '@src/apiServices/contentRepositoryService'; import { updateContentRepository } from '@src/store/features/metadataSlice'; import { UserTypeIdEnum } from 'lib/shared/src'; import { usePathname } from 'next/navigation'; import { useAppDispatch } from '@src/store/hooks'; import { RouteEnum } from '@src/constants/route.enum'; -import { fetchSystemPreferences } from '@src/store/features/systemPreferenceSlice'; +import { updateSystemPreferencesData } from '@src/store/features/systemPreferenceSlice'; // Custom hook to fetch content repository metadata export const useFetchContentRepositoryMetadata = (forceFetch = false) => { @@ -26,12 +29,13 @@ export const useFetchContentRepositoryMetadata = (forceFetch = false) => { } }; - const fetchApprovalData = (user_type: number) => { + const fetchApprovalData = async (user_type: number) => { if ( path !== RouteEnum.APPROVALS && ![UserTypeIdEnum.EDITOR, UserTypeIdEnum.MEMBER].includes(user_type) ) { - dispatch(fetchSystemPreferences()); + const res = await getSystemPreferences(); + dispatch(updateSystemPreferencesData(res.data)); } }; diff --git a/apps/quick-learn-frontend/src/shared/components/Breadcrumb.tsx b/apps/quick-learn-frontend/src/shared/components/Breadcrumb.tsx index 1bd36886..f02a9d42 100644 --- a/apps/quick-learn-frontend/src/shared/components/Breadcrumb.tsx +++ b/apps/quick-learn-frontend/src/shared/components/Breadcrumb.tsx @@ -1,6 +1,6 @@ import { TBreadcrumb } from '../types/breadcrumbType'; import { FC } from 'react'; -import Link from 'next/link'; +import { SuperLink } from '@src/utils/HiLink'; import { ArrowRightIcon, HomeIcon } from './UIElements'; interface Props { @@ -16,13 +16,13 @@ function customLink({ link, name }: TBreadcrumb, isLast = false) { ); } return ( - {name} - + ); } @@ -34,7 +34,7 @@ const Breadcrumb: FC = ({ links }) => { {links.map(({ name, link }, index) => (
  • {index != 0 && index != links.length && } {index == 0 ? : ''} diff --git a/apps/quick-learn-frontend/src/shared/components/Card.tsx b/apps/quick-learn-frontend/src/shared/components/Card.tsx index 99da6adb..d5d45568 100644 --- a/apps/quick-learn-frontend/src/shared/components/Card.tsx +++ b/apps/quick-learn-frontend/src/shared/components/Card.tsx @@ -1,7 +1,7 @@ -import Link from 'next/link'; import { FC, useRef, useEffect, useState } from 'react'; import { ExclamationTriangleIcon, PlusIcon } from '@heroicons/react/20/solid'; import { en } from '@src/constants/lang/en'; +import { SuperLink } from '@src/utils/HiLink'; interface CardProps { title: string; description: string; @@ -130,9 +130,9 @@ const Card: FC = ({ } return ( - + - + ); }; diff --git a/apps/quick-learn-frontend/src/shared/components/Navbar.tsx b/apps/quick-learn-frontend/src/shared/components/Navbar.tsx index 43a68a90..ccf3a548 100644 --- a/apps/quick-learn-frontend/src/shared/components/Navbar.tsx +++ b/apps/quick-learn-frontend/src/shared/components/Navbar.tsx @@ -8,8 +8,8 @@ import { MenuItem, MenuItems, } from '@headlessui/react'; -import Link from 'next/link'; import Image from 'next/image'; +import { SuperLink } from '@src/utils/HiLink'; import { usePathname } from 'next/navigation'; import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline'; @@ -103,7 +103,7 @@ const Navbar = () => { async function doLogout() { try { - localStorage.removeItem('searchHistory'); + localStorage.clear(); await logoutApiCall(); window.location.href = '/'; } catch (error) { @@ -143,12 +143,12 @@ const Navbar = () => { return ( - {item.name} - + ); }; @@ -171,19 +171,19 @@ const Navbar = () => {
    -

    {en.common.quickLearn}

    - +
    {links.map((item, index) => ( - { > {item.name} {showApprovalCount(item, 'desktop')} - + ))}
    @@ -285,12 +285,12 @@ const Navbar = () => { .map((item) => renderMenuItem(item))} {user?.user_type_id !== UserTypeIdEnum.SUPERADMIN && ( - {en.component.profile} - + )}
    @@ -364,7 +364,7 @@ const Navbar = () => {
    { {menuItems.map( (item, index) => item.isExtended && ( - { className="block rounded-md px-3 py-2 text-base font-medium text-gray-400 hover:bg-gray-700 hover:text-white" > {item.name} - + ), )}
    diff --git a/apps/quick-learn-frontend/src/shared/components/ProgressCard.tsx b/apps/quick-learn-frontend/src/shared/components/ProgressCard.tsx index a0bb8347..a3bd210c 100644 --- a/apps/quick-learn-frontend/src/shared/components/ProgressCard.tsx +++ b/apps/quick-learn-frontend/src/shared/components/ProgressCard.tsx @@ -1,11 +1,11 @@ 'use client'; import React, { useEffect, useState, forwardRef } from 'react'; -import Link from 'next/link'; import { MdOutlineDone } from 'react-icons/md'; import { format } from 'date-fns'; import { DateFormats } from '@src/constants/dateFormats'; import { LessonProgress } from '../types/LessonProgressTypes'; import { en } from '@src/constants/lang/en'; +import { SuperLink } from '@src/utils/HiLink'; interface ProgressCardProps { id: number; @@ -46,7 +46,12 @@ const ProgressCard = forwardRef( const baseClassName = `inline-block col-span-1 rounded-lg bg-white shadow-sm hover:shadow-lg border border-gray-100 group relative transition-shadow duration-200 w-full ${className}`; return ( - +

    @@ -123,7 +128,7 @@ const ProgressCard = forwardRef( )}

    - +
    ); }, ); diff --git a/apps/quick-learn-frontend/src/shared/components/RouteTab.tsx b/apps/quick-learn-frontend/src/shared/components/RouteTab.tsx index c05d75c4..fa447ab1 100644 --- a/apps/quick-learn-frontend/src/shared/components/RouteTab.tsx +++ b/apps/quick-learn-frontend/src/shared/components/RouteTab.tsx @@ -1,4 +1,4 @@ -import Link from 'next/link'; +import { SuperLink } from '@src/utils/HiLink'; import React from 'react'; interface RouteTabProps { @@ -6,7 +6,6 @@ interface RouteTabProps { name: string; baseLink: string; course_id?: number; - roadmap_id?: number; type: 'roadmaps' | 'courses' | 'lesson'; onClick?: () => void; } @@ -28,14 +27,15 @@ const RouteTab: React.FC = ({ const link = navLinks[type]; return ( - -
    +
    - + + ); }; diff --git a/apps/quick-learn-frontend/src/shared/components/Sidebar.tsx b/apps/quick-learn-frontend/src/shared/components/Sidebar.tsx index 70acd35a..8446fe1c 100644 --- a/apps/quick-learn-frontend/src/shared/components/Sidebar.tsx +++ b/apps/quick-learn-frontend/src/shared/components/Sidebar.tsx @@ -1,8 +1,8 @@ 'use client'; -import Link from 'next/link'; import React, { FC } from 'react'; import { RouteEnum } from '@src/constants/route.enum'; import { usePathname } from 'next/navigation'; +import { SuperLink } from '@src/utils/HiLink'; export type TNavLink = { title: string; @@ -19,7 +19,7 @@ const Sidebar: FC = ({ navLinks }) => { return ( ); diff --git a/apps/quick-learn-frontend/src/shared/formElements/InputField.tsx b/apps/quick-learn-frontend/src/shared/formElements/InputField.tsx index 970fd876..212cdc06 100644 --- a/apps/quick-learn-frontend/src/shared/formElements/InputField.tsx +++ b/apps/quick-learn-frontend/src/shared/formElements/InputField.tsx @@ -1,9 +1,9 @@ import React, { FC, useEffect, useState } from 'react'; -import Link from 'next/link'; import { FieldType } from '../types/formTypes'; import { OpenEyeIcon, ClosedEyeIcon } from '../components/UIElements'; import { FieldValues, UseFormRegister } from 'react-hook-form'; import { RouteEnum } from '@src/constants/route.enum'; +import { SuperLink } from '@src/utils/HiLink'; interface Props { label?: string; @@ -50,14 +50,14 @@ const InputField: FC = ({
    {/* TODO: Remove this and make independent component for login */} {name === 'rememberMe' && ( - Forgot password? - + )}
    ); @@ -88,12 +88,12 @@ const InputField: FC = ({