From 4fd69a00b20c95e34e78ebbeece23dd0e304d876 Mon Sep 17 00:00:00 2001 From: ShravyaKudlu Date: Wed, 12 Nov 2025 15:20:25 -0500 Subject: [PATCH 1/7] ActivityLog --- src/components/ActivityLog/DailyLogPage.jsx | 743 ++++++++++++++++++++ src/components/ActivityLog/MockLogs.js | 58 ++ src/routes.jsx | 3 +- 3 files changed, 803 insertions(+), 1 deletion(-) create mode 100644 src/components/ActivityLog/DailyLogPage.jsx create mode 100644 src/components/ActivityLog/MockLogs.js diff --git a/src/components/ActivityLog/DailyLogPage.jsx b/src/components/ActivityLog/DailyLogPage.jsx new file mode 100644 index 0000000000..cd79fe2a73 --- /dev/null +++ b/src/components/ActivityLog/DailyLogPage.jsx @@ -0,0 +1,743 @@ +import React, { useState, useMemo, useEffect } from 'react'; +import { MOCK_USERS, INITIAL_MOCK_LOGS } from './MockLogs'; + +import { + Sun, + Moon, + User, + Briefcase, + GraduationCap, + Send, + MessageSquare, + BookOpen, + CheckCircle, + PlusSquare, +} from 'lucide-react'; + +// --- UTILITY COMPONENTS --- + +const IconByRole = ({ role, className = 'w-4 h-4' }) => { + switch (role) { + case 'Educator': + return ; + case 'Student': + return ; + case 'Support': + return ; + default: + return ; + } +}; + +const Tag = ({ children, colorClass }) => ( + + {children} + +); + +// --- FUNCTIONALITY COMPONENTS --- + +/** + * Component for Educators to submit feedback on a log. + */ +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 handleSubmit = e => { + e.preventDefault(); + if (feedback.trim()) { + handleFeedbackSubmit(logId, feedback); + setFeedback(''); // Clear input + setIsSubmitted(true); + setTimeout(() => setIsSubmitted(false), 2000); + } + }; + + return ( +
+

{labelText}

+ + {isSubmitted && ( +
+ + Success! Feedback submitted for the student. +
+ )} + +
+ + +
+
+ ); +}; + +/** + * Component for Students and Support to create a new log entry. + * ADDED handleAddLog prop to submit the new log to the global state. + */ +const CreateLogForm = ({ userRole, currentUserName, setViewMode, handleAddLog }) => { + const isSupport = userRole === 'Support'; + const roleName = isSupport ? 'Support Member' : 'Student'; + + 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); // Clear error on change + }; + + const handleSubmit = e => { + e.preventDefault(); + + if (!formData.logContent.trim()) { + setError('Log Content is required to submit a log entry.'); + return; + } + + // 1. Construct the new log object (Simulation of a new entry) + const newLog = { + id: Date.now(), // Use timestamp as unique ID + submittedBy: currentUserName, + role: userRole, + timestamp: new Date().toISOString(), + logContent: formData.logContent, + course: formData.course, + notesToTeacher: formData.notesToTeacher || 'N/A', + // If submitted by Support, record it as assisted + 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, // Assign a mock teacher + teacherFeedback: null, + comments: [], + }; + + // 2. Add log to global state + handleAddLog(newLog); + + // 3. Simulate successful submission + setIsSubmitted(true); + setFormData({ logContent: '', course: 'Course A', notesToTeacher: '' }); + + setTimeout(() => { + setIsSubmitted(false); + // Automatically switch back to the viewer after submission + if (setViewMode) { + setViewMode('viewer'); + } + }, 2000); + }; + + return ( +
+

+ Create Daily Log +

+

+ Add your log details below. Currently acting as a{' '} + {roleName}. +

+ + {/* Submission Status Message */} + {isSubmitted && ( +
+ + Success! Log entry submitted successfully. Switching + back to Viewer... +
+ )} + + {/* Error Message */} + {error && ( +
+ Error: {error} +
+ )} + +
+ {/* Log Content */} +
+ + +
+ + {/* Course/Assignment Selection & Notes */} +
+
+ + +
+ +
+ + +
+ + +
+
+
+ ); +}; + +/** + * Component to display teacher feedback. + */ +const TeacherFeedback = ({ feedbackData }) => ( +
+

Teacher Feedback

+ + {feedbackData ? ( +
+

+ {feedbackData.teacherName} +

+

{feedbackData.feedback}

+
+ ) : ( +
+ No feedback available yet. +
+ )} +
+); + +/** + * Component for interaction/comment section. + */ +const CommentSection = ({ logId, comments, userRole, handleCommentSubmit, currentUserName }) => { + const [newComment, setNewComment] = useState(''); + + const onSubmit = () => { + if (newComment.trim()) { + handleCommentSubmit(logId, newComment); + setNewComment(''); // Clear input after submission + } + }; + + return ( +
+

+ Interaction / Comments +

+ + {/* Display Existing Comments */} +
+ {comments.length === 0 && ( +

+ No comments yet. Start the conversation! +

+ )} + {comments.map(comment => ( +
+
+ + + {comment.author} + + + {comment.role} + +
+

{comment.text}

+
+ ))} +
+ + {/* New Comment Input */} +
+ + +
+
+ ); +}; + +/** + * Main component displaying a single log entry. + */ +const LogEntryView = ({ + log, + currentUserRole, + currentUserName, + toggleAssistedStatus, + handleCommentSubmit, + handleFeedbackSubmit, +}) => { + const isEducator = currentUserRole === 'Educator'; + const showAssistedTag = log.assistedBy; + + 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 (Only visible for Educators) */} +
+ {isEducator && ( + + )} + +
+
+ + {/* Log Content & Notes */} +
+
+

Log Content

+

{log.logContent}

+
+
+

+ Notes to Teacher +

+

+ {log.notesToTeacher || 'No optional notes provided.'} +

+
+
+ + {/* Teacher Feedback Section (Visible to ALL roles) */} + + + {/* Educator Feedback Form (Only visible to Educator) */} + {isEducator && ( + + )} + + {/* Comment/Interaction Section (Visible to ALL roles) */} + +
+ ); +}; + +// --- MAIN APP COMPONENT --- + +const ActivityLogs = () => { + const [theme, setTheme] = useState('light'); + // State to simulate different user roles viewing the page + const [currentUserRole, setCurrentUserRole] = useState('Educator'); // Default to Educator + // State for all logs + const [logs, setLogs] = useState(INITIAL_MOCK_LOGS); + // Default to Log ID 1 (John Doe's, initially unassisted) for viewing + const [logToDisplayId, setLogToDisplayId] = useState(1); + // State to switch between viewing a log and creating a new one (Only for Student/Support) + const [viewMode, setViewMode] = useState('viewer'); + + // Get current user details + const currentUserName = MOCK_USERS[currentUserRole.toLowerCase()]?.name || 'Unknown User'; + const isEducator = currentUserRole === 'Educator'; + const isCreator = currentUserRole === 'Student' || currentUserRole === 'Support'; + + // Find the currently displayed log + const logToDisplay = useMemo(() => logs.find(log => log.id === logToDisplayId), [ + logs, + logToDisplayId, + ]); + + // Effect to apply/remove dark class to the HTML element + useEffect(() => { + const root = document.documentElement; + if (theme === 'dark') { + root.classList.add('dark'); + } else { + root.classList.remove('dark'); + } + }, [theme]); + + const toggleTheme = () => { + setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light')); + }; + + /** + * NEW: Function to add a new log entry to the state. + */ + const handleAddLog = newLog => { + // Add the new log to the beginning of the array so it's easily visible. + setLogs(prevLogs => [newLog, ...prevLogs]); + // Also switch to viewing the newly created log immediately + setLogToDisplayId(newLog.id); + }; + + /** + * Educator function to toggle the assisted status on a log. + */ + const toggleAssistedStatus = logId => { + const supportUser = MOCK_USERS.support; // Get the mock support user details + + setLogs(prevLogs => + prevLogs.map(log => { + if (log.id === logId) { + const isCurrentlyAssisted = !!log.assistedBy; + return { + ...log, + // If not assisted, set the assistedBy to the mock Support user. + // If currently assisted, set to null. + assistedBy: isCurrentlyAssisted + ? null + : { name: supportUser.name, role: supportUser.role }, + }; + } + return log; + }), + ); + + // Logging for observation + const currentLog = logs.find(log => log.id === logId); + const newStatusName = !currentLog?.assistedBy ? supportUser.name : 'None'; + }; + + /** + * Function for Educator to submit feedback, which updates teacherFeedback. + */ + 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; + }), + ); + }; + + /** + * Function to add a new comment to a 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); + + // Ensure the Educator always starts in viewer mode + useEffect(() => { + if (isEducator) { + setViewMode('viewer'); + } + // If the log we were viewing got deleted (not happening here, but defensive) + if (!logToDisplay && logs.length > 0) { + setLogToDisplayId(logs[0].id); + } + }, [currentUserRole, logs, logToDisplay]); + + // Determine the content based on the view mode + let PageContent; + + if (viewMode === 'viewer' && logToDisplay) { + PageContent = ( + + ); + } else if (viewMode === 'creator' && isCreator) { + // Only Student/Support use the creator form + PageContent = ( + + ); + } else { + // Fallback for an empty state (e.g., if the user switches to Educator and no logs exist) + PageContent = ( +
+ No logs are available to display or review. Try submitting one as a Student/Support user + first! +
+ ); + } + + return ( +
+ {/* Header and Controls */} +
+

+ Daily Log System +

+
+ {/* Create New Log / View Log Button (Only for Student/Support) */} + {isCreator && ( + + )} + + {/* Log Switcher (For all roles in viewer mode) */} + {logs.length > 0 && viewMode === 'viewer' && ( +
+ + + View Log: + + +
+ )} + + {/* User Role Switcher */} +
+ + User Role: + +
+ + {/* Theme Toggle Button */} + +
+
+ + {/* Main Content Area */} +
{PageContent}
+ + {/* Footer / Role Information */} +
+ Current User: **{currentUserName}** ({currentUserRole}). +
+ **Test:** Switch to **Student** or **Support**, create a new log, and then switch to + **Educator** to confirm the new log appears in the Log Switcher. +
+
+ ); +}; + +export default ActivityLogs; 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/routes.jsx b/src/routes.jsx index faedb641bf..ddef51afb4 100644 --- a/src/routes.jsx +++ b/src/routes.jsx @@ -153,7 +153,7 @@ import PRDashboardTopReviewedPRs from './components/HGNPRDashboard/PRDashboardTo import PRDashboardDetails from './components/HGNPRDashboard/PRDashboardDetails'; import PromotionEligibility from './components/HGNPRDashboard/PromotionEligibility'; import PRPromotionsPage from './components/PRPromotions/PRPromotionsPage'; - +import ActivityLogs from './components/ActivityLog/DailyLogPage'; // eslint-disable-next-line import/order, import/no-unresolved import LogTools from './components/BMDashboard/LogTools/LogTools'; // import IssueDashboard from './components/BMDashboard/Issues/IssueDashboard'; @@ -529,6 +529,7 @@ export default ( fallback allowedRoles={[UserRole.Owner]} /> + {/* ----- BEGIN BM Dashboard Routing ----- */} From 7e344ac2087676e29831c6e35956beb50638863a Mon Sep 17 00:00:00 2001 From: ShravyaKudlu Date: Thu, 13 Nov 2025 10:47:08 -0500 Subject: [PATCH 2/7] refactor: change the structure of the code --- src/components/ActivityLog/DailyLogPage.jsx | 467 +++++++------------- 1 file changed, 166 insertions(+), 301 deletions(-) diff --git a/src/components/ActivityLog/DailyLogPage.jsx b/src/components/ActivityLog/DailyLogPage.jsx index cd79fe2a73..ef0d29cc7a 100644 --- a/src/components/ActivityLog/DailyLogPage.jsx +++ b/src/components/ActivityLog/DailyLogPage.jsx @@ -1,6 +1,9 @@ import React, { useState, useMemo, useEffect } from 'react'; import { MOCK_USERS, INITIAL_MOCK_LOGS } from './MockLogs'; - +import { useSelector } from 'react-redux'; +import styles3 from './CreateLogForm.module.css'; +import styles1 from './LogEntryView.module.css'; // renamed from styles to styles1 +import styles from './DailyLogPage.module.css'; import { Sun, Moon, @@ -42,6 +45,7 @@ const Tag = ({ children, colorClass }) => ( /** * Component for Educators to submit feedback on a log. */ + const EducatorFeedbackForm = ({ logId, currentTeacherName, @@ -57,23 +61,21 @@ const EducatorFeedbackForm = ({ e.preventDefault(); if (feedback.trim()) { handleFeedbackSubmit(logId, feedback); - setFeedback(''); // Clear input + setFeedback(''); setIsSubmitted(true); setTimeout(() => setIsSubmitted(false), 2000); } }; return ( -
-

{labelText}

+
+

{labelText}

{isSubmitted && ( -
- - Success! Feedback submitted for the student. +
+ + Success! Feedback submitted for the + student.
)} @@ -83,18 +85,16 @@ const EducatorFeedbackForm = ({ placeholder={`Enter your feedback for the student here, ${currentTeacherName}...`} value={feedback} onChange={e => setFeedback(e.target.value)} - className="w-full rounded-lg border-yellow-300 dark:border-yellow-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-500 dark:placeholder-gray-400 focus:ring-yellow-500 focus:border-yellow-500 p-3 transition duration-150 ease-in-out" + className={`${styles1.feedbackTextarea}`} > @@ -106,6 +106,7 @@ const EducatorFeedbackForm = ({ * Component for Students and Support to create a new log entry. * ADDED handleAddLog prop to submit the new log to the global state. */ + const CreateLogForm = ({ userRole, currentUserName, setViewMode, handleAddLog }) => { const isSupport = userRole === 'Support'; const roleName = isSupport ? 'Support Member' : 'Student'; @@ -132,79 +133,59 @@ const CreateLogForm = ({ userRole, currentUserName, setViewMode, handleAddLog }) return; } - // 1. Construct the new log object (Simulation of a new entry) const newLog = { - id: Date.now(), // Use timestamp as unique ID + id: Date.now(), submittedBy: currentUserName, role: userRole, timestamp: new Date().toISOString(), logContent: formData.logContent, course: formData.course, notesToTeacher: formData.notesToTeacher || 'N/A', - // If submitted by Support, record it as assisted 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, // Assign a mock teacher + teacher: isSupport ? 'Educator to be assigned' : MOCK_USERS.educator.name, teacherFeedback: null, comments: [], }; - // 2. Add log to global state handleAddLog(newLog); - // 3. Simulate successful submission setIsSubmitted(true); setFormData({ logContent: '', course: 'Course A', notesToTeacher: '' }); setTimeout(() => { setIsSubmitted(false); - // Automatically switch back to the viewer after submission - if (setViewMode) { - setViewMode('viewer'); - } + if (setViewMode) setViewMode('viewer'); }, 2000); }; return ( -
-

- Create Daily Log -

-

+

+

Create Daily Log

+

Add your log details below. Currently acting as a{' '} - {roleName}. + {roleName}.

- {/* Submission Status Message */} {isSubmitted && ( -
- - Success! Log entry submitted successfully. Switching - back to Viewer... +
+ + Success! Log entry submitted successfully. + Switching back to Viewer...
)} - {/* Error Message */} {error && ( -
- Error: {error} +
+ Error: {error}
)} -
+ {/* Log Content */}
-
- {/* Course/Assignment Selection & Notes */} -
+ {/* Course Selection & Notes */} +
-
@@ -277,20 +248,16 @@ const CreateLogForm = ({ userRole, currentUserName, setViewMode, handleAddLog }) * Component to display teacher feedback. */ const TeacherFeedback = ({ feedbackData }) => ( -
-

Teacher Feedback

+
+

Teacher Feedback

{feedbackData ? ( -
-

- {feedbackData.teacherName} -

-

{feedbackData.feedback}

+
+

{feedbackData.teacherName}

+

{feedbackData.feedback}

) : ( -
- No feedback available yet. -
+
No feedback available yet.
)}
); @@ -304,57 +271,48 @@ const CommentSection = ({ logId, comments, userRole, handleCommentSubmit, curren const onSubmit = () => { if (newComment.trim()) { handleCommentSubmit(logId, newComment); - setNewComment(''); // Clear input after submission + setNewComment(''); } }; return ( -
-

- Interaction / Comments -

+
+

Interaction / Comments

{/* Display Existing Comments */} -
+
{comments.length === 0 && ( -

- No comments yet. Start the conversation! -

+

No comments yet. Start the conversation!

)} {comments.map(comment => ( -
-
- - - {comment.author} - - - {comment.role} - +
+
+ + {comment.author} + {comment.role}
-

{comment.text}

+

{comment.text}

))}
{/* New Comment Input */} -
+
@@ -362,9 +320,6 @@ const CommentSection = ({ logId, comments, userRole, handleCommentSubmit, curren ); }; -/** - * Main component displaying a single log entry. - */ const LogEntryView = ({ log, currentUserRole, @@ -377,72 +332,62 @@ const LogEntryView = ({ const showAssistedTag = log.assistedBy; return ( -
+
{/* Student/Log Header Card */} -
-
-
- +
+
+
+
-

+

{log.studentName} {showAssistedTag && ( - - + + Assisted by: {log.assistedBy.name} )}

-

+

{log.studentRole} | Teacher: {log.teacher}

-

- Log for {log.course} -

+

Log for {log.course}

{/* Educator Assisted Tag Toggle (Only visible for Educators) */} -
+
{isEducator && ( )} - +
{/* Log Content & Notes */} -
-
-

Log Content

-

{log.logContent}

+
+
+

Log Content

+

{log.logContent}

-
-

- Notes to Teacher -

-

+

+

Notes to Teacher

+

{log.notesToTeacher || 'No optional notes provided.'}

- {/* Teacher Feedback Section (Visible to ALL roles) */} + {/* Teacher Feedback Section */} - {/* Educator Feedback Form (Only visible to Educator) */} + {/* Educator Feedback Form */} {isEducator && ( )} - {/* Comment/Interaction Section (Visible to ALL roles) */} + {/* Comment/Interaction Section */} { - const [theme, setTheme] = useState('light'); - // State to simulate different user roles viewing the page - const [currentUserRole, setCurrentUserRole] = useState('Educator'); // Default to Educator - // State for all logs + const darkMode = useSelector(state => state.theme.darkMode); + const [currentUserRole, setCurrentUserRole] = useState('Educator'); const [logs, setLogs] = useState(INITIAL_MOCK_LOGS); - // Default to Log ID 1 (John Doe's, initially unassisted) for viewing const [logToDisplayId, setLogToDisplayId] = useState(1); - // State to switch between viewing a log and creating a new one (Only for Student/Support) const [viewMode, setViewMode] = useState('viewer'); - // Get current user details const currentUserName = MOCK_USERS[currentUserRole.toLowerCase()]?.name || 'Unknown User'; const isEducator = currentUserRole === 'Educator'; const isCreator = currentUserRole === 'Student' || currentUserRole === 'Support'; - // Find the currently displayed log const logToDisplay = useMemo(() => logs.find(log => log.id === logToDisplayId), [ logs, logToDisplayId, ]); - // Effect to apply/remove dark class to the HTML element - useEffect(() => { - const root = document.documentElement; - if (theme === 'dark') { - root.classList.add('dark'); - } else { - root.classList.remove('dark'); - } - }, [theme]); - - const toggleTheme = () => { - setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light')); - }; - - /** - * NEW: Function to add a new log entry to the state. - */ const handleAddLog = newLog => { - // Add the new log to the beginning of the array so it's easily visible. setLogs(prevLogs => [newLog, ...prevLogs]); - // Also switch to viewing the newly created log immediately setLogToDisplayId(newLog.id); }; - /** - * Educator function to toggle the assisted status on a log. - */ const toggleAssistedStatus = logId => { - const supportUser = MOCK_USERS.support; // Get the mock support user details - + const supportUser = MOCK_USERS.support; setLogs(prevLogs => prevLogs.map(log => { if (log.id === logId) { const isCurrentlyAssisted = !!log.assistedBy; return { ...log, - // If not assisted, set the assistedBy to the mock Support user. - // If currently assisted, set to null. assistedBy: isCurrentlyAssisted ? null : { name: supportUser.name, role: supportUser.role }, @@ -534,19 +446,10 @@ const ActivityLogs = () => { return log; }), ); - - // Logging for observation - const currentLog = logs.find(log => log.id === logId); - const newStatusName = !currentLog?.assistedBy ? supportUser.name : 'None'; }; - /** - * Function for Educator to submit feedback, which updates teacherFeedback. - */ const handleFeedbackSubmit = (logId, feedbackContent) => { - if (!isEducator) { - return; - } + if (!isEducator) return; setLogs(prevLogs => prevLogs.map(log => { if (log.id === logId) { @@ -564,9 +467,6 @@ const ActivityLogs = () => { ); }; - /** - * Function to add a new comment to a log. - */ const handleCommentSubmit = (logId, commentText) => { if (!commentText.trim()) return; @@ -581,10 +481,7 @@ const ActivityLogs = () => { setLogs(prevLogs => prevLogs.map(log => { if (log.id === logId) { - return { - ...log, - comments: [...log.comments, newComment], - }; + return { ...log, comments: [...log.comments, newComment] }; } return log; }), @@ -593,20 +490,12 @@ const ActivityLogs = () => { const roleOptions = Object.keys(MOCK_USERS); - // Ensure the Educator always starts in viewer mode useEffect(() => { - if (isEducator) { - setViewMode('viewer'); - } - // If the log we were viewing got deleted (not happening here, but defensive) - if (!logToDisplay && logs.length > 0) { - setLogToDisplayId(logs[0].id); - } + if (isEducator) setViewMode('viewer'); + if (!logToDisplay && logs.length > 0) setLogToDisplayId(logs[0].id); }, [currentUserRole, logs, logToDisplay]); - // Determine the content based on the view mode let PageContent; - if (viewMode === 'viewer' && logToDisplay) { PageContent = ( { currentUserName={currentUserName} toggleAssistedStatus={toggleAssistedStatus} handleCommentSubmit={handleCommentSubmit} - handleFeedbackSubmit={handleFeedbackSubmit} // Passed down for Educator form + handleFeedbackSubmit={handleFeedbackSubmit} /> ); } else if (viewMode === 'creator' && isCreator) { - // Only Student/Support use the creator form PageContent = ( ); } else { - // Fallback for an empty state (e.g., if the user switches to Educator and no logs exist) PageContent = ( -
+
No logs are available to display or review. Try submitting one as a Student/Support user first!
@@ -639,103 +526,81 @@ const ActivityLogs = () => { } return ( -
- {/* Header and Controls */} -
-

- Daily Log System -

-
- {/* Create New Log / View Log Button (Only for Student/Support) */} - {isCreator && ( - - )} - - {/* Log Switcher (For all roles in viewer mode) */} - {logs.length > 0 && viewMode === 'viewer' && ( -
- - - View Log: - +
+
+
+

Daily Log System

+
+ {isCreator && ( + + )} + + {logs.length > 0 && viewMode === 'viewer' && ( +
+ + View Log: + +
+ )} + +
+ + User Role:
- )} - - {/* User Role Switcher */} -
- - User Role: -
+
- {/* Theme Toggle Button */} - -
-
- - {/* Main Content Area */} -
{PageContent}
- - {/* Footer / Role Information */} -
- Current User: **{currentUserName}** ({currentUserRole}). -
- **Test:** Switch to **Student** or **Support**, create a new log, and then switch to - **Educator** to confirm the new log appears in the Log Switcher. -
+
{PageContent}
+ +
+ Current User: {currentUserName} ({currentUserRole}). +
+ Test: Switch to Student or Support, + create a new log, and then switch to Educator to confirm the new log + appears in the Log Switcher. +
+
); }; From 915ff0cf560996dba2bcbdc3ba2b2e3c6e5ceeb7 Mon Sep 17 00:00:00 2001 From: ShravyaKudlu Date: Thu, 13 Nov 2025 17:47:36 -0500 Subject: [PATCH 3/7] feat: added respective assisted section --- src/components/ActivityLog/CommentSection.jsx | 64 +++ src/components/ActivityLog/CreateLogForm.jsx | 147 +++++++ src/components/ActivityLog/DailyLogPage.jsx | 412 +----------------- .../ActivityLog/EducatorFeedbackForm.jsx | 64 +++ src/components/ActivityLog/LogEntryView.jsx | 100 +++++ .../ActivityLog/TeacherFeedback.jsx | 25 ++ src/components/ActivityLog/icons.jsx | 21 + 7 files changed, 425 insertions(+), 408 deletions(-) create mode 100644 src/components/ActivityLog/CommentSection.jsx create mode 100644 src/components/ActivityLog/CreateLogForm.jsx create mode 100644 src/components/ActivityLog/EducatorFeedbackForm.jsx create mode 100644 src/components/ActivityLog/LogEntryView.jsx create mode 100644 src/components/ActivityLog/TeacherFeedback.jsx create mode 100644 src/components/ActivityLog/icons.jsx diff --git a/src/components/ActivityLog/CommentSection.jsx b/src/components/ActivityLog/CommentSection.jsx new file mode 100644 index 0000000000..c00926ad39 --- /dev/null +++ b/src/components/ActivityLog/CommentSection.jsx @@ -0,0 +1,64 @@ +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

+ + {/* Display Existing Comments */} +
+ {comments.length === 0 && ( +

No comments yet. Start the conversation!

+ )} + {comments.map(comment => ( +
+
+ + {comment.author} + {comment.role} +
+

{comment.text}

+
+ ))} +
+ +
+ + +
+
+
+ ); +}; + +export default CommentSection; diff --git a/src/components/ActivityLog/CreateLogForm.jsx b/src/components/ActivityLog/CreateLogForm.jsx new file mode 100644 index 0000000000..d342584722 --- /dev/null +++ b/src/components/ActivityLog/CreateLogForm.jsx @@ -0,0 +1,147 @@ +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} +
+ )} + + + {/* Log Content */} +
+ + +
+ + {/* Course Selection & Notes */} +
+
+ + +
+ +
+ + +
+ + +
+ +
+
+ ); +}; + +export default CreateLogForm; diff --git a/src/components/ActivityLog/DailyLogPage.jsx b/src/components/ActivityLog/DailyLogPage.jsx index ef0d29cc7a..66a17f39bc 100644 --- a/src/components/ActivityLog/DailyLogPage.jsx +++ b/src/components/ActivityLog/DailyLogPage.jsx @@ -1,414 +1,10 @@ import React, { useState, useMemo, useEffect } from 'react'; import { MOCK_USERS, INITIAL_MOCK_LOGS } from './MockLogs'; import { useSelector } from 'react-redux'; -import styles3 from './CreateLogForm.module.css'; -import styles1 from './LogEntryView.module.css'; // renamed from styles to styles1 -import styles from './DailyLogPage.module.css'; -import { - Sun, - Moon, - User, - Briefcase, - GraduationCap, - Send, - MessageSquare, - BookOpen, - CheckCircle, - PlusSquare, -} from 'lucide-react'; - -// --- UTILITY COMPONENTS --- - -const IconByRole = ({ role, className = 'w-4 h-4' }) => { - switch (role) { - case 'Educator': - return ; - case 'Student': - return ; - case 'Support': - return ; - default: - return ; - } -}; - -const Tag = ({ children, colorClass }) => ( - - {children} - -); - -// --- FUNCTIONALITY COMPONENTS --- - -/** - * Component for Educators to submit feedback on a log. - */ - -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 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. -
- )} - -
- - -
-
- ); -}; - -/** - * Component for Students and Support to create a new log entry. - * ADDED handleAddLog prop to submit the new log to the global state. - */ - -const CreateLogForm = ({ userRole, currentUserName, setViewMode, handleAddLog }) => { - const isSupport = userRole === 'Support'; - const roleName = isSupport ? 'Support Member' : 'Student'; - - 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); // Clear error on change - }; - - 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} -
- )} - -
- {/* Log Content */} -
- - -
- - {/* Course Selection & Notes */} -
-
- - -
- -
- - -
- - -
-
-
- ); -}; - -/** - * Component to display teacher feedback. - */ -const TeacherFeedback = ({ feedbackData }) => ( -
-

Teacher Feedback

- - {feedbackData ? ( -
-

{feedbackData.teacherName}

-

{feedbackData.feedback}

-
- ) : ( -
No feedback available yet.
- )} -
-); - -/** - * Component for interaction/comment section. - */ -const CommentSection = ({ logId, comments, userRole, handleCommentSubmit, currentUserName }) => { - const [newComment, setNewComment] = useState(''); - - const onSubmit = () => { - if (newComment.trim()) { - handleCommentSubmit(logId, newComment); - setNewComment(''); - } - }; - - return ( -
-

Interaction / Comments

- - {/* Display Existing Comments */} -
- {comments.length === 0 && ( -

No comments yet. Start the conversation!

- )} - {comments.map(comment => ( -
-
- - {comment.author} - {comment.role} -
-

{comment.text}

-
- ))} -
- - {/* New Comment Input */} -
- - -
-
- ); -}; - -const LogEntryView = ({ - log, - currentUserRole, - currentUserName, - toggleAssistedStatus, - handleCommentSubmit, - handleFeedbackSubmit, -}) => { - const isEducator = currentUserRole === 'Educator'; - const showAssistedTag = log.assistedBy; - - 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 (Only visible for Educators) */} -
- {isEducator && ( - - )} - -
-
- - {/* Log Content & Notes */} -
-
-

Log Content

-

{log.logContent}

-
-
-

Notes to Teacher

-

- {log.notesToTeacher || 'No optional notes provided.'} -

-
-
- - {/* Teacher Feedback Section */} - - - {/* Educator Feedback Form */} - {isEducator && ( - - )} - - {/* Comment/Interaction Section */} - -
- ); -}; - +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'); diff --git a/src/components/ActivityLog/EducatorFeedbackForm.jsx b/src/components/ActivityLog/EducatorFeedbackForm.jsx new file mode 100644 index 0000000000..cc2c69bbe6 --- /dev/null +++ b/src/components/ActivityLog/EducatorFeedbackForm.jsx @@ -0,0 +1,64 @@ +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. +
+ )} + +
+ + +
+
+
+ ); +}; + +export default EducatorFeedbackForm; diff --git a/src/components/ActivityLog/LogEntryView.jsx b/src/components/ActivityLog/LogEntryView.jsx new file mode 100644 index 0000000000..f77541bfb7 --- /dev/null +++ b/src/components/ActivityLog/LogEntryView.jsx @@ -0,0 +1,100 @@ +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 (Only visible for Educators) */} +
+ {isEducator && ( + + )} + +
+
+ + {/* Log Content & Notes */} +
+
+

Log Content

+

{log.logContent}

+
+
+

Notes to Teacher

+

+ {log.notesToTeacher || 'No optional notes provided.'} +

+
+
+ + + + {/* Educator Feedback Form */} + {isEducator && ( + + )} + + {/* Comment/Interaction Section */} + +
+
+ ); +}; + +export default LogEntryView; diff --git a/src/components/ActivityLog/TeacherFeedback.jsx b/src/components/ActivityLog/TeacherFeedback.jsx new file mode 100644 index 0000000000..ab46f87b57 --- /dev/null +++ b/src/components/ActivityLog/TeacherFeedback.jsx @@ -0,0 +1,25 @@ +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.
+ )} +
+
+ ); +}; + +export default TeacherFeedback; diff --git a/src/components/ActivityLog/icons.jsx b/src/components/ActivityLog/icons.jsx new file mode 100644 index 0000000000..a3be3bd586 --- /dev/null +++ b/src/components/ActivityLog/icons.jsx @@ -0,0 +1,21 @@ +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 ; + } +}; + +const Tag = ({ children, color }) => ( + {children} +); + +export { IconByRole, Tag }; From 6c19a557bddf9e52e2d91504bcb51db487e1bd98 Mon Sep 17 00:00:00 2001 From: ShravyaKudlu Date: Thu, 13 Nov 2025 17:50:40 -0500 Subject: [PATCH 4/7] style: Adding styles for the Components --- .../styles/CommentSection.module.css | 167 +++++++++++++ .../styles/CreateLogForm.module.css | 192 +++++++++++++++ .../styles/DailyLogPage.module.css | 182 ++++++++++++++ .../styles/EducatorFeedback.module.css | 126 ++++++++++ .../styles/LogEntryView.module.css | 232 ++++++++++++++++++ .../styles/TeacherFeedbackForm.module.css | 64 +++++ .../ActivityLog/styles/icons.module.css | 36 +++ 7 files changed, 999 insertions(+) create mode 100644 src/components/ActivityLog/styles/CommentSection.module.css create mode 100644 src/components/ActivityLog/styles/CreateLogForm.module.css create mode 100644 src/components/ActivityLog/styles/DailyLogPage.module.css create mode 100644 src/components/ActivityLog/styles/EducatorFeedback.module.css create mode 100644 src/components/ActivityLog/styles/LogEntryView.module.css create mode 100644 src/components/ActivityLog/styles/TeacherFeedbackForm.module.css create mode 100644 src/components/ActivityLog/styles/icons.module.css diff --git a/src/components/ActivityLog/styles/CommentSection.module.css b/src/components/ActivityLog/styles/CommentSection.module.css new file mode 100644 index 0000000000..753bf7055c --- /dev/null +++ b/src/components/ActivityLog/styles/CommentSection.module.css @@ -0,0 +1,167 @@ +/* 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; + ring: 2px solid #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..79168e6374 --- /dev/null +++ b/src/components/ActivityLog/styles/EducatorFeedback.module.css @@ -0,0 +1,126 @@ +/* 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; + ring: 2px solid #fbbf24; + 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..a1ca5d69e1 --- /dev/null +++ b/src/components/ActivityLog/styles/LogEntryView.module.css @@ -0,0 +1,232 @@ +.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 rgba(0, 0, 0, 0.05); + 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: 6px; + + background-color: #991b1b; /* dark red badge */ + color: #ffe5e5; /* softer contrast text */ + 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 rgba(0, 0, 0, 0.1); + 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 rgba(0, 0, 0, 0.1); + transition: background-color 0.2s; +} + +.removeAssistedBtn:hover { + background-color: #b91c1c; +} + +.printBtn { + background-color: #e5e7eb; + color: #1f2937; + font-weight: 600; + padding: 8px 16px; + border-radius: 12px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + transition: background-color 0.2s; +} + +.printBtn:hover { + background-color: #d1d5db; +} + +/* Grid for Log Content & Notes */ +.grid { + display: grid; + grid-template-columns: 1fr; + gap: 24px; +} + +@media (min-width: 768px) { + .grid { + grid-template-columns: repeat(2, 1fr); + } +} + +.gridItem { + padding: 24px; + background-color: #fff; + border-radius: 16px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05); + 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 rgba(0, 0, 0, 0.5); +} + +.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 .printBtn { + background-color: #374151; + color: #f3f4f6; +} + +.darkMode .printBtn:hover { + background-color: #4b5563; +} + +.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..74271abe14 --- /dev/null +++ b/src/components/ActivityLog/styles/icons.module.css @@ -0,0 +1,36 @@ +.icon { + width: 1rem; + height: 1rem; +} + +/* Base tag styling */ +.tag { + display: inline-flex; + align-items: center; + 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; +} From a9af0cc262ed9197316219d969a534d39edc518b Mon Sep 17 00:00:00 2001 From: ShravyaKudlu Date: Thu, 13 Nov 2025 18:34:00 -0500 Subject: [PATCH 5/7] fix: sonarcube validation and reliability fix --- src/components/ActivityLog/CommentSection.jsx | 18 ++++++++-- src/components/ActivityLog/CreateLogForm.jsx | 10 ++++-- src/components/ActivityLog/DailyLogPage.jsx | 2 +- .../ActivityLog/EducatorFeedbackForm.jsx | 11 +++++- src/components/ActivityLog/LogEntryView.jsx | 35 +++++++++++++++++-- .../ActivityLog/TeacherFeedback.jsx | 8 +++++ src/components/ActivityLog/icons.jsx | 11 ++++++ .../styles/CommentSection.module.css | 1 - .../styles/EducatorFeedback.module.css | 1 - 9 files changed, 86 insertions(+), 11 deletions(-) diff --git a/src/components/ActivityLog/CommentSection.jsx b/src/components/ActivityLog/CommentSection.jsx index c00926ad39..2a4ad03b75 100644 --- a/src/components/ActivityLog/CommentSection.jsx +++ b/src/components/ActivityLog/CommentSection.jsx @@ -1,3 +1,4 @@ +import PropTypes from 'prop-types'; import { useState } from 'react'; import { MessageSquare } from 'lucide-react'; import styles from './styles/CommentSection.module.css'; @@ -6,8 +7,8 @@ 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); @@ -20,7 +21,6 @@ const CommentSection = ({ logId, comments, userRole, handleCommentSubmit }) => {

Interaction / Comments

- {/* Display Existing Comments */}
{comments.length === 0 && (

No comments yet. Start the conversation!

@@ -61,4 +61,18 @@ const CommentSection = ({ logId, comments, userRole, handleCommentSubmit }) => { ); }; +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 index d342584722..576bc987a5 100644 --- a/src/components/ActivityLog/CreateLogForm.jsx +++ b/src/components/ActivityLog/CreateLogForm.jsx @@ -1,3 +1,4 @@ +import PropTypes from 'prop-types'; import { useState } from 'react'; import { CheckCircle, Send } from 'lucide-react'; import styles from './styles/CreateLogForm.module.css'; @@ -82,7 +83,6 @@ const CreateLogForm = ({ userRole, currentUserName, setViewMode, handleAddLog }) )}
- {/* Log Content */}
- {/* Course Selection & Notes */}