([])
const { mutate: mutateEditGroup } = useMutation(
['editGroup'],
(data: { id: number; payload: CreateGroup }) =>
@@ -96,17 +99,14 @@ const Group = () => {
+ setIsConfirmModalOpen(false)}
+ confirmFn={() => {
+ if (name && project_supervisor) {
+ mutateEditGroup({
+ id: Number(groupId),
+ payload: {
+ name,
+ project_supervisor_id: project_supervisor.id,
+ students: studentsToDelete,
+ },
+ })
+ setIsConfirmModalOpen(false)
+ }
+ }}
+ />
)
}
diff --git a/frontend/src/views/coordinator/Schedule.tsx b/frontend/src/views/coordinator/Schedule.tsx
index 1a2bce4..d684b8f 100644
--- a/frontend/src/views/coordinator/Schedule.tsx
+++ b/frontend/src/views/coordinator/Schedule.tsx
@@ -283,7 +283,7 @@ const Schedule = () => {
ROZPOCZNIJ
+ setIsConfirmModalOpen(false)}
+ confirmFn={() => {
+ mutateDelete(studentToDeleteId)
+ setIsConfirmModalOpen(false)
+ }}
+ />
>
)}
diff --git a/frontend/src/views/student/Enrollment.tsx b/frontend/src/views/student/Enrollment.tsx
index 7c765dd..43717b2 100644
--- a/frontend/src/views/student/Enrollment.tsx
+++ b/frontend/src/views/student/Enrollment.tsx
@@ -62,7 +62,6 @@ const Enrollment = () => {
Imię |
Nazwisko |
Email |
- Tryb |
Wolne miejsca |
@@ -76,7 +75,6 @@ const Enrollment = () => {
{first_name} |
{last_name} |
{email} |
- {mode ? 'Stacjonarny' : 'Niestacjonarny'} |
{available_groups} |
))}
diff --git a/frontend/src/views/student/Student.tsx b/frontend/src/views/student/Student.tsx
index 0ad0c66..81c7a79 100644
--- a/frontend/src/views/student/Student.tsx
+++ b/frontend/src/views/student/Student.tsx
@@ -1,16 +1,46 @@
-import { Outlet } from 'react-router-dom'
+import { useState } from 'react'
+import { useQuery } from 'react-query'
+import { Outlet, useNavigate } from 'react-router-dom'
+import useLocalStorageState from 'use-local-storage-state'
+import { getStudentDetails } from '../../api/students'
import TopBar from '../../components/TopBar'
const Student = () => {
+ const [studentId] = useLocalStorageState('userId')
+ const [routes, setRoutes] = useState<
+ {
+ name: string
+ path: string
+ }[]
+ >([{ name: 'Zapisy', path: '/student/enrollment' }])
+ let navigate = useNavigate()
+
+ useQuery(
+ ['getStudent', studentId],
+ () => getStudentDetails(Number(studentId)),
+ {
+ onSuccess: (data) => {
+ if (data?.data.groups?.length) {
+ navigate(`/student/groups/${data?.data.groups[0].id}`)
+ }
+ setRoutes(
+ data?.data.groups?.length
+ ? [
+ {
+ name: 'Grupa',
+ path: `/student/groups/${data?.data.groups[0].id}`,
+ },
+ { name: 'Harmonogram', path: '/student/schedule' },
+ ]
+ : [{ name: 'Zapisy', path: '/student/enrollment' }],
+ )
+ },
+ },
+ )
+
return (
<>
-
+
diff --git a/frontend/src/views/student/StudentGradeCard.tsx b/frontend/src/views/student/StudentGradeCard.tsx
new file mode 100644
index 0000000..242a3b1
--- /dev/null
+++ b/frontend/src/views/student/StudentGradeCard.tsx
@@ -0,0 +1,1331 @@
+import { useForm, Controller } from 'react-hook-form'
+import { useMutation, useQuery } from 'react-query'
+import { useParams } from 'react-router-dom'
+import ReactSelect from 'react-select'
+import useLocalStorageState from 'use-local-storage-state'
+import { getGradesForStudent } from '../../api/grades'
+import { getGroup } from '../../api/groups'
+import { gradeOptions } from '../../utils/gradeCard'
+import styles from '../GradeCard.module.css'
+
+const StudentGradeCard = () => {
+ const { handleSubmit, setValue, control, watch, getValues } = useForm()
+ const { id } = useParams<{ id: string }>()
+ const [studentId] = useLocalStorageState('userId')
+ const [yearGroupId] = useLocalStorageState('yearGroupId')
+
+ const {
+ data: groupDetails,
+ refetch: refetchGroup,
+ isLoading: isGroupLoading,
+ isSuccess,
+ } = useQuery(['getGroup', id], () => getGroup(Number(id)))
+
+ useQuery(
+ ['getGradesFirstStudent'],
+ () => getGradesForStudent(Number(yearGroupId), 1, Number(studentId)),
+ {
+ onSuccess: (data) => {
+ for (const [key, value] of Object.entries(data.data)) {
+ if (key !== 'id') setValue(key, value)
+ }
+ },
+ enabled: isSuccess,
+ },
+ )
+
+ useQuery(
+ ['getGradesSecondStudent'],
+ () => getGradesForStudent(Number(yearGroupId), 2, Number(studentId)),
+ {
+ onSuccess: (data) => {
+ for (const [key, value] of Object.entries(data.data)) {
+ if (key !== 'id') setValue(key, value)
+ }
+ },
+ enabled: isSuccess,
+ },
+ )
+
+ const gradeColor: { [key: number]: string } = {
+ 0: '#f8696b',
+ 1: 'orange',
+ 3: '#9cec9c',
+ 4: '#63BE7B',
+ }
+
+ const getStyles = (value: number) => {
+ return {
+ control: (styles: any) => ({
+ ...styles,
+ padding: '0.3rem',
+ borderRadius: '0.5rem',
+ width: '300px',
+ borderColor: gradeColor[value],
+ borderWidth: 3,
+ }),
+ singleValue: (styles: any) => ({
+ ...styles,
+ overflow: 'visible',
+ textOverflow: 'initial',
+ whiteSpace: 'initial',
+ display: '-webkit-box',
+ '-webkit-line-clamp': '2',
+ '-webkit-box-orient': 'vertical',
+ }),
+ placeholder: (styles: any) => ({
+ ...styles,
+ color: 'black',
+ display: '-webkit-box',
+ '-webkit-line-clamp': '2',
+ '-webkit-box-orient': 'vertical',
+ }),
+ }
+ }
+
+ const SumRow = () => {
+ return (
+
+
+ Suma uzyskanych punktów:
+ |
+
+ {groupDetails?.data?.points_for_first_term}%
+ |
+
+ {groupDetails?.data?.points_for_second_term}%
+ |
+
+ )
+ }
+
+ return (
+
+ )
+}
+
+export default StudentGradeCard
diff --git a/frontend/src/views/student/StudentGroup.tsx b/frontend/src/views/student/StudentGroup.tsx
new file mode 100644
index 0000000..dbdac80
--- /dev/null
+++ b/frontend/src/views/student/StudentGroup.tsx
@@ -0,0 +1,85 @@
+import { useState } from 'react'
+import { useQuery } from 'react-query'
+import { Link, useLocation, useParams } from 'react-router-dom'
+import ReactSelect from 'react-select'
+import useLocalStorageState from 'use-local-storage-state'
+import { getGroup } from '../../api/groups'
+import { getStudents } from '../../api/students'
+import { ReactComponent as IconRemove } from '../../assets/svg/icon-remove.svg'
+
+type SelectValue = {
+ value: string | number
+ label: string
+}
+
+const StudentGroup = () => {
+ const { id: groupId } = useParams<{ id: string }>()
+ const location = useLocation()
+
+ const {
+ data: groups,
+ refetch,
+ isLoading: isGroupLoading,
+ } = useQuery(['getGroup', groupId], () => getGroup(Number(groupId)))
+ const { name, project_supervisor, students } = groups?.data || {}
+ const [yearGroupId] = useLocalStorageState('yearGroupId')
+
+ const [studentOptions, setStudentOptions] = useState([])
+ const { isLoading: areStudentsLoading, refetch: refetchStudents } = useQuery(
+ 'students',
+ () => getStudents({ year_group_id: Number(yearGroupId), per_page: 1000 }),
+ {
+ onSuccess: (data) => {
+ setStudentOptions(
+ data?.data.students
+ .filter(({ groups }) => !groups?.length)
+ .map(({ first_name, last_name, index, id }) => {
+ return {
+ value: id,
+ label: `${first_name} ${last_name} (${index})`,
+ }
+ }),
+ )
+ },
+ },
+ )
+
+ if (isGroupLoading || areStudentsLoading) {
+ return Ładowanie
+ }
+ return (
+
+ {name}
+
+ Opiekun: {project_supervisor?.first_name}{' '}
+ {project_supervisor?.last_name}
+
+
+
+ KARTA OCENY
+
+
+
+
+
+
+ Imię |
+ Nazwisko |
+ Indeks |
+
+
+
+ {students?.map(({ first_name, last_name, index, id }) => (
+
+ {first_name} |
+ {last_name} |
+ {index} |
+
+ ))}
+
+
+
+
+ )
+}
+export default StudentGroup
diff --git a/frontend/src/views/student/StudentSchedule.tsx b/frontend/src/views/student/StudentSchedule.tsx
index 51248f2..604dcee 100644
--- a/frontend/src/views/student/StudentSchedule.tsx
+++ b/frontend/src/views/student/StudentSchedule.tsx
@@ -42,6 +42,7 @@ const StudentSchedule = () => {
id: number
resource: any
}>()
+ const [showAvailable, setShowAvailable] = useState(false)
const [view, setView] = useState(Views.WEEK)
const onView = useCallback((newView: any) => setView(newView), [setView])
@@ -55,23 +56,35 @@ const StudentSchedule = () => {
}>({ mode: 'onBlur' })
const { refetch } = useQuery(
- ['studentSchedules'],
- () => getStudentsTermsOfDefences(Number(id), Number(studentId)),
+ ['studentSchedules', showAvailable],
+ () =>
+ getStudentsTermsOfDefences(Number(id), Number(studentId), showAvailable),
{
onSuccess: (data) => {
setEvents(
data.data.term_of_defences.map(
- ({
- id,
- start_date,
- end_date,
- title = 'Obrona',
- members_of_committee,
- group,
- }) => {
+ ({ id, start_date, end_date, members_of_committee, group }) => {
+ let initials = ''
+ let title = ''
+ members_of_committee.forEach((member) => {
+ initials +=
+ `${member.first_name} ${member.last_name}`
+ .split(' ')
+ .map((n) => n[0])
+ .join('') + ' '
+ })
+ if (group?.name && initials) {
+ title = `${group.name} | ${initials}`
+ } else if (group?.name) {
+ title = group.name
+ } else if (initials) {
+ title = `- | ${initials}`
+ } else {
+ title = '-'
+ }
return {
id,
- title: `${group?.name ?? '-'}`,
+ title: title,
start: new Date(start_date),
end: new Date(end_date),
resource: {
@@ -98,7 +111,6 @@ const StudentSchedule = () => {
end: Date
resource: any
}) => {
- console.log(event)
setSelectedDate(event)
setIsEditModalOpen(true)
},
@@ -129,11 +141,23 @@ const StudentSchedule = () => {
Wybierz i zatwierdź termin obrony dla swojej grupy
+
+
+
{
Nazwa |
Opiekun |
- Semestr 1 |
+ Punkty Semestr 1 |
Semestr 2 |
|
@@ -125,8 +125,8 @@ const SupervisorGroups = () => {
{`${project_supervisor.first_name} ${project_supervisor.last_name}`}
|
- {points_for_first_term} |
- {points_for_second_term} |
+ {points_for_first_term}% |
+ {points_for_second_term}% |
{
id: number
resource: any
}>()
- const [view, setView] = useState(Views.MONTH)
+ const [view, setView] = useState (Views.WEEK)
const onView = useCallback((newView: any) => setView(newView), [setView])
const [isModalOpen, setIsModalOpen] = useState(false)
+ const [isWeekModalOpen, setIsWeekModalOpen] = useState(false)
const [isEditModalOpen, setIsEditModalOpen] = useState(false)
Modal.setAppElement('#root')
@@ -65,7 +69,7 @@ const SupervisorSchedule = () => {
const { refetch, isFetching } = useQuery(
['schedules'],
- () => getSupervisorTermsOfDefences(Number(id)),
+ () => getSupervisorTermsOfDefences(Number(id), Number(supervisorId)),
{
onSuccess: (data) => {
setEvents(
@@ -96,7 +100,7 @@ const SupervisorSchedule = () => {
const { refetch: refetchAvailability } = useQuery(
['availability'],
- () => getAvailabilityForSupervisor(Number(id)),
+ () => getAvailabilityForSupervisor(Number(id), Number(supervisorId)),
{
onSuccess: (data) => {
setEvents([
@@ -125,9 +129,32 @@ const SupervisorSchedule = () => {
}) => addAvailability(data),
)
+ const { mutate: mutateDeleteAvailability } = useMutation(
+ ['deleteAvailability'],
+ (data: {
+ availabilityId: number
+ scheduleId: number
+ supervisorId: number
+ }) =>
+ supervisorDeleteAvailability(
+ data.scheduleId,
+ data.availabilityId,
+ data.supervisorId,
+ ),
+ {
+ onSuccess: async () => {
+ setIsEditModalOpen(false)
+ await refetch()
+ await refetchAvailability()
+ },
+ },
+ )
+
const handleSelectSlot = async (event: any) => {
setSelectedDate(event)
- if (view === Views.MONTH) {
+ if (view === Views.WEEK || view === Views.DAY) {
+ setIsWeekModalOpen(true)
+ } else if (view === Views.MONTH) {
setIsModalOpen(true)
}
}
@@ -149,6 +176,7 @@ const SupervisorSchedule = () => {
function closeModal() {
setIsModalOpen(false)
}
+
const onSubmit = async (data: any) => {
if (selectedDate && view === Views.MONTH) {
const from = data.from.split(':')
@@ -166,12 +194,26 @@ const SupervisorSchedule = () => {
project_supervisor_id: Number(supervisorId),
})
setEvents([])
- refetch()
- refetchAvailability()
+ await refetch()
+ await refetchAvailability()
reset()
closeModal()
}
}
+ const submitSlot = async () => {
+ if (selectedDate && (view === Views.WEEK || view === Views.DAY)) {
+ await mutateAddAvailability({
+ start_date: dayjs(selectedDate.start).format('YYYY-MM-DD HH:mm:ss'),
+ end_date: dayjs(selectedDate.end).format('YYYY-MM-DD HH:mm:ss'),
+ scheduleId: Number(id),
+ project_supervisor_id: Number(supervisorId),
+ })
+ setEvents([])
+ await refetch()
+ await refetchAvailability()
+ setIsWeekModalOpen(false)
+ }
+ }
const eventGetter = (event: any) => {
return event?.title === '-'
@@ -205,7 +247,26 @@ const SupervisorSchedule = () => {
max={dayjs().set('hour', 16).set('minute', 0).toDate()}
messages={bigCalendarTranslations}
/>
-
+ setIsWeekModalOpen(false)}
+ contentLabel="modal"
+ style={customStyles}
+ >
+ Dostępne godziny
+ {dayjs(selectedDate?.start).format('YYYY-MM-DD')}
+
+
+ Od {dayjs(selectedDate?.start).format('HH:mm')}
+
+
+ Do {dayjs(selectedDate?.end).format('HH:mm')}
+
+
+
+ Dodaj dostępność
+
+
{
Dodaj dostępność
- {/* setIsEditModalOpen(false)}
contentLabel="modal"
style={customStyles}
>
{selectedDate && id ? (
-
+
+ Dostępność
+
+ {dayjs(selectedDate.start).format('YYYY-MM-DD HH:mm')} -{' '}
+ {dayjs(selectedDate.end).format('HH:mm')}
+
+
+ mutateDeleteAvailability({
+ availabilityId: selectedDate.id,
+ scheduleId: Number(id),
+ supervisorId: Number(supervisorId),
+ })
+ }
+ >
+ Usuń dostępność
+
+
) : null}
- */}
+
)
}
| |