feat: enhance assignment page with edit functionality and description display

This commit is contained in:
swve 2025-03-12 14:10:42 +01:00
parent 67ac0b9d67
commit 0229380cba
3 changed files with 285 additions and 39 deletions

View file

@ -1,6 +1,6 @@
'use client';
import BreadCrumbs from '@components/Dashboard/Misc/BreadCrumbs'
import { BookOpen, BookX, EllipsisVertical, Eye, Layers2, Monitor, UserRoundPen } from 'lucide-react'
import { ArrowRight, BookOpen, BookX, EllipsisVertical, Eye, Layers2, Monitor, Pencil, UserRoundPen } from 'lucide-react'
import React, { useEffect } from 'react'
import { AssignmentProvider, useAssignments } from '@components/Contexts/Assignments/AssignmentContext';
import ToolTip from '@components/Objects/StyledElements/Tooltip/Tooltip';
@ -16,6 +16,7 @@ import { updateActivity } from '@services/courses/activities';
import dynamic from 'next/dynamic';
import AssignmentEditorSubPage from './subpages/AssignmentEditorSubPage';
import { useMediaQuery } from 'usehooks-ts';
import EditAssignmentModal from '@components/Objects/Modals/Activities/Assignments/EditAssignmentModal';
const AssignmentSubmissionsSubPage = dynamic(() => import('./subpages/AssignmentSubmissionsSubPage'))
function AssignmentEdit() {
@ -46,7 +47,9 @@ function AssignmentEdit() {
<div className="pl-10 mr-10 tracking-tighter">
<BrdCmpx />
<div className="w-100 flex justify-between">
<div className="flex font-bold text-2xl">Assignment Tools </div>
<div className="flex font-bold text-2xl">
<AssignmentTitle />
</div>
</div>
</div>
<div className='flex flex-col justify-center antialiased'>
@ -106,6 +109,7 @@ function PublishingState() {
const assignment = useAssignments() as any;
const session = useLHSession() as any;
const access_token = session?.data?.tokens?.access_token;
const [isEditModalOpen, setIsEditModalOpen] = React.useState(false);
async function updateAssignmentPublishState(assignmentUUID: string) {
const res = await updateAssignment({ published: !assignment?.assignment_object?.published }, assignmentUUID, access_token)
@ -125,12 +129,26 @@ function PublishingState() {
}, [assignment])
return (
<>
<div className='flex mx-auto mt-5 items-center space-x-4'>
<div className={`flex text-xs rounded-full px-3.5 py-2 mx-auto font-bold outline outline-1 ${!assignment?.assignment_object?.published ? 'outline-gray-300 bg-gray-200/60' : 'outline-green-300 bg-green-200/60'}`}>
{assignment?.assignment_object?.published ? 'Published' : 'Unpublished'}
</div>
<div><EllipsisVertical className='text-gray-500' size={13} /></div>
<ToolTip
side='left'
slateBlack
sideOffset={10}
content="Edit Assignment Details">
<div
onClick={() => setIsEditModalOpen(true)}
className='flex px-3 py-2 cursor-pointer rounded-md space-x-2 items-center bg-linear-to-bl text-blue-800 font-medium from-blue-400/50 to-blue-200/80 border border-blue-600/10 shadow-blue-900/10 shadow-lg'>
<Pencil size={18} />
<p className='text-sm font-bold'>Edit</p>
</div>
</ToolTip>
<ToolTip
side='left'
slateBlack
@ -170,5 +188,24 @@ function PublishingState() {
</div>
</ToolTip>}
</div>
{isEditModalOpen && (
<EditAssignmentModal
isOpen={isEditModalOpen}
onClose={() => setIsEditModalOpen(false)}
assignment={assignment?.assignment_object}
accessToken={access_token}
/>
)}
</>
)
}
function AssignmentTitle() {
const assignment = useAssignments() as any;
return (
<div className="flex items-center gap-2">
Assignment Tools
</div>
);
}

View file

@ -40,7 +40,22 @@ function AssignmentStudentActivity() {
</div>
</div>
<div className='w-full rounded-full bg-slate-500/5 nice-shadow h-[2px]'></div>
{assignments?.assignment_object?.description && (
<div className='flex flex-col space-y-2 p-4 md:p-6 bg-slate-100/30 rounded-md nice-shadow'>
<div className='flex flex-col space-y-3'>
<div className='flex items-center gap-2 text-slate-700'>
<Info size={16} className="text-slate-500" />
<h3 className='text-sm font-semibold'>Assignment Description</h3>
</div>
<div className='pl-6'>
<p className='text-sm leading-relaxed text-slate-600'>{assignments.assignment_object.description}</p>
</div>
</div>
</div>
)}
{assignments && assignments?.assignment_tasks?.sort((a: any, b: any) => a.id - b.id).map((task: any, index: number) => {
return (

View file

@ -0,0 +1,194 @@
import React from 'react';
import { updateAssignment } from '@services/courses/assignments';
import { mutate } from 'swr';
import { getAPIUrl } from '@services/config/config';
import toast from 'react-hot-toast';
import FormLayout, {
FormField,
FormLabelAndMessage,
Input,
Textarea,
Flex,
FormLabel,
FormMessage
} from '@components/Objects/StyledElements/Form/Form';
import * as Form from '@radix-ui/react-form';
import { useFormik } from 'formik';
import Modal from '@components/Objects/StyledElements/Modal/Modal';
interface Assignment {
assignment_uuid: string;
title: string;
description: string;
due_date?: string;
grading_type?: 'ALPHABET' | 'NUMERIC' | 'PERCENTAGE';
}
interface EditAssignmentFormProps {
onClose: () => void;
assignment: Assignment;
accessToken: string;
}
interface EditAssignmentModalProps {
isOpen: boolean;
onClose: () => void;
assignment: Assignment;
accessToken: string;
}
const EditAssignmentForm: React.FC<EditAssignmentFormProps> = ({
onClose,
assignment,
accessToken
}) => {
const formik = useFormik({
initialValues: {
title: assignment.title || '',
description: assignment.description || '',
due_date: assignment.due_date || '',
grading_type: assignment.grading_type || 'ALPHABET'
},
enableReinitialize: true,
onSubmit: async (values, { setSubmitting }) => {
const toast_loading = toast.loading('Updating assignment...');
try {
const res = await updateAssignment(values, assignment.assignment_uuid, accessToken);
if (res.success) {
mutate(`${getAPIUrl()}assignments/${assignment.assignment_uuid}`);
toast.success('Assignment updated successfully');
onClose();
} else {
toast.error('Failed to update assignment');
}
} catch (error) {
toast.error('An error occurred while updating the assignment');
} finally {
toast.dismiss(toast_loading);
setSubmitting(false);
}
}
});
return (
<FormLayout onSubmit={formik.handleSubmit}>
<FormField name="title">
<Flex css={{ alignItems: 'baseline', justifyContent: 'space-between' }}>
<FormLabel>Assignment Title</FormLabel>
<FormMessage match="valueMissing">
Please provide a name for your assignment
</FormMessage>
</Flex>
<Form.Control asChild>
<Input
onChange={formik.handleChange}
value={formik.values.title}
type="text"
required
/>
</Form.Control>
</FormField>
<FormField name="description">
<Flex css={{ alignItems: 'baseline', justifyContent: 'space-between' }}>
<FormLabel>Assignment Description</FormLabel>
<FormMessage match="valueMissing">
Please provide a description for your assignment
</FormMessage>
</Flex>
<Form.Control asChild>
<Textarea
onChange={formik.handleChange}
value={formik.values.description}
required
/>
</Form.Control>
</FormField>
<FormField name="due_date">
<Flex css={{ alignItems: 'baseline', justifyContent: 'space-between' }}>
<FormLabel>Due Date</FormLabel>
<FormMessage match="valueMissing">
Please provide a due date for your assignment
</FormMessage>
</Flex>
<Form.Control asChild>
<Input
type="date"
onChange={formik.handleChange}
value={formik.values.due_date}
required
/>
</Form.Control>
</FormField>
<FormField name="grading_type">
<Flex css={{ alignItems: 'baseline', justifyContent: 'space-between' }}>
<FormLabel>Grading Type</FormLabel>
<FormMessage match="valueMissing">
Please provide a grading type for your assignment
</FormMessage>
</Flex>
<select
id="grading_type"
name="grading_type"
className='w-full bg-gray-100/40 rounded-lg px-3 py-2 outline outline-1 outline-gray-100'
onChange={(e) => formik.setFieldValue('grading_type', e.target.value, true)}
value={formik.values.grading_type}
required
>
<option value="ALPHABET">Alphabet</option>
<option value="NUMERIC">Numeric</option>
<option value="PERCENTAGE">Percentage</option>
</select>
</FormField>
<div className="flex justify-end space-x-3 mt-6">
<button
type="button"
onClick={onClose}
className="px-4 py-2 text-gray-600 hover:bg-gray-100 rounded-md"
>
Cancel
</button>
<Form.Submit asChild>
<button
type="submit"
disabled={formik.isSubmitting}
className="px-4 py-2 bg-black text-white font-bold rounded-md hover:bg-black/90"
>
{formik.isSubmitting ? 'Saving...' : 'Save Changes'}
</button>
</Form.Submit>
</div>
</FormLayout>
);
};
const EditAssignmentModal: React.FC<EditAssignmentModalProps> = ({
isOpen,
onClose,
assignment,
accessToken
}) => {
return (
<Modal
isDialogOpen={isOpen}
onOpenChange={onClose}
minHeight="md"
minWidth="lg"
dialogContent={
<EditAssignmentForm
onClose={onClose}
assignment={assignment}
accessToken={accessToken}
/>
}
dialogTitle="Edit Assignment"
dialogDescription="Update assignment details"
dialogTrigger={null}
/>
);
};
export default EditAssignmentModal;