mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
feat: create and delete assignment activities from UI
This commit is contained in:
parent
04c05e4f9a
commit
10e9be1d33
14 changed files with 358 additions and 14 deletions
|
|
@ -1,7 +1,7 @@
|
|||
import importlib
|
||||
from logging.config import fileConfig
|
||||
import os
|
||||
|
||||
import alembic_postgresql_enum
|
||||
from sqlalchemy import engine_from_config
|
||||
from sqlalchemy import pool
|
||||
from sqlmodel import SQLModel
|
||||
|
|
|
|||
41
apps/api/migrations/versions/6295e05ff7d0_enum_updates.py
Normal file
41
apps/api/migrations/versions/6295e05ff7d0_enum_updates.py
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
"""Enum updates
|
||||
|
||||
Revision ID: 6295e05ff7d0
|
||||
Revises: df2981bf24dd
|
||||
Create Date: 2024-07-11 20:46:26.582170
|
||||
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import sqlmodel
|
||||
from alembic_postgresql_enum import TableReference # type: ignore
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = '6295e05ff7d0'
|
||||
down_revision: Union[str, None] = 'df2981bf24dd'
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.sync_enum_values('public', 'activitytypeenum', ['TYPE_VIDEO', 'TYPE_DOCUMENT', 'TYPE_DYNAMIC', 'TYPE_ASSIGNMENT', 'TYPE_CUSTOM'],
|
||||
[TableReference(table_schema='public', table_name='activity', column_name='activity_type')],
|
||||
enum_values_to_rename=[])
|
||||
op.sync_enum_values('public', 'activitysubtypeenum', ['SUBTYPE_DYNAMIC_PAGE', 'SUBTYPE_VIDEO_YOUTUBE', 'SUBTYPE_VIDEO_HOSTED', 'SUBTYPE_DOCUMENT_PDF', 'SUBTYPE_DOCUMENT_DOC', 'SUBTYPE_ASSIGNMENT_ANY', 'SUBTYPE_CUSTOM'],
|
||||
[TableReference(table_schema='public', table_name='activity', column_name='activity_sub_type')],
|
||||
enum_values_to_rename=[])
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.sync_enum_values('public', 'activitysubtypeenum', ['SUBTYPE_DYNAMIC_PAGE', 'SUBTYPE_VIDEO_YOUTUBE', 'SUBTYPE_VIDEO_HOSTED', 'SUBTYPE_DOCUMENT_PDF', 'SUBTYPE_DOCUMENT_DOC', 'SUBTYPE_ASSESSMENT_QUIZ', 'SUBTYPE_CUSTOM'],
|
||||
[TableReference(table_schema='public', table_name='activity', column_name='activity_sub_type')],
|
||||
enum_values_to_rename=[])
|
||||
op.sync_enum_values('public', 'activitytypeenum', ['TYPE_VIDEO', 'TYPE_DOCUMENT', 'TYPE_DYNAMIC', 'TYPE_ASSESSMENT', 'TYPE_CUSTOM'],
|
||||
[TableReference(table_schema='public', table_name='activity', column_name='activity_type')],
|
||||
enum_values_to_rename=[])
|
||||
# ### end Alembic commands ###
|
||||
|
|
@ -23,6 +23,9 @@ depends_on: Union[str, Sequence[str], None] = None
|
|||
def upgrade() -> None:
|
||||
# ### commands auto generated by Alembic - please adjust! ###
|
||||
op.add_column('activity', sa.Column('published', sa.Boolean(), nullable=False, server_default=sa.true()))
|
||||
# If you need to rename columns instead of dropping them, use the rename_column command
|
||||
# For example, if we are changing the name 'published_version' to 'published', we would use:
|
||||
# op.alter_column('activity', 'published_version', new_column_name='published', existing_type=sa.Boolean())
|
||||
op.drop_column('activity', 'published_version')
|
||||
op.drop_column('activity', 'version')
|
||||
|
||||
|
|
@ -32,7 +35,6 @@ def upgrade() -> None:
|
|||
op.create_foreign_key('trail_org_id_fkey', 'trail', 'organization', ['org_id'], ['id'], ondelete='CASCADE')
|
||||
op.drop_constraint('trail_user_id_fkey', 'trail', type_='foreignkey')
|
||||
op.create_foreign_key('trail_user_id_fkey', 'trail', 'user', ['user_id'], ['id'], ondelete='CASCADE')
|
||||
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
||||
|
|
@ -45,7 +47,8 @@ def downgrade() -> None:
|
|||
|
||||
op.add_column('assignmentusersubmission', sa.Column('assignment_user_uuid', sa.VARCHAR(), autoincrement=False, nullable=False))
|
||||
|
||||
op.add_column('activity', sa.Column('version', sa.INTEGER(), autoincrement=False, nullable=False , server_default=sa.text('1')))
|
||||
op.add_column('activity', sa.Column('published_version', sa.INTEGER(), autoincrement=False, nullable=False , server_default=sa.text('1')) )
|
||||
op.add_column('activity', sa.Column('version', sa.INTEGER(), autoincrement=False, nullable=False, server_default=sa.text('1')))
|
||||
op.add_column('activity', sa.Column('published_version', sa.INTEGER(), autoincrement=False, nullable=False, server_default=sa.text('1')))
|
||||
op.drop_column('activity', 'published')
|
||||
# ### end Alembic commands ###
|
||||
|
||||
|
|
|
|||
45
apps/api/poetry.lock
generated
45
apps/api/poetry.lock
generated
|
|
@ -128,6 +128,21 @@ typing-extensions = ">=4"
|
|||
[package.extras]
|
||||
tz = ["backports.zoneinfo"]
|
||||
|
||||
[[package]]
|
||||
name = "alembic-postgresql-enum"
|
||||
version = "1.2.0"
|
||||
description = "Alembic autogenerate support for creation, alteration and deletion of enums"
|
||||
optional = false
|
||||
python-versions = "<4.0,>=3.7"
|
||||
files = [
|
||||
{file = "alembic_postgresql_enum-1.2.0-py3-none-any.whl", hash = "sha256:bd156e882a10c680fc88ebad25cfe78ccf9f826dec89670f8aeb28e5359e502b"},
|
||||
{file = "alembic_postgresql_enum-1.2.0.tar.gz", hash = "sha256:971bd3a4c35ea38869bb5e263ea79e5b4a9c4a02f174a3dd7ddcb29d41260cba"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
alembic = ">=1.7"
|
||||
SQLAlchemy = ">=1.4"
|
||||
|
||||
[[package]]
|
||||
name = "anyio"
|
||||
version = "4.4.0"
|
||||
|
|
@ -3018,6 +3033,34 @@ postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"]
|
|||
pymysql = ["pymysql"]
|
||||
sqlcipher = ["sqlcipher3_binary"]
|
||||
|
||||
[[package]]
|
||||
name = "sqlalchemy-utils"
|
||||
version = "0.41.2"
|
||||
description = "Various utility functions for SQLAlchemy."
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "SQLAlchemy-Utils-0.41.2.tar.gz", hash = "sha256:bc599c8c3b3319e53ce6c5c3c471120bd325d0071fb6f38a10e924e3d07b9990"},
|
||||
{file = "SQLAlchemy_Utils-0.41.2-py3-none-any.whl", hash = "sha256:85cf3842da2bf060760f955f8467b87983fb2e30f1764fd0e24a48307dc8ec6e"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
SQLAlchemy = ">=1.3"
|
||||
|
||||
[package.extras]
|
||||
arrow = ["arrow (>=0.3.4)"]
|
||||
babel = ["Babel (>=1.3)"]
|
||||
color = ["colour (>=0.0.4)"]
|
||||
encrypted = ["cryptography (>=0.6)"]
|
||||
intervals = ["intervals (>=0.7.1)"]
|
||||
password = ["passlib (>=1.6,<2.0)"]
|
||||
pendulum = ["pendulum (>=2.0.5)"]
|
||||
phone = ["phonenumbers (>=5.9.2)"]
|
||||
test = ["Jinja2 (>=2.3)", "Pygments (>=1.2)", "backports.zoneinfo", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "isort (>=4.2.2)", "pg8000 (>=1.12.4)", "psycopg (>=3.1.8)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (==7.4.4)", "python-dateutil (>=2.6)", "pytz (>=2014.2)"]
|
||||
test-all = ["Babel (>=1.3)", "Jinja2 (>=2.3)", "Pygments (>=1.2)", "arrow (>=0.3.4)", "backports.zoneinfo", "colour (>=0.0.4)", "cryptography (>=0.6)", "docutils (>=0.10)", "flake8 (>=2.4.0)", "flexmock (>=0.9.7)", "furl (>=0.4.1)", "intervals (>=0.7.1)", "isort (>=4.2.2)", "passlib (>=1.6,<2.0)", "pendulum (>=2.0.5)", "pg8000 (>=1.12.4)", "phonenumbers (>=5.9.2)", "psycopg (>=3.1.8)", "psycopg2 (>=2.5.1)", "psycopg2cffi (>=2.8.1)", "pymysql", "pyodbc", "pytest (==7.4.4)", "python-dateutil", "python-dateutil (>=2.6)", "pytz (>=2014.2)"]
|
||||
timezone = ["python-dateutil"]
|
||||
url = ["furl (>=0.4.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "sqlmodel"
|
||||
version = "0.0.19"
|
||||
|
|
@ -3871,4 +3914,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools",
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.12"
|
||||
content-hash = "76c4defc807fe83375766ac085982a2edf16e57b2d092a4494021f00a0424a4c"
|
||||
content-hash = "49d72c6871e3ecffae3b55ccad3a6b140f9a1ebbca84d7632dafd54e1d2b7f9d"
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ uvicorn = "0.30.1"
|
|||
typer = "^0.12.3"
|
||||
chromadb = "^0.5.3"
|
||||
alembic = "^1.13.2"
|
||||
alembic-postgresql-enum = "^1.2.0"
|
||||
sqlalchemy-utils = "^0.41.2"
|
||||
|
||||
[build-system]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
|
|
|||
|
|
@ -5,8 +5,12 @@ from sqlmodel import Field, SQLModel
|
|||
|
||||
class CollectionCourse(SQLModel, table=True):
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
collection_id: int = Field(sa_column=Column(Integer, ForeignKey("collection.id", ondelete="CASCADE")))
|
||||
course_id: int = Field(sa_column=Column(Integer, ForeignKey("course.id", ondelete="CASCADE")))
|
||||
collection_id: int = Field(
|
||||
sa_column=Column(Integer, ForeignKey("collection.id", ondelete="CASCADE"))
|
||||
)
|
||||
course_id: int = Field(
|
||||
sa_column=Column(Integer, ForeignKey("course.id", ondelete="CASCADE"))
|
||||
)
|
||||
org_id: int = Field(default=None, foreign_key="organization.id")
|
||||
creation_date: str
|
||||
update_date: str
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ class Assignment(AssignmentBase, table=True):
|
|||
class AssignmentTaskTypeEnum(str, Enum):
|
||||
FILE_SUBMISSION = "FILE_SUBMISSION"
|
||||
QUIZ = "QUIZ"
|
||||
FORM = "FORM" # soon to be implemented
|
||||
FORM = "FORM" # soon to be implemented
|
||||
OTHER = "OTHER"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,12 @@ class TrailBase(SQLModel):
|
|||
|
||||
class Trail(TrailBase, table=True):
|
||||
id: Optional[int] = Field(default=None, primary_key=True)
|
||||
org_id: int = Field(
|
||||
sa_column=Column(Integer, ForeignKey("organization.id", ondelete="CASCADE"))
|
||||
)
|
||||
user_id: int = Field(
|
||||
sa_column=Column(Integer, ForeignKey("user.id", ondelete="CASCADE"))
|
||||
)
|
||||
trail_uuid: str = ""
|
||||
creation_date: str = ""
|
||||
update_date: str = ""
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ from src.services.courses.activities.assignments import (
|
|||
create_assignment_task,
|
||||
create_assignment_task_submission,
|
||||
delete_assignment,
|
||||
delete_assignment_from_activity_uuid,
|
||||
delete_assignment_submission,
|
||||
delete_assignment_task,
|
||||
delete_assignment_task_submission,
|
||||
|
|
@ -90,6 +91,18 @@ async def api_delete_assignment(
|
|||
"""
|
||||
return await delete_assignment(request, assignment_uuid, current_user, db_session)
|
||||
|
||||
@router.delete("/activity/{activity_uuid}")
|
||||
async def api_delete_assignment_from_activity(
|
||||
request: Request,
|
||||
activity_uuid: str,
|
||||
current_user: PublicUser = Depends(get_current_user),
|
||||
db_session=Depends(get_db_session),
|
||||
):
|
||||
"""
|
||||
Delete an assignment
|
||||
"""
|
||||
return await delete_assignment_from_activity_uuid(request, activity_uuid, current_user, db_session)
|
||||
|
||||
|
||||
## ASSIGNMENTS Tasks ##
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ from uuid import uuid4
|
|||
from fastapi import HTTPException, Request
|
||||
from sqlmodel import Session, select
|
||||
|
||||
from src.db.courses.activities import Activity
|
||||
from src.db.courses.assignments import (
|
||||
Assignment,
|
||||
AssignmentCreate,
|
||||
|
|
@ -184,6 +185,53 @@ async def delete_assignment(
|
|||
|
||||
return {"message": "Assignment deleted"}
|
||||
|
||||
async def delete_assignment_from_activity_uuid(
|
||||
request: Request,
|
||||
activity_uuid: str,
|
||||
current_user: PublicUser | AnonymousUser,
|
||||
db_session: Session,
|
||||
):
|
||||
# Check if activity exists
|
||||
statement = select(Activity).where(Activity.activity_uuid == activity_uuid)
|
||||
|
||||
activity = db_session.exec(statement).first()
|
||||
|
||||
if not activity:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="Activity not found",
|
||||
)
|
||||
|
||||
# Check if course exists
|
||||
statement = select(Course).where(Course.id == activity.course_id)
|
||||
course = db_session.exec(statement).first()
|
||||
|
||||
if not course:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="Course not found",
|
||||
)
|
||||
|
||||
# Check if assignment exists
|
||||
statement = select(Assignment).where(Assignment.activity_id == activity.id)
|
||||
assignment = db_session.exec(statement).first()
|
||||
|
||||
if not assignment:
|
||||
raise HTTPException(
|
||||
status_code=404,
|
||||
detail="Assignment not found",
|
||||
)
|
||||
|
||||
# RBAC check
|
||||
await rbac_check(request, course.course_uuid, current_user, "delete", db_session)
|
||||
|
||||
# Delete Assignment
|
||||
db_session.delete(assignment)
|
||||
|
||||
db_session.commit()
|
||||
|
||||
return {"message": "Assignment deleted"}
|
||||
|
||||
|
||||
## > Assignments Tasks CRUD
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import { useRouter } from 'next/navigation'
|
|||
import React from 'react'
|
||||
import { Draggable } from 'react-beautiful-dnd'
|
||||
import { mutate } from 'swr'
|
||||
import { deleteAssignment, deleteAssignmentUsingActivityUUID } from '@services/courses/assignments'
|
||||
|
||||
type ActivitiyElementProps = {
|
||||
orgslug: string
|
||||
|
|
@ -45,6 +46,11 @@ function ActivityElement(props: ActivitiyElementProps) {
|
|||
const activityUUID = props.activity.activity_uuid
|
||||
|
||||
async function deleteActivityUI() {
|
||||
// Assignments
|
||||
if(props.activity.activity_type === 'TYPE_ASSIGNMENT') {
|
||||
await deleteAssignmentUsingActivityUUID(props.activity.activity_uuid, access_token)
|
||||
}
|
||||
|
||||
await deleteActivity(props.activity.activity_uuid, access_token)
|
||||
mutate(`${getAPIUrl()}courses/${props.course_uuid}/meta`)
|
||||
await revalidateTags(['courses'], props.orgslug)
|
||||
|
|
|
|||
|
|
@ -102,9 +102,10 @@ function NewActivityModal({
|
|||
|
||||
{selectedView === 'assignments' && (
|
||||
<Assignment
|
||||
submitFileActivity={submitFileActivity}
|
||||
submitActivity={submitActivity}
|
||||
chapterId={chapterId}
|
||||
course={course}
|
||||
closeModal={closeModal}
|
||||
/>)
|
||||
}
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,153 @@
|
|||
import React from 'react'
|
||||
import FormLayout, {
|
||||
ButtonBlack,
|
||||
Flex,
|
||||
FormField,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
Input,
|
||||
|
||||
function Assignment() {
|
||||
return (
|
||||
<div>Assignment</div>
|
||||
)
|
||||
} from '@components/StyledElements/Form/Form'
|
||||
import * as Form from '@radix-ui/react-form'
|
||||
import { BarLoader } from 'react-spinners'
|
||||
import { useOrg } from '@components/Contexts/OrgContext'
|
||||
import { getAPIUrl } from '@services/config/config'
|
||||
import { mutate } from 'swr'
|
||||
import { createAssignment } from '@services/courses/assignments'
|
||||
import { useLHSession } from '@components/Contexts/LHSessionContext'
|
||||
import { createActivity } from '@services/courses/activities'
|
||||
|
||||
function NewAssignment({ submitActivity, chapterId, course, closeModal }: any) {
|
||||
const org = useOrg() as any;
|
||||
const session = useLHSession() as any
|
||||
const [activityName, setActivityName] = React.useState('')
|
||||
const [isSubmitting, setIsSubmitting] = React.useState(false)
|
||||
const [activityDescription, setActivityDescription] = React.useState('')
|
||||
const [dueDate, setDueDate] = React.useState('')
|
||||
const [gradingType, setGradingType] = React.useState('ALPHABET')
|
||||
|
||||
const handleNameChange = (e: any) => {
|
||||
setActivityName(e.target.value)
|
||||
}
|
||||
|
||||
const handleDescriptionChange = (e: any) => {
|
||||
setActivityDescription(e.target.value)
|
||||
}
|
||||
|
||||
const handleDueDateChange = (e: any) => {
|
||||
setDueDate(e.target.value)
|
||||
}
|
||||
|
||||
const handleGradingTypeChange = (e: any) => {
|
||||
setGradingType(e.target.value)
|
||||
}
|
||||
|
||||
const handleSubmit = async (e: any) => {
|
||||
e.preventDefault()
|
||||
setIsSubmitting(true)
|
||||
const activity = {
|
||||
name: activityName,
|
||||
chapter_id: chapterId,
|
||||
activity_type: 'TYPE_ASSIGNMENT',
|
||||
activity_sub_type: 'SUBTYPE_ASSIGNMENT_ANY',
|
||||
published: false,
|
||||
course_id: course?.courseStructure.id,
|
||||
}
|
||||
|
||||
const activity_res = await createActivity(activity, chapterId, org?.id, session.data?.tokens?.access_token)
|
||||
console.log(course)
|
||||
console.log(activity_res)
|
||||
await createAssignment({
|
||||
title: activityName,
|
||||
description: activityDescription,
|
||||
due_date: dueDate,
|
||||
grading_type: gradingType,
|
||||
course_id: course?.courseStructure.id,
|
||||
org_id: org?.id,
|
||||
chapter_id: chapterId,
|
||||
activity_id: activity_res?.id,
|
||||
}, session.data?.tokens?.access_token)
|
||||
|
||||
mutate(`${getAPIUrl()}courses/${course.courseStructure.course_uuid}/meta`)
|
||||
setIsSubmitting(false)
|
||||
closeModal()
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<FormLayout onSubmit={handleSubmit}>
|
||||
<FormField name="assignment-activity-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={handleNameChange} type="text" required />
|
||||
</Form.Control>
|
||||
</FormField>
|
||||
|
||||
{/* Description */}
|
||||
<FormField name="assignment-activity-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>
|
||||
<Input onChange={handleDescriptionChange} type="text" required />
|
||||
</Form.Control>
|
||||
</FormField>
|
||||
|
||||
{/* Due date */}
|
||||
<FormField name="assignment-activity-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 onChange={handleDueDateChange} type="date" required />
|
||||
</Form.Control>
|
||||
</FormField>
|
||||
|
||||
{/* Grading type */}
|
||||
<FormField name="assignment-activity-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>
|
||||
<Form.Control asChild>
|
||||
<select className='bg-gray-100/40 rounded-lg px-1 py-2 outline outline-1 outline-gray-100' onChange={handleGradingTypeChange} required>
|
||||
<option value="ALPHABET">Alphabet</option>
|
||||
<option value="NUMERIC">Numeric</option>
|
||||
<option value="PERCENTAGE">Percentage</option>
|
||||
</select>
|
||||
</Form.Control>
|
||||
</FormField>
|
||||
|
||||
<Flex css={{ marginTop: 25, justifyContent: 'flex-end' }}>
|
||||
<Form.Submit asChild>
|
||||
<ButtonBlack type="submit" css={{ marginTop: 10 }}>
|
||||
{isSubmitting ? (
|
||||
<BarLoader
|
||||
cssOverride={{ borderRadius: 60 }}
|
||||
width={60}
|
||||
color="#ffffff"
|
||||
/>
|
||||
) : (
|
||||
'Create activity'
|
||||
)}
|
||||
</ButtonBlack>
|
||||
</Form.Submit>
|
||||
</Flex>
|
||||
</FormLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default Assignment
|
||||
export default NewAssignment
|
||||
33
apps/web/services/courses/assignments.ts
Normal file
33
apps/web/services/courses/assignments.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import { getAPIUrl } from '@services/config/config'
|
||||
import {
|
||||
RequestBodyWithAuthHeader,
|
||||
getResponseMetadata,
|
||||
} from '@services/utils/ts/requests'
|
||||
|
||||
export async function createAssignment(body: any, access_token: string) {
|
||||
const result: any = await fetch(
|
||||
`${getAPIUrl()}assignments`,
|
||||
RequestBodyWithAuthHeader('POST', body, null, access_token)
|
||||
)
|
||||
const res = await getResponseMetadata(result)
|
||||
return res
|
||||
}
|
||||
|
||||
// Delete an assignment
|
||||
export async function deleteAssignment(assignmentUUID: string, access_token: string) {
|
||||
const result: any = await fetch(
|
||||
`${getAPIUrl()}assignments/${assignmentUUID}`,
|
||||
RequestBodyWithAuthHeader('DELETE', null, null, access_token)
|
||||
)
|
||||
const res = await getResponseMetadata(result)
|
||||
return res
|
||||
}
|
||||
|
||||
export async function deleteAssignmentUsingActivityUUID(activityUUID: string, access_token: string) {
|
||||
const result: any = await fetch(
|
||||
`${getAPIUrl()}assignments/activity/${activityUUID}`,
|
||||
RequestBodyWithAuthHeader('DELETE', null, null, access_token)
|
||||
)
|
||||
const res = await getResponseMetadata(result)
|
||||
return res
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue