UNPKG

@defikitdotnet/education-module-ai

Version:
270 lines (269 loc) 25 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var jsx_runtime_1 = require("react/jsx-runtime"); var react_1 = require("react"); var router_1 = require("next/router"); var link_1 = __importDefault(require("next/link")); var sonner_1 = require("sonner"); var axios_1 = __importDefault(require("axios")); var UserProfileComponent_1 = require("../../components/UserProfileComponent"); // Updated path var UserContext_1 = require("../../context/UserContext"); // Updated path var TeacherContext_1 = require("../../context/TeacherContext"); // Updated path var StudentProfilePage = function () { // Constants var COOKIE_NAME = "studentAuthToken"; var router = (0, router_1.useRouter)(); var teacherId = router.query.teacherId; // Extract teacherId from URL query var _a = (0, react_1.useState)(null), localTeacherId = _a[0], setLocalTeacherId = _a[1]; // Use isVerifying from the context var _b = (0, UserContext_1.useUser)(), contextIsAuthenticated = _b.isAuthenticated, userId = _b.userId, contextIsVerifying = _b.isVerifying, userError = _b.error; var _c = (0, TeacherContext_1.useTeacher)(), teacher = _c.teacher, isTeacherAuthenticated = _c.isTeacherAuthenticated; var _d = (0, react_1.useState)(0), refreshKey = _d[0], setRefreshKey = _d[1]; // Add local authentication state to override context if needed var _e = (0, react_1.useState)(contextIsAuthenticated), isAuthenticated = _e[0], setIsAuthenticated = _e[1]; var _f = (0, react_1.useState)(contextIsVerifying), isVerifying = _f[0], setIsVerifying = _f[1]; var _g = (0, react_1.useState)(null), student = _g[0], setStudent = _g[1]; // Add direct login success state var _h = (0, react_1.useState)(false), directLoginSuccess = _h[0], setDirectLoginSuccess = _h[1]; // Store teacherId from query params for later use (0, react_1.useEffect)(function () { // Extract teacherId from URL query if (router.isReady && teacherId && typeof teacherId === 'string') { console.log("Setting teacherId from URL:", teacherId); setLocalTeacherId(teacherId); // If teacherId is not in URL but we have it stored, add it to URL // This keeps the teacherId consistent across navigation } else if (router.isReady && !teacherId) { // Try to get teacherId from localStorage if not in URL var storedTeacherId = localStorage.getItem('currentTeacherId'); if (storedTeacherId) { console.log("Retrieved teacherId from localStorage:", storedTeacherId); setLocalTeacherId(storedTeacherId); } } // Debug cookie detection console.log("Document cookies:", document.cookie); // Check authentication status directly checkAuthStatus(); }, [router.isReady, teacherId, contextIsAuthenticated]); // Direct authentication check function var checkAuthStatus = function () { return __awaiter(void 0, void 0, void 0, function () { var response, error_1; return __generator(this, function (_a) { switch (_a.label) { case 0: setIsVerifying(true); _a.label = 1; case 1: _a.trys.push([1, 3, 4, 5]); console.log("Directly checking authentication status..."); return [4 /*yield*/, axios_1.default.get("".concat(process.env.NEXT_PUBLIC_BACKEND_URL, "/api/auth/student/status"), { withCredentials: true })]; case 2: response = _a.sent(); console.log("Direct auth check result:", response.data); if (response.data.isAuthenticated) { console.log("User is authenticated!"); setIsAuthenticated(true); setStudent(response.data.student); // If we get here with authentication confirmed, force success state setDirectLoginSuccess(true); // toast.success("Profile loaded successfully"); } else { console.log("Response indicates not authenticated"); setIsAuthenticated(false); setStudent(null); } return [3 /*break*/, 5]; case 3: error_1 = _a.sent(); console.error("Error checking auth status:", error_1); setIsAuthenticated(false); setStudent(null); return [3 /*break*/, 5]; case 4: setIsVerifying(false); return [7 /*endfinally*/]; case 5: return [2 /*return*/]; } }); }); }; // Save teacherId to localStorage whenever it changes (0, react_1.useEffect)(function () { if (localTeacherId) { localStorage.setItem('currentTeacherId', localTeacherId); } }, [localTeacherId]); // API base URL for the education module API var apiBaseUrl = process.env.NEXT_PUBLIC_BACKEND_URL || "http://localhost:3009"; // Handle profile updates var handleProfileUpdated = function () { // Increment refresh key to force a re-render setRefreshKey(function (prevKey) { return prevKey + 1; }); }; // Determine if we're in student mode or teacher mode // For this page, we assume student context primarily, but check teacher for header/footer consistency var isTeacherView = isTeacherAuthenticated && teacher; // Create dashboard URL with teacherId if available var getDashboardUrl = function () { return localTeacherId ? "/student?teacherId=".concat(localTeacherId) : "/student"; }; // Added function to force login var handleSignInClick = function () { // Navigate to login with proper redirect parameters var loginUrl = "/login?redirect=/student/profile".concat(localTeacherId ? "&teacherId=".concat(localTeacherId) : ''); router.push(loginUrl); }; // Modified direct login form handler var handleDirectLogin = function (e) { return __awaiter(void 0, void 0, void 0, function () { var email, password, response, error_2; var _a, _b; return __generator(this, function (_c) { switch (_c.label) { case 0: e.preventDefault(); email = e.currentTarget.elements.namedItem('email').value; password = e.currentTarget.elements.namedItem('password').value; _c.label = 1; case 1: _c.trys.push([1, 4, , 5]); console.log('Attempting direct login for:', email); return [4 /*yield*/, axios_1.default.post('/api/auth/student/direct-login', { email: email, password: password, redirectUrl: "/student/profile".concat(localTeacherId ? "?teacherId=".concat(localTeacherId) : '') }, { withCredentials: true })]; case 2: response = _c.sent(); console.log('Direct login response:', response.data); sonner_1.toast.success('Login successful!'); // Set the student data directly from the response if (response.data.student) { setStudent(response.data.student); setIsAuthenticated(true); // Set direct login success flag setDirectLoginSuccess(true); console.log('Setting direct login success and student data:', response.data.student); } // Force auth status check return [4 /*yield*/, checkAuthStatus()]; case 3: // Force auth status check _c.sent(); // Force a re-render setRefreshKey(function (prev) { return prev + 1; }); return [3 /*break*/, 5]; case 4: error_2 = _c.sent(); console.error('Direct login error:', error_2); sonner_1.toast.error(((_b = (_a = error_2.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.message) || 'Login failed'); return [3 /*break*/, 5]; case 5: return [2 /*return*/]; } }); }); }; // Add useEffect to check cookies on page load (0, react_1.useEffect)(function () { // Add a small delay to ensure cookies are fully loaded var timer = setTimeout(function () { // Check if auth cookies exist in the document var cookies = document.cookie; var hasCookie = cookies.includes(COOKIE_NAME) || cookies.includes("".concat(COOKIE_NAME, "_session")); console.log("Cookies on page load:", document.cookie); console.log("Has auth cookie:", hasCookie); // If we have cookie but no auth state, force auth check if (hasCookie && !isAuthenticated && !directLoginSuccess) { console.log("Found auth cookie but not authenticated - running auth check"); checkAuthStatus(); } }, 500); // Small delay to ensure page is fully loaded return function () { return clearTimeout(timer); }; }, []); // Helper function to render main content based on state var renderProfileContent = function () { console.log("Rendering profile content with states:", { isVerifying: isVerifying, isAuthenticated: isAuthenticated, directLoginSuccess: directLoginSuccess, student: student }); // Priority 0: If we have a successful direct login, show the profile immediately if (directLoginSuccess && student) { console.log("Rendering profile due to direct login success"); return ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsxs)("div", { className: "bg-white p-6 rounded-lg shadow-md", children: [(0, jsx_runtime_1.jsxs)("div", { className: "mb-4 pb-4 border-b border-gray-200", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-xl font-semibold text-gray-800", children: "Student Information" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-gray-500", children: "Successfully authenticated with direct login" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm text-gray-500 mb-1", children: "Name" }), (0, jsx_runtime_1.jsx)("p", { className: "font-medium text-gray-800", children: student.name })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm text-gray-500 mb-1", children: "Email" }), (0, jsx_runtime_1.jsx)("p", { className: "font-medium text-gray-800", children: student.email })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm text-gray-500 mb-1", children: "Student ID" }), (0, jsx_runtime_1.jsx)("p", { className: "font-medium text-gray-800", children: student.id })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("p", { className: "text-sm text-gray-500 mb-1", children: "Joined" }), (0, jsx_runtime_1.jsx)("p", { className: "font-medium text-gray-800", children: new Date(student.created_at).toLocaleDateString() })] })] })] }) }, refreshKey)); } // Priority 1: Show loading spinner while verifying session if (isVerifying) { return ((0, jsx_runtime_1.jsxs)("div", { className: "flex justify-center items-center p-10 bg-white rounded-lg shadow-md", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-gray-600", children: "Verifying session..." }), (0, jsx_runtime_1.jsx)("div", { className: "ml-2 h-5 w-5 border-t-2 border-blue-500 border-solid rounded-full animate-spin" })] })); } // Priority 2: Show error message if verification failed if (userError && !isAuthenticated) { return ((0, jsx_runtime_1.jsxs)("div", { className: "bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded relative", role: "alert", children: [(0, jsx_runtime_1.jsx)("strong", { className: "font-bold", children: "Error:" }), (0, jsx_runtime_1.jsxs)("span", { className: "block sm:inline", children: [" ", userError, ". Please try signing in again."] }), (0, jsx_runtime_1.jsx)("button", { onClick: handleSignInClick, className: "mt-4 ml-4 inline-block bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700 transition-colors", children: "Sign In" })] })); } // Priority 3: If authenticated and not a teacher, show the profile component if (isAuthenticated && !isTeacherView) { return ((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)(UserProfileComponent_1.UserProfileComponent, { apiBaseUrl: apiBaseUrl, showFullDetails: true, onProfileUpdated: handleProfileUpdated }) }, refreshKey)); } // Priority 4: If it's a teacher viewing, show message if (isTeacherView) { return ((0, jsx_runtime_1.jsxs)("div", { className: "bg-white rounded-lg shadow-md p-6 text-center", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-gray-600", children: "This profile page is intended for students. Teacher profiles are managed elsewhere." }), (0, jsx_runtime_1.jsx)(link_1.default, { href: "/teacher", className: "mt-4 inline-block bg-blue-600 text-white px-4 py-2 rounded-md hover:bg-blue-700 transition-colors", children: "Go to Teacher Dashboard" })] })); } // Default Fallback: If not verifying, no error, not authenticated -> show sign in prompt return ((0, jsx_runtime_1.jsxs)("div", { className: "bg-white rounded-lg shadow-md p-6 text-center", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-gray-600 mb-4", children: "Please sign in to view your profile." }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-gray-50 p-4 rounded-lg border border-gray-200 mb-4", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-medium text-gray-700 mb-3", children: "Quick Login" }), (0, jsx_runtime_1.jsxs)("form", { onSubmit: handleDirectLogin, className: "space-y-3", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col", children: [(0, jsx_runtime_1.jsx)("label", { htmlFor: "email", className: "text-sm text-gray-600 text-left mb-1", children: "Email" }), (0, jsx_runtime_1.jsx)("input", { type: "email", id: "email", name: "email", required: true, className: "px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-1 focus:ring-indigo-500" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col", children: [(0, jsx_runtime_1.jsx)("label", { htmlFor: "password", className: "text-sm text-gray-600 text-left mb-1", children: "Password" }), (0, jsx_runtime_1.jsx)("input", { type: "password", id: "password", name: "password", required: true, className: "px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-1 focus:ring-indigo-500" })] }), (0, jsx_runtime_1.jsx)("button", { type: "submit", className: "w-full bg-indigo-600 text-white py-2 px-4 rounded-md hover:bg-indigo-700 transition-colors", children: "Login" })] })] }), (0, jsx_runtime_1.jsx)("p", { className: "mb-4", children: "Or use the regular login page:" }), (0, jsx_runtime_1.jsx)("button", { onClick: handleSignInClick, className: "inline-block bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700 transition-colors", children: "Sign In" }), (0, jsx_runtime_1.jsxs)("div", { className: "mt-4 text-xs text-gray-400", children: [(0, jsx_runtime_1.jsxs)("p", { children: ["Having trouble? Try going back to the ", (0, jsx_runtime_1.jsx)(link_1.default, { href: getDashboardUrl(), className: "text-indigo-500 hover:underline", children: "dashboard" }), " first."] }), (0, jsx_runtime_1.jsx)("p", { className: "mt-2", children: "Or check if cookies are enabled in your browser." })] })] })); }; return ((0, jsx_runtime_1.jsxs)("div", { className: "min-h-screen bg-gray-50", children: [(0, jsx_runtime_1.jsx)(sonner_1.Toaster, { position: "top-center", richColors: true }), (0, jsx_runtime_1.jsx)("header", { className: "".concat(isTeacherView ? "bg-blue-600" : "bg-indigo-600", " text-white shadow-md"), children: (0, jsx_runtime_1.jsxs)("div", { className: "container mx-auto px-4 py-4 flex justify-between items-center", children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-2xl font-bold", children: isTeacherView ? "Teacher Portal" : "Learning Portal" }), (0, jsx_runtime_1.jsx)("div", { className: "flex items-center space-x-4", children: isTeacherView ? ( // Teacher navigation (0, jsx_runtime_1.jsxs)("nav", { className: "flex items-center space-x-6", children: [(0, jsx_runtime_1.jsx)(link_1.default, { href: "/teacher", className: "text-white hover:text-gray-200 transition-colors", children: "Dashboard" }), (0, jsx_runtime_1.jsx)(link_1.default, { href: "/h5p-editor", className: "text-white hover:text-gray-200 transition-colors", children: "Content Editor" }), (0, jsx_runtime_1.jsx)(link_1.default, { href: "/teacher/profile" // Assuming a future teacher profile route , className: "text-white font-medium hover:text-gray-200 transition-colors underline", children: "Profile" })] })) : isAuthenticated || directLoginSuccess ? ( // Show nav if authenticated or direct login successful // Student navigation (0, jsx_runtime_1.jsxs)("nav", { className: "flex items-center space-x-6", children: [(0, jsx_runtime_1.jsx)(link_1.default, { href: getDashboardUrl(), className: "text-white hover:text-gray-200 transition-colors", children: "Dashboard" }), (0, jsx_runtime_1.jsx)(link_1.default, { href: "/student/profile".concat(localTeacherId ? "?teacherId=".concat(localTeacherId) : ''), className: "text-white font-medium hover:text-gray-200 transition-colors underline", children: "Profile" }), (0, jsx_runtime_1.jsx)("button", { onClick: function () { return window.location.reload(); }, className: "bg-white text-indigo-600 px-3 py-1 rounded hover:bg-gray-100 transition-colors font-medium", title: "Force reload the page to refresh authentication state", children: "\u21BB Reload" })] })) : ( // Only show Sign In link if definitely not authenticated AND not verifying !isVerifying && (0, jsx_runtime_1.jsx)("button", { onClick: handleSignInClick, className: "text-white hover:text-gray-200 transition-colors", children: "Sign In" })) })] }) }), (0, jsx_runtime_1.jsxs)("main", { className: "container mx-auto px-4 py-8 max-w-4xl", children: [(0, jsx_runtime_1.jsxs)("div", { className: "mb-6", children: [(0, jsx_runtime_1.jsx)("h2", { className: "text-2xl font-bold text-gray-800", children: "My Profile" }), (0, jsx_runtime_1.jsx)("p", { className: "text-gray-600", children: "Manage your account information and learning preferences." })] }), renderProfileContent()] }), (0, jsx_runtime_1.jsx)("footer", { className: "bg-gray-800 text-white py-8 mt-16", children: (0, jsx_runtime_1.jsxs)("div", { className: "container mx-auto px-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-8", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-semibold mb-4", children: "Learning Portal" }), (0, jsx_runtime_1.jsx)("p", { className: "text-gray-400 text-sm", children: "An interactive educational platform designed to enhance learning through personalized content and adaptive teaching methods." })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-semibold mb-4", children: "Quick Links" }), (0, jsx_runtime_1.jsxs)("ul", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("li", { children: (0, jsx_runtime_1.jsx)(link_1.default, { href: isTeacherView ? "/teacher" : getDashboardUrl(), className: "text-gray-400 hover:text-white transition-colors", children: "Dashboard" }) }), (isVerifying || isAuthenticated) && !isTeacherView && ((0, jsx_runtime_1.jsx)("li", { children: (0, jsx_runtime_1.jsx)(link_1.default, { href: "/student/profile".concat(localTeacherId ? "?teacherId=".concat(localTeacherId) : ''), className: "text-gray-400 hover:text-white transition-colors", children: "My Profile" }) })), isTeacherView && ((0, jsx_runtime_1.jsx)("li", { children: (0, jsx_runtime_1.jsx)(link_1.default, { href: "/teacher/settings", className: "text-gray-400 hover:text-white transition-colors", children: "Settings" }) }))] })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-semibold mb-4", children: "Support" }), (0, jsx_runtime_1.jsxs)("ul", { className: "space-y-2", children: [(0, jsx_runtime_1.jsx)("li", { children: (0, jsx_runtime_1.jsx)("a", { href: "#", className: "text-gray-400 hover:text-white transition-colors", children: "Help Center" }) }), (0, jsx_runtime_1.jsx)("li", { children: (0, jsx_runtime_1.jsx)("a", { href: "#", className: "text-gray-400 hover:text-white transition-colors", children: "Contact Support" }) })] })] })] }), (0, jsx_runtime_1.jsx)("div", { className: "border-t border-gray-700 mt-8 pt-6 text-sm text-gray-400 text-center", children: (0, jsx_runtime_1.jsxs)("p", { children: ["\u00A9 ", new Date().getFullYear(), " Education Platform. All rights reserved."] }) })] }) })] })); }; exports.default = StudentProfilePage; // Renamed export