diff --git a/apps/api/src/routers/courses/assignments.py b/apps/api/src/routers/courses/assignments.py index 8f564915..6f4c4aa8 100644 --- a/apps/api/src/routers/courses/assignments.py +++ b/apps/api/src/routers/courses/assignments.py @@ -22,6 +22,7 @@ from src.services.courses.activities.assignments import ( delete_assignment_task, delete_assignment_task_submission, put_assignment_task_reference_file, + put_assignment_task_submission_file, read_assignment, read_assignment_from_activity_uuid, read_assignment_submissions, @@ -205,6 +206,21 @@ async def api_put_assignment_task_ref_file( request, db_session, assignment_task_uuid, current_user, reference_file ) +@router.post("/{assignment_uuid}/tasks/{assignment_task_uuid}/sub_file") +async def api_put_assignment_task_sub_file( + request: Request, + assignment_task_uuid: str, + sub_file: UploadFile | None = None, + current_user: PublicUser = Depends(get_current_user), + db_session=Depends(get_db_session), +): + """ + Update tasks for an assignment + """ + return await put_assignment_task_submission_file( + request, db_session, assignment_task_uuid, current_user, sub_file + ) + @router.delete("/{assignment_uuid}/tasks/{assignment_task_uuid}") async def api_delete_assignment_tasks( diff --git a/apps/api/src/services/courses/activities/assignments.py b/apps/api/src/services/courses/activities/assignments.py index 4d58e196..f8f196d6 100644 --- a/apps/api/src/services/courses/activities/assignments.py +++ b/apps/api/src/services/courses/activities/assignments.py @@ -33,6 +33,7 @@ from src.security.rbac.rbac import ( authorization_verify_if_element_is_public, authorization_verify_if_user_is_anon, ) +from src.services.courses.activities.uploads.sub_file import upload_submission_file from src.services.courses.activities.uploads.tasks_ref_files import ( upload_reference_file, ) @@ -493,6 +494,68 @@ async def put_assignment_task_reference_file( # return assignment task read return AssignmentTaskRead.model_validate(assignment_task) +async def put_assignment_task_submission_file( + request: Request, + db_session: Session, + assignment_task_uuid: str, + current_user: PublicUser | AnonymousUser, + sub_file: UploadFile | None = None, +): + # Check if assignment task exists + statement = select(AssignmentTask).where( + AssignmentTask.assignment_task_uuid == assignment_task_uuid + ) + assignment_task = db_session.exec(statement).first() + + if not assignment_task: + raise HTTPException( + status_code=404, + detail="Assignment Task not found", + ) + + # Check if assignment exists + statement = select(Assignment).where(Assignment.id == assignment_task.assignment_id) + assignment = db_session.exec(statement).first() + + if not assignment: + raise HTTPException( + status_code=404, + detail="Assignment not found", + ) + + # Check for activity + statement = select(Activity).where(Activity.id == assignment.activity_id) + activity = db_session.exec(statement).first() + + # Check if course exists + statement = select(Course).where(Course.id == assignment.course_id) + course = db_session.exec(statement).first() + + if not course: + raise HTTPException( + status_code=404, + detail="Course not found", + ) + + # Get org uuid + org_statement = select(Organization).where(Organization.id == course.org_id) + org = db_session.exec(org_statement).first() + + # RBAC check + await rbac_check(request, course.course_uuid, current_user, "read", db_session) + + # Upload reference file + if sub_file and sub_file.filename and activity and org: + name_in_disk = ( + f"{assignment_task_uuid}_sub_{current_user.email}_{uuid4()}.{sub_file.filename.split('.')[-1]}" + ) + await upload_submission_file( + sub_file, name_in_disk, activity.activity_uuid, org.org_uuid, course.course_uuid, assignment.assignment_uuid, assignment_task_uuid + ) + + return {"message": "Assignment Task Submission File uploaded"} + + async def update_assignment_task( request: Request, diff --git a/apps/api/src/services/courses/activities/uploads/sub_file.py b/apps/api/src/services/courses/activities/uploads/sub_file.py new file mode 100644 index 00000000..48df3cc5 --- /dev/null +++ b/apps/api/src/services/courses/activities/uploads/sub_file.py @@ -0,0 +1,24 @@ +from uuid import uuid4 +from src.services.utils.upload_content import upload_content + + +async def upload_submission_file( + file, + name_in_disk, + activity_uuid, + org_uuid, + course_uuid, + assignment_uuid, + assignment_task_uuid, +): + contents = file.file.read() + file_format = file.filename.split(".")[-1] + + await upload_content( + f"courses/{course_uuid}/activities/{activity_uuid}/assignments/{assignment_uuid}/tasks/{assignment_task_uuid}/subs", + "orgs", + org_uuid, + contents, + f"{name_in_disk}", + ["pdf", "docx", "mp4", "jpg", "jpeg", "png", "pptx"], + ) diff --git a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx index 9bc369cd..a00aa3ae 100644 --- a/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx +++ b/apps/web/app/orgs/[orgslug]/(withmenu)/course/[courseuuid]/activity/[activityid]/activity.tsx @@ -16,6 +16,11 @@ import { CourseProvider } from '@components/Contexts/CourseContext' import AIActivityAsk from '@components/Objects/Activities/AI/AIActivityAsk' import AIChatBotProvider from '@components/Contexts/AI/AIChatBotContext' import { useLHSession } from '@components/Contexts/LHSessionContext' +import React, { useEffect } from 'react' +import { getAssignmentFromActivityUUID } from '@services/courses/assignments' +import AssignmentStudentActivity from '@components/Objects/Activities/Assignment/AssignmentStudentActivity' +import { AssignmentProvider } from '@components/Contexts/Assignments/AssignmentContext' +import { AssignmentsTaskProvider } from '@components/Contexts/Assignments/AssignmentsTaskContext' interface ActivityClientProps { activityid: string @@ -32,6 +37,11 @@ function ActivityClient(props: ActivityClientProps) { const activity = props.activity const course = props.course const org = useOrg() as any + const session = useLHSession() as any; + const access_token = session?.data?.tokens?.access_token; + const [bgColor, setBgColor] = React.useState('bg-white') + const [assignment, setAssignment] = React.useState(null) as any; + const [markStatusButtonActive, setMarkStatusButtonActive] = React.useState(false); function getChapterNameByActivityId(course: any, activity_id: any) { for (let i = 0; i < course.chapters.length; i++) { @@ -46,6 +56,26 @@ function ActivityClient(props: ActivityClientProps) { return null // return null if no matching activity is found } + async function getAssignmentUI() { + const assignment = await getAssignmentFromActivityUUID(activity.activity_uuid, access_token) + setAssignment(assignment.data) + } + + useEffect(() => { + if (activity.activity_type == 'TYPE_DYNAMIC') { + setBgColor('bg-white nice-shadow'); + } + else if (activity.activity_type == 'TYPE_ASSIGNMENT') { + setMarkStatusButtonActive(false); + setBgColor('bg-white nice-shadow'); + getAssignmentUI(); + } + else { + setBgColor('bg-zinc-950'); + } + } + , [activity]) + return ( <> @@ -93,24 +123,26 @@ function ActivityClient(props: ActivityClientProps) {
- - - + {activity.activity_type != 'TYPE_ASSIGNMENT' && + <> + + + + + } +
{activity ? (
{activity.activity_type == 'TYPE_DYNAMIC' && ( @@ -126,6 +158,19 @@ function ActivityClient(props: ActivityClientProps) { activity={activity} /> )} + {activity.activity_type == 'TYPE_ASSIGNMENT' && ( +
+ {assignment ? ( + + + + + + ) : ( +
+ )} +
+ )}
) : ( diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx index ee38744a..afddc310 100644 --- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx +++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/AssignmentTaskContentEdit.tsx @@ -16,7 +16,7 @@ function AssignmentTaskContentEdit() { return (
- {assignment_task?.assignmentTask.assignment_type === 'QUIZ' && } + {assignment_task?.assignmentTask.assignment_type === 'QUIZ' && } {assignment_task?.assignmentTask.assignment_type === 'FILE_SUBMISSION' && }
) diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx index ed7bd2e8..4aafcee3 100644 --- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx +++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject.tsx @@ -1,14 +1,146 @@ -import AssignmentBoxUI from '@components/Objects/Assignments/AssignmentBoxUI' -import { Info } from 'lucide-react' -import React from 'react' +import { useAssignments } from '@components/Contexts/Assignments/AssignmentContext'; +import { useAssignmentsTask, useAssignmentsTaskDispatch } from '@components/Contexts/Assignments/AssignmentsTaskContext'; +import { useLHSession } from '@components/Contexts/LHSessionContext'; +import AssignmentBoxUI from '@components/Objects/Activities/Assignment/AssignmentBoxUI' +import { getAssignmentTask, updateSubFile } from '@services/courses/assignments'; +import { Cloud, File, Info, Loader, UploadCloud } from 'lucide-react' +import React, { useEffect } from 'react' +import toast from 'react-hot-toast'; + +type FileSchema = { + fileID: string; +}; + +type TaskFileObjectProps = { + view: 'teacher' | 'student'; + assignmentTaskUUID?: string; +}; + +export default function TaskFileObject({ view, assignmentTaskUUID }: TaskFileObjectProps) { + const session = useLHSession() as any; + const access_token = session?.data?.tokens?.access_token; + const [isLoading, setIsLoading] = React.useState(false); + const [localUploadFile, setLocalUploadFile] = React.useState(null); + const [error, setError] = React.useState(null); + const [assignmentTask, setAssignmentTask] = React.useState(null); + const assignmentTaskStateHook = useAssignmentsTaskDispatch() as any; + const assignment = useAssignments() as any; + + const handleFileChange = async (event: any) => { + const file = event.target.files[0] + + setLocalUploadFile(file) + setIsLoading(true) + const res = await updateSubFile( + file, + assignmentTask.assignment_task_uuid, + assignment.assignment_object.assignment_uuid, + access_token + ) + assignmentTaskStateHook({ type: 'reload' }) + // wait for 1 second to show loading animation + await new Promise((r) => setTimeout(r, 1500)) + if (res.success === false) { + setError(res.data.detail) + setIsLoading(false) + } else { + setIsLoading(false) + setError('') + } + + } + + async function getAssignmentTaskUI() { + if (assignmentTaskUUID) { + const res = await getAssignmentTask(assignmentTaskUUID, access_token); + if (res.success) { + setAssignmentTask(res.data); + } + + } + } + + useEffect(() => { + getAssignmentTaskUI() + } + , [assignmentTaskUUID]) -export default function TaskFileObject({ view }: any) { return ( -
- -

User will be able to submit a file for this task, you'll be able to review it in the Submissions Tab

-
+ {view === 'teacher' && ( +
+ +

User will be able to submit a file for this task, you'll be able to review it in the Submissions Tab

+
+ )} + {view === 'student' && ( + <> +
+
+
+
+ {error && ( +
+
{error}
+
+ )} + +
+ {localUploadFile && !isLoading && ( +
+
+ +
+ +
+ + +
+ {localUploadFile.name} +
+
+
+ )} +
+ +

Allowed formats : pdf, docx, mp4, jpg, jpeg, pptx

+
+ {isLoading ? ( +
+ +
+ + Loading +
+
+ ) : ( +
+ + +
+ )} + +
+
+
+ + )}
) } diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx index 1b53c085..69ab4d0b 100644 --- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx +++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject.tsx @@ -1,8 +1,8 @@ import { useAssignments } from '@components/Contexts/Assignments/AssignmentContext'; import { useAssignmentsTask, useAssignmentsTaskDispatch } from '@components/Contexts/Assignments/AssignmentsTaskContext'; import { useLHSession } from '@components/Contexts/LHSessionContext'; -import AssignmentBoxUI from '@components/Objects/Assignments/AssignmentBoxUI'; -import { updateAssignmentTask } from '@services/courses/assignments'; +import AssignmentBoxUI from '@components/Objects/Activities/Assignment/AssignmentBoxUI'; +import { getAssignmentTask, updateAssignmentTask } from '@services/courses/assignments'; import { Check, Minus, Plus, PlusCircle, X } from 'lucide-react'; import React, { useEffect, useState } from 'react'; import toast from 'react-hot-toast'; @@ -20,14 +20,19 @@ type QuizSchema = { }[]; }; -function TaskQuizObject() { +type TaskQuizObjectProps = { + view: 'teacher' | 'student'; + assignmentTaskUUID?: string; +}; + +function TaskQuizObject({ view, assignmentTaskUUID }: TaskQuizObjectProps) { const session = useLHSession() as any; const access_token = session?.data?.tokens?.access_token; const assignmentTaskState = useAssignmentsTask() as any; const assignmentTaskStateHook = useAssignmentsTaskDispatch() as any; const assignment = useAssignments() as any; - // Teacher area + /* TEACHER VIEW CODE */ const [questions, setQuestions] = useState([ { questionText: '', questionUUID: 'question_' + uuidv4(), options: [{ text: '', fileID: '', type: 'text', correct: false, optionUUID: 'option_' + uuidv4() }] }, ]); @@ -92,99 +97,136 @@ function TaskQuizObject() { toast.error('Error saving task, please retry later.'); } }; + /* TEACHER VIEW CODE */ + + /* STUDENT VIEW CODE */ + async function getAssignmentTaskUI() { + if (assignmentTaskUUID) { + const res = await getAssignmentTask(assignmentTaskUUID, access_token); + if (res.success) { + setQuestions(res.data.contents.questions); + } + + } + } + + /* STUDENT VIEW CODE */ useEffect(() => { - if (assignmentTaskState.assignmentTask.contents?.questions) { + assignmentTaskStateHook({ + setSelectedAssignmentTaskUUID: assignmentTaskUUID, + }); + // Teacher area + if (view == 'teacher' && assignmentTaskState.assignmentTask.contents?.questions) { setQuestions(assignmentTaskState.assignmentTask.contents.questions); } - }, [assignmentTaskState,assignment,assignmentTaskStateHook,access_token]); + // Student area + else if (view == 'student') { + getAssignmentTaskUI(); + } + }, [assignmentTaskState, assignment, assignmentTaskStateHook, access_token]); - // Teacher area end return ( - +
- {questions.map((question, qIndex) => ( + {questions && questions.map((question, qIndex) => (
- handleQuestionChange(qIndex, e.target.value)} - placeholder="Question" - className="w-full px-3 text-neutral-600 bg-[#00008b00] border-2 border-gray-200 rounded-md border-dotted text-sm font-bold" - /> -
removeQuestion(qIndex)} - > - -
+ {view === 'teacher' ? ( + handleQuestionChange(qIndex, e.target.value)} + placeholder="Question" + className="w-full px-3 text-neutral-600 bg-[#00008b00] border-2 border-gray-200 rounded-md border-dotted text-sm font-bold" + /> + ) : ( +

+ {question.questionText} +

+ )} + {view === 'teacher' && ( +
removeQuestion(qIndex)} + > + +
+ )}
{question.options.map((option, oIndex) => (

{String.fromCharCode(65 + oIndex)}

- handleOptionChange(qIndex, oIndex, e.target.value)} - placeholder="Option" - className="w-full mx-2 px-3 pr-6 text-neutral-600 bg-[#00008b00] border-2 border-gray-200 rounded-md border-dotted text-sm font-bold" - /> -
toggleCorrectOption(qIndex, oIndex)} - > - {option.correct ? : } - {option.correct ? ( -

Correct

- ) : ( -

Incorrect

- )} -
-
removeOption(qIndex, oIndex)} - > - -
-
-
- {/* Show this at the last option */} - {oIndex === question.options.length - 1 && ( -
+ {view === 'teacher' ? ( + handleOptionChange(qIndex, oIndex, e.target.value)} + placeholder="Option" + className="w-full mx-2 px-3 pr-6 text-neutral-600 bg-[#00008b00] border-2 border-gray-200 rounded-md border-dotted text-sm font-bold" + /> + ) : ( +

+ {option.text} +

+ )} + {view === 'teacher' && ( + <>
addOption(qIndex)} + className={`w-fit flex-none flex text-xs px-2 py-0.5 space-x-1 items-center h-fit rounded-lg ${option.correct ? 'bg-lime-200 text-lime-600' : 'bg-rose-200/60 text-rose-500' + } hover:bg-lime-300 text-sm transition-all ease-linear cursor-pointer`} + onClick={() => toggleCorrectOption(qIndex, oIndex)} > - - + {option.correct ? : } + {option.correct ? ( +

Correct

+ ) : ( +

Incorrect

+ )}
-
+
removeOption(qIndex, oIndex)} + > + +
+ )}
+ {view === 'teacher' && oIndex === question.options.length - 1 && ( +
+
addOption(qIndex)} + > + + +
+
+ )}
))}
))}
-
-
- - Add Question + {view === 'teacher' && ( +
+
+ + Add Question +
-
+ )} ); } diff --git a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx index 44b2c164..b1605d25 100644 --- a/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx +++ b/apps/web/app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/page.tsx @@ -1,10 +1,9 @@ 'use client'; import BreadCrumbs from '@components/Dashboard/UI/BreadCrumbs' -import { BookOpen, BookX, EllipsisVertical, LayoutList } from 'lucide-react' +import { BookOpen, BookX, EllipsisVertical, Eye, LayoutList } from 'lucide-react' import React, { useEffect } from 'react' import { AssignmentProvider, useAssignments } from '@components/Contexts/Assignments/AssignmentContext'; import AssignmentTasks from './_components/Tasks'; -import { useParams } from 'next/navigation'; import { AssignmentsTaskProvider } from '@components/Contexts/Assignments/AssignmentsTaskContext'; import ToolTip from '@components/StyledElements/Tooltip/Tooltip'; import AssignmentTaskEditor from './_components/TaskEditor/TaskEditor'; @@ -13,6 +12,8 @@ import { useLHSession } from '@components/Contexts/LHSessionContext'; import { mutate } from 'swr'; import { getAPIUrl } from '@services/config/config'; import toast from 'react-hot-toast'; +import Link from 'next/link'; +import { useParams } from 'next/navigation'; function AssignmentEdit() { const params = useParams<{ assignmentuuid: string; }>() @@ -83,7 +84,7 @@ function PublishingState() { } useEffect(() => { - console.log('assignment', assignment?.assignment_object?.assignment_uuid) + console.log('assignment', assignment) }, [assignment]) return ( @@ -104,6 +105,19 @@ function PublishingState() {

Unpublish

} + + + +

Preview

+ +
{!assignment?.assignment_object?.published && swrFetcher(url, accessToken) ) - // Define a key for the course object based on assignment data const course_id = assignment?.course_id const { data: course_object, error: courseObjectError } = useSWR( @@ -38,12 +37,14 @@ export function AssignmentProvider({ children, assignment_uuid }: { children: Re ) useEffect(() => { - setAssignmentsFull({ assignment_object: assignment, assignment_tasks: assignment_tasks, course_object: course_object, activity_object: activity_object }) - }, [assignment, assignment_tasks, course_object, activity_object]) + if (assignment && assignment_tasks && (!course_id || course_object) && (!activity_id || activity_object)) { + setAssignmentsFull({ assignment_object: assignment, assignment_tasks: assignment_tasks, course_object: course_object, activity_object: activity_object }) + } + }, [assignment, assignment_tasks, course_object, activity_object, course_id, activity_id]) - if (assignmentError || assignmentTasksError || courseObjectError) return
+ if (assignmentError || assignmentTasksError || courseObjectError || activityObjectError) return
- if (!assignment || !assignment_tasks || (course_id && !course_object)) return
+ if (!assignment || !assignment_tasks || (course_id && !course_object) || (activity_id && !activity_object)) return
return {children} } diff --git a/apps/web/components/Objects/Assignments/AssignmentBoxUI.tsx b/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx similarity index 55% rename from apps/web/components/Objects/Assignments/AssignmentBoxUI.tsx rename to apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx index f91f10d9..b8c25ca9 100644 --- a/apps/web/components/Objects/Assignments/AssignmentBoxUI.tsx +++ b/apps/web/components/Objects/Activities/Assignment/AssignmentBoxUI.tsx @@ -1,17 +1,18 @@ -import { BookUser, EllipsisVertical, FileUp, ListTodo, Save } from 'lucide-react' +import { BookUser, EllipsisVertical, FileUp, Forward, ListTodo, Save } from 'lucide-react' import React from 'react' type AssignmentBoxProps = { type: 'quiz' | 'file' view?: 'teacher' | 'student' saveFC?: () => void + submitFC?: () => void children: React.ReactNode } -function AssignmentBoxUI({ type, view, saveFC, children }: AssignmentBoxProps) { +function AssignmentBoxUI({ type, view, saveFC, submitFC, children }: AssignmentBoxProps) { return ( -
+
@@ -20,13 +21,13 @@ function AssignmentBoxUI({ type, view, saveFC, children }: AssignmentBoxProps) {

Quiz

} - {type === 'file' && + {type === 'file' &&

File Submission

}
- +
@@ -41,12 +42,22 @@ function AssignmentBoxUI({ type, view, saveFC, children }: AssignmentBoxProps) {
{/* Save button */} -
saveFC && saveFC()} - className='flex px-2 py-1 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-slate-500 bg-white/60 hover:bg-white/80 linear transition-all nice-shadow '> - -

Save

-
+ {view === 'teacher' && +
saveFC && saveFC()} + className='flex px-2 py-1 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-slate-500 bg-white/60 hover:bg-white/80 linear transition-all nice-shadow '> + +

Save

+
+ } + {view === 'student' && +
submitFC && submitFC()} + className='flex px-2 py-1 cursor-pointer rounded-md space-x-2 items-center bg-gradient-to-bl text-slate-500 bg-white/60 hover:bg-white/80 linear transition-all nice-shadow '> + +

Save

+
+ }
diff --git a/apps/web/components/Objects/Activities/Assignment/AssignmentStudentActivity.tsx b/apps/web/components/Objects/Activities/Assignment/AssignmentStudentActivity.tsx new file mode 100644 index 00000000..d428d021 --- /dev/null +++ b/apps/web/components/Objects/Activities/Assignment/AssignmentStudentActivity.tsx @@ -0,0 +1,89 @@ +import { useAssignments } from '@components/Contexts/Assignments/AssignmentContext'; +import { useAssignmentsTask } from '@components/Contexts/Assignments/AssignmentsTaskContext'; +import { useCourse } from '@components/Contexts/CourseContext'; +import { useOrg } from '@components/Contexts/OrgContext'; +import { getTaskRefFileDir } from '@services/media/media'; +import TaskFileObject from 'app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskFileObject'; +import TaskQuizObject from 'app/orgs/[orgslug]/dash/assignments/[assignmentuuid]/_components/TaskEditor/Subs/TaskTypes/TaskQuizObject' +import { Backpack, Calendar, Download, EllipsisVertical, Info } from 'lucide-react'; +import Link from 'next/link'; +import React, { useEffect } from 'react' + +function AssignmentStudentActivity() { + const assignments = useAssignments() as any; + const course = useCourse() as any; + const org = useOrg() as any; + + useEffect(() => { + console.log(assignments) + }, [assignments, org]) + + + return ( +
+
+
+
+ +

Assignment

+
+
+
+
+ +
+
+ +

Due Date

+

{assignments?.assignment_object?.due_date}

+
+
+
+
+ +
+
+ {assignments && assignments?.assignment_tasks?.sort((a: any, b: any) => a.id - b.id).map((task: any, index: number) => { + return ( +
+
+
+

Task {index + 1} :

+

{task.description}

+
+
+
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'> + +

View Hint

+
+ + +

Reference file

+ +
+
+
+ {task.assignment_type === 'QUIZ' && } + {task.assignment_type === 'FILE_SUBMISSION' && } +
+
+ ) + })} +
+ ) +} + +export default AssignmentStudentActivity \ No newline at end of file diff --git a/apps/web/services/courses/assignments.ts b/apps/web/services/courses/assignments.ts index 1a6e54e8..16f57945 100644 --- a/apps/web/services/courses/assignments.ts +++ b/apps/web/services/courses/assignments.ts @@ -138,3 +138,25 @@ export async function updateReferenceFile( const res = await getResponseMetadata(result) return res } + + +export async function updateSubFile( + file: any, + assignmentTaskUUID: string, + assignmentUUID: string, + access_token: string +) { + + // Send file thumbnail as form data + const formData = new FormData() + + if (file) { + formData.append('sub_file', file) + } + const result: any = await fetch( + `${getAPIUrl()}assignments/${assignmentUUID}/tasks/${assignmentTaskUUID}/sub_file`, + RequestBodyFormWithAuthHeader('POST', formData, null, access_token) + ) + const res = await getResponseMetadata(result) + return res +}