From dffc279b4a9fe58be4eeba11221c19c0f666f1f4 Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Sun, 10 Jan 2021 00:30:24 +0100 Subject: [PATCH] More stuff --- src/api/dto/internship-registration.ts | 39 ++++++++++++- src/components/proposalPreview.tsx | 8 +-- src/management/api/internship.ts | 68 ++++++++++++++++++---- src/management/edition/internship/list.tsx | 39 +++++++++---- 4 files changed, 125 insertions(+), 29 deletions(-) diff --git a/src/api/dto/internship-registration.ts b/src/api/dto/internship-registration.ts index acb869a..4aedc10 100644 --- a/src/api/dto/internship-registration.ts +++ b/src/api/dto/internship-registration.ts @@ -1,5 +1,5 @@ -import { Address, Company, Identifiable, Internship, Mentor, Office } from "@/data"; -import { momentSerializationTransformer, OneWayTransformer } from "@/serialization"; +import { Address, Company, Identifiable, Internship, Mentor, Office, Student } from "@/data"; +import { momentSerializationTransformer, OneWayTransformer, Transformer } from "@/serialization"; import { Nullable } from "@/helpers"; import { MentorDTO, mentorDtoTransformer } from "@/api/dto/mentor"; import { InternshipTypeDTO, internshipTypeDtoTransformer } from "@/api/dto/type"; @@ -7,6 +7,8 @@ import { Moment } from "moment-timezone"; import { sampleStudent } from "@/provider/dummy"; import { UploadType } from "@/api/upload"; import { ProgramEntryDTO, programEntryDtoTransformer } from "@/api/dto/edition"; +import { StudentDTO } from "@/api/dto/student"; +import { SubmissionStatus } from "@/state/reducer/submission"; export enum SubmissionState { Draft = "Draft", @@ -16,6 +18,35 @@ export enum SubmissionState { Archival = "Archival", } +export const submissionStateDtoTransformer: Transformer = { + reverseTransform(subject: SubmissionStatus, context: undefined): SubmissionState { + switch (subject) { + case "draft": + return SubmissionState.Draft; + case "awaiting": + return SubmissionState.Submitted; + case "accepted": + return SubmissionState.Accepted; + case "declined": + return SubmissionState.Rejected; + } + }, + transform(subject: SubmissionState, context: undefined): SubmissionStatus { + switch (subject) { + case SubmissionState.Draft: + return "draft"; + case SubmissionState.Submitted: + return "awaiting"; + case SubmissionState.Accepted: + return "accepted"; + case SubmissionState.Rejected: + return "declined"; + case SubmissionState.Archival: + return "declined"; + } + } +} + export interface NewBranchOffice extends Address { } @@ -50,6 +81,7 @@ export interface InternshipRegistrationDTO extends Identifiable { branchAddress: Office, declaredHours: number, subjects: { subject: ProgramEntryDTO }[], + submissionDate: string, } export interface InternshipDocument extends Identifiable { @@ -60,9 +92,10 @@ export interface InternshipDocument extends Identifiable { const reference = (subject: Identifiable | null): Identifiable | null => subject && { id: subject.id }; -export interface InternshipInfoDTO { +export interface InternshipInfoDTO extends Identifiable { internshipRegistration: InternshipRegistrationDTO; documentation: InternshipDocument[], + student: StudentDTO, } export const internshipRegistrationUpdateTransformer: OneWayTransformer, Nullable> = { diff --git a/src/components/proposalPreview.tsx b/src/components/proposalPreview.tsx index d169680..370639d 100644 --- a/src/components/proposalPreview.tsx +++ b/src/components/proposalPreview.tsx @@ -24,7 +24,7 @@ export const ProposalPreview = ({ proposal }: ProposalPreviewProps) => { -
+ { proposal.company && proposal.office &&
{ proposal.company.name } @@ -36,12 +36,12 @@ export const ProposalPreview = ({ proposal }: ProposalPreviewProps) => { { t('internship.address.city', proposal.office.address) } { t('internship.address.street', proposal.office.address) } -
+
} -
+ { proposal.type &&
{ proposal.type.label.pl } -
+
}
diff --git a/src/management/api/internship.ts b/src/management/api/internship.ts index 3f626d9..595279d 100644 --- a/src/management/api/internship.ts +++ b/src/management/api/internship.ts @@ -1,12 +1,20 @@ import { Identifiable, Identifier, Internship } from "@/data"; import { sampleCompanies, sampleStudent } from "@/provider/dummy"; import moment, { Moment } from "moment-timezone"; -import { OneOrMany } from "@/helpers"; -import { SubmissionState, SubmissionStatus } from "@/state/reducer/submission"; +import { encapsulate, Nullable, OneOrMany } from "@/helpers"; +import { SubmissionStatus } from "@/state/reducer/submission"; +import { axios } from "@/api"; +import { prepare, query } from "@/routing"; +import { InternshipInfoDTO, submissionStateDtoTransformer } from "@/api/dto/internship-registration"; +import { Transformer } from "@/serialization"; +import { mentorDtoTransformer } from "@/api/dto/mentor"; +import { internshipTypeDtoTransformer } from "@/api/dto/type"; +import { studentDtoTransfer } from "@/api/dto/student"; +import { programEntryDtoTransformer } from "@/api/dto/edition"; -export type InternshipSubmission = Internship & { +export type InternshipSubmission = Nullable & { state: SubmissionStatus, - changed: Moment + changed: Moment | null, } const sampleInternship: InternshipSubmission = { @@ -44,15 +52,55 @@ const sampleInternship: InternshipSubmission = { changed: moment(), } +const INTERNSHIP_MANAGEMENT_INDEX_ENDPOINT = "/management/internship"; +const INTERNSHIP_MANAGEMENT_ENDPOINT = "/management/internship/:id"; +const INTERNSHIP_ACCEPT_ENDPOINT = "/management/internship/accept/:id"; +const INTERNSHIP_REJECT_ENDPOINT = "/management/internship/reject/:id"; + +const internshipInfoDtoTransformer: Transformer = { + transform(subject: InternshipInfoDTO, context?: never): InternshipSubmission { + return { + changed: moment(subject.internshipRegistration.submissionDate), + company: subject.internshipRegistration.company, + startDate: moment(subject.internshipRegistration.start), + endDate: moment(subject.internshipRegistration.end), + hours: subject.internshipRegistration.declaredHours, + id: subject.id, + intern: subject.student && studentDtoTransfer.transform(subject.student), + isAccepted: false, + lengthInWeeks: 0, + mentor: subject.internshipRegistration.mentor && mentorDtoTransformer.transform(subject.internshipRegistration.mentor), + office: subject.internshipRegistration.branchAddress, + program: (subject.internshipRegistration.subjects || []).map(subject => programEntryDtoTransformer.transform(subject.subject)), + state: submissionStateDtoTransformer.transform(subject.internshipRegistration.state), + type: subject.internshipRegistration.type && internshipTypeDtoTransformer.transform(subject.internshipRegistration.type), + }; + }, + reverseTransform(subject: InternshipSubmission, context: undefined): InternshipInfoDTO { + return {} as any; + }, +} + export async function all(edition: Identifiable): Promise { - return [ - sampleInternship, - ] + const result = await axios.get(query(INTERNSHIP_MANAGEMENT_INDEX_ENDPOINT, { EditionId: edition.id || "" })); + + return result.data.map(result => internshipInfoDtoTransformer.transform(result)) } export async function get(id: Identifier): Promise { - return sampleInternship; + const result = await axios.get(prepare(INTERNSHIP_MANAGEMENT_ENDPOINT, { id })) + + return internshipInfoDtoTransformer.transform(result.data); } -export async function approve(internship: OneOrMany, comment?: string): Promise {} -export async function decline(internship: OneOrMany, comment: string): Promise {} +export async function accept(internship: OneOrMany, comment?: string): Promise { + const internships = encapsulate(internship) + + await Promise.all(internships.map(internship => axios.put(prepare(INTERNSHIP_ACCEPT_ENDPOINT, { id: internship.id || ""})))) +} + +export async function discard(internship: OneOrMany, comment: string): Promise { + const internships = encapsulate(internship) + + await Promise.all(internships.map(internship => axios.put(prepare(INTERNSHIP_REJECT_ENDPOINT, { id: internship.id || ""})))) +} diff --git a/src/management/edition/internship/list.tsx b/src/management/edition/internship/list.tsx index 389f9c3..f8cd8ea 100644 --- a/src/management/edition/internship/list.tsx +++ b/src/management/edition/internship/list.tsx @@ -1,6 +1,6 @@ -import React, { useEffect, useState } from "react"; +import React, { useCallback, useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; -import { useAsyncState } from "@/hooks"; +import { useAsync, useAsyncState } from "@/hooks"; import { useSpacing } from "@/styles"; import api from "@/management/api"; import { Box, Button, Container, IconButton, Typography } from "@material-ui/core"; @@ -15,11 +15,12 @@ import { MaterialTableTitle } from "@/management/common/MaterialTableTitle"; import { EditionManagement, EditionManagementProps } from "@/management/edition/manage"; import { Link as RouterLink } from "react-router-dom"; import { route } from "@/routing"; -import { AcceptanceActions, AcceptSubmissionDialog, DiscardSubmissionDialog } from "@/components/acceptance-action"; +import { AcceptSubmissionDialog, DiscardSubmissionDialog } from "@/components/acceptance-action"; import { ProposalPreview } from "@/components/proposalPreview"; import { InternshipSubmission } from "@/management/api/internship"; import { canAccept, canDiscard, StateLabel } from "@/management/edition/internship/common"; import { createPortal } from "react-dom"; +import { Internship } from "@/data"; const title = "edition.internships.title"; @@ -35,16 +36,19 @@ export const InternshipManagement = ({ edition }: EditionManagementProps) => { useEffect(updateInternshipList, []); - const handleSubmissionAccept = api.internship.approve - const handleSubmissionDiscard = api.internship.decline - const AcceptAction = ({ internship }: { internship: InternshipSubmission }) => { const [open, setOpen] = useState(false); + const handleSubmissionAccept = async (comment?: string) => { + setOpen(false); + await api.internship.accept(internship as Internship, comment); + updateInternshipList(); + } + return <> setOpen(true) }> { createPortal( - handleSubmissionAccept(internship, comment) } label="internship" open={ open } onClose={ () => setOpen(false) }/>, + setOpen(false) }/>, document.getElementById("modals") as Element, ) } ; @@ -53,19 +57,30 @@ export const InternshipManagement = ({ edition }: EditionManagementProps) => { const DiscardAction = ({ internship }: { internship: InternshipSubmission }) => { const [open, setOpen] = useState(false); + const handleSubmissionDiscard = async (comment: string) => { + setOpen(false); + await api.internship.discard(internship as Internship, comment); + updateInternshipList(); + } + return <> setOpen(true) }> { createPortal( - handleSubmissionDiscard(internship, comment) } label="internship" open={ open } onClose={ () => setOpen(false) }/>, + setOpen(false) }/>, document.getElementById("modals") as Element, ) } ; } + const InternshipDetails = ({ summary }: { summary: InternshipSubmission }) => { + const internship = useAsync(useCallback(() => api.internship.get(summary.id || ""), [ summary.id ])) + return { internship => } + } + const columns: Column[] = [ { title: t("internship.column.student"), - render: internship => <>{internship.intern.name} {internship.intern.surname}, + render: internship => <>{internship.intern?.name} {internship.intern?.surname}, }, { title: t("internship.column.album"), @@ -77,7 +92,7 @@ export const InternshipManagement = ({ edition }: EditionManagementProps) => { }, { title: t("internship.column.changed"), - render: summary => summary.changed.format("yyyy-MM-DD HH:mm") + render: summary => summary.changed?.format("yyyy-MM-DD") }, { title: t("internship.column.status"), @@ -102,7 +117,7 @@ export const InternshipManagement = ({ edition }: EditionManagementProps) => { { selected.length > 0 && - handleSubmissionAccept(selected, comment) } onDiscard={ comment => handleSubmissionDiscard(selected, comment) } /> + } { internships => { data={ internships } onSelectionChange={ internships => setSelected(internships) } options={ { selection: true, pageSize: 10 } } - detailPanel={ internship => } + detailPanel={ summary => } /> }