From 5967679f8ad78dc80ed505c973e55d83e8591f52 Mon Sep 17 00:00:00 2001 From: Coder_Srinivas Date: Mon, 12 Aug 2024 03:27:52 -0500 Subject: [PATCH 1/7] Baseline commit --- frontend/src/routes.tsx | 2 + frontend/src/screens/achievements.tsx | 367 ++++++++++++++++++++++++ frontend/src/screens/learner/studies.ts | 9 + 3 files changed, 378 insertions(+) create mode 100644 frontend/src/screens/achievements.tsx diff --git a/frontend/src/routes.tsx b/frontend/src/routes.tsx index ac37bc66a..f46443a99 100644 --- a/frontend/src/routes.tsx +++ b/frontend/src/routes.tsx @@ -17,6 +17,7 @@ const ResearcherAccountPage = loadAsync('Researcher Account Page', () => import( const EditStudy = loadAsync('Edit Study Page', () => import('./screens/researcher/studies/create/edit-study')) const ResearcherStudyLanding = loadAsync('New Study Landing Page', () => import('./screens/researcher/studies/create/researcher-study-landing')) const StudyOverview = loadAsync('Study Overview', () => import('./screens/researcher/studies/overview/study-overview')) +const Achievements = loadAsync('Achievements', () => import('./screens/achievements')) const StudiesHomepage = () => { const user = useCurrentUser() @@ -83,6 +84,7 @@ export const AppRoutes = () => { { path: 'study/create', element: }, { path: 'study/overview/:id', element: }, { path: 'study/edit/:id', element: }, + { path: '/achievements', element: }, { path: 'account', element: }, { path: 'researcher-account', element: }, { path: 'studies/status/:studyStatus', element: }, diff --git a/frontend/src/screens/achievements.tsx b/frontend/src/screens/achievements.tsx new file mode 100644 index 000000000..9db1b4219 --- /dev/null +++ b/frontend/src/screens/achievements.tsx @@ -0,0 +1,367 @@ +import React, { useState, useRef, useEffect } from 'react'; +import { + Box, + Text, + Button, + SimpleGrid, + Container, + Title, + Tabs, + RingProgress, + Image, +} from '@mantine/core'; +import { useApi } from '@lib'; +import { TopNavBar, Footer } from '@components'; +import { colors } from '@theme'; +import { StudyDetailsPreview } from '../screens/learner/details'; +import { useFetchLearningPaths, useLearningPathStudies } from './learner/studies'; +import { useCurrentUser } from '@lib'; + +const useStyles = () => ({ + badgeDetailContainer: { + position: 'fixed' as const, + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + backgroundColor: 'white', + borderRadius: '8px', + boxShadow: '0px 4px 20px rgba(0, 0, 0, 0.1)', + zIndex: 1001, + maxWidth: '400px', + width: '100%', + padding: 'md', + }, + closeButton: { + position: 'absolute' as const, + top: '10px', + right: '10px', + }, + achievementBadgeContainer: { + width: 280, + height: 400, + display: 'flex', + flexDirection: 'column' as const, + alignItems: 'center', + justifyContent: 'center', + position: 'relative' as const, + margin: '0 20px', + cursor: 'pointer', + borderRadius: '8px', + }, + errorMessage: { + color: 'red', + marginBottom: '10px', + }, + ringProgressContainer: { + width: '100%', + height: '280px', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + position: 'relative' as const, + }, + badgeImageContainer: { + width: '250px', + height: '250px', + clipPath: 'polygon(50% 0%, 100% 38%, 82% 100%, 18% 100%, 0% 38%)', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + }, + badgeImage: { + width: '95%', + height: '95%', + objectFit: 'contain' as const, + }, + badgeDetails: { + marginTop: '20px', + display: 'flex', + flexDirection: 'column' as const, + alignItems: 'center', + padding: '10px', + paddingTop: '30px', + }, + learningText: { + fontFamily: 'Helvetica Neue', + fontSize: 16, + lineHeight: '24px', + textAlign: 'center' as const, + }, + badgeLabel: { + fontFamily: 'System-ui', + fontSize: 18, + fontWeight: 700, + lineHeight: '28px', + textAlign: 'center' as const, + }, + badgeCompletionText: { + fontFamily: 'System-ui', + fontSize: 12, + lineHeight: '18px', + textAlign: 'center' as const, + color: colors.gray70, + }, + button: { + width: '200px', + height: '30px', + padding: '8px 20px', + gap: '30px', + borderRadius: '4px', + border: `1px solid ${colors.purple}`, + backgroundColor: 'white', + color: colors.purple, + fontSize: '14px', + fontWeight: 'bold' as const, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }, + tabsList: { + display: 'inline-flex', + alignItems: 'center', + }, + tab: { + color: colors.blue, + fontSize: '20px', + fontWeight: 400, + textTransform: 'uppercase' as const, + borderBottom: 'none', + padding: 0, + marginBottom: '10px', + marginRight: '20px', + }, + tabsPanelText: { + marginBottom: '30px', + fontSize: '16px', + color: colors.text, + }, + simpleGrid: { + marginTop: '100px', + }, +}); + +const BadgeDetail = ({ + badge, + onClose, +}: { + badge: any; + onClose: () => void; +}) => { + const detailRef = useRef(null); + const styles = useStyles(); + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + detailRef.current && + !detailRef.current.contains(event.target as Node) + ) { + onClose(); + } + }; + + document.addEventListener('mousedown', handleClickOutside); + return () => { + document.removeEventListener('mousedown', handleClickOutside); + }; + }, [onClose]); + + if (!badge) return null; + return ( + + + + {badge?.learningPath?.label} + + {badge?.learningPath?.description} + + {badge?.learningPath?.level2Metadata + .map((item: string) => `#${item}`) + .join(', ')} + + {badge?.learningPath?.level2Metadata.map( + (item: any, index: number) => ( + + {item} + {item.description} + + ) + )} + + + ); +}; + +const convertBase64ToPdf = (base64PDF: string) => { + const byteCharacters = atob(base64PDF); + const byteNumbers = new Array(byteCharacters.length); + for (let i = 0; i < byteCharacters.length; i++) { + byteNumbers[i] = byteCharacters.charCodeAt(i); + } + const byteArray = new Uint8Array(byteNumbers); + const blob = new Blob([byteArray], { type: 'application/pdf' }); + const url = URL.createObjectURL(blob); + return url; +}; + +const AchievementBadge = ({ + study, + onBadgeClick, + onStudySelect, +}: { + study: any; + onBadgeClick: (study: any) => void; + onStudySelect: (study: any) => void; +}) => { + const [errorMessage, setErrorMessage] = useState(''); + const completedStudies = study?.learningPath?.studies.filter( + (s: any) => s.completedCount !== 0 + ).length; + const progress = + (completedStudies / study?.learningPath?.studies.length) * 100 || 0; + const isCompleted = progress === 100; + const buttonText = isCompleted + ? 'Download Certificate' + : progress > 0 + ? 'Continue' + : 'Start'; + + const api = useApi(); + const currentUser = useCurrentUser(); + const styles = useStyles(); + + const handleButtonClick = async ( + e: React.MouseEvent, + badgeId: string + ) => { + e.stopPropagation(); + if (isCompleted) { + try { + let userEmail = ''; + + if (currentUser && currentUser.contactInfos) { + const emailInfo = currentUser.contactInfos.find( + (info) => info.type === 'EmailAddress' + ); + if (emailInfo && emailInfo.value) { + userEmail = emailInfo.value; + } + } + + } catch (error) { + setErrorMessage('Error fetching PDF. Please try again later.'); + } + } else { + const nextStudy = study?.learningPath?.studies.find( + (s: any) => s.completedCount === 0 + ); + if (nextStudy) { + onStudySelect(study); + } + } + }; + + return ( + onBadgeClick(study)}> + {errorMessage && ( + + {errorMessage} + + )} + + + + {`Badge + + + + + Learning + + + {study?.learningPath?.label} + + + {`${completedStudies} of ${study?.learningPath?.studies.length}`} + + + + + ); +}; + +const Achievements = () => { + const [selectedTab, setSelectedTab] = useState('Badges'); + const learningPaths = useLearningPathStudies() + + console.log(learningPaths) + + return ( + + + + + Achievements + + setSelectedTab(value as 'Badges')} + variant="unstyled" + > + + + BADGES + + + +
Hello
+
+
+
+