Skip to content

Commit

Permalink
Merge pull request #35 from ls1intum/mail-service
Browse files Browse the repository at this point in the history
Fix the application assessment form
  • Loading branch information
airelawaleria authored Jun 29, 2023
2 parents 3bf9a03 + 82fcacb commit 3104557
Show file tree
Hide file tree
Showing 33 changed files with 998 additions and 648 deletions.
222 changes: 222 additions & 0 deletions client/src/forms/ApplicationAssessmentForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
import { useForm } from '@mantine/form'
import { type ApplicationAssessment } from '../redux/applicationsSlice/applicationsSlice'
import { Button, Checkbox, Divider, Group, Text, TextInput, Textarea } from '@mantine/core'
import { StudentApplicationComment } from './StudentApplicationComment'
import {
createInstructorCommentForCoachApplication,
createInstructorCommentForDeveloperApplication,
createInstructorCommentForTutorApplication,
} from '../redux/applicationsSlice/thunks/createInstructorComment'
import { useDispatch } from 'react-redux'
import { useAppSelector, type AppDispatch } from '../redux/store'
import { useState } from 'react'
import { IconSend } from '@tabler/icons-react'
import { type Patch } from '../service/configService'
import {
updateCoachApplicationAssessment,
updateDeveloperApplicationAssessment,
updateTutorApplicationAssessment,
} from '../redux/applicationsSlice/thunks/updateApplicationAssessment'

interface ApplicationAssessmentFormProps {
applicationId: string
applicationType: 'developer' | 'coach' | 'tutor'
assessment?: ApplicationAssessment
}

export const ApplicationAssessmentForm = ({
applicationId,
assessment,
applicationType,
}: ApplicationAssessmentFormProps): JSX.Element => {
const dispatch = useDispatch<AppDispatch>()
const auth = useAppSelector((state) => state.auth)
const [comment, setComment] = useState('')
const assessmentForm = useForm<ApplicationAssessment>({
initialValues: {
instructorComments: assessment?.instructorComments ?? [],
suggestedAsCoach: assessment?.suggestedAsCoach ?? false,
suggestedAsTutor: assessment?.suggestedAsTutor ?? false,
blockedByPM: assessment?.blockedByPM ?? false,
reasonForBlockedByPM: assessment?.reasonForBlockedByPM ?? '',
assessmentScore: assessment?.assessmentScore ?? 0,
accepted: assessment?.accepted ?? false,
assessed: assessment?.accepted ?? false,
},
})

return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '2vh' }}>
<Divider />
<Group grow>
<Checkbox
mt='md'
label='Suggested as Coach'
{...assessmentForm.getInputProps('suggestedAsCoach', {
type: 'checkbox',
})}
/>
<Checkbox
mt='md'
label='Suggested as Tutor'
{...assessmentForm.getInputProps('suggestedAsTutor', {
type: 'checkbox',
})}
/>
<Checkbox
mt='md'
label='Blocked by PM'
{...assessmentForm.getInputProps('blockedByPM', {
type: 'checkbox',
})}
/>
</Group>
{assessmentForm.values.blockedByPM && (
<Textarea
autosize
label='Reason for Blocked by PM'
placeholder='Reason for blocked by PM'
minRows={5}
{...assessmentForm.getInputProps('reasonForBlockedByPM')}
/>
)}
<TextInput
withAsterisk
type='number'
label='Assessment Score'
placeholder='Assessment Score'
{...assessmentForm.getInputProps('assessmentScore')}
/>
<Group grow style={{ alignItems: 'center' }}>
<Checkbox
mt='md'
label='Accepted for the Course'
{...assessmentForm.getInputProps('accepted', {
type: 'checkbox',
})}
/>
<Checkbox
mt='md'
label='Application Assessed'
{...assessmentForm.getInputProps('assessed', {
type: 'checkbox',
})}
/>
</Group>
<Group position='right'>
<Button
disabled={!assessmentForm.isDirty()}
onClick={() => {
const assessmentPatchObjectArray: Patch[] = []
Object.keys(assessmentForm.values).forEach((key) => {
if (assessmentForm.isTouched(key)) {
const assessmentPatchObject = new Map()
assessmentPatchObject.set('op', 'replace')
assessmentPatchObject.set('path', '/' + key)
assessmentPatchObject.set('value', assessmentForm.getInputProps(key).value)
const obj = Object.fromEntries(assessmentPatchObject)
assessmentPatchObjectArray.push(obj)
}
})

if (applicationType === 'developer') {
void dispatch(
updateDeveloperApplicationAssessment({
applicationId,
applicationAssessmentPatch: assessmentPatchObjectArray,
}),
)
} else if (applicationType === 'coach') {
void dispatch(
updateCoachApplicationAssessment({
applicationId,
applicationAssessmentPatch: assessmentPatchObjectArray,
}),
)
} else if (applicationType === 'tutor') {
void dispatch(
updateTutorApplicationAssessment({
applicationId,
applicationAssessmentPatch: assessmentPatchObjectArray,
}),
)
}
}}
>
Submit
</Button>
</Group>
<Divider />
<div style={{ display: 'flex', flexDirection: 'column', gap: '2vh' }}>
<Text fz='sm' weight={500}>
Additional Notes
</Text>
{assessmentForm.values.instructorComments.map((comment, idx) => (
<div key={`${comment.id ?? idx} ${comment.timestamp ?? ''}`}>
<StudentApplicationComment instructorComment={comment} />
</div>
))}
</div>
<Group position='left' style={{ alignItems: 'center' }}>
<Textarea
placeholder='Comment'
value={comment}
onChange={(e) => {
setComment(e.target.value)
}}
/>
<Button
leftIcon={<IconSend />}
onClick={() => {
if (comment && comment.length !== 0 && assessmentForm.values) {
assessmentForm.setValues({
...assessmentForm.values,
instructorComments: [
...assessmentForm.values.instructorComments,
{
author: auth ? `${auth.firstName} ${auth.lastName}` : '',
text: comment,
},
],
})
setComment('')
if (applicationType === 'developer') {
void dispatch(
createInstructorCommentForDeveloperApplication({
applicationId,
instructorComment: {
author: auth ? `${auth.firstName} ${auth.lastName}` : '',
text: comment,
},
}),
)
} else if (applicationType === 'coach') {
void dispatch(
createInstructorCommentForCoachApplication({
applicationId,
instructorComment: {
author: auth ? `${auth.firstName} ${auth.lastName}` : '',
text: comment,
},
}),
)
} else if (applicationType === 'tutor') {
void dispatch(
createInstructorCommentForTutorApplication({
applicationId,
instructorComment: {
author: auth ? `${auth.firstName} ${auth.lastName}` : '',
text: comment,
},
}),
)
}
}
}}
>
Send
</Button>
</Group>
</div>
)
}
93 changes: 43 additions & 50 deletions client/src/forms/CoachApplicationForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import {
Button,
Center,
Checkbox,
Container,
Group,
Loader,
Spoiler,
Stack,
Text,
Textarea,
Title,
} from '@mantine/core'
import {
type CoachApplication,
Expand All @@ -21,10 +21,10 @@ import { useEffect, useState } from 'react'
import { fetchCourseIterationsWithOpenApplicationPeriod } from '../redux/courseIterationSlice/thunks/fetchAllCourseIterations'
import { useDispatch } from 'react-redux'
import { useAppSelector, type AppDispatch } from '../redux/store'
import { type Patch } from '../service/configService'
import { createCoachApplication } from '../service/applicationsService'
import { ApplicationSuccessfulSubmission } from '../student/StudentApplicationSubmissionPage/ApplicationSuccessfulSubmission'
import { DeclarationOfDataConsent } from './DeclarationOfDataConsent'
import { ApplicationAssessmentForm } from './ApplicationAssessmentForm'

interface CoachApplicationFormProps {
coachApplication?: CoachApplication
Expand Down Expand Up @@ -177,25 +177,33 @@ export const CoachApplicationForm = ({
required
{...coachForm.getInputProps('solvedProblem')}
/>
<Stack>
<Checkbox
mt='md'
label='I have read the declaration of consent below and agree to the processing of my data.'
{...consentForm.getInputProps('dataConsent', { type: 'checkbox' })}
/>
<Spoiler maxHeight={0} showLabel='View Data Consent Agreement' hideLabel='Hide'>
<DeclarationOfDataConsent />
</Spoiler>
<Checkbox
mt='md'
label={`I am aware that the Agile Project Mamagement is a very demanding 10 ECTS practical course and I agree to put in the required amount of work, time and effort.`}
{...consentForm.getInputProps('workloadConsent', { type: 'checkbox' })}
/>
</Stack>
{accessMode === ApplicationFormAccessMode.STUDENT && (
<Stack>
<Checkbox
mt='md'
label='I have read the declaration of consent below and agree to the processing of my data.'
{...consentForm.getInputProps('dataConsent', { type: 'checkbox' })}
/>
<Spoiler
maxHeight={0}
showLabel={<Text fz='sm'>Show Data Consent Agreement</Text>}
hideLabel={<Text fz='sm'>Hide</Text>}
>
<DeclarationOfDataConsent />
</Spoiler>
<Checkbox
mt='md'
label={`I am aware that the Agile Project Mamagement is a very demanding 10 ECTS practical course and I agree to put in the required amount of work, time and effort.`}
{...consentForm.getInputProps('workloadConsent', { type: 'checkbox' })}
/>
</Stack>
)}
<Group position='right' mt='md'>
<Button
disabled={
!defaultForm.isValid() || !coachForm.isValid() || !consentForm.isValid()
!defaultForm.isValid() ||
!coachForm.isValid() ||
(!consentForm.isValid() && accessMode === ApplicationFormAccessMode.STUDENT)
}
type='submit'
onClick={() => {
Expand All @@ -219,48 +227,33 @@ export const CoachApplicationForm = ({
})
.catch(() => {})
onSuccess()
} else if (
defaultForm.isValid() &&
coachForm.isValid() &&
coachApplication
) {
// TODO: differentiate between assessment and student application changes
if (defaultForm.values.assessment) {
const studentApplicationAssessmentPatchObjectArray: Patch[] = []
Object.keys(defaultForm.values.assessment).forEach((key) => {
if (defaultForm.isTouched('assessment.' + key)) {
const studentApplicationPatchObject = new Map()
studentApplicationPatchObject.set('op', 'replace')
studentApplicationPatchObject.set('path', '/' + key)
studentApplicationPatchObject.set(
'value',
defaultForm.getInputProps('assessment.' + key).value,
)
const obj = Object.fromEntries(studentApplicationPatchObject)
studentApplicationAssessmentPatchObjectArray.push(obj)
}
})
/* void dispatch(
updateDeveloperApplicationAssessment({
applicationId: developerApplication.id,
applicationAssessmentPatch: studentApplicationAssessmentPatchObjectArray,
}),
) */
onSuccess()
}
}
}}
>
Submit
</Button>
</Group>
{accessMode === ApplicationFormAccessMode.INSTRUCTOR && coachApplication && (
<ApplicationAssessmentForm
applicationId={coachApplication.id}
assessment={coachApplication.assessment}
applicationType='coach'
/>
)}
</>
)}
</Box>
) : (
<Container>
<Text>Application period is closed.</Text>
</Container>
<div
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '100vh',
}}
>
<Title order={5}>Application period is closed.</Title>
</div>
)}
</>
)}
Expand Down
Loading

0 comments on commit 3104557

Please sign in to comment.