Create Compenents
This commit is contained in:
100
package-lock.json
generated
100
package-lock.json
generated
@@ -34,6 +34,7 @@
|
||||
"@radix-ui/react-toggle": "^1.1.2",
|
||||
"@radix-ui/react-toggle-group": "^1.1.2",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"@reduxjs/toolkit": "^2.9.0",
|
||||
"@tailwindcss/postcss": "^4.1.12",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "*",
|
||||
@@ -48,6 +49,7 @@
|
||||
"react-day-picker": "^8.10.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-hook-form": "^7.55.0",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-resizable-panels": "^2.1.7",
|
||||
"react-router-dom": "^7.8.2",
|
||||
"recharts": "^2.15.2",
|
||||
@@ -1891,6 +1893,32 @@
|
||||
"integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@reduxjs/toolkit": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.9.0.tgz",
|
||||
"integrity": "sha512-fSfQlSRu9Z5yBkvsNhYF2rPS8cGXn/TZVrlwN1948QyZ8xMZ0JvP50S2acZNaf+o63u6aEeMjipFyksjIcWrog==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@standard-schema/spec": "^1.0.0",
|
||||
"@standard-schema/utils": "^0.3.0",
|
||||
"immer": "^10.0.3",
|
||||
"redux": "^5.0.1",
|
||||
"redux-thunk": "^3.1.0",
|
||||
"reselect": "^5.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.9.0 || ^17.0.0 || ^18 || ^19",
|
||||
"react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-redux": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@rolldown/pluginutils": {
|
||||
"version": "1.0.0-beta.27",
|
||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
|
||||
@@ -2178,6 +2206,18 @@
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@standard-schema/spec": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
|
||||
"integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@standard-schema/utils": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz",
|
||||
"integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@swc/core": {
|
||||
"version": "1.13.5",
|
||||
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.13.5.tgz",
|
||||
@@ -2765,6 +2805,12 @@
|
||||
"@types/react": "^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/use-sync-external-store": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz",
|
||||
"integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@vitejs/plugin-react-swc": {
|
||||
"version": "3.11.0",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.11.0.tgz",
|
||||
@@ -3167,6 +3213,16 @@
|
||||
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/immer": {
|
||||
"version": "10.1.3",
|
||||
"resolved": "https://registry.npmjs.org/immer/-/immer-10.1.3.tgz",
|
||||
"integrity": "sha512-tmjF/k8QDKydUlm3mZU+tjM6zeq9/fFpPqH9SzWmBnVVKsPBg/V66qsMwb3/Bo90cgUN+ghdVBess+hPsxUyRw==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/immer"
|
||||
}
|
||||
},
|
||||
"node_modules/input-otp": {
|
||||
"version": "1.4.2",
|
||||
"resolved": "https://registry.npmjs.org/input-otp/-/input-otp-1.4.2.tgz",
|
||||
@@ -3691,6 +3747,29 @@
|
||||
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-redux": {
|
||||
"version": "9.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
|
||||
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/use-sync-external-store": "^0.0.6",
|
||||
"use-sync-external-store": "^1.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^18.2.25 || ^19",
|
||||
"react": "^18.0 || ^19",
|
||||
"redux": "^5.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"redux": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-remove-scroll": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz",
|
||||
@@ -3871,6 +3950,27 @@
|
||||
"decimal.js-light": "^2.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/redux": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
|
||||
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/redux-thunk": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz",
|
||||
"integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"redux": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/reselect": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz",
|
||||
"integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.49.0",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.49.0.tgz",
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"@radix-ui/react-toggle": "^1.1.2",
|
||||
"@radix-ui/react-toggle-group": "^1.1.2",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"@reduxjs/toolkit": "^2.9.0",
|
||||
"@tailwindcss/postcss": "^4.1.12",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "*",
|
||||
@@ -43,6 +44,7 @@
|
||||
"react-day-picker": "^8.10.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-hook-form": "^7.55.0",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-resizable-panels": "^2.1.7",
|
||||
"react-router-dom": "^7.8.2",
|
||||
"recharts": "^2.15.2",
|
||||
|
||||
11
src/Redux/Store.tsx
Normal file
11
src/Redux/Store.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import {configureStore} from '@reduxjs/toolkit';
|
||||
import { demoApi } from './services/demo.service';
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
[demoApi.reducerPath]: demoApi.reducer},
|
||||
middleware: (getDefaultMiddleware) =>
|
||||
getDefaultMiddleware().concat(demoApi.middleware),
|
||||
});
|
||||
export type RootState = ReturnType<typeof store.getState>;
|
||||
export type AppDispatch = typeof store.dispatch;
|
||||
16
src/Redux/services/demo.service.ts
Normal file
16
src/Redux/services/demo.service.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
// import { createApi } from '@reduxjs/toolkit/query'
|
||||
import { fetchBaseQuery, createApi } from '@reduxjs/toolkit/query/react'
|
||||
|
||||
|
||||
export const demoApi = createApi({
|
||||
reducerPath: 'demoApi',
|
||||
baseQuery: fetchBaseQuery({ baseUrl: "https://jsonplaceholder.typicode.com" }),
|
||||
endpoints: (builder) => ({
|
||||
// GET example
|
||||
getPosts: builder.query<any[], void>({
|
||||
query: () => "/posts",
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
export const { useGetPostsQuery } = demoApi;
|
||||
@@ -2,9 +2,13 @@ import { createRoot } from "react-dom/client";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
import App from "./App.tsx";
|
||||
import "./styles/globals.css";
|
||||
import { Provider } from "react-redux";
|
||||
import { store } from "./Redux/Store.tsx";
|
||||
|
||||
createRoot(document.getElementById("root")!).render(
|
||||
<Provider store={store}>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
</BrowserRouter>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
@@ -40,8 +40,9 @@ import {
|
||||
ExternalLink
|
||||
} from 'lucide-react';
|
||||
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, PieChart, Pie, Cell } from 'recharts';
|
||||
import exampleImage from 'figma:asset/c501c3d3f3a828828d4cb2dadb9558b43986718f.png';
|
||||
// import exampleImage from 'figma:asset/c501c3d3f3a828828d4cb2dadb9558b43986718f.png';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
const exampleImage = 'https://via.placeholder.com/600x400?text=Example+Image';
|
||||
|
||||
interface SurveyProps {
|
||||
userType: 'individual' | 'corporate';
|
||||
|
||||
56
src/pages/learner/ConnectionStatus.tsx
Normal file
56
src/pages/learner/ConnectionStatus.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { WifiOff, Wifi, RefreshCw } from "lucide-react";
|
||||
import { Alert, AlertDescription } from "../../components/ui/alert";
|
||||
import { Button } from "../../components/ui/button";
|
||||
|
||||
|
||||
// Connection status component
|
||||
export function ConnectionStatus() {
|
||||
const [isOnline, setIsOnline] = useState(navigator.onLine);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const handleOnline = () => setIsOnline(true);
|
||||
const handleOffline = () => setIsOnline(false);
|
||||
|
||||
window.addEventListener('online', handleOnline);
|
||||
window.addEventListener('offline', handleOffline);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('online', handleOnline);
|
||||
window.removeEventListener('offline', handleOffline);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleRetry = async () => {
|
||||
setIsLoading(true);
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
setIsLoading(false);
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
if (isOnline) return null;
|
||||
|
||||
return (
|
||||
<Alert className="mb-8 border-destructive/30 bg-gradient-to-r from-destructive/5 to-destructive/10 backdrop-blur-sm shadow-lg">
|
||||
<WifiOff className="h-5 w-5 text-destructive" />
|
||||
<AlertDescription className="flex items-center justify-between text-base">
|
||||
<span className="font-medium">You're currently offline. Some features may not be available.</span>
|
||||
<Button
|
||||
onClick={handleRetry}
|
||||
disabled={isLoading}
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="ml-4 text-base min-h-[44px] border-destructive/30 text-destructive hover:bg-destructive hover:text-destructive-foreground transition-all duration-200"
|
||||
>
|
||||
{isLoading ? (
|
||||
<RefreshCw className="h-4 w-4 animate-spin mr-2" />
|
||||
) : (
|
||||
<Wifi className="h-4 w-4 mr-2" />
|
||||
)}
|
||||
Retry
|
||||
</Button>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
206
src/pages/learner/CurrentLearningProgress.tsx
Normal file
206
src/pages/learner/CurrentLearningProgress.tsx
Normal file
@@ -0,0 +1,206 @@
|
||||
import React from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Play, FastForward, CheckCircle, ChevronRight, BookOpen } from "lucide-react";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "../../components/ui/card";
|
||||
import CurrentLearningHeaderIcon from "../../imports/CurrentLearningHeaderIcon-4285-106";
|
||||
import { Badge } from "../../components/ui/badge";
|
||||
import { Button } from "../../components/ui/button";
|
||||
|
||||
export function CurrentLearningProgress({ userType = 'individual' }: { userType?: 'individual' | 'corporate' }) {
|
||||
const currentCourse = {
|
||||
title: "Strategic Leadership Excellence Program",
|
||||
rating: 4.9,
|
||||
provider: "Dr. Rajesh Sharma, KLC",
|
||||
dueDate: "Aug 30, 2025",
|
||||
totalModules: 8,
|
||||
currentModule: {
|
||||
title: "Building High-Performance Teams",
|
||||
number: 6,
|
||||
progress: 65,
|
||||
lessonsRemaining: 3
|
||||
},
|
||||
nextModule: {
|
||||
title: "Leadership Communication Mastery",
|
||||
number: 7
|
||||
}
|
||||
};
|
||||
|
||||
// Sample module data to match the image layout
|
||||
const moduleList = [
|
||||
{ title: "Leadership Fundamentals", duration: "1h 15m", completed: true },
|
||||
{ title: "Emotional Intelligence for Leaders", duration: "1h 30m", completed: true },
|
||||
{ title: "Strategic Decision Making", duration: "1h", completed: true },
|
||||
{ title: "Conflict Resolution & Negotiation", duration: "50m", completed: true },
|
||||
{ title: "Change Management Principles", duration: "40m", completed: true },
|
||||
{ title: "Building High-Performance Teams", duration: "1h 20m", completed: false, current: true },
|
||||
{ title: "Leadership Communication Mastery", duration: "1h 45m", completed: false, upcoming: true },
|
||||
{ title: "Innovation & Strategic Thinking", duration: "2h", completed: false }
|
||||
];
|
||||
|
||||
const completedModules = moduleList.filter(module => module.completed).length;
|
||||
const totalModules = moduleList.length;
|
||||
const overallProgress = Math.round((completedModules / totalModules) * 100);
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<Card className="h-fit bg-white shadow-md border border-gray-200 rounded-lg overflow-hidden">
|
||||
<CardHeader>
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-3 bg-gradient-to-br from-brand-navy to-brand-navy/90 rounded-lg shadow-lg">
|
||||
<div className="h-6 w-6">
|
||||
<CurrentLearningHeaderIcon />
|
||||
</div>
|
||||
</div>
|
||||
<CardTitle className="text-xl font-semibold text-gray-900">
|
||||
Current Learning Progress
|
||||
</CardTitle>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="px-6 pb-6">
|
||||
{/* Course Header */}
|
||||
<div className="flex items-start justify-between mb-4">
|
||||
<div className="flex-1">
|
||||
<h2 className="text-xl font-semibold text-gray-900 mb-2">
|
||||
{currentCourse.title}
|
||||
</h2>
|
||||
<p className="text-base text-gray-600">
|
||||
with {currentCourse.provider}
|
||||
</p>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<Badge className="bg-brand-navy/5 text-brand-navy border border-brand-navy px-3 py-1.5 text-sm font-medium mb-2">
|
||||
In Progress
|
||||
</Badge>
|
||||
<p className="text-sm text-gray-600">2h 30m remaining</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Overall Progress */}
|
||||
<div className="mb-4">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<span className="text-sm font-medium text-gray-700">Overall Progress</span>
|
||||
<span className="text-sm font-medium text-gray-700">Modules</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<span className="text-2xl font-bold text-gray-900">{overallProgress}%</span>
|
||||
<span className="text-2xl font-bold text-gray-900">{completedModules}/{totalModules}</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<span className="text-sm text-gray-500">Started</span>
|
||||
<span className="text-sm text-gray-500">Completed</span>
|
||||
</div>
|
||||
|
||||
{/* Progress Bar */}
|
||||
<div className="w-full bg-gray-200 rounded-full h-3 mb-2">
|
||||
<div
|
||||
className="bg-brand-navy h-3 rounded-full transition-all duration-300"
|
||||
style={{ width: `${overallProgress}%` }}
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Current and Up Next Modules */}
|
||||
<div className="grid grid-cols-2 gap-6 mb-4">
|
||||
{/* Current Module */}
|
||||
<div className="bg-brand-gold/10 border border-brand-gold/30 rounded-lg p-4">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<div className="w-6 h-6 bg-brand-gold rounded flex items-center justify-center">
|
||||
<Play className="h-3 w-3 text-brand-charcoal" />
|
||||
</div>
|
||||
<span className="text-sm font-medium text-brand-charcoal uppercase tracking-wide">Current</span>
|
||||
</div>
|
||||
<h3 className="text-base font-semibold text-gray-900 mb-3">
|
||||
{currentCourse.currentModule.title}
|
||||
</h3>
|
||||
<Button
|
||||
onClick={() => navigate(`/course?view=${userType}&courseId=strategic-leadership&module=${currentCourse.currentModule.number}`)}
|
||||
className="w-full text-base min-h-[48px] bg-brand-gold hover:bg-brand-gold/90 text-brand-charcoal font-medium"
|
||||
>
|
||||
Continue Module →
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Up Next Module */}
|
||||
<div className="bg-brand-navy/10 border border-brand-navy/30 rounded-lg p-4">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<div className="w-6 h-6 bg-brand-navy rounded flex items-center justify-center">
|
||||
<FastForward className="h-3 w-3 text-white" />
|
||||
</div>
|
||||
<span className="text-sm font-medium text-brand-navy uppercase tracking-wide">Up Next</span>
|
||||
</div>
|
||||
<h3 className="text-base font-semibold text-gray-900 mb-3">
|
||||
{currentCourse.nextModule.title}
|
||||
</h3>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => navigate(`/course?view=${userType}&courseId=strategic-leadership&module=${currentCourse.nextModule.number}`)}
|
||||
className="w-full text-base min-h-[48px] border-brand-navy text-brand-navy hover:bg-brand-navy/10 font-medium"
|
||||
>
|
||||
Preview Module →
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Course Modules List */}
|
||||
<div className="mb-4">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="text-base font-semibold text-gray-900">Course Modules</h3>
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => navigate(`/course?view=${userType}&courseId=strategic-leadership`)}
|
||||
className="text-sm text-brand-navy hover:text-brand-navy hover:bg-brand-navy/10 p-0 h-auto font-medium"
|
||||
>
|
||||
View All →
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
{moduleList.slice(0, 5).map((module, index) => (
|
||||
<div key={index} className="flex items-center justify-between py-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-5 h-5 flex items-center justify-center">
|
||||
{module.completed ? (
|
||||
<CheckCircle className="h-5 w-5 text-brand-gold" />
|
||||
) : (
|
||||
<div className="w-4 h-4 border-2 border-gray-300 rounded-full"></div>
|
||||
)}
|
||||
</div>
|
||||
<span className={`text-sm ${module.completed ? 'text-gray-900' : 'text-gray-600'}`}>
|
||||
{module.title}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm text-gray-500">{module.duration}</span>
|
||||
<ChevronRight className="h-4 w-4 text-gray-400" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<div className="flex items-center justify-between">
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => navigate(`/course?view=${userType}&courseId=strategic-leadership`)}
|
||||
className="text-base text-gray-600 hover:text-gray-900 hover:bg-gray-50 p-0 min-h-[48px] font-medium flex items-center gap-1"
|
||||
>
|
||||
<BookOpen className="h-4 w-4" />
|
||||
View Full Course
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
onClick={() => navigate(`/course?view=${userType}&courseId=strategic-leadership&module=${currentCourse.currentModule.number}`)}
|
||||
className="text-base min-h-[48px] bg-brand-navy hover:bg-brand-navy/90 text-white font-medium px-6"
|
||||
>
|
||||
<Play className="h-4 w-4 mr-2" />
|
||||
Continue Learning
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -78,250 +78,25 @@ import {
|
||||
// import { navigate } from '../../components/Router';
|
||||
import { ImageWithFallback } from '../../components/figma/ImageWithFallback';
|
||||
import CurrentLearningHeaderIcon from '../../imports/CurrentLearningHeaderIcon-4285-106';
|
||||
import platinumTrophy from 'figma:asset/a224fb6efc954992c535e482fe88d93f1f4178d8.png';
|
||||
import goldTrophy from 'figma:asset/9ebc01e8eb24f9d71683b2ee63d224583a979590.png';
|
||||
import silverTrophy from 'figma:asset/9852710543a90e291ecb85d77ea02234139264c5.png';
|
||||
import bronzeTrophy from 'figma:asset/5fddc261d2e35ee810113f2537c5a59a97fd7fbd.png';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { RecentActivity } from './RecentActivity';
|
||||
import { WelcomeMessage } from './WelcomeMessage';
|
||||
import { CurrentLearningProgress } from './CurrentLearningProgress';
|
||||
import { ConnectionStatus } from './ConnectionStatus';
|
||||
|
||||
const platinumTrophy = 'https://via.placeholder.com/150?text=Platinum+Trophy';
|
||||
const goldTrophy = 'https://via.placeholder.com/150?text=Gold+Trophy';
|
||||
const silverTrophy = 'https://via.placeholder.com/150?text=Silver+Trophy';
|
||||
const bronzeTrophy = 'https://via.placeholder.com/150?text=Bronze+Trophy';
|
||||
|
||||
interface DashboardProps {
|
||||
userType?: 'individual' | 'corporate';
|
||||
}
|
||||
|
||||
// Recent Activity component - increased height to match Global Leaderboard
|
||||
function RecentActivity() {
|
||||
const activities = [
|
||||
{
|
||||
id: 1,
|
||||
type: 'course_completed',
|
||||
title: 'Completed "Strategic Decision Making"',
|
||||
description: 'Module 3 of 4 • Leadership Fundamentals',
|
||||
timestamp: '2 hours ago',
|
||||
icon: CheckCircle,
|
||||
iconColor: 'text-green-600',
|
||||
iconBg: 'bg-green-100'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
type: 'webinar_joined',
|
||||
title: 'Attended Live Webinar',
|
||||
description: 'Digital Transformation for Leaders',
|
||||
timestamp: '5 hours ago',
|
||||
icon: Video,
|
||||
iconColor: 'text-blue-600',
|
||||
iconBg: 'bg-blue-100'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
type: 'assessment_completed',
|
||||
title: 'Assessment Completed',
|
||||
description: 'Leadership Style Assessment • Score: 92%',
|
||||
timestamp: '1 day ago',
|
||||
icon: FileText,
|
||||
iconColor: 'text-purple-600',
|
||||
iconBg: 'bg-purple-100'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
type: 'certificate_earned',
|
||||
title: 'Certificate Earned',
|
||||
description: 'Leadership Foundation Certification',
|
||||
timestamp: '2 days ago',
|
||||
icon: Award,
|
||||
iconColor: 'text-brand-gold',
|
||||
iconBg: 'bg-yellow-100'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
type: 'course_started',
|
||||
title: 'Started New Course',
|
||||
description: 'Innovation Leadership Track',
|
||||
timestamp: '3 days ago',
|
||||
icon: PlayCircle,
|
||||
iconColor: 'text-green-600',
|
||||
iconBg: 'bg-green-100'
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
type: 'discussion_posted',
|
||||
title: 'Discussion Contribution',
|
||||
description: 'Team Management Best Practices',
|
||||
timestamp: '4 days ago',
|
||||
icon: MessageSquare,
|
||||
iconColor: 'text-orange-600',
|
||||
iconBg: 'bg-orange-100'
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
type: 'resource_downloaded',
|
||||
title: 'Resource Downloaded',
|
||||
description: 'Leadership Skills Handbook PDF',
|
||||
timestamp: '5 days ago',
|
||||
icon: BookOpen,
|
||||
iconColor: 'text-gray-600',
|
||||
iconBg: 'bg-gray-100'
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
type: 'peer_connection',
|
||||
title: 'New Connection',
|
||||
description: 'Connected with 3 peer learners',
|
||||
timestamp: '1 week ago',
|
||||
icon: Users,
|
||||
iconColor: 'text-brand-navy',
|
||||
iconBg: 'bg-blue-100'
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<Card className="h-96 flex flex-col border-0 shadow-lg bg-white">
|
||||
<CardHeader className="pb-3 flex-shrink-0">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 bg-gradient-to-br from-brand-navy to-brand-navy/90 rounded-lg flex items-center justify-center">
|
||||
<Activity className="h-4 w-4 text-white" />
|
||||
</div>
|
||||
<CardTitle className="text-lg font-semibold text-gray-900">
|
||||
Recent Activity
|
||||
</CardTitle>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => navigate('/dashboard?view=individual&tab=activity')}
|
||||
className="text-brand-navy hover:bg-brand-navy/10 border-brand-navy/20 text-base px-3 py-1.5 min-h-[48px] font-medium"
|
||||
>
|
||||
View All
|
||||
</Button>
|
||||
</div>
|
||||
<p className="text-sm text-gray-600 mt-1">
|
||||
Your recent learning activities
|
||||
</p>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="px-6 pb-4 flex-1 min-h-0">
|
||||
<ScrollArea className="h-full">
|
||||
<div className="space-y-2 pr-2">
|
||||
{activities.map((activity) => {
|
||||
const Icon = activity.icon;
|
||||
return (
|
||||
<div
|
||||
key={activity.id}
|
||||
className="flex items-start gap-3 p-3 rounded-lg bg-gray-50 hover:bg-gray-100 transition-all duration-200"
|
||||
>
|
||||
{/* Activity Icon */}
|
||||
<div className={`p-2 rounded-lg ${activity.iconBg} flex-shrink-0`}>
|
||||
<Icon className={`h-3 w-3 ${activity.iconColor}`} />
|
||||
</div>
|
||||
|
||||
{/* Activity Content */}
|
||||
<div className="flex-1 min-w-0">
|
||||
<h4 className="text-sm font-semibold text-gray-900 mb-1 leading-tight">
|
||||
{activity.title}
|
||||
</h4>
|
||||
<p className="text-xs text-gray-600 mb-1 leading-relaxed">
|
||||
{activity.description}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 font-medium">
|
||||
{activity.timestamp}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
// Welcome Message component with simple visible emoji
|
||||
function WelcomeMessage({ user }: { user: any }) {
|
||||
const [showEmoji, setShowEmoji] = useState(true);
|
||||
const emojiChar = '👋';
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setShowEmoji(false);
|
||||
}, 5000);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="text-4xl font-bold mb-3">
|
||||
<span className="bg-gradient-to-r from-gray-800 via-gray-700 to-gray-600 bg-clip-text text-transparent">
|
||||
Welcome back, Priya Sharma!
|
||||
</span>
|
||||
{showEmoji && (
|
||||
<span
|
||||
className="text-yellow-500 ml-2 inline-block animate-wave-emoji"
|
||||
style={{
|
||||
fontSize: '2.5rem',
|
||||
fontFamily: 'Apple Color Emoji, Segoe UI Emoji, Noto Color Emoji, sans-serif',
|
||||
backgroundColor: 'transparent',
|
||||
color: '#EAB308'
|
||||
}}
|
||||
>
|
||||
{emojiChar}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Connection status component
|
||||
function ConnectionStatus() {
|
||||
const [isOnline, setIsOnline] = useState(navigator.onLine);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const handleOnline = () => setIsOnline(true);
|
||||
const handleOffline = () => setIsOnline(false);
|
||||
|
||||
window.addEventListener('online', handleOnline);
|
||||
window.addEventListener('offline', handleOffline);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('online', handleOnline);
|
||||
window.removeEventListener('offline', handleOffline);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleRetry = async () => {
|
||||
setIsLoading(true);
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
setIsLoading(false);
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
if (isOnline) return null;
|
||||
|
||||
return (
|
||||
<Alert className="mb-8 border-destructive/30 bg-gradient-to-r from-destructive/5 to-destructive/10 backdrop-blur-sm shadow-lg">
|
||||
<WifiOff className="h-5 w-5 text-destructive" />
|
||||
<AlertDescription className="flex items-center justify-between text-base">
|
||||
<span className="font-medium">You're currently offline. Some features may not be available.</span>
|
||||
<Button
|
||||
onClick={handleRetry}
|
||||
disabled={isLoading}
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="ml-4 text-base min-h-[44px] border-destructive/30 text-destructive hover:bg-destructive hover:text-destructive-foreground transition-all duration-200"
|
||||
>
|
||||
{isLoading ? (
|
||||
<RefreshCw className="h-4 w-4 animate-spin mr-2" />
|
||||
) : (
|
||||
<Wifi className="h-4 w-4 mr-2" />
|
||||
)}
|
||||
Retry
|
||||
</Button>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
// Weekly Progress Goal Setting Modal component
|
||||
function WeeklyProgressModal({
|
||||
@@ -698,205 +473,6 @@ function AchievementBadges() {
|
||||
);
|
||||
}
|
||||
|
||||
// Current Learning Progress component
|
||||
function CurrentLearningProgress({ userType = 'individual' }: { userType?: 'individual' | 'corporate' }) {
|
||||
const currentCourse = {
|
||||
title: "Strategic Leadership Excellence Program",
|
||||
rating: 4.9,
|
||||
provider: "Dr. Rajesh Sharma, KLC",
|
||||
dueDate: "Aug 30, 2025",
|
||||
totalModules: 8,
|
||||
currentModule: {
|
||||
title: "Building High-Performance Teams",
|
||||
number: 6,
|
||||
progress: 65,
|
||||
lessonsRemaining: 3
|
||||
},
|
||||
nextModule: {
|
||||
title: "Leadership Communication Mastery",
|
||||
number: 7
|
||||
}
|
||||
};
|
||||
|
||||
// Sample module data to match the image layout
|
||||
const moduleList = [
|
||||
{ title: "Leadership Fundamentals", duration: "1h 15m", completed: true },
|
||||
{ title: "Emotional Intelligence for Leaders", duration: "1h 30m", completed: true },
|
||||
{ title: "Strategic Decision Making", duration: "1h", completed: true },
|
||||
{ title: "Conflict Resolution & Negotiation", duration: "50m", completed: true },
|
||||
{ title: "Change Management Principles", duration: "40m", completed: true },
|
||||
{ title: "Building High-Performance Teams", duration: "1h 20m", completed: false, current: true },
|
||||
{ title: "Leadership Communication Mastery", duration: "1h 45m", completed: false, upcoming: true },
|
||||
{ title: "Innovation & Strategic Thinking", duration: "2h", completed: false }
|
||||
];
|
||||
|
||||
const completedModules = moduleList.filter(module => module.completed).length;
|
||||
const totalModules = moduleList.length;
|
||||
const overallProgress = Math.round((completedModules / totalModules) * 100);
|
||||
|
||||
return (
|
||||
<Card className="h-fit bg-white shadow-md border border-gray-200 rounded-lg overflow-hidden">
|
||||
<CardHeader>
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="p-3 bg-gradient-to-br from-brand-navy to-brand-navy/90 rounded-lg shadow-lg">
|
||||
<div className="h-6 w-6">
|
||||
<CurrentLearningHeaderIcon />
|
||||
</div>
|
||||
</div>
|
||||
<CardTitle className="text-xl font-semibold text-gray-900">
|
||||
Current Learning Progress
|
||||
</CardTitle>
|
||||
</div>
|
||||
</div>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="px-6 pb-6">
|
||||
{/* Course Header */}
|
||||
<div className="flex items-start justify-between mb-4">
|
||||
<div className="flex-1">
|
||||
<h2 className="text-xl font-semibold text-gray-900 mb-2">
|
||||
{currentCourse.title}
|
||||
</h2>
|
||||
<p className="text-base text-gray-600">
|
||||
with {currentCourse.provider}
|
||||
</p>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<Badge className="bg-brand-navy/5 text-brand-navy border border-brand-navy px-3 py-1.5 text-sm font-medium mb-2">
|
||||
In Progress
|
||||
</Badge>
|
||||
<p className="text-sm text-gray-600">2h 30m remaining</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Overall Progress */}
|
||||
<div className="mb-4">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<span className="text-sm font-medium text-gray-700">Overall Progress</span>
|
||||
<span className="text-sm font-medium text-gray-700">Modules</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<span className="text-2xl font-bold text-gray-900">{overallProgress}%</span>
|
||||
<span className="text-2xl font-bold text-gray-900">{completedModules}/{totalModules}</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<span className="text-sm text-gray-500">Started</span>
|
||||
<span className="text-sm text-gray-500">Completed</span>
|
||||
</div>
|
||||
|
||||
{/* Progress Bar */}
|
||||
<div className="w-full bg-gray-200 rounded-full h-3 mb-2">
|
||||
<div
|
||||
className="bg-brand-navy h-3 rounded-full transition-all duration-300"
|
||||
style={{ width: `${overallProgress}%` }}
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Current and Up Next Modules */}
|
||||
<div className="grid grid-cols-2 gap-6 mb-4">
|
||||
{/* Current Module */}
|
||||
<div className="bg-brand-gold/10 border border-brand-gold/30 rounded-lg p-4">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<div className="w-6 h-6 bg-brand-gold rounded flex items-center justify-center">
|
||||
<Play className="h-3 w-3 text-brand-charcoal" />
|
||||
</div>
|
||||
<span className="text-sm font-medium text-brand-charcoal uppercase tracking-wide">Current</span>
|
||||
</div>
|
||||
<h3 className="text-base font-semibold text-gray-900 mb-3">
|
||||
{currentCourse.currentModule.title}
|
||||
</h3>
|
||||
<Button
|
||||
onClick={() => navigate(`/course?view=${userType}&courseId=strategic-leadership&module=${currentCourse.currentModule.number}`)}
|
||||
className="w-full text-base min-h-[48px] bg-brand-gold hover:bg-brand-gold/90 text-brand-charcoal font-medium"
|
||||
>
|
||||
Continue Module →
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Up Next Module */}
|
||||
<div className="bg-brand-navy/10 border border-brand-navy/30 rounded-lg p-4">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<div className="w-6 h-6 bg-brand-navy rounded flex items-center justify-center">
|
||||
<FastForward className="h-3 w-3 text-white" />
|
||||
</div>
|
||||
<span className="text-sm font-medium text-brand-navy uppercase tracking-wide">Up Next</span>
|
||||
</div>
|
||||
<h3 className="text-base font-semibold text-gray-900 mb-3">
|
||||
{currentCourse.nextModule.title}
|
||||
</h3>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => navigate(`/course?view=${userType}&courseId=strategic-leadership&module=${currentCourse.nextModule.number}`)}
|
||||
className="w-full text-base min-h-[48px] border-brand-navy text-brand-navy hover:bg-brand-navy/10 font-medium"
|
||||
>
|
||||
Preview Module →
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Course Modules List */}
|
||||
<div className="mb-4">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h3 className="text-base font-semibold text-gray-900">Course Modules</h3>
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => navigate(`/course?view=${userType}&courseId=strategic-leadership`)}
|
||||
className="text-sm text-brand-navy hover:text-brand-navy hover:bg-brand-navy/10 p-0 h-auto font-medium"
|
||||
>
|
||||
View All →
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-3">
|
||||
{moduleList.slice(0, 5).map((module, index) => (
|
||||
<div key={index} className="flex items-center justify-between py-2">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-5 h-5 flex items-center justify-center">
|
||||
{module.completed ? (
|
||||
<CheckCircle className="h-5 w-5 text-brand-gold" />
|
||||
) : (
|
||||
<div className="w-4 h-4 border-2 border-gray-300 rounded-full"></div>
|
||||
)}
|
||||
</div>
|
||||
<span className={`text-sm ${module.completed ? 'text-gray-900' : 'text-gray-600'}`}>
|
||||
{module.title}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm text-gray-500">{module.duration}</span>
|
||||
<ChevronRight className="h-4 w-4 text-gray-400" />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Action Buttons */}
|
||||
<div className="flex items-center justify-between">
|
||||
<Button
|
||||
variant="ghost"
|
||||
onClick={() => navigate(`/course?view=${userType}&courseId=strategic-leadership`)}
|
||||
className="text-base text-gray-600 hover:text-gray-900 hover:bg-gray-50 p-0 min-h-[48px] font-medium flex items-center gap-1"
|
||||
>
|
||||
<BookOpen className="h-4 w-4" />
|
||||
View Full Course
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
onClick={() => navigate(`/course?view=${userType}&courseId=strategic-leadership&module=${currentCourse.currentModule.number}`)}
|
||||
className="text-base min-h-[48px] bg-brand-navy hover:bg-brand-navy/90 text-white font-medium px-6"
|
||||
>
|
||||
<Play className="h-4 w-4 mr-2" />
|
||||
Continue Learning
|
||||
</Button>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
// Global Leaderboard component - increased height to match Recent Activity
|
||||
function GlobalLeaderboard() {
|
||||
const leaderboardData = [
|
||||
@@ -976,6 +552,7 @@ function GlobalLeaderboard() {
|
||||
default: return 'bg-gray-100 text-gray-600';
|
||||
}
|
||||
};
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<Card className="h-96 flex flex-col border-0 shadow-lg bg-white">
|
||||
@@ -1443,9 +1020,9 @@ export default function Dashboard({ userType = 'individual' }: DashboardProps) {
|
||||
const user = { name: 'Alex', email: 'alex@example.com' };
|
||||
|
||||
return (
|
||||
<LearnerLayout currentPage="/dashboard" userType={userType}>
|
||||
<LearnerLayout currentPage="/dashboard" userType={userType}>
|
||||
<div className="container mx-auto px-4 lg:px-8 py-8 space-y-8">
|
||||
<ConnectionStatus />
|
||||
<ConnectionStatus />
|
||||
|
||||
{/* Welcome Section */}
|
||||
<div className="mb-8">
|
||||
|
||||
167
src/pages/learner/RecentActivity.tsx
Normal file
167
src/pages/learner/RecentActivity.tsx
Normal file
@@ -0,0 +1,167 @@
|
||||
import {
|
||||
CheckCircle,
|
||||
Video,
|
||||
FileText,
|
||||
Award,
|
||||
PlayCircle,
|
||||
MessageSquare,
|
||||
BookOpen,
|
||||
Users,
|
||||
Activity
|
||||
} from "lucide-react";
|
||||
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "../../components/ui/card";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { ScrollArea } from "../../components/ui/scroll-area";
|
||||
// import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
||||
// import { Button } from "@/components/ui/button";
|
||||
// import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
|
||||
// Recent Activity component - increased height to match Global Leaderboard
|
||||
export function RecentActivity() {
|
||||
const activities = [
|
||||
{
|
||||
id: 1,
|
||||
type: 'course_completed',
|
||||
title: 'Completed "Strategic Decision Making"',
|
||||
description: 'Module 3 of 4 • Leadership Fundamentals',
|
||||
timestamp: '2 hours ago',
|
||||
icon: CheckCircle,
|
||||
iconColor: 'text-green-600',
|
||||
iconBg: 'bg-green-100'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
type: 'webinar_joined',
|
||||
title: 'Attended Live Webinar',
|
||||
description: 'Digital Transformation for Leaders',
|
||||
timestamp: '5 hours ago',
|
||||
icon: Video,
|
||||
iconColor: 'text-blue-600',
|
||||
iconBg: 'bg-blue-100'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
type: 'assessment_completed',
|
||||
title: 'Assessment Completed',
|
||||
description: 'Leadership Style Assessment • Score: 92%',
|
||||
timestamp: '1 day ago',
|
||||
icon: FileText,
|
||||
iconColor: 'text-purple-600',
|
||||
iconBg: 'bg-purple-100'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
type: 'certificate_earned',
|
||||
title: 'Certificate Earned',
|
||||
description: 'Leadership Foundation Certification',
|
||||
timestamp: '2 days ago',
|
||||
icon: Award,
|
||||
iconColor: 'text-brand-gold',
|
||||
iconBg: 'bg-yellow-100'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
type: 'course_started',
|
||||
title: 'Started New Course',
|
||||
description: 'Innovation Leadership Track',
|
||||
timestamp: '3 days ago',
|
||||
icon: PlayCircle,
|
||||
iconColor: 'text-green-600',
|
||||
iconBg: 'bg-green-100'
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
type: 'discussion_posted',
|
||||
title: 'Discussion Contribution',
|
||||
description: 'Team Management Best Practices',
|
||||
timestamp: '4 days ago',
|
||||
icon: MessageSquare,
|
||||
iconColor: 'text-orange-600',
|
||||
iconBg: 'bg-orange-100'
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
type: 'resource_downloaded',
|
||||
title: 'Resource Downloaded',
|
||||
description: 'Leadership Skills Handbook PDF',
|
||||
timestamp: '5 days ago',
|
||||
icon: BookOpen,
|
||||
iconColor: 'text-gray-600',
|
||||
iconBg: 'bg-gray-100'
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
type: 'peer_connection',
|
||||
title: 'New Connection',
|
||||
description: 'Connected with 3 peer learners',
|
||||
timestamp: '1 week ago',
|
||||
icon: Users,
|
||||
iconColor: 'text-brand-navy',
|
||||
iconBg: 'bg-blue-100'
|
||||
}
|
||||
];
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<Card className="h-96 flex flex-col border-0 shadow-lg bg-white">
|
||||
<CardHeader className="pb-3 flex-shrink-0">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-8 h-8 bg-gradient-to-br from-brand-navy to-brand-navy/90 rounded-lg flex items-center justify-center">
|
||||
<Activity className="h-4 w-4 text-white" />
|
||||
</div>
|
||||
<CardTitle className="text-lg font-semibold text-gray-900">
|
||||
Recent Activity
|
||||
</CardTitle>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => navigate('/dashboard?view=individual&tab=activity')}
|
||||
className="text-brand-navy hover:bg-brand-navy/10 border-brand-navy/20 text-base px-3 py-1.5 min-h-[48px] font-medium"
|
||||
>
|
||||
View All
|
||||
</Button>
|
||||
</div>
|
||||
<p className="text-sm text-gray-600 mt-1">
|
||||
Your recent learning activities
|
||||
</p>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent className="px-6 pb-4 flex-1 min-h-0">
|
||||
<ScrollArea className="h-full">
|
||||
<div className="space-y-2 pr-2">
|
||||
{activities.map((activity) => {
|
||||
const Icon = activity.icon;
|
||||
return (
|
||||
<div
|
||||
key={activity.id}
|
||||
className="flex items-start gap-3 p-3 rounded-lg bg-gray-50 hover:bg-gray-100 transition-all duration-200"
|
||||
>
|
||||
{/* Activity Icon */}
|
||||
<div className={`p-2 rounded-lg ${activity.iconBg} flex-shrink-0`}>
|
||||
<Icon className={`h-3 w-3 ${activity.iconColor}`} />
|
||||
</div>
|
||||
|
||||
{/* Activity Content */}
|
||||
<div className="flex-1 min-w-0">
|
||||
<h4 className="text-sm font-semibold text-gray-900 mb-1 leading-tight">
|
||||
{activity.title}
|
||||
</h4>
|
||||
<p className="text-xs text-gray-600 mb-1 leading-relaxed">
|
||||
{activity.description}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500 font-medium">
|
||||
{activity.timestamp}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
36
src/pages/learner/WelcomeMessage.tsx
Normal file
36
src/pages/learner/WelcomeMessage.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
|
||||
// Welcome Message component with simple visible emoji
|
||||
export function WelcomeMessage({ user }: { user: any }) {
|
||||
const [showEmoji, setShowEmoji] = useState(true);
|
||||
const emojiChar = '👋';
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setShowEmoji(false);
|
||||
}, 5000);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="text-4xl font-bold mb-3">
|
||||
<span className="bg-gradient-to-r from-gray-800 via-gray-700 to-gray-600 bg-clip-text text-transparent">
|
||||
Welcome back, Priya Sharma!
|
||||
</span>
|
||||
{showEmoji && (
|
||||
<span
|
||||
className="text-yellow-500 ml-2 inline-block animate-wave-emoji"
|
||||
style={{
|
||||
fontSize: '2.5rem',
|
||||
fontFamily: 'Apple Color Emoji, Segoe UI Emoji, Noto Color Emoji, sans-serif',
|
||||
backgroundColor: 'transparent',
|
||||
color: '#EAB308'
|
||||
}}
|
||||
>
|
||||
{emojiChar}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user