From d7cbfc89c36ab4e24bca4ecdcf2a089d1cc9758c Mon Sep 17 00:00:00 2001 From: namita-25 Date: Tue, 28 Jan 2025 15:30:11 +0530 Subject: [PATCH 1/3] Progress bar,logout button --- libs/shared-lib/src/index.ts | 1 + libs/shared-lib/src/lib/Card/CommonCard.tsx | 108 +++++++++--- libs/shared-lib/src/lib/Header/TopAppBar.tsx | 6 +- libs/shared-lib/src/lib/Layout/Layout.tsx | 17 +- libs/shared-lib/src/lib/Progress/Progress.tsx | 34 ++++ .../content/src/components/CommonCollapse.tsx | 160 +++++++++++++++++- .../pages/content-details/[identifier].tsx | 4 +- mfes/content/src/pages/content.tsx | 39 ++++- .../src/pages/details/[identifier].tsx | 5 +- 9 files changed, 329 insertions(+), 45 deletions(-) create mode 100644 libs/shared-lib/src/lib/Progress/Progress.tsx diff --git a/libs/shared-lib/src/index.ts b/libs/shared-lib/src/index.ts index e92ea7a..0643ea6 100644 --- a/libs/shared-lib/src/index.ts +++ b/libs/shared-lib/src/index.ts @@ -23,6 +23,7 @@ export * from './lib/Dialog/CommonDialog'; export * from './lib/theme'; export * from './lib/ThemeProvider'; export * from './lib/Progress/Circular'; +export * from './lib/Progress/Progress'; import Image from '../images/default.png'; export const IMAGES = { DEFAULT_PLACEHOLDER: Image, diff --git a/libs/shared-lib/src/lib/Card/CommonCard.tsx b/libs/shared-lib/src/lib/Card/CommonCard.tsx index 3b79108..9c595ef 100644 --- a/libs/shared-lib/src/lib/Card/CommonCard.tsx +++ b/libs/shared-lib/src/lib/Card/CommonCard.tsx @@ -8,6 +8,7 @@ import Avatar from '@mui/material/Avatar'; import Typography from '@mui/material/Typography'; import { red } from '@mui/material/colors'; import { Box } from '@mui/material'; +import { Progress } from '../Progress/Progress'; interface CommonCardProps { title: string; @@ -21,6 +22,8 @@ interface CommonCardProps { children?: React.ReactNode; orientation?: 'vertical' | 'horizontal'; minheight?: string; + status?: 'Not started' | 'Completed' | 'In progress' | string; + progress?: number; onClick?: () => void; } @@ -36,6 +39,8 @@ export const CommonCard: React.FC = ({ children, orientation, minheight, + status, + progress, onClick, }) => { return ( @@ -58,22 +63,83 @@ export const CommonCard: React.FC = ({ }} onClick={onClick} > - {image && orientation === 'horizontal' && ( - + {image && ( + - )} + height: orientation === 'horizontal' ? '297px' : 'auto', + objectFit: 'cover', //set contain + '@media (max-width: 600px)': { + height: '200px', + }, + }} + /> + )} + + {/* Progress Bar Overlay */} + {progress !== undefined && ( + + + + + {status && + actions && + actions?.toString().toLowerCase() === 'resource' && + status} + {status && + actions && + actions?.toString().toLowerCase() === 'course' && + `${progress}%`} + + + )} + + = ({ ) } - action={ - orientation === 'vertical' ? ( - - ) : undefined - } title={ = ({ WebkitBoxOrient: 'vertical', WebkitLineClamp: 1, paddingLeft: '5px', - // height: '70px', }} > {title} @@ -124,9 +184,9 @@ export const CommonCard: React.FC = ({ diff --git a/libs/shared-lib/src/lib/Header/TopAppBar.tsx b/libs/shared-lib/src/lib/Header/TopAppBar.tsx index 2b4387f..2bb64e9 100644 --- a/libs/shared-lib/src/lib/Header/TopAppBar.tsx +++ b/libs/shared-lib/src/lib/Header/TopAppBar.tsx @@ -9,7 +9,9 @@ import ArrowBackIcon from '@mui/icons-material/ArrowBack'; interface ActionIcon { icon: React.ReactNode; ariaLabel: string; - onClick: () => void; + onLogoutClick: ( + event: React.MouseEvent + ) => void; } interface CommonAppBarProps { title?: string; @@ -100,7 +102,7 @@ export const TopAppBar: React.FC = ({ key={index} color={actionButtonColor} aria-label={action.ariaLabel} - // onClick={action.onClick} + onClick={action.onLogoutClick} > {action.icon} diff --git a/libs/shared-lib/src/lib/Layout/Layout.tsx b/libs/shared-lib/src/lib/Layout/Layout.tsx index 8e4e893..5445c0c 100644 --- a/libs/shared-lib/src/lib/Layout/Layout.tsx +++ b/libs/shared-lib/src/lib/Layout/Layout.tsx @@ -70,7 +70,9 @@ interface LayoutProps { actionIcons?: { icon: React.ReactNode; ariaLabel: string; - onClick: () => void; + onLogoutClick: ( + event: React.MouseEvent + ) => void; }[]; }; topAppBarIcons?: { @@ -83,7 +85,8 @@ interface LayoutProps { language?: string[]; subject?: string[]; contentType?: string[]; - };currentSelectedValues + }; + currentSelectedValues?; language?: string; selectedSubjects?: string[]; selectedContentTypes?: string[]; @@ -144,7 +147,10 @@ const FilterDialog = ({ open={open} onClose={onClose} fullWidth - sx={{ borderRadius: '16px' }} + sx={{ + borderRadius: '16px', + '& .MuiDialog-paper': { backgroundColor: '#FEF7FF' }, + }} > Filters = ({ bgcolor="#FDF7FF" actionIcons={topAppBarIcons} menuIconClick={() => setIsDrawerOpen(true)} + onLogoutClick={(event) => action.onLogoutClick(event)} {...showTopAppBar} /> diff --git a/libs/shared-lib/src/lib/Progress/Progress.tsx b/libs/shared-lib/src/lib/Progress/Progress.tsx new file mode 100644 index 0000000..53477b2 --- /dev/null +++ b/libs/shared-lib/src/lib/Progress/Progress.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import CircularProgress from '@mui/material/CircularProgress'; +import { SxProps, Theme } from '@mui/material/styles'; + +interface CommonCircularProgressProps { + variant?: 'determinate' | 'indeterminate'; + value?: number; + size?: number; + thickness?: number; + color?: string; + sx?: SxProps; +} + +export const Progress: React.FC = ({ + variant = 'determinate', + value = 0, + size = 40, + thickness = 3.6, + color = 'primary', + sx = {}, +}) => { + return ( + + ); +}; diff --git a/mfes/content/src/components/CommonCollapse.tsx b/mfes/content/src/components/CommonCollapse.tsx index e86b0a8..fd0112a 100644 --- a/mfes/content/src/components/CommonCollapse.tsx +++ b/mfes/content/src/components/CommonCollapse.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useState } from 'react'; import { Box, Typography, Button } from '@mui/material'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import ExpandLessIcon from '@mui/icons-material/ExpandLess'; @@ -8,6 +8,7 @@ import PlayCircleOutlineOutlinedIcon from '@mui/icons-material/PlayCircleOutline import TextSnippetOutlinedIcon from '@mui/icons-material/TextSnippetOutlined'; import LensOutlinedIcon from '@mui/icons-material/LensOutlined'; import ArrowForwardOutlinedIcon from '@mui/icons-material/ArrowForwardOutlined'; +import { Progress } from '@shared-lib'; // Types for nested data structure and actions interface NestedItem { identifier: string; @@ -22,6 +23,8 @@ interface CommonAccordionProps { data: NestedItem[]; actions?: { label: string; onClick: () => void }[]; defaultExpanded?: boolean; + status?: 'Not started' | 'Completed' | 'In progress' | string; + progress?: number; } const getIconByMimeType = (mimeType?: string): React.ReactNode => { @@ -29,6 +32,7 @@ const getIconByMimeType = (mimeType?: string): React.ReactNode => { 'application/pdf': , 'video/mp4': , 'video/webm': , + 'video/x-youtube': , 'application/vnd.sunbird.questionset': , }; return icons[mimeType] || ; @@ -37,8 +41,10 @@ const getIconByMimeType = (mimeType?: string): React.ReactNode => { const RenderNestedData: React.FC<{ data: NestedItem[]; expandedItems: Set; + status?: 'Not started' | 'Completed' | 'In progress' | string; + progressNumber?: number; toggleExpanded: (identifier: string) => void; -}> = ({ data, expandedItems, toggleExpanded }) => { +}> = ({ data, expandedItems, toggleExpanded, progressNumber }) => { const router = useRouter(); return ( @@ -101,6 +107,53 @@ const RenderNestedData: React.FC<{ )} + {progressNumber !== undefined && ( + + + + + {`${progressNumber}%`} + + + )} @@ -125,6 +178,8 @@ export const CommonCollapse: React.FC = ({ title, data, actions = [], + progress, + status, defaultExpanded = false, }) => { const router = useRouter(); @@ -162,6 +217,55 @@ export const CommonCollapse: React.FC = ({ {title} + {progress !== undefined && ( + + + + + {status && + data?.mimeType === 'application/vnd.ekstep.content-collection' + ? status + : `${progress}%`} + + + )} { @@ -180,7 +284,7 @@ export const CommonCollapse: React.FC = ({ handleItemClick(identifier)} @@ -188,6 +292,55 @@ export const CommonCollapse: React.FC = ({ {getIconByMimeType(data?.mimeType)} {title} + {progress !== undefined && ( + + + + + {status && + data?.mimeType === 'application/vnd.ekstep.content-collection' + ? status + : `${progress}%`} + + + )} )} @@ -197,6 +350,7 @@ export const CommonCollapse: React.FC = ({ data={data} expandedItems={expandedItems} toggleExpanded={toggleExpanded} + progressNumber={progress} /> )} diff --git a/mfes/content/src/pages/content-details/[identifier].tsx b/mfes/content/src/pages/content-details/[identifier].tsx index 32e27a4..301f784 100644 --- a/mfes/content/src/pages/content-details/[identifier].tsx +++ b/mfes/content/src/pages/content-details/[identifier].tsx @@ -5,12 +5,10 @@ import React, { useEffect, useState } from 'react'; import { Box, Button, Divider, Typography } from '@mui/material'; import { Layout } from '@shared-lib'; import AccountCircleIcon from '@mui/icons-material/AccountCircle'; -import ArrowBackIcon from '@mui/icons-material/ArrowBack'; import Grid from '@mui/material/Grid2'; import { useRouter } from 'next/router'; import { fetchContent } from '../../services/Read'; -import PlayerPage from '../player/[identifier]'; interface ContentDetailsObject { name: string; @@ -104,7 +102,7 @@ const ContentDetails = () => { } alt="Course Thumbnail" style={{ - // width: '100%', + width: '80%', borderRadius: '8px', marginBottom: '16px', }} diff --git a/mfes/content/src/pages/content.tsx b/mfes/content/src/pages/content.tsx index 64565bb..255beae 100644 --- a/mfes/content/src/pages/content.tsx +++ b/mfes/content/src/pages/content.tsx @@ -1,10 +1,10 @@ 'use client'; import React, { useEffect, useState, useCallback } from 'react'; -import { Box } from '@mui/material'; +import { Box, Menu, MenuItem } from '@mui/material'; import { CommonCard, CommonTabs, Layout, Circular } from '@shared-lib'; import { ContentSearch } from '../services/Search'; -import AccountCircleIcon from '@mui/icons-material/AccountCircle'; +import LogoutIcon from '@mui/icons-material/Logout'; import SearchIcon from '@mui/icons-material/Search'; import Grid from '@mui/material/Grid2'; import { useRouter, useSearchParams } from 'next/navigation'; @@ -33,6 +33,7 @@ export default function Content() { const [contentData, setContentData] = useState([]); const [isLoading, setIsLoading] = useState(false); const [selectedContent, setSelectedContent] = useState(null); + const [anchorEl, setAnchorEl] = React.useState(null); // const [language, setLanguage] = useState(''); // const [selectedSubjects, setSelectedSubjects] = useState([]); // const [selectedContentTypes, setSelectedContentTypes] = useState( @@ -67,8 +68,14 @@ export default function Content() { fetchContent(type, searchValue, filterValues); }, [tabValue]); - const handleAccountClick = () => { + const handleAccountClick = (event: React.MouseEvent) => { console.log('Account clicked'); + setAnchorEl(event.currentTarget); + }; + const handleClose = () => { + setAnchorEl(null); + localStorage.removeItem('accToken'); + router.push(`${process.env.NEXT_PUBLIC_LOGIN}`); }; const handleSearchClick = () => { @@ -104,6 +111,7 @@ export default function Content() { 'video/mp4', 'video/webm', 'application/epub', + 'video/x-youtube', 'application/vnd.sunbird.questionset', ].includes(contentMimeType) ) { @@ -130,7 +138,7 @@ export default function Content() { ) : ( - {contentData.map((item) => ( + {contentData?.map((item) => ( handleCardClick(item?.identifier, item?.mimeType) } @@ -241,9 +251,9 @@ export default function Content() { actionButtonLabel: 'Action', actionIcons: [ { - icon: , + icon: , ariaLabel: 'Account', - onClick: handleAccountClick, + onLogoutClick: (e: any) => handleAccountClick(e), }, ], }} @@ -296,6 +306,23 @@ export default function Content() { ariaLabel="Custom icon label tabs" /> + + Logout + ); } diff --git a/mfes/content/src/pages/details/[identifier].tsx b/mfes/content/src/pages/details/[identifier].tsx index 3da67a7..699ecea 100644 --- a/mfes/content/src/pages/details/[identifier].tsx +++ b/mfes/content/src/pages/details/[identifier].tsx @@ -3,8 +3,7 @@ import { useRouter } from 'next/router'; import { Box, Typography } from '@mui/material'; import { Layout } from '@shared-lib'; import AccountCircleIcon from '@mui/icons-material/AccountCircle'; -import SearchIcon from '@mui/icons-material/Search'; -import CheckCircleIcon from '@mui/icons-material/CheckCircle'; + import Grid from '@mui/material/Grid2'; import CommonCollapse from '../../components/CommonCollapse'; // Adjust the import based on your folder structure import { hierarchyAPI } from '../../services/Hierarchy'; @@ -69,6 +68,8 @@ export default function Details({ details }: DetailsProps) { title={item.name} data={item?.children} defaultExpanded={false} + progress={20} + status={'Not started'} /> )); }; From c36152d26b453a98ca3536436e15fb1389523c14 Mon Sep 17 00:00:00 2001 From: namita-25 Date: Tue, 28 Jan 2025 16:43:51 +0530 Subject: [PATCH 2/3] logout menu from common topapp bar --- libs/shared-lib/src/lib/Header/TopAppBar.tsx | 24 ++++++++++++++++++++ libs/shared-lib/src/lib/Layout/Layout.tsx | 3 ++- mfes/content/src/pages/content.tsx | 2 ++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/libs/shared-lib/src/lib/Header/TopAppBar.tsx b/libs/shared-lib/src/lib/Header/TopAppBar.tsx index 2bb64e9..d07d5e3 100644 --- a/libs/shared-lib/src/lib/Header/TopAppBar.tsx +++ b/libs/shared-lib/src/lib/Header/TopAppBar.tsx @@ -6,9 +6,11 @@ import Typography from '@mui/material/Typography'; import IconButton from '@mui/material/IconButton'; import MenuIcon from '@mui/icons-material/Menu'; import ArrowBackIcon from '@mui/icons-material/ArrowBack'; +import { Menu, MenuItem } from '@mui/material'; interface ActionIcon { icon: React.ReactNode; ariaLabel: string; + anchorEl?: HTMLElement | null; onLogoutClick: ( event: React.MouseEvent ) => void; @@ -26,6 +28,7 @@ interface CommonAppBarProps { color?: 'primary' | 'secondary' | 'default' | 'transparent' | 'inherit'; actionIcons?: ActionIcon[]; bgcolor?: string; + onMenuClose?: () => void; } export const TopAppBar: React.FC = ({ @@ -34,6 +37,7 @@ export const TopAppBar: React.FC = ({ showBackIcon = false, menuIconClick, backIconClick, + onMenuClose, actionButtonLabel = 'Action', actionButtonClick, actionButtonColor = 'inherit', @@ -42,6 +46,7 @@ export const TopAppBar: React.FC = ({ actionIcons = [], bgcolor = '#FDF7FF', }) => { + const accountIcon = actionIcons.find((icon) => icon.ariaLabel === 'Account'); return ( = ({ ))} + {accountIcon?.anchorEl && ( + + Logout + + )} ); }; diff --git a/libs/shared-lib/src/lib/Layout/Layout.tsx b/libs/shared-lib/src/lib/Layout/Layout.tsx index 5445c0c..99ba901 100644 --- a/libs/shared-lib/src/lib/Layout/Layout.tsx +++ b/libs/shared-lib/src/lib/Layout/Layout.tsx @@ -61,7 +61,7 @@ interface LayoutProps { showMenuIcon?: boolean; showBackIcon?: boolean; menuIconClick?: () => void; - + onMenuClose?: () => void; actionButtonLabel?: string; actionButtonClick?: () => void; actionButtonColor?: 'inherit' | 'primary' | 'secondary' | 'default'; @@ -70,6 +70,7 @@ interface LayoutProps { actionIcons?: { icon: React.ReactNode; ariaLabel: string; + anchorEl?: HTMLElement | null; onLogoutClick: ( event: React.MouseEvent ) => void; diff --git a/mfes/content/src/pages/content.tsx b/mfes/content/src/pages/content.tsx index 255beae..0303db9 100644 --- a/mfes/content/src/pages/content.tsx +++ b/mfes/content/src/pages/content.tsx @@ -254,8 +254,10 @@ export default function Content() { icon: , ariaLabel: 'Account', onLogoutClick: (e: any) => handleAccountClick(e), + anchorEl: anchorEl, }, ], + onMenuClose: handleClose, }} showSearch={{ placeholder: 'Search content..', From 099cfb70dbbd232fa47ea5e8238c8cd50a883117 Mon Sep 17 00:00:00 2001 From: namita-25 Date: Tue, 28 Jan 2025 17:05:23 +0530 Subject: [PATCH 3/3] logout option added in all pages --- libs/shared-lib/src/lib/Layout/Layout.tsx | 2 +- .../pages/content-details/[identifier].tsx | 18 +++++++++++++---- .../src/pages/details/[identifier].tsx | 20 ++++++++++++++----- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/libs/shared-lib/src/lib/Layout/Layout.tsx b/libs/shared-lib/src/lib/Layout/Layout.tsx index 99ba901..7136714 100644 --- a/libs/shared-lib/src/lib/Layout/Layout.tsx +++ b/libs/shared-lib/src/lib/Layout/Layout.tsx @@ -71,7 +71,7 @@ interface LayoutProps { icon: React.ReactNode; ariaLabel: string; anchorEl?: HTMLElement | null; - onLogoutClick: ( + onLogoutClick?: ( event: React.MouseEvent ) => void; }[]; diff --git a/mfes/content/src/pages/content-details/[identifier].tsx b/mfes/content/src/pages/content-details/[identifier].tsx index 301f784..2715007 100644 --- a/mfes/content/src/pages/content-details/[identifier].tsx +++ b/mfes/content/src/pages/content-details/[identifier].tsx @@ -4,7 +4,8 @@ import React, { useEffect, useState } from 'react'; import { Box, Button, Divider, Typography } from '@mui/material'; import { Layout } from '@shared-lib'; -import AccountCircleIcon from '@mui/icons-material/AccountCircle'; +import LogoutIcon from '@mui/icons-material/Logout'; + import Grid from '@mui/material/Grid2'; import { useRouter } from 'next/router'; @@ -19,13 +20,20 @@ const ContentDetails = () => { const router = useRouter(); const { identifier } = router.query; const [searchValue, setSearchValue] = useState(''); + const [anchorEl, setAnchorEl] = React.useState(null); const [contentDetails, setContentDetails] = useState(null); const handleBackClick = () => { router.back(); // Navigate to the previous page }; - const handleAccountClick = () => { + const handleAccountClick = (event: React.MouseEvent) => { console.log('Account clicked'); + setAnchorEl(event.currentTarget); + }; + const handleClose = () => { + setAnchorEl(null); + localStorage.removeItem('accToken'); + router.push(`${process.env.NEXT_PUBLIC_LOGIN}`); }; const handleMenuClick = () => { @@ -70,11 +78,13 @@ const ContentDetails = () => { actionButtonLabel: 'Action', actionIcons: [ { - icon: , + icon: , ariaLabel: 'Account', - onClick: handleAccountClick, + onLogoutClick: (e: any) => handleAccountClick(e), + anchorEl: anchorEl, }, ], + onMenuClose: handleClose, }} showBack={true} backTitle="Course Details" diff --git a/mfes/content/src/pages/details/[identifier].tsx b/mfes/content/src/pages/details/[identifier].tsx index 699ecea..ff210d8 100644 --- a/mfes/content/src/pages/details/[identifier].tsx +++ b/mfes/content/src/pages/details/[identifier].tsx @@ -1,8 +1,8 @@ -import { useState, useEffect } from 'react'; +import React, { useState, useEffect } from 'react'; import { useRouter } from 'next/router'; import { Box, Typography } from '@mui/material'; import { Layout } from '@shared-lib'; -import AccountCircleIcon from '@mui/icons-material/AccountCircle'; +import LogoutIcon from '@mui/icons-material/Logout'; import Grid from '@mui/material/Grid2'; import CommonCollapse from '../../components/CommonCollapse'; // Adjust the import based on your folder structure @@ -16,6 +16,8 @@ export default function Details({ details }: DetailsProps) { const router = useRouter(); const { identifier } = router.query; // Fetch the 'id' from the URL const [searchValue, setSearchValue] = useState(''); + const [anchorEl, setAnchorEl] = React.useState(null); + const [selectedContent, setSelectedContent] = useState(null); useEffect(() => { if (identifier) { @@ -23,8 +25,14 @@ export default function Details({ details }: DetailsProps) { } }, [identifier]); - const handleAccountClick = () => { + const handleAccountClick = (event: React.MouseEvent) => { console.log('Account clicked'); + setAnchorEl(event.currentTarget); + }; + const handleClose = () => { + setAnchorEl(null); + localStorage.removeItem('accToken'); + router.push(`${process.env.NEXT_PUBLIC_LOGIN}`); }; const handleMenuClick = () => { @@ -85,11 +93,13 @@ export default function Details({ details }: DetailsProps) { actionButtonLabel: 'Action', actionIcons: [ { - icon: , + icon: , ariaLabel: 'Account', - onClick: handleAccountClick, + onLogoutClick: (e: any) => handleAccountClick(e), + anchorEl: anchorEl, }, ], + onMenuClose: handleClose, }} isFooter={false} showLogo={true}