mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: Improve Assignment UI and File Upload Responsiveness
This commit is contained in:
parent
df4cc587ba
commit
85cbb100fe
3 changed files with 133 additions and 94 deletions
|
|
@ -1,6 +1,7 @@
|
|||
import { useAssignmentSubmission } from '@components/Contexts/Assignments/AssignmentSubmissionContext'
|
||||
import { BookPlus, BookUser, EllipsisVertical, FileUp, Forward, InfoIcon, ListTodo, Save } from 'lucide-react'
|
||||
import React, { useEffect } from 'react'
|
||||
import { useLHSession } from '@components/Contexts/LHSessionContext'
|
||||
|
||||
type AssignmentBoxProps = {
|
||||
type: 'quiz' | 'file'
|
||||
|
|
@ -13,21 +14,25 @@ type AssignmentBoxProps = {
|
|||
gradeCustomFC?: (grade: number) => void
|
||||
showSavingDisclaimer?: boolean
|
||||
children: React.ReactNode
|
||||
|
||||
}
|
||||
|
||||
function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitFC, gradeFC, gradeCustomFC, showSavingDisclaimer, children }: AssignmentBoxProps) {
|
||||
const [customGrade, setCustomGrade] = React.useState<number>(0)
|
||||
const submission = useAssignmentSubmission() as any
|
||||
const session = useLHSession() as any
|
||||
|
||||
useEffect(() => {
|
||||
console.log(submission)
|
||||
}
|
||||
, [submission])
|
||||
}, [submission])
|
||||
|
||||
// Check if user is authenticated
|
||||
const isAuthenticated = session?.status === 'authenticated'
|
||||
|
||||
return (
|
||||
<div className='flex flex-col px-6 py-4 nice-shadow rounded-md bg-slate-100/30'>
|
||||
<div className='flex justify-between space-x-2 pb-2 text-slate-400 items-center'>
|
||||
<div className='flex space-x-1 items-center'>
|
||||
<div className='flex flex-col px-3 sm:px-6 py-4 nice-shadow rounded-md bg-slate-100/30'>
|
||||
<div className='flex flex-col sm:flex-row sm:justify-between sm:space-x-2 pb-2 text-slate-400 sm:items-center'>
|
||||
{/* Left side with type and badges */}
|
||||
<div className='flex flex-wrap gap-2 items-center mb-2 sm:mb-0'>
|
||||
<div className='text-lg font-semibold'>
|
||||
{type === 'quiz' &&
|
||||
<div className='flex space-x-1.5 items-center'>
|
||||
|
|
@ -41,26 +46,27 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF
|
|||
</div>}
|
||||
</div>
|
||||
|
||||
|
||||
<div className='flex items-center space-x-1'>
|
||||
<EllipsisVertical size={15} />
|
||||
</div>
|
||||
{view === 'teacher' &&
|
||||
<div className='flex bg-amber-200/20 text-xs rounded-full space-x-1 px-2 py-0.5 mx-auto font-bold outline items-center text-amber-600 outline-1 outline-amber-300/40'>
|
||||
<div className='flex bg-amber-200/20 text-xs rounded-full space-x-1 px-2 py-0.5 font-bold outline items-center text-amber-600 outline-1 outline-amber-300/40'>
|
||||
<BookUser size={12} />
|
||||
<p>Teacher view</p>
|
||||
</div>
|
||||
}
|
||||
{maxPoints &&
|
||||
<div className='flex bg-emerald-200/20 text-xs rounded-full space-x-1 px-2 py-0.5 mx-auto font-bold outline items-center text-emerald-600 outline-1 outline-emerald-300/40'>
|
||||
<div className='flex bg-emerald-200/20 text-xs rounded-full space-x-1 px-2 py-0.5 font-bold outline items-center text-emerald-600 outline-1 outline-emerald-300/40'>
|
||||
<BookPlus size={12} />
|
||||
<p>{maxPoints} points</p>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div className='flex px-1 py-1 rounded-md items-center'>
|
||||
|
||||
{/* Right side with buttons and actions */}
|
||||
<div className='flex flex-wrap gap-2 items-center'>
|
||||
{showSavingDisclaimer &&
|
||||
<div className='flex space-x-2 items-center font-semibold px-3 py-1 outline-dashed outline-red-200 text-red-400 mr-5 rounded-full'>
|
||||
<div className='flex space-x-2 items-center font-semibold px-3 py-1 outline-dashed outline-red-200 text-red-400 sm:mr-5 rounded-full w-full sm:w-auto mb-2 sm:mb-0'>
|
||||
<InfoIcon size={14} />
|
||||
<p className='text-xs'>Don't forget to save your progress</p>
|
||||
</div>
|
||||
|
|
@ -70,17 +76,17 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF
|
|||
{view === 'teacher' &&
|
||||
<div
|
||||
onClick={() => saveFC && saveFC()}
|
||||
className='flex px-2 py-1 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-emerald-700 bg-emerald-300/20 hover:bg-emerald-300/10 hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-emerald-500/60'>
|
||||
className='flex px-2 py-1 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-emerald-700 bg-emerald-300/20 hover:bg-emerald-300/10 hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-emerald-500/60'>
|
||||
<Save size={14} />
|
||||
<p className='text-xs font-semibold'>Save</p>
|
||||
</div>
|
||||
}
|
||||
|
||||
{/* Student button */}
|
||||
{view === 'student' && submission && submission.length <= 0 &&
|
||||
{/* Student button - only show if authenticated */}
|
||||
{view === 'student' && isAuthenticated && submission && submission.length <= 0 &&
|
||||
<div
|
||||
onClick={() => submitFC && submitFC()}
|
||||
className='flex px-2 py-1 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-emerald-700 bg-emerald-300/20 hover:bg-emerald-300/10 hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-emerald-500/60'>
|
||||
className='flex px-2 py-1 cursor-pointer rounded-md space-x-2 items-center justify-center mx-auto w-full sm:w-auto bg-gradient-to-bl text-emerald-700 bg-emerald-300/20 hover:bg-emerald-300/10 hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-emerald-500/60'>
|
||||
<Forward size={14} />
|
||||
<p className='text-xs font-semibold'>Save your progress</p>
|
||||
</div>
|
||||
|
|
@ -89,11 +95,11 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF
|
|||
{/* Grading button */}
|
||||
{view === 'grading' &&
|
||||
<div
|
||||
className='flex px-0.5 py-0.5 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-orange-500/60'>
|
||||
<p className='font-semibold px-2 text-xs text-orange-700'>Current points : {currentPoints}</p>
|
||||
className='flex flex-wrap sm:flex-nowrap w-full sm:w-auto px-0.5 py-0.5 cursor-pointer rounded-md gap-2 sm:space-x-2 items-center bg-gradient-to-bl hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-orange-500/60'>
|
||||
<p className='font-semibold px-2 text-xs text-orange-700'>Current points: {currentPoints}</p>
|
||||
<div
|
||||
onClick={() => gradeFC && gradeFC()}
|
||||
className='bg-gradient-to-bl text-orange-700 bg-orange-300/20 hover:bg-orange-300/10 items-center flex rounded-md px-2 py-1 space-x-2'>
|
||||
className='bg-gradient-to-bl text-orange-700 bg-orange-300/20 hover:bg-orange-300/10 items-center flex rounded-md px-2 py-1 space-x-2 ml-auto'>
|
||||
<BookPlus size={14} />
|
||||
<p className='text-xs font-semibold'>Grade</p>
|
||||
</div>
|
||||
|
|
@ -103,16 +109,21 @@ function AssignmentBoxUI({ type, view, currentPoints, maxPoints, saveFC, submitF
|
|||
{/* CustomGrading button */}
|
||||
{view === 'custom-grading' && maxPoints &&
|
||||
<div
|
||||
className='flex px-0.5 py-0.5 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-orange-500/60'>
|
||||
<p className='font-semibold px-2 text-xs text-orange-700'>Current points : {currentPoints}</p>
|
||||
<input
|
||||
onChange={(e) => setCustomGrade(parseInt(e.target.value))}
|
||||
placeholder={maxPoints.toString()} className='w-[100px] light-shadow text-sm py-0.5 outline outline-gray-200 rounded-lg px-2' type="number" />
|
||||
<div
|
||||
onClick={() => gradeCustomFC && gradeCustomFC(customGrade)}
|
||||
className='bg-gradient-to-bl text-orange-700 bg-orange-300/20 hover:bg-orange-300/10 items-center flex rounded-md px-2 py-1 space-x-2'>
|
||||
<BookPlus size={14} />
|
||||
<p className='text-xs font-semibold'>Grade</p>
|
||||
className='flex flex-wrap sm:flex-nowrap w-full sm:w-auto px-0.5 py-0.5 cursor-pointer rounded-md gap-2 sm:space-x-2 items-center bg-gradient-to-bl hover:outline-offset-4 active:outline-offset-1 linear transition-all outline-offset-2 outline-dashed outline-orange-500/60'>
|
||||
<p className='font-semibold px-2 text-xs text-orange-700 w-full sm:w-auto'>Current points: {currentPoints}</p>
|
||||
<div className='flex items-center gap-2 w-full sm:w-auto'>
|
||||
<input
|
||||
onChange={(e) => setCustomGrade(parseInt(e.target.value))}
|
||||
placeholder={maxPoints.toString()}
|
||||
className='w-full sm:w-[100px] light-shadow text-sm py-0.5 outline outline-gray-200 rounded-lg px-2'
|
||||
type="number"
|
||||
/>
|
||||
<div
|
||||
onClick={() => gradeCustomFC && gradeCustomFC(customGrade)}
|
||||
className='bg-gradient-to-bl text-orange-700 bg-orange-300/20 hover:bg-orange-300/10 items-center flex rounded-md px-2 py-1 space-x-2 whitespace-nowrap'>
|
||||
<BookPlus size={14} />
|
||||
<p className='text-xs font-semibold'>Grade</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,38 +18,39 @@ function AssignmentStudentActivity() {
|
|||
|
||||
|
||||
return (
|
||||
<div className='flex flex-col space-y-6'>
|
||||
<div className='flex flex-row justify-center space-x-3 items-center '>
|
||||
<div className='text-xs h-fit flex space-x-3 items-center '>
|
||||
<div className='flex space-x-2 py-2 px-5 h-fit text-sm text-slate-700 bg-slate-100/5 rounded-full nice-shadow'>
|
||||
<Backpack size={18} />
|
||||
<div className='flex flex-col space-y-4 md:space-y-6'>
|
||||
<div className='flex flex-col md:flex-row justify-center md:space-x-3 space-y-3 md:space-y-0 items-center'>
|
||||
<div className='text-xs h-fit flex space-x-3 items-center'>
|
||||
<div className='flex space-x-2 py-2 px-4 md:px-5 h-fit text-sm text-slate-700 bg-slate-100/5 rounded-full nice-shadow'>
|
||||
<Backpack size={16} className="md:size-18" />
|
||||
<p className='font-semibold'>Assignment</p>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className='flex space-x-2 items-center'>
|
||||
<EllipsisVertical className='text-slate-400' size={18} />
|
||||
<EllipsisVertical className='text-slate-400 hidden md:block' size={18} />
|
||||
<div className='flex space-x-2 items-center'>
|
||||
<div className='flex space-x-2 text-xs items-center text-slate-400'>
|
||||
<div className='flex space-x-1 md:space-x-2 text-xs items-center text-slate-400'>
|
||||
<Calendar size={14} />
|
||||
<p className=' font-semibold'>Due Date</p>
|
||||
<p className=' font-semibold'>{assignments?.assignment_object?.due_date}</p>
|
||||
<p className='font-semibold'>Due Date</p>
|
||||
<p className='font-semibold'>{assignments?.assignment_object?.due_date}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className='w-full rounded-full bg-slate-500/5 nice-shadow h-[2px]'></div>
|
||||
|
||||
{assignments && assignments?.assignment_tasks?.sort((a: any, b: any) => a.id - b.id).map((task: any, index: number) => {
|
||||
return (
|
||||
<div className='flex flex-col space-y-2' key={task.assignment_task_uuid}>
|
||||
<div className='flex justify-between py-2'>
|
||||
<div className='flex space-x-2 font-semibold text-slate-800'>
|
||||
<div className='flex flex-col md:flex-row md:justify-between py-2 space-y-2 md:space-y-0'>
|
||||
<div className='flex flex-wrap space-x-2 font-semibold text-slate-800'>
|
||||
<p>Task {index + 1} : </p>
|
||||
<p className='text-slate-500'>{task.description}</p>
|
||||
<p className='text-slate-500 break-words'>{task.description}</p>
|
||||
</div>
|
||||
<div className='flex space-x-2'>
|
||||
<div className='flex flex-wrap gap-2'>
|
||||
<div
|
||||
onClick={() => alert(task.hint)}
|
||||
className='px-3 py-1 flex items-center nice-shadow bg-amber-50/40 text-amber-900 rounded-full space-x-2 cursor-pointer'>
|
||||
|
|
@ -67,9 +68,9 @@ function AssignmentStudentActivity() {
|
|||
)}
|
||||
target='_blank'
|
||||
download={true}
|
||||
className='px-3 py-1 flex items-center nice-shadow bg-cyan-50/40 text-cyan-900 rounded-full space-x-2 cursor-pointer'>
|
||||
className='px-3 py-1 flex items-center nice-shadow bg-cyan-50/40 text-cyan-900 rounded-full space-x-1 md:space-x-2 cursor-pointer'>
|
||||
<Download size={13} />
|
||||
<div className='flex items-center space-x-2'>
|
||||
<div className='flex items-center space-x-1 md:space-x-2'>
|
||||
{task.reference_file && (
|
||||
<span className='relative'>
|
||||
<span className='absolute right-0 top-0 block h-2 w-2 rounded-full ring-2 ring-white bg-green-400'></span>
|
||||
|
|
@ -80,7 +81,7 @@ function AssignmentStudentActivity() {
|
|||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className='w-full'>
|
||||
{task.assignment_type === 'QUIZ' && <TaskQuizObject key={task.assignment_task_uuid} view='student' assignmentTaskUUID={task.assignment_task_uuid} />}
|
||||
{task.assignment_type === 'FILE_SUBMISSION' && <TaskFileObject key={task.assignment_task_uuid} view='student' assignmentTaskUUID={task.assignment_task_uuid} />}
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue