diff --git a/src/components/ActivityLog/CommentSection.jsx b/src/components/ActivityLog/CommentSection.jsx
new file mode 100644
index 0000000000..2a4ad03b75
--- /dev/null
+++ b/src/components/ActivityLog/CommentSection.jsx
@@ -0,0 +1,78 @@
+import PropTypes from 'prop-types';
+import { useState } from 'react';
+import { MessageSquare } from 'lucide-react';
+import styles from './styles/CommentSection.module.css';
+import { IconByRole, Tag } from './icons';
+import { useSelector } from 'react-redux';
+
+const CommentSection = ({ logId, comments, userRole, handleCommentSubmit }) => {
+ const [newComment, setNewComment] = useState('');
+ const darkMode = useSelector(state => state.theme.darkMode);
+
+ const onSubmit = () => {
+ if (newComment.trim()) {
+ handleCommentSubmit(logId, newComment);
+ setNewComment('');
+ }
+ };
+
+ return (
+
+
+
Interaction / Comments
+
+
+ {comments.length === 0 && (
+
No comments yet. Start the conversation!
+ )}
+ {comments.map(comment => (
+
+
+
+ {comment.author}
+ {comment.role}
+
+
{comment.text}
+
+ ))}
+
+
+
+
+
+
+
+
+ );
+};
+
+CommentSection.propTypes = {
+ logId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
+ comments: PropTypes.arrayOf(
+ PropTypes.shape({
+ id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
+ role: PropTypes.string.isRequired,
+ author: PropTypes.string.isRequired,
+ text: PropTypes.string.isRequired,
+ }),
+ ).isRequired,
+ userRole: PropTypes.string.isRequired,
+ handleCommentSubmit: PropTypes.func.isRequired,
+};
+
+export default CommentSection;
diff --git a/src/components/ActivityLog/CreateLogForm.jsx b/src/components/ActivityLog/CreateLogForm.jsx
new file mode 100644
index 0000000000..576bc987a5
--- /dev/null
+++ b/src/components/ActivityLog/CreateLogForm.jsx
@@ -0,0 +1,153 @@
+import PropTypes from 'prop-types';
+import { useState } from 'react';
+import { CheckCircle, Send } from 'lucide-react';
+import styles from './styles/CreateLogForm.module.css';
+import { MOCK_USERS } from './MockLogs';
+import { useSelector } from 'react-redux';
+
+const CreateLogForm = ({ userRole, currentUserName, setViewMode, handleAddLog }) => {
+ const isSupport = userRole === 'Support';
+ const roleName = isSupport ? 'Support Member' : 'Student';
+
+ const darkMode = useSelector(state => state.theme.darkMode);
+ const [formData, setFormData] = useState({
+ logContent: '',
+ course: 'Course A',
+ notesToTeacher: '',
+ });
+ const [isSubmitted, setIsSubmitted] = useState(false);
+ const [error, setError] = useState(null);
+
+ const handleChange = e => {
+ const { id, value } = e.target;
+ setFormData(prev => ({ ...prev, [id]: value }));
+ setError(null);
+ };
+
+ const handleSubmit = e => {
+ e.preventDefault();
+
+ if (!formData.logContent.trim()) {
+ setError('Log Content is required to submit a log entry.');
+ return;
+ }
+
+ const newLog = {
+ id: Date.now(),
+ submittedBy: currentUserName,
+ role: userRole,
+ timestamp: new Date().toISOString(),
+ logContent: formData.logContent,
+ course: formData.course,
+ notesToTeacher: formData.notesToTeacher || 'N/A',
+ assistedBy: isSupport ? { name: currentUserName, role: 'Support' } : null,
+ studentName: isSupport ? 'Young Learner Placeholder' : currentUserName,
+ studentRole: isSupport ? 'Unknown Grade' : MOCK_USERS.student.role,
+ teacher: isSupport ? 'Educator to be assigned' : MOCK_USERS.educator.name,
+ teacherFeedback: null,
+ comments: [],
+ };
+
+ handleAddLog(newLog);
+
+ setIsSubmitted(true);
+ setFormData({ logContent: '', course: 'Course A', notesToTeacher: '' });
+
+ setTimeout(() => {
+ setIsSubmitted(false);
+ if (setViewMode) setViewMode('viewer');
+ }, 2000);
+ };
+
+ return (
+
+
+
Create Daily Log
+
+ Add your log details below. Currently acting as a{' '}
+ {roleName}.
+
+
+ {isSubmitted && (
+
+
+ Success! Log entry submitted successfully.
+ Switching back to Viewer...
+
+ )}
+
+ {error && (
+
+ Error: {error}
+
+ )}
+
+
+
+
+ );
+};
+
+CreateLogForm.propTypes = {
+ userRole: PropTypes.string.isRequired,
+ currentUserName: PropTypes.string.isRequired,
+ setViewMode: PropTypes.func,
+ handleAddLog: PropTypes.func.isRequired,
+};
+
+export default CreateLogForm;
diff --git a/src/components/ActivityLog/DailyLogPage.jsx b/src/components/ActivityLog/DailyLogPage.jsx
new file mode 100644
index 0000000000..65a24f8af4
--- /dev/null
+++ b/src/components/ActivityLog/DailyLogPage.jsx
@@ -0,0 +1,204 @@
+import React, { useState, useMemo, useEffect } from 'react';
+import { MOCK_USERS, INITIAL_MOCK_LOGS } from './MockLogs';
+import { useSelector } from 'react-redux';
+import styles from './styles/DailyLogPage.module.css';
+import CreateLogForm from './CreateLogForm';
+import { User, BookOpen, PlusSquare } from 'lucide-react';
+import LogEntryView from './LogEntryView';
+const ActivityLogs = () => {
+ const darkMode = useSelector(state => state.theme.darkMode);
+ const [currentUserRole, setCurrentUserRole] = useState('Educator');
+ const [logs, setLogs] = useState(INITIAL_MOCK_LOGS);
+ const [logToDisplayId, setLogToDisplayId] = useState(1);
+ const [viewMode, setViewMode] = useState('viewer');
+
+ const currentUserName = MOCK_USERS[currentUserRole.toLowerCase()]?.name || 'Unknown User';
+ const isEducator = currentUserRole === 'Educator';
+ const isCreator = currentUserRole === 'Student' || currentUserRole === 'Support';
+
+ const logToDisplay = useMemo(() => logs.find(log => log.id === logToDisplayId), [
+ logs,
+ logToDisplayId,
+ ]);
+
+ const handleAddLog = newLog => {
+ setLogs(prevLogs => [newLog, ...prevLogs]);
+ setLogToDisplayId(newLog.id);
+ };
+
+ const toggleAssistedStatus = logId => {
+ const supportUser = MOCK_USERS.support;
+ setLogs(prevLogs =>
+ prevLogs.map(log => {
+ if (log.id === logId) {
+ const isCurrentlyAssisted = !!log.assistedBy;
+ return {
+ ...log,
+ assistedBy: isCurrentlyAssisted
+ ? null
+ : { name: supportUser.name, role: supportUser.role },
+ };
+ }
+ return log;
+ }),
+ );
+ };
+
+ const handleFeedbackSubmit = (logId, feedbackContent) => {
+ if (!isEducator) return;
+ setLogs(prevLogs =>
+ prevLogs.map(log => {
+ if (log.id === logId) {
+ return {
+ ...log,
+ teacherFeedback: {
+ teacherName: currentUserName,
+ feedback: feedbackContent,
+ timestamp: new Date().toISOString(),
+ },
+ };
+ }
+ return log;
+ }),
+ );
+ };
+
+ const handleCommentSubmit = (logId, commentText) => {
+ if (!commentText.trim()) return;
+
+ const newComment = {
+ id: Date.now(),
+ author: currentUserName,
+ role: currentUserRole,
+ text: commentText,
+ timestamp: new Date().toISOString(),
+ };
+
+ setLogs(prevLogs =>
+ prevLogs.map(log => {
+ if (log.id === logId) {
+ return { ...log, comments: [...log.comments, newComment] };
+ }
+ return log;
+ }),
+ );
+ };
+
+ const roleOptions = Object.keys(MOCK_USERS);
+
+ useEffect(() => {
+ if (isEducator) setViewMode('viewer');
+ if (!logToDisplay && logs.length > 0) setLogToDisplayId(logs[0].id);
+ }, [currentUserRole, logs, logToDisplay]);
+
+ let PageContent;
+ if (viewMode === 'viewer' && logToDisplay) {
+ PageContent = (
+
+ );
+ } else if (viewMode === 'creator' && isCreator) {
+ PageContent = (
+
+ );
+ } else {
+ PageContent = (
+
+ No logs are available to display or review. Try submitting one as a Student/Support user
+ first!
+
+ );
+ }
+
+ return (
+
+
+
+ Daily Log System
+
+ {isCreator && (
+
+ )}
+
+ {logs.length > 0 && viewMode === 'viewer' && (
+
+
+ View Log:
+
+
+ )}
+
+
+
+ User Role:
+
+
+
+
+
+
{PageContent}
+
+
+
+
+ );
+};
+
+export default ActivityLogs;
diff --git a/src/components/ActivityLog/EducatorFeedbackForm.jsx b/src/components/ActivityLog/EducatorFeedbackForm.jsx
new file mode 100644
index 0000000000..d233959742
--- /dev/null
+++ b/src/components/ActivityLog/EducatorFeedbackForm.jsx
@@ -0,0 +1,73 @@
+import PropTypes from 'prop-types';
+import { useState } from 'react';
+import { CheckCircle, Send } from 'lucide-react';
+import styles from './styles/EducatorFeedback.module.css';
+import { useSelector } from 'react-redux';
+
+const EducatorFeedbackForm = ({
+ logId,
+ currentTeacherName,
+ logHasFeedback,
+ handleFeedbackSubmit,
+}) => {
+ const [feedback, setFeedback] = useState('');
+ const [isSubmitted, setIsSubmitted] = useState(false);
+
+ const labelText = logHasFeedback ? 'Update Teacher Feedback' : 'Submit Teacher Feedback';
+ const darkMode = useSelector(state => state.theme.darkMode);
+
+ const handleSubmit = e => {
+ e.preventDefault();
+ if (feedback.trim()) {
+ handleFeedbackSubmit(logId, feedback);
+ setFeedback('');
+ setIsSubmitted(true);
+ setTimeout(() => setIsSubmitted(false), 2000);
+ }
+ };
+
+ return (
+
+
+
{labelText}
+
+ {isSubmitted && (
+
+
+ Success! Feedback submitted for the
+ student.
+
+ )}
+
+
+
+
+ );
+};
+
+EducatorFeedbackForm.propTypes = {
+ logId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
+ currentTeacherName: PropTypes.string.isRequired,
+ logHasFeedback: PropTypes.bool.isRequired,
+ handleFeedbackSubmit: PropTypes.func.isRequired,
+};
+
+export default EducatorFeedbackForm;
diff --git a/src/components/ActivityLog/LogEntryView.jsx b/src/components/ActivityLog/LogEntryView.jsx
new file mode 100644
index 0000000000..b914db50ba
--- /dev/null
+++ b/src/components/ActivityLog/LogEntryView.jsx
@@ -0,0 +1,128 @@
+import PropTypes from 'prop-types';
+import { User, BookOpen } from 'lucide-react';
+import styles from './styles/LogEntryView.module.css';
+import { Tag } from './icons';
+import { useSelector } from 'react-redux';
+import TeacherFeedback from './TeacherFeedback';
+import EducatorFeedbackForm from './EducatorFeedbackForm';
+import CommentSection from './CommentSection';
+
+const LogEntryView = ({
+ log,
+ currentUserRole,
+ currentUserName,
+ toggleAssistedStatus,
+ handleCommentSubmit,
+ handleFeedbackSubmit,
+}) => {
+ const isEducator = currentUserRole === 'Educator';
+ const showAssistedTag = log.assistedBy;
+
+ const darkMode = useSelector(state => state.theme.darkMode);
+ return (
+
+
+ {/* Student/Log Header Card */}
+
+
+
+
+
+
+
+ {log.studentName}
+ {showAssistedTag && (
+
+
+ Assisted by: {log.assistedBy.name}
+
+ )}
+
+
+ {log.studentRole} | Teacher: {log.teacher}
+
+
Log for {log.course}
+
+
+
+ {/* Educator Assisted Tag Toggle */}
+
+ {isEducator && (
+
+ )}
+
+
+
+ {/* Log Content & Notes */}
+
+
+
Log Content
+
{log.logContent}
+
+
+
Notes to Teacher
+
+ {log.notesToTeacher || 'No optional notes provided.'}
+
+
+
+
+
+
+ {isEducator && (
+
+ )}
+
+
+
+
+ );
+};
+
+LogEntryView.propTypes = {
+ log: PropTypes.shape({
+ id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
+ studentName: PropTypes.string.isRequired,
+ studentRole: PropTypes.string.isRequired,
+ teacher: PropTypes.string.isRequired,
+ course: PropTypes.string.isRequired,
+ logContent: PropTypes.string.isRequired,
+ notesToTeacher: PropTypes.string,
+ teacherFeedback: PropTypes.any,
+ assistedBy: PropTypes.shape({
+ name: PropTypes.string.isRequired,
+ role: PropTypes.string,
+ }),
+ comments: PropTypes.arrayOf(
+ PropTypes.shape({
+ id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
+ role: PropTypes.string.isRequired,
+ author: PropTypes.string.isRequired,
+ text: PropTypes.string.isRequired,
+ }),
+ ),
+ }).isRequired,
+ currentUserRole: PropTypes.string.isRequired,
+ currentUserName: PropTypes.string.isRequired,
+ toggleAssistedStatus: PropTypes.func.isRequired,
+ handleCommentSubmit: PropTypes.func.isRequired,
+ handleFeedbackSubmit: PropTypes.func.isRequired,
+};
+
+export default LogEntryView;
diff --git a/src/components/ActivityLog/MockLogs.js b/src/components/ActivityLog/MockLogs.js
new file mode 100644
index 0000000000..2fbad305e1
--- /dev/null
+++ b/src/components/ActivityLog/MockLogs.js
@@ -0,0 +1,58 @@
+const INITIAL_MOCK_LOGS = [
+ {
+ id: 1,
+ studentName: 'John Doe',
+ studentRole: 'Grade A',
+ teacher: 'Mr. Smith',
+ course: 'Course A',
+ logContent: 'Completed chapter 3 exercises on geometric proofs.',
+ notesToTeacher: 'I found the last proof very challenging.',
+ teacherFeedback: {
+ teacherName: 'Mr. Smith',
+ feedback: 'Great work! Well done. Focus on the deductive reasoning steps.',
+ },
+ assistedBy: null, // Initial state: Log created by student
+ comments: [
+ {
+ id: 101,
+ author: 'Mr. Smith',
+ role: 'Educator',
+ text: 'Please review the feedback before starting chapter 4.',
+ },
+ {
+ id: 102,
+ author: 'John Doe',
+ role: 'Student',
+ text: 'Will do, thank you for the clarity on deductive reasoning.',
+ },
+ ],
+ },
+ {
+ id: 2,
+ studentName: 'Jane Doe',
+ studentRole: 'Grade B',
+ teacher: 'Ms. Johnson',
+ course: 'General Log',
+ logContent: 'Had difficulty logging into the learning platform today. Submitted a ticket.',
+ notesToTeacher: 'N/A',
+ teacherFeedback: null,
+ assistedBy: { name: 'Sarah Connor', role: 'Support' }, // Log created by support on behalf of student
+ comments: [
+ {
+ id: 201,
+ author: 'Jane Doe',
+ role: 'Student',
+ text: 'Thanks Sarah for helping me report this.',
+ },
+ { id: 202, author: 'Ms. Johnson', role: 'Educator', text: "Issue noted. I've contacted IT." },
+ ],
+ },
+];
+
+const MOCK_USERS = {
+ educator: { name: 'Mr. Smith', role: 'Educator' },
+ student: { name: 'John Doe', role: 'Student' },
+ support: { name: 'Sarah Connor', role: 'Support' },
+};
+
+export { INITIAL_MOCK_LOGS, MOCK_USERS };
diff --git a/src/components/ActivityLog/TeacherFeedback.jsx b/src/components/ActivityLog/TeacherFeedback.jsx
new file mode 100644
index 0000000000..9cc02848e2
--- /dev/null
+++ b/src/components/ActivityLog/TeacherFeedback.jsx
@@ -0,0 +1,33 @@
+import PropTypes from 'prop-types';
+import styles from './styles/TeacherFeedbackForm.module.css';
+import { useSelector } from 'react-redux';
+
+const TeacherFeedback = ({ feedbackData }) => {
+ const darkMode = useSelector(state => state.theme.darkMode);
+
+ return (
+
+
+
Teacher Feedback
+
+ {feedbackData ? (
+
+
{feedbackData.teacherName}
+
{feedbackData.feedback}
+
+ ) : (
+
No feedback available yet.
+ )}
+
+
+ );
+};
+
+TeacherFeedback.propTypes = {
+ feedbackData: PropTypes.shape({
+ teacherName: PropTypes.string.isRequired,
+ feedback: PropTypes.string.isRequired,
+ }),
+};
+
+export default TeacherFeedback;
diff --git a/src/components/ActivityLog/icons.jsx b/src/components/ActivityLog/icons.jsx
new file mode 100644
index 0000000000..c5ecfe591d
--- /dev/null
+++ b/src/components/ActivityLog/icons.jsx
@@ -0,0 +1,40 @@
+import PropTypes from 'prop-types';
+import icons from './styles/icons.module.css';
+import { Briefcase, GraduationCap, User } from 'lucide-react';
+
+const IconByRole = ({ role, className = icons.icon }) => {
+ switch (role) {
+ case 'Educator':
+ return ;
+ case 'Student':
+ return ;
+ case 'Support':
+ return ;
+ default:
+ return ;
+ }
+};
+
+IconByRole.propTypes = {
+ role: PropTypes.string.isRequired,
+ className: PropTypes.string,
+};
+
+const Tag = ({ children, color, darkMode }) => {
+ const darkColor = darkMode ? `${color}Dark` : undefined;
+ return (
+
+ {children}
+
+ );
+};
+
+Tag.propTypes = {
+ children: PropTypes.node.isRequired,
+ color: PropTypes.string,
+ darkMode: PropTypes.bool,
+};
+
+export { IconByRole, Tag };
diff --git a/src/components/ActivityLog/styles/CommentSection.module.css b/src/components/ActivityLog/styles/CommentSection.module.css
new file mode 100644
index 0000000000..bbba6edce7
--- /dev/null
+++ b/src/components/ActivityLog/styles/CommentSection.module.css
@@ -0,0 +1,166 @@
+/* Comment Section */
+.commentSectionContainer {
+ margin-top: 32px;
+}
+
+.commentSectionTitle {
+ font-size: 1.5rem;
+ font-weight: 800;
+ color: #111827;
+ margin-bottom: 16px;
+}
+
+.commentList {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ max-height: 16rem;
+ overflow-y: auto;
+ padding-right: 8px;
+ margin-bottom: 16px;
+}
+
+.noComments {
+ text-align: center;
+ color: #6b7280;
+ font-style: italic;
+}
+
+.commentCard {
+ padding: 12px;
+ background-color: #ffffff;
+ border-radius: 12px;
+ border: 1px solid #e5e7eb;
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
+}
+
+.commentHeader {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ margin-bottom: 4px;
+}
+
+.commentIcon {
+ width: 12px;
+ height: 12px;
+ color: #6366f1;
+}
+
+.commentAuthor {
+ font-weight: 600;
+ font-size: 0.875rem;
+ color: #111827;
+}
+
+.commentRoleTag {
+ background-color: #e0e7ff;
+ color: #4338ca;
+ padding: 0 6px;
+ border-radius: 6px;
+ font-size: 0.75rem;
+}
+
+.commentText {
+ color: #374151;
+ font-size: 0.875rem;
+}
+
+/* New Comment Input */
+.commentInputWrapper {
+ display: flex;
+ align-items: flex-start;
+ gap: 12px;
+}
+
+.commentTextarea {
+ flex-grow: 1;
+ padding: 12px;
+ border-radius: 12px;
+ border: 1px solid #d1d5db;
+ background-color: #f9fafb;
+ color: #111827;
+ font-size: 0.875rem;
+ transition: all 0.15s ease-in-out;
+}
+
+.commentTextarea:focus {
+ outline: none;
+ border-color: #6366f1;
+}
+
+.commentSubmitBtn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ font-weight: 700;
+ padding: 12px 20px;
+ border-radius: 12px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ background-color: #16a34a;
+ color: #ffffff;
+ cursor: pointer;
+ transition: background-color 0.2s ease-in-out;
+}
+
+.commentSubmitBtn:hover {
+ background-color: #15803d;
+}
+
+.commentSubmitDisabled {
+ background-color: #9ca3af;
+ color: #374151;
+ cursor: not-allowed;
+}
+
+.submitIcon {
+ width: 20px;
+ height: 20px;
+}
+
+/* Dark Mode Overrides */
+.darkMode .commentSectionTitle {
+ color: #f3f4f6;
+}
+
+.darkMode .commentCard {
+ background-color: #1f2937;
+ border-color: #374151;
+}
+
+.darkMode .commentAuthor {
+ color: #f3f4f6;
+}
+
+.darkMode .commentText {
+ color: #d1d5db;
+}
+
+.darkMode .noComments {
+ color: #d1d5db;
+}
+
+.darkMode .commentTextarea {
+ background-color: #374151;
+ border-color: #4b5563;
+ color: #f3f4f6;
+}
+
+.darkMode .commentSubmitBtn {
+ background-color: #16a34a;
+ color: #f3f4f6;
+}
+
+.darkMode .commentSubmitBtn:hover {
+ background-color: #15803d;
+}
+
+.darkMode .commentSubmitDisabled {
+ background-color: #4b5563;
+ color: #d1d5db;
+}
+
+.darkMode .submitIcon {
+ color: #f3f4f6;
+}
diff --git a/src/components/ActivityLog/styles/CreateLogForm.module.css b/src/components/ActivityLog/styles/CreateLogForm.module.css
new file mode 100644
index 0000000000..1824f7429d
--- /dev/null
+++ b/src/components/ActivityLog/styles/CreateLogForm.module.css
@@ -0,0 +1,192 @@
+.formContainer {
+ padding: 24px;
+ background-color: #ffffff;
+ border-radius: 12px;
+ border: 1px solid #e5e7eb;
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05);
+}
+
+.title {
+ font-size: 1.5rem;
+ font-weight: 800;
+ color: #111827;
+ margin-bottom: 8px;
+}
+
+.description {
+ font-size: 0.875rem;
+ color: #6b7280;
+ margin-bottom: 24px;
+}
+
+.roleName {
+ font-weight: 600;
+ color: #6366f1;
+}
+
+.successMessage {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 16px;
+ margin-bottom: 16px;
+ background-color: #dcfce7;
+ color: #166534;
+ border-radius: 12px;
+ font-size: 0.875rem;
+ transition: opacity 0.3s;
+}
+
+.errorMessage {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 16px;
+ margin-bottom: 16px;
+ background-color: #fef2f2;
+ color: #991b1b;
+ border-radius: 12px;
+ font-size: 0.875rem;
+ transition: opacity 0.3s;
+}
+
+.bold {
+ font-weight: 600;
+}
+
+.icon {
+ width: 20px;
+ height: 20px;
+}
+
+.formGrid {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: 24px;
+}
+
+.rightColumn {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+}
+
+.label {
+ display: block;
+ font-size: 0.875rem;
+ font-weight: 500;
+ color: #374151;
+ margin-bottom: 4px;
+}
+
+.textarea {
+ width: 100%;
+ padding: 12px;
+ border-radius: 12px;
+ border: 1px solid #d1d5db;
+ background-color: #f9fafb;
+ color: #111827;
+ font-size: 0.875rem;
+ transition: all 0.15s ease-in-out;
+}
+
+.textarea:focus {
+ outline: none;
+ border-color: #6366f1;
+}
+
+.input {
+ width: 100%;
+ padding: 12px;
+ border-radius: 12px;
+ border: 1px solid #d1d5db;
+ background-color: #f9fafb;
+ color: #111827;
+ font-size: 0.875rem;
+ transition: all 0.15s ease-in-out;
+}
+
+.select {
+ width: 100%;
+ padding: 12px;
+ border-radius: 12px;
+ border: 1px solid #d1d5db;
+ background-color: #f9fafb;
+ color: #111827;
+ font-size: 0.875rem;
+ transition: all 0.15s ease-in-out;
+}
+
+.submitBtn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ font-weight: 700;
+ padding: 12px;
+ border-radius: 12px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ background-color: #4f46e5;
+ color: #ffffff;
+ cursor: pointer;
+ transition: background-color 0.2s ease-in-out;
+ margin-top: 16px;
+}
+
+.submitBtn:hover {
+ background-color: #4338ca;
+}
+
+.disabledBtn {
+ background-color: #9ca3af;
+ color: #374151;
+ cursor: not-allowed;
+}
+
+/* Dark Mode Overrides */
+.darkMode .formContainer {
+ background-color: #1f2937;
+ border-color: #374151;
+}
+
+.darkMode .title {
+ color: #f3f4f6;
+}
+
+.darkMode .description {
+ color: #d1d5db;
+}
+
+.darkMode .label {
+ color: #e5e7eb;
+}
+
+.darkMode .textarea,
+.darkMode .input,
+.darkMode .select {
+ background-color: #374151;
+ border-color: #4b5563;
+ color: #f3f4f6;
+}
+
+.darkMode .submitBtn {
+ background-color: #4f46e5;
+ color: #f3f4f6;
+}
+
+.darkMode .submitBtn:hover {
+ background-color: #4338ca;
+}
+
+.darkMode .disabledBtn {
+ background-color: #4b5563;
+ color: #d1d5db;
+}
+
+.darkMode .icon {
+ color: #f3f4f6;
+}
+
+.darkMode .roleName {
+ color: #818cf8;
+}
diff --git a/src/components/ActivityLog/styles/DailyLogPage.module.css b/src/components/ActivityLog/styles/DailyLogPage.module.css
new file mode 100644
index 0000000000..f3ff939629
--- /dev/null
+++ b/src/components/ActivityLog/styles/DailyLogPage.module.css
@@ -0,0 +1,182 @@
+/* Light Mode Styles */
+.container {
+ min-height: 100vh;
+ padding: 16px;
+ font-family: sans-serif;
+ background-color: #f9fafb;
+ color: #111827;
+}
+
+.header {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 40px;
+ padding: 16px;
+ background-color: #fff;
+ border-radius: 16px;
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
+ border-bottom: 1px solid #f3f4f6;
+}
+
+.title {
+ font-size: 2rem;
+ font-weight: 900;
+ color: #4f46e5;
+ margin-bottom: 16px;
+}
+
+.controls {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 16px;
+ align-items: center;
+}
+
+.createButton {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-weight: bold;
+ padding: 8px 16px;
+ border-radius: 12px;
+ background-color: #4f46e5;
+ color: #fff;
+ cursor: pointer;
+ transition: background-color 0.2s ease-in-out;
+}
+
+.createButton:hover {
+ background-color: #4338ca;
+}
+
+.viewButton {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-weight: bold;
+ padding: 8px 16px;
+ border-radius: 12px;
+ background-color: #9ca3af;
+ color: #1f2937;
+ cursor: pointer;
+ transition: background-color 0.2s ease-in-out;
+}
+
+.viewButton:hover {
+ background-color: #6b7280;
+}
+
+.icon {
+ width: 20px;
+ height: 20px;
+}
+
+.iconSmall {
+ width: 16px;
+ height: 16px;
+}
+
+.logSwitcher,
+.roleSelector {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 8px;
+ background-color: #f3f4f6;
+ border-radius: 12px;
+}
+
+.select {
+ background-color: #fff;
+ border: 1px solid #d1d5db;
+ border-radius: 8px;
+ padding: 4px 8px;
+ font-size: 0.875rem;
+ color: #111827;
+}
+
+.main {
+ max-width: 1024px;
+ margin: 0 auto;
+}
+
+.footer {
+ margin-top: 40px;
+ padding-top: 16px;
+ border-top: 1px solid #e5e7eb;
+ text-align: center;
+ font-size: 0.875rem;
+ color: #6b7280;
+}
+
+.noLogs {
+ text-align: center;
+ padding: 40px;
+ background-color: #fff;
+ border-radius: 16px;
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
+ color: #6b7280;
+}
+
+/* Dark Mode Overrides */
+.darkMode .container {
+ background-color: #1f2937;
+ color: #f3f4f6;
+}
+
+.darkMode .header {
+ background-color: #374151;
+ border-bottom: 1px solid #4b5563;
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.5);
+}
+
+.darkMode .title {
+ color: #818cf8;
+}
+
+.darkMode .createButton {
+ background-color: #6366f1;
+ color: #f9fafb;
+}
+
+.darkMode .createButton:hover {
+ background-color: #4f46e5;
+}
+
+.darkMode .viewButton {
+ background-color: #6b7280;
+ color: #f3f4f6;
+}
+
+.darkMode .viewButton:hover {
+ background-color: #4b5563;
+}
+
+.darkMode .logSwitcher,
+.darkMode .roleSelector {
+ background-color: #4b5563;
+}
+
+.darkMode .select {
+ background-color: #374151;
+ border: 1px solid #6b7280;
+ color: #f3f4f6;
+}
+
+.darkMode .main {
+ max-width: 1024px;
+ margin: 0 auto;
+}
+
+.darkMode .footer {
+ border-top: 1px solid #6b7280;
+ color: #d1d5db;
+}
+
+.darkMode .noLogs {
+ background-color: #374151;
+ color: #d1d5db;
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.5);
+}
diff --git a/src/components/ActivityLog/styles/EducatorFeedback.module.css b/src/components/ActivityLog/styles/EducatorFeedback.module.css
new file mode 100644
index 0000000000..3611a81635
--- /dev/null
+++ b/src/components/ActivityLog/styles/EducatorFeedback.module.css
@@ -0,0 +1,125 @@
+/* Educator Feedback Form */
+.feedbackFormContainer {
+ margin-top: 32px;
+ padding: 24px;
+ background-color: #fef3c7;
+ border-radius: 16px;
+ border: 1px solid #fde68a;
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
+}
+
+.feedbackFormTitle {
+ font-size: 1.25rem;
+ font-weight: 700;
+ color: #b45309;
+ margin-bottom: 16px;
+}
+
+.successAlert {
+ display: flex;
+ align-items: center;
+ padding: 12px;
+ margin-bottom: 16px;
+ font-size: 0.875rem;
+ color: #065f46;
+ background-color: #d1fae5;
+ border-radius: 12px;
+ transition: opacity 0.3s;
+}
+
+.alertIcon {
+ width: 20px;
+ height: 20px;
+ margin-right: 12px;
+}
+
+.alertText {
+ font-weight: 600;
+}
+
+.feedbackTextarea {
+ width: 100%;
+ padding: 12px;
+ border-radius: 12px;
+ border: 1px solid #fcd34d;
+ background-color: #ffffff;
+ color: #111827;
+ font-size: 0.875rem;
+ transition: all 0.15s ease-in-out;
+}
+
+.feedbackTextarea:focus {
+ outline: none;
+ border-color: #fbbf24;
+}
+
+.feedbackSubmitBtn {
+ width: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ font-weight: 700;
+ padding: 12px;
+ border-radius: 12px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ margin-top: 12px;
+ background-color: #d97706;
+ color: #fff;
+ cursor: pointer;
+ transition: background-color 0.2s ease-in-out;
+}
+
+.feedbackSubmitBtn:hover {
+ background-color: #b45309;
+}
+
+.feedbackSubmitDisabled {
+ background-color: #9ca3af;
+ color: #374151;
+ cursor: not-allowed;
+}
+
+.submitIcon {
+ width: 20px;
+ height: 20px;
+}
+
+/* Dark Mode */
+.darkMode .feedbackFormContainer {
+ background-color: rgba(202, 138, 4, 0.2); /* yellow-900/30 */
+ border-color: #78350f; /* dark yellow border */
+}
+
+.darkMode .feedbackFormTitle {
+ color: #facc15; /* yellow-300 */
+}
+
+.darkMode .successAlert {
+ color: #86efac;
+ background-color: rgba(22, 163, 74, 0.2);
+}
+
+.darkMode .feedbackTextarea {
+ background-color: #374151;
+ border-color: #ca8a04;
+ color: #f3f4f6;
+}
+
+.darkMode .feedbackSubmitBtn {
+ background-color: #d97706;
+ color: #f3f4f6;
+}
+
+.darkMode .feedbackSubmitBtn:hover {
+ background-color: #b45309;
+}
+
+.darkMode .feedbackSubmitDisabled {
+ background-color: #4b5563;
+ color: #d1d5db;
+}
+
+.darkMode .submitIcon {
+ color: #f3f4f6;
+}
diff --git a/src/components/ActivityLog/styles/LogEntryView.module.css b/src/components/ActivityLog/styles/LogEntryView.module.css
new file mode 100644
index 0000000000..558301e352
--- /dev/null
+++ b/src/components/ActivityLog/styles/LogEntryView.module.css
@@ -0,0 +1,206 @@
+.container {
+ display: flex;
+ flex-direction: column;
+ gap: 32px;
+}
+
+/* Header Card */
+.headerCard {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+ align-items: flex-start;
+ padding: 24px;
+ background-color: #fff;
+ border-radius: 16px;
+ box-shadow: 0 4px 6px rgb(0 0 0 / 5%);
+ border: 1px solid #f3f4f6;
+}
+
+.headerLeft {
+ display: flex;
+ gap: 16px;
+ align-items: flex-start;
+}
+
+.avatar {
+ flex-shrink: 0;
+ width: 64px;
+ height: 64px;
+ background-color: #e0e7ff;
+ border-radius: 50%;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ color: #4f46e5;
+}
+
+.avatarIcon {
+ width: 32px;
+ height: 32px;
+}
+
+.studentName {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-size: 1.25rem;
+ font-weight: 700;
+ color: #111827;
+}
+
+.assistedTag {
+ display: inline-flex;
+ align-items: center;
+ padding: 4px 8px;
+ gap: 18px;
+ background-color: #991b1b;
+ color: #ffe5e5;
+ border-radius: 6px;
+ font-size: 0.75rem;
+ font-weight: 500;
+ line-height: 1;
+}
+
+.assistedIcon {
+ width: 14px;
+ height: 14px;
+ flex-shrink: 0;
+ color: inherit;
+}
+
+.studentRole {
+ font-size: 0.875rem;
+ color: #6b7280;
+}
+
+.courseInfo {
+ font-size: 1rem;
+ font-weight: 500;
+ color: #4f46e5;
+ margin-top: 4px;
+}
+
+/* Header Right Buttons */
+.headerRight {
+ display: flex;
+ gap: 8px;
+ margin-top: 16px;
+}
+
+.markAssistedBtn {
+ background-color: #16a34a;
+ color: #fff;
+ font-weight: 600;
+ padding: 8px 16px;
+ border-radius: 12px;
+ box-shadow: 0 2px 4px rgb(0 0 0 / 10%);
+ transition: background-color 0.2s;
+}
+
+.markAssistedBtn:hover {
+ background-color: #15803d;
+}
+
+.removeAssistedBtn {
+ background-color: #dc2626;
+ color: #fff;
+ font-weight: 600;
+ padding: 8px 16px;
+ border-radius: 12px;
+ box-shadow: 0 2px 4px rgb(0 0 0 / 10%);
+ transition: background-color 0.2s;
+}
+
+.removeAssistedBtn:hover {
+ background-color: #b91c1c;
+}
+
+/* Grid for Log Content & Notes */
+.grid {
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: 24px;
+}
+
+@media (width >= 768px) {
+ .grid {
+ grid-template-columns: repeat(2, 1fr);
+ }
+}
+
+.gridItem {
+ padding: 24px;
+ background-color: #fff;
+ border-radius: 16px;
+ box-shadow: 0 4px 6px rgb(0 0 0 / 5%);
+ border: 1px solid #f3f4f6;
+}
+
+.gridTitle {
+ font-size: 1.125rem;
+ font-weight: 600;
+ color: #111827;
+ margin-bottom: 8px;
+}
+
+.gridContent {
+ color: #374151;
+ white-space: pre-wrap;
+}
+
+.gridContentItalic {
+ color: #374151;
+ font-style: italic;
+}
+
+/* Dark Mode Overrides */
+.darkMode .headerCard,
+.darkMode .gridItem {
+ background-color: #1f2937;
+ border-color: #4b5563;
+ box-shadow: 0 4px 6px rgb(0 0 0 / 50%);
+}
+
+.darkMode .studentName,
+.darkMode .gridTitle {
+ color: #f3f4f6;
+}
+
+.darkMode .studentRole,
+.darkMode .gridContent,
+.darkMode .gridContentItalic {
+ color: #d1d5db;
+}
+
+.darkMode .courseInfo {
+ color: #818cf8;
+}
+
+.darkMode .markAssistedBtn {
+ background-color: #16a34a;
+ color: #f3f4f6;
+}
+
+.darkMode .markAssistedBtn:hover {
+ background-color: #15803d;
+}
+
+.darkMode .removeAssistedBtn {
+ background-color: #dc2626;
+ color: #f3f4f6;
+}
+
+.darkMode .removeAssistedBtn:hover {
+ background-color: #b91c1c;
+}
+
+.darkMode .avatar {
+ background-color: #4338ca;
+ color: #c7d2fe;
+}
+
+.darkMode .assistedTag {
+ background-color: #991b1b;
+ color: #fca5a5;
+}
diff --git a/src/components/ActivityLog/styles/TeacherFeedbackForm.module.css b/src/components/ActivityLog/styles/TeacherFeedbackForm.module.css
new file mode 100644
index 0000000000..4aa65fcbf7
--- /dev/null
+++ b/src/components/ActivityLog/styles/TeacherFeedbackForm.module.css
@@ -0,0 +1,64 @@
+/* Teacher Feedback Styles */
+.feedbackContainer {
+ margin-top: 32px;
+}
+
+.feedbackTitle {
+ font-size: 1.5rem;
+ font-weight: 800;
+ color: #111827;
+ margin-bottom: 16px;
+}
+
+.feedbackCard {
+ padding: 24px;
+ background-color: #f3f4f6;
+ border-radius: 16px;
+ border: 1px solid #e5e7eb;
+}
+
+.feedbackTeacherName {
+ font-size: 0.875rem;
+ font-weight: 600;
+ color: #111827;
+ margin-bottom: 8px;
+}
+
+.feedbackText {
+ color: #374151;
+ font-style: italic;
+}
+
+/* No Feedback Card */
+.noFeedbackCard {
+ padding: 24px;
+ text-align: center;
+ color: #6b7280;
+ background-color: #f9fafb;
+ border-radius: 16px;
+ border: 1px dashed #d1d5db;
+}
+
+/* Dark Mode Overrides */
+.darkMode .feedbackTitle {
+ color: #f3f4f6;
+}
+
+.darkMode .feedbackCard {
+ background-color: #374151;
+ border-color: #4b5563;
+}
+
+.darkMode .feedbackTeacherName {
+ color: #f3f4f6;
+}
+
+.darkMode .feedbackText {
+ color: #d1d5db;
+}
+
+.darkMode .noFeedbackCard {
+ background-color: #1f2937;
+ color: #d1d5db;
+ border-color: #4b5563;
+}
diff --git a/src/components/ActivityLog/styles/icons.module.css b/src/components/ActivityLog/styles/icons.module.css
new file mode 100644
index 0000000000..1fb548c5b3
--- /dev/null
+++ b/src/components/ActivityLog/styles/icons.module.css
@@ -0,0 +1,43 @@
+.icon {
+ width: 1rem;
+ height: 1rem;
+}
+
+/* Base tag styling */
+.tag {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ border-radius: 9999px;
+ padding: 0.125rem 0.5rem;
+ font-size: 0.75rem;
+ font-weight: 500;
+}
+
+/* Color variants */
+.tagEducator {
+ background-color: #e0f2fe;
+ color: #0369a1;
+}
+
+.tagStudent {
+ background-color: #dcfce7;
+ color: #166534;
+}
+
+.tagSupport {
+ background-color: #fef9c3;
+ color: #854d0e;
+}
+
+/* Fallback neutral tag */
+.tagDefault {
+ background-color: #f3f4f6;
+ color: #374151;
+}
+
+/* Dark mode variants */
+.tagSupportDark {
+ background-color: #fef9c3;
+ color: #854d0e;
+}
diff --git a/src/routes.jsx b/src/routes.jsx
index e233e5d23a..45437d39a8 100644
--- a/src/routes.jsx
+++ b/src/routes.jsx
@@ -183,6 +183,7 @@ import TaskDetails from './components/EductionPortal/StudentTasks/TaskDetails';
import PRReviewTeamAnalytics from './components/HGNPRDashboard/PRReviewTeamAnalytics';
import PRPromotionsPage from './components/PRPromotions/PRPromotionsPage';
import SimpleToolChart from './components/BMDashboard/Tools/SimpleToolChart';
+import ActivityLogs from './components/ActivityLog/DailyLogPage';
import ProtectedRoute from './components/common/ProtectedRoute';
import IntermediateTaskList from './components/EductionPortal/IntermediateTasks/IntermediateTaskList';
import WriteTaskUpload from './components/EductionPortal/Tasks/WriteTaskUpload';
@@ -785,6 +786,7 @@ export default (
fallback
allowedRoles={[UserRole.Owner]}
/>
+