mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: add assignment submission from the activity page
This commit is contained in:
parent
c13a7b4538
commit
e9caa2ceb4
7 changed files with 207 additions and 29 deletions
|
|
@ -4,7 +4,6 @@ from sqlmodel import Field, SQLModel
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Assignment ##
|
## Assignment ##
|
||||||
class GradingTypeEnum(str, Enum):
|
class GradingTypeEnum(str, Enum):
|
||||||
ALPHABET = "ALPHABET"
|
ALPHABET = "ALPHABET"
|
||||||
|
|
@ -103,8 +102,6 @@ class AssignmentTaskBase(SQLModel):
|
||||||
max_grade_value: int = 0 # Value is always between 0-100
|
max_grade_value: int = 0 # Value is always between 0-100
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class AssignmentTaskCreate(AssignmentTaskBase):
|
class AssignmentTaskCreate(AssignmentTaskBase):
|
||||||
"""Model for creating a new assignment task."""
|
"""Model for creating a new assignment task."""
|
||||||
|
|
||||||
|
|
@ -194,6 +191,7 @@ class AssignmentTaskSubmissionRead(AssignmentTaskSubmissionBase):
|
||||||
|
|
||||||
class AssignmentTaskSubmissionUpdate(SQLModel):
|
class AssignmentTaskSubmissionUpdate(SQLModel):
|
||||||
"""Model for updating an assignment task submission."""
|
"""Model for updating an assignment task submission."""
|
||||||
|
|
||||||
assignment_task_id: Optional[int]
|
assignment_task_id: Optional[int]
|
||||||
assignment_task_submission_uuid: Optional[str]
|
assignment_task_submission_uuid: Optional[str]
|
||||||
task_submission: Optional[Dict] = Field(default=None, sa_column=Column(JSON))
|
task_submission: Optional[Dict] = Field(default=None, sa_column=Column(JSON))
|
||||||
|
|
@ -233,10 +231,12 @@ class AssignmentTaskSubmission(AssignmentTaskSubmissionBase, table=True):
|
||||||
creation_date: str
|
creation_date: str
|
||||||
update_date: str
|
update_date: str
|
||||||
|
|
||||||
|
|
||||||
## AssignmentTaskSubmission ##
|
## AssignmentTaskSubmission ##
|
||||||
|
|
||||||
## AssignmentUserSubmission ##
|
## AssignmentUserSubmission ##
|
||||||
|
|
||||||
|
|
||||||
class AssignmentUserSubmissionStatus(str, Enum):
|
class AssignmentUserSubmissionStatus(str, Enum):
|
||||||
PENDING = "PENDING"
|
PENDING = "PENDING"
|
||||||
SUBMITTED = "SUBMITTED"
|
SUBMITTED = "SUBMITTED"
|
||||||
|
|
@ -248,11 +248,10 @@ class AssignmentUserSubmissionStatus(str, Enum):
|
||||||
class AssignmentUserSubmissionBase(SQLModel):
|
class AssignmentUserSubmissionBase(SQLModel):
|
||||||
"""Represents the submission status of an assignment for a user."""
|
"""Represents the submission status of an assignment for a user."""
|
||||||
|
|
||||||
|
|
||||||
submission_status: AssignmentUserSubmissionStatus = (
|
submission_status: AssignmentUserSubmissionStatus = (
|
||||||
AssignmentUserSubmissionStatus.PENDING
|
AssignmentUserSubmissionStatus.PENDING
|
||||||
)
|
)
|
||||||
grade: str
|
grade: int
|
||||||
user_id: int = Field(
|
user_id: int = Field(
|
||||||
sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
|
sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
|
||||||
)
|
)
|
||||||
|
|
@ -262,11 +261,14 @@ class AssignmentUserSubmissionBase(SQLModel):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
class AssignmentUserSubmissionCreate(AssignmentUserSubmissionBase):
|
|
||||||
|
class AssignmentUserSubmissionCreate(SQLModel):
|
||||||
"""Model for creating a new assignment user submission."""
|
"""Model for creating a new assignment user submission."""
|
||||||
|
|
||||||
|
assignment_id: int
|
||||||
pass # Inherits all fields from AssignmentUserSubmissionBase
|
pass # Inherits all fields from AssignmentUserSubmissionBase
|
||||||
|
|
||||||
|
|
||||||
class AssignmentUserSubmissionRead(AssignmentUserSubmissionBase):
|
class AssignmentUserSubmissionRead(AssignmentUserSubmissionBase):
|
||||||
"""Model for reading an assignment user submission."""
|
"""Model for reading an assignment user submission."""
|
||||||
|
|
||||||
|
|
@ -274,6 +276,7 @@ class AssignmentUserSubmissionRead(AssignmentUserSubmissionBase):
|
||||||
creation_date: str
|
creation_date: str
|
||||||
update_date: str
|
update_date: str
|
||||||
|
|
||||||
|
|
||||||
class AssignmentUserSubmissionUpdate(SQLModel):
|
class AssignmentUserSubmissionUpdate(SQLModel):
|
||||||
"""Model for updating an assignment user submission."""
|
"""Model for updating an assignment user submission."""
|
||||||
|
|
||||||
|
|
@ -282,17 +285,19 @@ class AssignmentUserSubmissionUpdate(SQLModel):
|
||||||
user_id: Optional[int]
|
user_id: Optional[int]
|
||||||
assignment_id: Optional[int]
|
assignment_id: Optional[int]
|
||||||
|
|
||||||
|
|
||||||
class AssignmentUserSubmission(AssignmentUserSubmissionBase, table=True):
|
class AssignmentUserSubmission(AssignmentUserSubmissionBase, table=True):
|
||||||
"""Represents the submission status of an assignment for a user."""
|
"""Represents the submission status of an assignment for a user."""
|
||||||
|
|
||||||
id: Optional[int] = Field(default=None, primary_key=True)
|
id: Optional[int] = Field(default=None, primary_key=True)
|
||||||
creation_date: str
|
creation_date: str
|
||||||
update_date: str
|
update_date: str
|
||||||
|
assignmentusersubmission_uuid: str
|
||||||
|
|
||||||
submission_status: AssignmentUserSubmissionStatus = (
|
submission_status: AssignmentUserSubmissionStatus = (
|
||||||
AssignmentUserSubmissionStatus.PENDING
|
AssignmentUserSubmissionStatus.PENDING
|
||||||
)
|
)
|
||||||
grade: str
|
grade: int
|
||||||
user_id: int = Field(
|
user_id: int = Field(
|
||||||
sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
|
sa_column=Column("user_id", ForeignKey("user.id", ondelete="CASCADE"))
|
||||||
)
|
)
|
||||||
|
|
@ -301,4 +306,3 @@ class AssignmentUserSubmission(AssignmentUserSubmissionBase, table=True):
|
||||||
"assignment_id", ForeignKey("assignment.id", ondelete="CASCADE")
|
"assignment_id", ForeignKey("assignment.id", ondelete="CASCADE")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ from src.services.courses.activities.assignments import (
|
||||||
read_assignment_task_submissions,
|
read_assignment_task_submissions,
|
||||||
read_assignment_tasks,
|
read_assignment_tasks,
|
||||||
read_user_assignment_submissions,
|
read_user_assignment_submissions,
|
||||||
|
read_user_assignment_submissions_me,
|
||||||
read_user_assignment_task_submissions,
|
read_user_assignment_task_submissions,
|
||||||
read_user_assignment_task_submissions_me,
|
read_user_assignment_task_submissions_me,
|
||||||
update_assignment,
|
update_assignment,
|
||||||
|
|
@ -208,6 +209,7 @@ async def api_put_assignment_task_ref_file(
|
||||||
request, db_session, assignment_task_uuid, current_user, reference_file
|
request, db_session, assignment_task_uuid, current_user, reference_file
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/{assignment_uuid}/tasks/{assignment_task_uuid}/sub_file")
|
@router.post("/{assignment_uuid}/tasks/{assignment_task_uuid}/sub_file")
|
||||||
async def api_put_assignment_task_sub_file(
|
async def api_put_assignment_task_sub_file(
|
||||||
request: Request,
|
request: Request,
|
||||||
|
|
@ -277,6 +279,7 @@ async def api_read_user_assignment_task_submissions(
|
||||||
request, assignment_task_uuid, user_id, current_user, db_session
|
request, assignment_task_uuid, user_id, current_user, db_session
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions/user/me")
|
@router.get("/{assignment_uuid}/tasks/{assignment_task_uuid}/submissions/user/me")
|
||||||
async def api_read_user_assignment_task_submissions_me(
|
async def api_read_user_assignment_task_submissions_me(
|
||||||
request: Request,
|
request: Request,
|
||||||
|
|
@ -331,7 +334,6 @@ async def api_delete_assignment_task_submissions(
|
||||||
async def api_create_assignment_submissions(
|
async def api_create_assignment_submissions(
|
||||||
request: Request,
|
request: Request,
|
||||||
assignment_uuid: str,
|
assignment_uuid: str,
|
||||||
assignment_submission: AssignmentUserSubmissionCreate,
|
|
||||||
current_user: PublicUser = Depends(get_current_user),
|
current_user: PublicUser = Depends(get_current_user),
|
||||||
db_session=Depends(get_db_session),
|
db_session=Depends(get_db_session),
|
||||||
):
|
):
|
||||||
|
|
@ -339,7 +341,7 @@ async def api_create_assignment_submissions(
|
||||||
Create new submissions for an assignment
|
Create new submissions for an assignment
|
||||||
"""
|
"""
|
||||||
return await create_assignment_submission(
|
return await create_assignment_submission(
|
||||||
request, assignment_uuid, assignment_submission, current_user, db_session
|
request, assignment_uuid, current_user, db_session
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -358,6 +360,21 @@ async def api_read_assignment_submissions(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/{assignment_uuid}/submissions/me")
|
||||||
|
async def api_read_user_assignment_submission_me(
|
||||||
|
request: Request,
|
||||||
|
assignment_uuid: str,
|
||||||
|
current_user: PublicUser = Depends(get_current_user),
|
||||||
|
db_session=Depends(get_db_session),
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Read submissions for an assignment from the current user
|
||||||
|
"""
|
||||||
|
return await read_user_assignment_submissions_me(
|
||||||
|
request, assignment_uuid, current_user, db_session
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{assignment_uuid}/submissions/{user_id}")
|
@router.get("/{assignment_uuid}/submissions/{user_id}")
|
||||||
async def api_read_user_assignment_submissions(
|
async def api_read_user_assignment_submissions(
|
||||||
request: Request,
|
request: Request,
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ from typing import Literal
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from fastapi import HTTPException, Request, UploadFile
|
from fastapi import HTTPException, Request, UploadFile
|
||||||
from sqlmodel import Session, select
|
from sqlmodel import Session, select
|
||||||
|
from sympy import Sum
|
||||||
|
|
||||||
from src.db.courses.activities import Activity
|
from src.db.courses.activities import Activity
|
||||||
from src.db.courses.assignments import (
|
from src.db.courses.assignments import (
|
||||||
|
|
@ -25,6 +26,7 @@ from src.db.courses.assignments import (
|
||||||
AssignmentUserSubmission,
|
AssignmentUserSubmission,
|
||||||
AssignmentUserSubmissionCreate,
|
AssignmentUserSubmissionCreate,
|
||||||
AssignmentUserSubmissionRead,
|
AssignmentUserSubmissionRead,
|
||||||
|
AssignmentUserSubmissionStatus,
|
||||||
)
|
)
|
||||||
from src.db.courses.courses import Course
|
from src.db.courses.courses import Course
|
||||||
from src.db.organizations import Organization
|
from src.db.organizations import Organization
|
||||||
|
|
@ -1028,7 +1030,6 @@ async def delete_assignment_task_submission(
|
||||||
async def create_assignment_submission(
|
async def create_assignment_submission(
|
||||||
request: Request,
|
request: Request,
|
||||||
assignment_uuid: str,
|
assignment_uuid: str,
|
||||||
assignment_user_submission_object: AssignmentUserSubmissionCreate,
|
|
||||||
current_user: PublicUser | AnonymousUser,
|
current_user: PublicUser | AnonymousUser,
|
||||||
db_session: Session,
|
db_session: Session,
|
||||||
):
|
):
|
||||||
|
|
@ -1045,7 +1046,7 @@ async def create_assignment_submission(
|
||||||
# Check if the submission has already been made
|
# Check if the submission has already been made
|
||||||
statement = select(AssignmentUserSubmission).where(
|
statement = select(AssignmentUserSubmission).where(
|
||||||
AssignmentUserSubmission.assignment_id == assignment.id,
|
AssignmentUserSubmission.assignment_id == assignment.id,
|
||||||
AssignmentUserSubmission.user_id == assignment_user_submission_object.user_id,
|
AssignmentUserSubmission.user_id == current_user.id,
|
||||||
)
|
)
|
||||||
|
|
||||||
assignment_user_submission = db_session.exec(statement).first()
|
assignment_user_submission = db_session.exec(statement).first()
|
||||||
|
|
@ -1066,21 +1067,33 @@ async def create_assignment_submission(
|
||||||
detail="Course not found",
|
detail="Course not found",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Check if User already submitted the assignment
|
||||||
|
statement = select(AssignmentUserSubmission).where(
|
||||||
|
AssignmentUserSubmission.assignment_id == assignment.id,
|
||||||
|
AssignmentUserSubmission.user_id == current_user.id,
|
||||||
|
)
|
||||||
|
assignment_user_submission = db_session.exec(statement).first()
|
||||||
|
|
||||||
|
if assignment_user_submission:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=400,
|
||||||
|
detail="Assignment User Submission already exists",
|
||||||
|
)
|
||||||
|
|
||||||
# RBAC check
|
# RBAC check
|
||||||
await rbac_check(request, course.course_uuid, current_user, "create", db_session)
|
await rbac_check(request, course.course_uuid, current_user, "create", db_session)
|
||||||
|
|
||||||
# Create Assignment User Submission
|
# Create Assignment User Submission
|
||||||
assignment_user_submission = AssignmentUserSubmission(
|
assignment_user_submission = AssignmentUserSubmission(
|
||||||
**assignment_user_submission_object.model_dump()
|
user_id=current_user.id,
|
||||||
|
assignment_id=assignment.id, # type: ignore
|
||||||
|
grade=0,
|
||||||
|
assignmentusersubmission_uuid=str(f"assignmentusersubmission_{uuid4()}"),
|
||||||
|
submission_status=AssignmentUserSubmissionStatus.PENDING,
|
||||||
|
creation_date=str(datetime.now()),
|
||||||
|
update_date=str(datetime.now()),
|
||||||
)
|
)
|
||||||
|
|
||||||
assignment_user_submission.assignment_user_submission_uuid = str(
|
|
||||||
f"assignmentusersubmission_{uuid4()}"
|
|
||||||
)
|
|
||||||
assignment_user_submission.creation_date = str(datetime.now())
|
|
||||||
assignment_user_submission.update_date = str(datetime.now())
|
|
||||||
assignment_user_submission.org_id = course.org_id
|
|
||||||
|
|
||||||
# Insert Assignment User Submission in DB
|
# Insert Assignment User Submission in DB
|
||||||
db_session.add(assignment_user_submission)
|
db_session.add(assignment_user_submission)
|
||||||
db_session.commit()
|
db_session.commit()
|
||||||
|
|
@ -1173,6 +1186,21 @@ async def read_user_assignment_submissions(
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
async def read_user_assignment_submissions_me(
|
||||||
|
request: Request,
|
||||||
|
assignment_uuid: str,
|
||||||
|
current_user: PublicUser | AnonymousUser,
|
||||||
|
db_session: Session,
|
||||||
|
):
|
||||||
|
return await read_user_assignment_submissions(
|
||||||
|
request,
|
||||||
|
assignment_uuid,
|
||||||
|
current_user.id,
|
||||||
|
current_user,
|
||||||
|
db_session,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def update_assignment_submission(
|
async def update_assignment_submission(
|
||||||
request: Request,
|
request: Request,
|
||||||
user_id: str,
|
user_id: str,
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
'use client'
|
'use client'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { getUriWithOrg } from '@services/config/config'
|
import { getAPIUrl, getUriWithOrg } from '@services/config/config'
|
||||||
import Canva from '@components/Objects/Activities/DynamicCanva/DynamicCanva'
|
import Canva from '@components/Objects/Activities/DynamicCanva/DynamicCanva'
|
||||||
import VideoActivity from '@components/Objects/Activities/Video/Video'
|
import VideoActivity from '@components/Objects/Activities/Video/Video'
|
||||||
import { Check, MoreVertical } from 'lucide-react'
|
import { BookOpenCheck, Check, MoreVertical, UserRoundPen } from 'lucide-react'
|
||||||
import { markActivityAsComplete } from '@services/courses/activity'
|
import { markActivityAsComplete } from '@services/courses/activity'
|
||||||
import DocumentPdfActivity from '@components/Objects/Activities/DocumentPdf/DocumentPdf'
|
import DocumentPdfActivity from '@components/Objects/Activities/DocumentPdf/DocumentPdf'
|
||||||
import ActivityIndicators from '@components/Pages/Courses/ActivityIndicators'
|
import ActivityIndicators from '@components/Pages/Courses/ActivityIndicators'
|
||||||
|
|
@ -17,10 +17,14 @@ import AIActivityAsk from '@components/Objects/Activities/AI/AIActivityAsk'
|
||||||
import AIChatBotProvider from '@components/Contexts/AI/AIChatBotContext'
|
import AIChatBotProvider from '@components/Contexts/AI/AIChatBotContext'
|
||||||
import { useLHSession } from '@components/Contexts/LHSessionContext'
|
import { useLHSession } from '@components/Contexts/LHSessionContext'
|
||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { getAssignmentFromActivityUUID } from '@services/courses/assignments'
|
import { getAssignmentFromActivityUUID, submitAssignmentForGrading } from '@services/courses/assignments'
|
||||||
import AssignmentStudentActivity from '@components/Objects/Activities/Assignment/AssignmentStudentActivity'
|
import AssignmentStudentActivity from '@components/Objects/Activities/Assignment/AssignmentStudentActivity'
|
||||||
import { AssignmentProvider } from '@components/Contexts/Assignments/AssignmentContext'
|
import { AssignmentProvider } from '@components/Contexts/Assignments/AssignmentContext'
|
||||||
import { AssignmentsTaskProvider } from '@components/Contexts/Assignments/AssignmentsTaskContext'
|
import { AssignmentsTaskProvider } from '@components/Contexts/Assignments/AssignmentsTaskContext'
|
||||||
|
import AssignmentSubmissionProvider, { AssignmentSubmissionContext, useAssignmentSubmission } from '@components/Contexts/Assignments/AssignmentSubmissionContext'
|
||||||
|
import toast from 'react-hot-toast'
|
||||||
|
import { mutate } from 'swr'
|
||||||
|
import ConfirmationModal from '@components/StyledElements/ConfirmationModal/ConfirmationModal'
|
||||||
|
|
||||||
interface ActivityClientProps {
|
interface ActivityClientProps {
|
||||||
activityid: string
|
activityid: string
|
||||||
|
|
@ -135,6 +139,21 @@ function ActivityClient(props: ActivityClientProps) {
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
{activity.activity_type == 'TYPE_ASSIGNMENT' &&
|
||||||
|
<>
|
||||||
|
|
||||||
|
<MoreVertical size={17} className="text-gray-300 " />
|
||||||
|
<AssignmentSubmissionProvider assignment_uuid={assignment?.assignment_uuid}>
|
||||||
|
<AssignmentTools
|
||||||
|
assignment={assignment}
|
||||||
|
activity={activity}
|
||||||
|
activityid={activityid}
|
||||||
|
course={course}
|
||||||
|
orgslug={orgslug}
|
||||||
|
/>
|
||||||
|
</AssignmentSubmissionProvider>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
</AuthenticatedClientElement>
|
</AuthenticatedClientElement>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -172,7 +191,9 @@ function ActivityClient(props: ActivityClientProps) {
|
||||||
{assignment ? (
|
{assignment ? (
|
||||||
<AssignmentProvider assignment_uuid={assignment?.assignment_uuid}>
|
<AssignmentProvider assignment_uuid={assignment?.assignment_uuid}>
|
||||||
<AssignmentsTaskProvider>
|
<AssignmentsTaskProvider>
|
||||||
|
<AssignmentSubmissionProvider assignment_uuid={assignment?.assignment_uuid}>
|
||||||
<AssignmentStudentActivity />
|
<AssignmentStudentActivity />
|
||||||
|
</AssignmentSubmissionProvider>
|
||||||
</AssignmentsTaskProvider>
|
</AssignmentsTaskProvider>
|
||||||
</AssignmentProvider>
|
</AssignmentProvider>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -225,7 +246,7 @@ export function MarkStatus(props: {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isActivityCompleted() ? (
|
{isActivityCompleted() ? (
|
||||||
<div className="bg-teal-600 rounded-full px-5 drop-shadow-md flex items-center space-x-1 p-2.5 text-white hover:cursor-pointer transition delay-150 duration-300 ease-in-out">
|
<div className="bg-teal-600 rounded-full px-5 drop-shadow-md flex items-center space-x-2 p-2.5 text-white hover:cursor-pointer transition delay-150 duration-300 ease-in-out">
|
||||||
<i>
|
<i>
|
||||||
<Check size={17}></Check>
|
<Check size={17}></Check>
|
||||||
</i>{' '}
|
</i>{' '}
|
||||||
|
|
@ -233,7 +254,7 @@ export function MarkStatus(props: {
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
className="bg-gray-800 rounded-full px-5 drop-shadow-md flex items-center space-x-1 p-2.5 text-white hover:cursor-pointer transition delay-150 duration-300 ease-in-out"
|
className="bg-gray-800 rounded-full px-5 drop-shadow-md flex items-center space-x-2 p-2.5 text-white hover:cursor-pointer transition delay-150 duration-300 ease-in-out"
|
||||||
onClick={markActivityAsCompleteFront}
|
onClick={markActivityAsCompleteFront}
|
||||||
>
|
>
|
||||||
{' '}
|
{' '}
|
||||||
|
|
@ -247,4 +268,64 @@ export function MarkStatus(props: {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function AssignmentTools(props: {
|
||||||
|
activity: any
|
||||||
|
activityid: string
|
||||||
|
course: any
|
||||||
|
orgslug: string
|
||||||
|
assignment: any
|
||||||
|
}) {
|
||||||
|
const submission = useAssignmentSubmission() as any
|
||||||
|
const session = useLHSession() as any;
|
||||||
|
|
||||||
|
const submitForGradingUI = async () => {
|
||||||
|
if (props.assignment) {
|
||||||
|
const res = await submitAssignmentForGrading(
|
||||||
|
props.assignment?.assignment_uuid,
|
||||||
|
session.data?.tokens?.access_token
|
||||||
|
)
|
||||||
|
if (res.success) {
|
||||||
|
toast.success('Assignment submitted for grading')
|
||||||
|
mutate(`${getAPIUrl()}assignments/${props.assignment?.assignment_uuid}/submissions/me`,)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
toast.error('Failed to submit assignment for grading')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
}
|
||||||
|
, [submission, props.assignment])
|
||||||
|
|
||||||
|
return <>
|
||||||
|
{submission && submission.length == 0 && (
|
||||||
|
<ConfirmationModal
|
||||||
|
confirmationButtonText="Submit Assignment"
|
||||||
|
confirmationMessage="Are you sure you want to submit your assignment for grading?, once submitted you will not be able to make any changes"
|
||||||
|
dialogTitle="Submit your assignment for grading"
|
||||||
|
dialogTrigger={
|
||||||
|
<div
|
||||||
|
className="bg-cyan-800 rounded-full px-5 drop-shadow-md flex items-center space-x-2 p-2.5 text-white hover:cursor-pointer transition delay-150 duration-300 ease-in-out">
|
||||||
|
<i>
|
||||||
|
<BookOpenCheck size={17}></BookOpenCheck>
|
||||||
|
</i>{' '}
|
||||||
|
<i className="not-italic text-xs font-bold">Submit for grading</i>
|
||||||
|
</div>}
|
||||||
|
functionToExecute={() => submitForGradingUI()}
|
||||||
|
status="info"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{submission && submission.length > 0 && (
|
||||||
|
<div
|
||||||
|
className="bg-amber-800 rounded-full px-5 drop-shadow-md flex items-center space-x-2 p-2.5 text-white transition delay-150 duration-300 ease-in-out">
|
||||||
|
<i>
|
||||||
|
<UserRoundPen size={17}></UserRoundPen>
|
||||||
|
</i>{' '}
|
||||||
|
<i className="not-italic text-xs font-bold">Grading in progress</i>
|
||||||
|
</div>)
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
export default ActivityClient
|
export default ActivityClient
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
'use client'
|
||||||
|
import React from 'react'
|
||||||
|
import { useLHSession } from '../LHSessionContext'
|
||||||
|
import { getAPIUrl } from '@services/config/config'
|
||||||
|
import { swrFetcher } from '@services/utils/ts/requests'
|
||||||
|
import useSWR from 'swr'
|
||||||
|
|
||||||
|
export const AssignmentSubmissionContext = React.createContext({})
|
||||||
|
|
||||||
|
function AssignmentSubmissionProvider({ children, assignment_uuid }: { children: React.ReactNode, assignment_uuid: string }) {
|
||||||
|
const session = useLHSession() as any
|
||||||
|
const accessToken = session?.data?.tokens?.access_token
|
||||||
|
|
||||||
|
const { data: assignmentSubmission, error: assignmentError } = useSWR(
|
||||||
|
`${getAPIUrl()}assignments/${assignment_uuid}/submissions/me`,
|
||||||
|
(url) => swrFetcher(url, accessToken)
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AssignmentSubmissionContext.Provider value={assignmentSubmission} >{children}</AssignmentSubmissionContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useAssignmentSubmission() {
|
||||||
|
return React.useContext(AssignmentSubmissionContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AssignmentSubmissionProvider
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
|
import { useAssignmentSubmission } from '@components/Contexts/Assignments/AssignmentSubmissionContext'
|
||||||
import { BookUser, EllipsisVertical, FileUp, Forward, Info, InfoIcon, ListTodo, Save } from 'lucide-react'
|
import { BookUser, EllipsisVertical, FileUp, Forward, Info, InfoIcon, ListTodo, Save } from 'lucide-react'
|
||||||
import React from 'react'
|
import React, { use, useEffect } from 'react'
|
||||||
|
|
||||||
type AssignmentBoxProps = {
|
type AssignmentBoxProps = {
|
||||||
type: 'quiz' | 'file'
|
type: 'quiz' | 'file'
|
||||||
|
|
@ -12,6 +13,10 @@ type AssignmentBoxProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
function AssignmentBoxUI({ type, view, saveFC, submitFC, showSavingDisclaimer, children }: AssignmentBoxProps) {
|
function AssignmentBoxUI({ type, view, saveFC, submitFC, showSavingDisclaimer, children }: AssignmentBoxProps) {
|
||||||
|
const submission = useAssignmentSubmission() as any
|
||||||
|
useEffect(() => {
|
||||||
|
}
|
||||||
|
, [submission])
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col px-6 py-4 nice-shadow rounded-md bg-slate-100/30'>
|
<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 justify-between space-x-2 pb-2 text-slate-400 items-center'>
|
||||||
|
|
@ -47,6 +52,7 @@ function AssignmentBoxUI({ type, view, saveFC, submitFC, showSavingDisclaimer, c
|
||||||
<p className='text-xs'>Don't forget to save your progress</p>
|
<p className='text-xs'>Don't forget to save your progress</p>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
{/* Save button */}
|
{/* Save button */}
|
||||||
{view === 'teacher' &&
|
{view === 'teacher' &&
|
||||||
<div
|
<div
|
||||||
|
|
@ -56,7 +62,7 @@ function AssignmentBoxUI({ type, view, saveFC, submitFC, showSavingDisclaimer, c
|
||||||
<p className='text-xs font-semibold'>Save</p>
|
<p className='text-xs font-semibold'>Save</p>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{view === 'student' &&
|
{view === 'student' && submission.length <= 0 &&
|
||||||
<div
|
<div
|
||||||
onClick={() => submitFC && submitFC()}
|
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 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'>
|
||||||
|
|
|
||||||
|
|
@ -187,3 +187,17 @@ export async function updateSubFile(
|
||||||
const res = await getResponseMetadata(result)
|
const res = await getResponseMetadata(result)
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// submissions
|
||||||
|
|
||||||
|
export async function submitAssignmentForGrading(
|
||||||
|
assignmentUUID: string,
|
||||||
|
access_token: string
|
||||||
|
) {
|
||||||
|
const result: any = await fetch(
|
||||||
|
`${getAPIUrl()}assignments/${assignmentUUID}/submissions`,
|
||||||
|
RequestBodyWithAuthHeader('POST', null, null, access_token)
|
||||||
|
)
|
||||||
|
const res = await getResponseMetadata(result)
|
||||||
|
return res
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue