diff --git a/src/api/dto/edition.ts b/src/api/dto/edition.ts index 20d47fd..2a361e4 100644 --- a/src/api/dto/edition.ts +++ b/src/api/dto/edition.ts @@ -1,9 +1,11 @@ -import { Identifiable, InternshipProgramEntry } from "@/data"; +import { Identifiable, Identifier, InternshipProgramEntry } from "@/data"; import { CourseDTO, courseDtoTransformer } from "@/api/dto/course"; import { OneWayTransformer, Transformer } from "@/serialization"; import { Edition } from "@/data/edition"; import moment from "moment-timezone"; import { Subset } from "@/helpers"; +import { InternshipTypeDTO, internshipTypeDtoTransformer } from "@/api/dto/type"; +import { ReportFieldDefinition, ReportFieldType } from "@/data/report"; export interface ProgramEntryDTO extends Identifiable { description: string; @@ -16,6 +18,8 @@ export interface EditionDTO extends Identifiable { reportingStart: string, course: CourseDTO, availableSubjects: ProgramEntryDTO[], + availableInternshipTypes: InternshipTypeDTO[], + reportSchema: FieldDefinitionDTO[], } export interface EditionTeaserDTO extends Identifiable { @@ -24,6 +28,83 @@ export interface EditionTeaserDTO extends Identifiable { courseName: string, } +export enum FieldDefinitionDTOType { + LongText = "LongText", + ShortText = "ShortText", + Select = "Select", + Radial = "Radial", + Checkbox = "Checkbox", +} + +export const fieldDefinitionDtoTypeTransformer: Transformer = { + transform(dto: FieldDefinitionDTOType, context?: unknown) { + switch (dto) { + case FieldDefinitionDTOType.LongText: + return "long-text" + case FieldDefinitionDTOType.ShortText: + return "short-text"; + case FieldDefinitionDTOType.Select: + return "select"; + case FieldDefinitionDTOType.Radial: + return "radio"; + case FieldDefinitionDTOType.Checkbox: + return "checkbox"; + } + }, + reverseTransform(type: ReportFieldType, context?: unknown) { + switch (type) { + case "short-text": + return FieldDefinitionDTOType.ShortText; + case "long-text": + return FieldDefinitionDTOType.LongText; + case "checkbox": + return FieldDefinitionDTOType.Checkbox; + case "radio": + return FieldDefinitionDTOType.Radial; + case "select": + return FieldDefinitionDTOType.Select; + } + } +} + +export interface FieldDefinitionDTO extends Identifiable { + label: string; + labelEng: string; + description: string; + descriptionEng: string; + fieldType: FieldDefinitionDTOType; + choices: string[]; +} + +export const fieldDefinitionDtoTransformer: Transformer = { + transform(dto: FieldDefinitionDTO, context?: unknown): ReportFieldDefinition { + return { + id: dto.id, + choices: (dto.choices || []).map(choice => JSON.parse(choice)), + description: { + pl: dto.description, + en: dto.descriptionEng, + }, + label: { + pl: dto.label, + en: dto.labelEng, + }, + type: fieldDefinitionDtoTypeTransformer.transform(dto.fieldType), + } + }, + reverseTransform(subject: ReportFieldDefinition, context?: unknown): FieldDefinitionDTO { + return { + id: subject.id, + choices: "choices" in subject && subject.choices.map(choice => JSON.stringify(choice)) || [], + description: subject.description.pl, + descriptionEng: subject.description.en, + fieldType: fieldDefinitionDtoTypeTransformer.reverseTransform(subject.type), + label: subject.label.pl, + labelEng: subject.label.en, + } + } +} + export const editionTeaserDtoTransformer: OneWayTransformer> = { transform(subject: EditionTeaserDTO, context?: undefined): Subset { return subject && { @@ -45,7 +126,9 @@ export const editionDtoTransformer: Transformer = { editionStart: subject.startDate.toISOString(), course: courseDtoTransformer.reverseTransform(subject.course), reportingStart: subject.reportingStart.toISOString(), - availableSubjects: [], + availableSubjects: subject.program.map(entry => programEntryDtoTransformer.reverseTransform(entry)), + availableInternshipTypes: subject.types.map(entry => internshipTypeDtoTransformer.reverseTransform(entry)), + reportSchema: subject.schema.map(entry => fieldDefinitionDtoTransformer.reverseTransform(entry)), }; }, transform(subject: EditionDTO, context: undefined): Edition { @@ -59,6 +142,9 @@ export const editionDtoTransformer: Transformer = { proposalDeadline: moment(subject.reportingStart), reportingStart: moment(subject.reportingStart), reportingEnd: moment(subject.reportingStart).add(1, 'month'), + program: (subject.availableSubjects || []).map(entry => programEntryDtoTransformer.transform(entry)), + types: (subject.availableInternshipTypes || []).map(entry => internshipTypeDtoTransformer.transform(entry)), + schema: (subject.reportSchema || []).map(entry => fieldDefinitionDtoTransformer.transform(entry)), }; } } @@ -78,3 +164,28 @@ export const programEntryDtoTransformer: Transformer = { + transform(subject: Edition, context?: undefined): EditionUpdateDTO { + return { + id: subject.id, + editionFinish: subject.endDate.toISOString(), + editionStart: subject.startDate.toISOString(), + course: courseDtoTransformer.reverseTransform(subject.course), + reportingStart: subject.reportingStart.toISOString(), + availableSubjectsIds: subject.program.map(x => x.id).filter(x => typeof x !== "undefined") as Identifier[], + availableInternshipTypesIds: subject.types.map(x => x.id).filter(x => typeof x !== "undefined") as Identifier[], + reportSchema: subject.schema.map(x => x.id).filter(x => typeof x !== "undefined") as Identifier[], + } + } +} diff --git a/src/api/dto/internship-registration.ts b/src/api/dto/internship-registration.ts index acb869a..e7f5c4b 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, Stateful } 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,14 @@ 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"; +import { Report } from "@/data/report"; + +export interface StatefulDTO { + state: SubmissionState; + changeStateComment: string; +} export enum SubmissionState { Draft = "Draft", @@ -16,6 +24,50 @@ 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 const statefulDtoTransformer: Transformer = { + reverseTransform(subject: Stateful, context: undefined): StatefulDTO { + return { + changeStateComment: subject.comment, + state: submissionStateDtoTransformer.reverseTransform(subject.state, context), + }; + }, + transform(subject: StatefulDTO, context: undefined): Stateful { + return { + comment: subject.changeStateComment, + state: submissionStateDtoTransformer.transform(subject.state), + } + } +} + export interface NewBranchOffice extends Address { } @@ -40,29 +92,50 @@ export interface InternshipRegistrationUpdate { subjects: string[], } -export interface InternshipRegistrationDTO extends Identifiable { +export interface InternshipRegistrationDTO extends Identifiable, StatefulDTO { start: string; end: string; type: InternshipTypeDTO, - state: SubmissionState, mentor: MentorDTO, company: Company, branchAddress: Office, declaredHours: number, subjects: { subject: ProgramEntryDTO }[], + submissionDate: string, } -export interface InternshipDocument extends Identifiable { +export interface InternshipDocument extends Identifiable, Stateful { description: null, type: UploadType, - state: SubmissionState, +} + +export interface InternshipDocumentDTO extends Identifiable, StatefulDTO { + description: null; + type: UploadType; +} + +export interface InternshipReportDTO extends StatefulDTO, Identifiable { + value: string; } const reference = (subject: Identifiable | null): Identifiable | null => subject && { id: subject.id }; -export interface InternshipInfoDTO { +export interface InternshipInfoDTO extends Identifiable { internshipRegistration: InternshipRegistrationDTO; - documentation: InternshipDocument[], + documentation: InternshipDocumentDTO[], + student: StudentDTO, + report: InternshipReportDTO, + grade: number, +} + +export const internshipReportDtoTransformer: OneWayTransformer = { + transform(subject: InternshipReportDTO, context?: unknown): Report { + return { + id: subject.id, + fields: JSON.parse(subject.value), + ...statefulDtoTransformer.transform(subject), + } + } } export const internshipRegistrationUpdateTransformer: OneWayTransformer, Nullable> = { @@ -106,3 +179,12 @@ export const internshipRegistrationDtoTransformer: OneWayTransformer = { + transform(dto: InternshipDocumentDTO, context?: unknown): InternshipDocument { + return { + ...dto, + ...statefulDtoTransformer.transform(dto), + } + } +} diff --git a/src/api/index.ts b/src/api/index.ts index 930d924..4d8e029 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -11,6 +11,7 @@ import * as type from "./type"; import * as companies from "./companies"; import * as internship from "./internship"; import * as upload from "./upload"; +import * as report from "./report"; export const axios = Axios.create({ baseURL: process.env.API_BASE_URL || `https://${window.location.hostname}/api/`, @@ -41,7 +42,8 @@ const api = { type, companies, internship, - upload + upload, + report, } export default api; diff --git a/src/api/report.ts b/src/api/report.ts new file mode 100644 index 0000000..aaed0b3 --- /dev/null +++ b/src/api/report.ts @@ -0,0 +1,8 @@ +import { Report, ReportFieldValues } from "@/data/report"; +import { axios } from "@/api/index"; + +const REPORT_SAVE_ENDPOINT = "/internship/report" + +export async function save(report: Report) { + await axios.post(REPORT_SAVE_ENDPOINT, report.fields); +} diff --git a/src/app.tsx b/src/app.tsx index 47d9ad6..b6974b6 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -1,6 +1,6 @@ import React, { HTMLProps, useEffect } from 'react'; import { Link, Route, Switch } from "react-router-dom" -import { processMiddlewares, route, routes } from "@/routing"; +import { processMiddlewares, route, Routes, routes } from "@/routing"; import { useSelector } from "react-redux"; import { AppState } from "@/state/reducer"; import { Trans, useTranslation } from "react-i18next"; @@ -97,14 +97,7 @@ function App() {
- { - { routes.map(({ name, content, middlewares = [], ...route }) => - { - const Next = () => processMiddlewares([ ...middlewares, content ]) - return - } } /> - ) } - } + !route.tags || route.tags.length == 0) }/>