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": "^1.1.2",
|
||||||
"@radix-ui/react-toggle-group": "^1.1.2",
|
"@radix-ui/react-toggle-group": "^1.1.2",
|
||||||
"@radix-ui/react-tooltip": "^1.1.8",
|
"@radix-ui/react-tooltip": "^1.1.8",
|
||||||
|
"@reduxjs/toolkit": "^2.9.0",
|
||||||
"@tailwindcss/postcss": "^4.1.12",
|
"@tailwindcss/postcss": "^4.1.12",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "*",
|
"clsx": "*",
|
||||||
@@ -48,6 +49,7 @@
|
|||||||
"react-day-picker": "^8.10.1",
|
"react-day-picker": "^8.10.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-hook-form": "^7.55.0",
|
"react-hook-form": "^7.55.0",
|
||||||
|
"react-redux": "^9.2.0",
|
||||||
"react-resizable-panels": "^2.1.7",
|
"react-resizable-panels": "^2.1.7",
|
||||||
"react-router-dom": "^7.8.2",
|
"react-router-dom": "^7.8.2",
|
||||||
"recharts": "^2.15.2",
|
"recharts": "^2.15.2",
|
||||||
@@ -1891,6 +1893,32 @@
|
|||||||
"integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
|
"integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/@rolldown/pluginutils": {
|
||||||
"version": "1.0.0-beta.27",
|
"version": "1.0.0-beta.27",
|
||||||
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
|
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz",
|
||||||
@@ -2178,6 +2206,18 @@
|
|||||||
"win32"
|
"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": {
|
"node_modules/@swc/core": {
|
||||||
"version": "1.13.5",
|
"version": "1.13.5",
|
||||||
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.13.5.tgz",
|
"resolved": "https://registry.npmjs.org/@swc/core/-/core-1.13.5.tgz",
|
||||||
@@ -2765,6 +2805,12 @@
|
|||||||
"@types/react": "^19.0.0"
|
"@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": {
|
"node_modules/@vitejs/plugin-react-swc": {
|
||||||
"version": "3.11.0",
|
"version": "3.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.11.0.tgz",
|
"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==",
|
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
|
||||||
"license": "ISC"
|
"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": {
|
"node_modules/input-otp": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/input-otp/-/input-otp-1.4.2.tgz",
|
"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==",
|
"integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==",
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/react-remove-scroll": {
|
||||||
"version": "2.7.1",
|
"version": "2.7.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz",
|
"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"
|
"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": {
|
"node_modules/rollup": {
|
||||||
"version": "4.49.0",
|
"version": "4.49.0",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.49.0.tgz",
|
"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": "^1.1.2",
|
||||||
"@radix-ui/react-toggle-group": "^1.1.2",
|
"@radix-ui/react-toggle-group": "^1.1.2",
|
||||||
"@radix-ui/react-tooltip": "^1.1.8",
|
"@radix-ui/react-tooltip": "^1.1.8",
|
||||||
|
"@reduxjs/toolkit": "^2.9.0",
|
||||||
"@tailwindcss/postcss": "^4.1.12",
|
"@tailwindcss/postcss": "^4.1.12",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "*",
|
"clsx": "*",
|
||||||
@@ -43,6 +44,7 @@
|
|||||||
"react-day-picker": "^8.10.1",
|
"react-day-picker": "^8.10.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-hook-form": "^7.55.0",
|
"react-hook-form": "^7.55.0",
|
||||||
|
"react-redux": "^9.2.0",
|
||||||
"react-resizable-panels": "^2.1.7",
|
"react-resizable-panels": "^2.1.7",
|
||||||
"react-router-dom": "^7.8.2",
|
"react-router-dom": "^7.8.2",
|
||||||
"recharts": "^2.15.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 { BrowserRouter } from "react-router-dom";
|
||||||
import App from "./App.tsx";
|
import App from "./App.tsx";
|
||||||
import "./styles/globals.css";
|
import "./styles/globals.css";
|
||||||
|
import { Provider } from "react-redux";
|
||||||
|
import { store } from "./Redux/Store.tsx";
|
||||||
|
|
||||||
createRoot(document.getElementById("root")!).render(
|
createRoot(document.getElementById("root")!).render(
|
||||||
|
<Provider store={store}>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<App />
|
<App />
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
|
</Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -40,8 +40,9 @@ import {
|
|||||||
ExternalLink
|
ExternalLink
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, PieChart, Pie, Cell } from 'recharts';
|
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';
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
const exampleImage = 'https://via.placeholder.com/600x400?text=Example+Image';
|
||||||
|
|
||||||
interface SurveyProps {
|
interface SurveyProps {
|
||||||
userType: 'individual' | 'corporate';
|
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 { navigate } from '../../components/Router';
|
||||||
import { ImageWithFallback } from '../../components/figma/ImageWithFallback';
|
import { ImageWithFallback } from '../../components/figma/ImageWithFallback';
|
||||||
import CurrentLearningHeaderIcon from '../../imports/CurrentLearningHeaderIcon-4285-106';
|
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 { 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 {
|
interface DashboardProps {
|
||||||
userType?: 'individual' | 'corporate';
|
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
|
// Weekly Progress Goal Setting Modal component
|
||||||
function WeeklyProgressModal({
|
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
|
// Global Leaderboard component - increased height to match Recent Activity
|
||||||
function GlobalLeaderboard() {
|
function GlobalLeaderboard() {
|
||||||
const leaderboardData = [
|
const leaderboardData = [
|
||||||
@@ -976,6 +552,7 @@ function GlobalLeaderboard() {
|
|||||||
default: return 'bg-gray-100 text-gray-600';
|
default: return 'bg-gray-100 text-gray-600';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="h-96 flex flex-col border-0 shadow-lg bg-white">
|
<Card className="h-96 flex flex-col border-0 shadow-lg bg-white">
|
||||||
|
|||||||
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