@defikitdotnet/education-module-ai
Version:
AI Education Module using Agent Framework
270 lines (269 loc) • 25 kB
JavaScript
;
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