Reporting api stuff
This commit is contained in:
parent
d6de1fb959
commit
c0ad0826d0
@ -5,6 +5,7 @@ import { Edition } from "@/data/edition";
|
|||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import { Subset } from "@/helpers";
|
import { Subset } from "@/helpers";
|
||||||
import { InternshipTypeDTO, internshipTypeDtoTransformer } from "@/api/dto/type";
|
import { InternshipTypeDTO, internshipTypeDtoTransformer } from "@/api/dto/type";
|
||||||
|
import { ReportFieldDefinition, ReportFieldType } from "@/data/report";
|
||||||
|
|
||||||
export interface ProgramEntryDTO extends Identifiable {
|
export interface ProgramEntryDTO extends Identifiable {
|
||||||
description: string;
|
description: string;
|
||||||
@ -18,6 +19,7 @@ export interface EditionDTO extends Identifiable {
|
|||||||
course: CourseDTO,
|
course: CourseDTO,
|
||||||
availableSubjects: ProgramEntryDTO[],
|
availableSubjects: ProgramEntryDTO[],
|
||||||
availableInternshipTypes: InternshipTypeDTO[],
|
availableInternshipTypes: InternshipTypeDTO[],
|
||||||
|
reportSchema: FieldDefinitionDTO[],
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EditionTeaserDTO extends Identifiable {
|
export interface EditionTeaserDTO extends Identifiable {
|
||||||
@ -26,6 +28,83 @@ export interface EditionTeaserDTO extends Identifiable {
|
|||||||
courseName: string,
|
courseName: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum FieldDefinitionDTOType {
|
||||||
|
LongText = "LongText",
|
||||||
|
ShortText = "ShortText",
|
||||||
|
Select = "Select",
|
||||||
|
Radial = "Radial",
|
||||||
|
Checkbox = "Checkbox",
|
||||||
|
}
|
||||||
|
|
||||||
|
export const fieldDefinitionDtoTypeTransformer: Transformer<FieldDefinitionDTOType, ReportFieldType> = {
|
||||||
|
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<FieldDefinitionDTO, ReportFieldDefinition> = {
|
||||||
|
transform(dto: FieldDefinitionDTO, context?: unknown): ReportFieldDefinition {
|
||||||
|
return {
|
||||||
|
...dto,
|
||||||
|
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 {
|
||||||
|
...subject,
|
||||||
|
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<EditionTeaserDTO, Subset<Edition>> = {
|
export const editionTeaserDtoTransformer: OneWayTransformer<EditionTeaserDTO, Subset<Edition>> = {
|
||||||
transform(subject: EditionTeaserDTO, context?: undefined): Subset<Edition> {
|
transform(subject: EditionTeaserDTO, context?: undefined): Subset<Edition> {
|
||||||
return subject && {
|
return subject && {
|
||||||
@ -48,7 +127,8 @@ export const editionDtoTransformer: Transformer<EditionDTO, Edition> = {
|
|||||||
course: courseDtoTransformer.reverseTransform(subject.course),
|
course: courseDtoTransformer.reverseTransform(subject.course),
|
||||||
reportingStart: subject.reportingStart.toISOString(),
|
reportingStart: subject.reportingStart.toISOString(),
|
||||||
availableSubjects: subject.program.map(entry => programEntryDtoTransformer.reverseTransform(entry)),
|
availableSubjects: subject.program.map(entry => programEntryDtoTransformer.reverseTransform(entry)),
|
||||||
availableInternshipTypes: subject.types.map(entry => internshipTypeDtoTransformer.reverseTransform(entry))
|
availableInternshipTypes: subject.types.map(entry => internshipTypeDtoTransformer.reverseTransform(entry)),
|
||||||
|
reportSchema: subject.schema.map(entry => fieldDefinitionDtoTransformer.reverseTransform(entry)),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
transform(subject: EditionDTO, context: undefined): Edition {
|
transform(subject: EditionDTO, context: undefined): Edition {
|
||||||
@ -63,7 +143,8 @@ export const editionDtoTransformer: Transformer<EditionDTO, Edition> = {
|
|||||||
reportingStart: moment(subject.reportingStart),
|
reportingStart: moment(subject.reportingStart),
|
||||||
reportingEnd: moment(subject.reportingStart).add(1, 'month'),
|
reportingEnd: moment(subject.reportingStart).add(1, 'month'),
|
||||||
program: (subject.availableSubjects || []).map(entry => programEntryDtoTransformer.transform(entry)),
|
program: (subject.availableSubjects || []).map(entry => programEntryDtoTransformer.transform(entry)),
|
||||||
types: (subject.availableInternshipTypes || []).map(entry => internshipTypeDtoTransformer.transform(entry))
|
types: (subject.availableInternshipTypes || []).map(entry => internshipTypeDtoTransformer.transform(entry)),
|
||||||
|
schema: (subject.reportSchema || []).map(entry => fieldDefinitionDtoTransformer.transform(entry)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Address, Company, Identifiable, Internship, Mentor, Office, Student } from "@/data";
|
import { Address, Company, Identifiable, Internship, Mentor, Office, Stateful } from "@/data";
|
||||||
import { momentSerializationTransformer, OneWayTransformer, Transformer } from "@/serialization";
|
import { momentSerializationTransformer, OneWayTransformer, Transformer } from "@/serialization";
|
||||||
import { Nullable } from "@/helpers";
|
import { Nullable } from "@/helpers";
|
||||||
import { MentorDTO, mentorDtoTransformer } from "@/api/dto/mentor";
|
import { MentorDTO, mentorDtoTransformer } from "@/api/dto/mentor";
|
||||||
@ -9,6 +9,12 @@ import { UploadType } from "@/api/upload";
|
|||||||
import { ProgramEntryDTO, programEntryDtoTransformer } from "@/api/dto/edition";
|
import { ProgramEntryDTO, programEntryDtoTransformer } from "@/api/dto/edition";
|
||||||
import { StudentDTO } from "@/api/dto/student";
|
import { StudentDTO } from "@/api/dto/student";
|
||||||
import { SubmissionStatus } from "@/state/reducer/submission";
|
import { SubmissionStatus } from "@/state/reducer/submission";
|
||||||
|
import { Report } from "@/data/report";
|
||||||
|
|
||||||
|
export interface StatefulDTO {
|
||||||
|
state: SubmissionState;
|
||||||
|
changeStateComment: string;
|
||||||
|
}
|
||||||
|
|
||||||
export enum SubmissionState {
|
export enum SubmissionState {
|
||||||
Draft = "Draft",
|
Draft = "Draft",
|
||||||
@ -47,6 +53,21 @@ export const submissionStateDtoTransformer: Transformer<SubmissionState, Submiss
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const statefulDtoTransformer: Transformer<StatefulDTO, Stateful> = {
|
||||||
|
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 {
|
export interface NewBranchOffice extends Address {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,30 +92,30 @@ export interface InternshipRegistrationUpdate {
|
|||||||
subjects: string[],
|
subjects: string[],
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InternshipRegistrationDTO extends Identifiable {
|
export interface InternshipRegistrationDTO extends Identifiable, StatefulDTO {
|
||||||
start: string;
|
start: string;
|
||||||
end: string;
|
end: string;
|
||||||
type: InternshipTypeDTO,
|
type: InternshipTypeDTO,
|
||||||
state: SubmissionState,
|
|
||||||
mentor: MentorDTO,
|
mentor: MentorDTO,
|
||||||
company: Company,
|
company: Company,
|
||||||
branchAddress: Office,
|
branchAddress: Office,
|
||||||
declaredHours: number,
|
declaredHours: number,
|
||||||
subjects: { subject: ProgramEntryDTO }[],
|
subjects: { subject: ProgramEntryDTO }[],
|
||||||
submissionDate: string,
|
submissionDate: string,
|
||||||
changeStateComment: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InternshipDocument extends Identifiable {
|
export interface InternshipDocument extends Identifiable, Stateful {
|
||||||
description: null,
|
description: null,
|
||||||
type: UploadType,
|
type: UploadType,
|
||||||
state: SubmissionStatus,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface InternshipDocumentDTO extends Identifiable {
|
export interface InternshipDocumentDTO extends Identifiable, StatefulDTO {
|
||||||
description: null,
|
description: null;
|
||||||
type: UploadType,
|
type: UploadType;
|
||||||
state: SubmissionState,
|
}
|
||||||
|
|
||||||
|
export interface InternshipReportDTO extends StatefulDTO, Identifiable {
|
||||||
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const reference = (subject: Identifiable | null): Identifiable | null => subject && { id: subject.id };
|
const reference = (subject: Identifiable | null): Identifiable | null => subject && { id: subject.id };
|
||||||
@ -103,6 +124,16 @@ export interface InternshipInfoDTO extends Identifiable {
|
|||||||
internshipRegistration: InternshipRegistrationDTO;
|
internshipRegistration: InternshipRegistrationDTO;
|
||||||
documentation: InternshipDocumentDTO[],
|
documentation: InternshipDocumentDTO[],
|
||||||
student: StudentDTO,
|
student: StudentDTO,
|
||||||
|
report: InternshipReportDTO,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const internshipReportDtoTransformer: OneWayTransformer<InternshipReportDTO, Report> = {
|
||||||
|
transform(subject: InternshipReportDTO, context?: unknown): Report {
|
||||||
|
return {
|
||||||
|
fields: JSON.parse(subject.value),
|
||||||
|
...statefulDtoTransformer.transform(subject),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const internshipRegistrationUpdateTransformer: OneWayTransformer<Nullable<Internship>, Nullable<InternshipRegistrationUpdate>> = {
|
export const internshipRegistrationUpdateTransformer: OneWayTransformer<Nullable<Internship>, Nullable<InternshipRegistrationUpdate>> = {
|
||||||
@ -151,7 +182,7 @@ export const internshipDocumentDtoTransformer: OneWayTransformer<InternshipDocum
|
|||||||
transform(dto: InternshipDocumentDTO, context?: unknown): InternshipDocument {
|
transform(dto: InternshipDocumentDTO, context?: unknown): InternshipDocument {
|
||||||
return {
|
return {
|
||||||
...dto,
|
...dto,
|
||||||
state: submissionStateDtoTransformer.transform(dto.state),
|
...statefulDtoTransformer.transform(dto),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import * as type from "./type";
|
|||||||
import * as companies from "./companies";
|
import * as companies from "./companies";
|
||||||
import * as internship from "./internship";
|
import * as internship from "./internship";
|
||||||
import * as upload from "./upload";
|
import * as upload from "./upload";
|
||||||
|
import * as report from "./report";
|
||||||
|
|
||||||
export const axios = Axios.create({
|
export const axios = Axios.create({
|
||||||
baseURL: process.env.API_BASE_URL || `https://${window.location.hostname}/api/`,
|
baseURL: process.env.API_BASE_URL || `https://${window.location.hostname}/api/`,
|
||||||
@ -41,7 +42,8 @@ const api = {
|
|||||||
type,
|
type,
|
||||||
companies,
|
companies,
|
||||||
internship,
|
internship,
|
||||||
upload
|
upload,
|
||||||
|
report,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default api;
|
export default api;
|
||||||
|
8
src/api/report.ts
Normal file
8
src/api/report.ts
Normal file
@ -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);
|
||||||
|
}
|
@ -75,7 +75,7 @@ export const FileInfo = ({ document, ...props }: FileInfoProps) => {
|
|||||||
<Async async={ fileinfo }>
|
<Async async={ fileinfo }>
|
||||||
{ fileinfo => <div className={ classes.grid }>
|
{ fileinfo => <div className={ classes.grid }>
|
||||||
<div className={ classes.iconColumn }>
|
<div className={ classes.iconColumn }>
|
||||||
<FileIcon mime={ fileinfo.mime } className={ classes.icon } />
|
<FileIcon mime={ fileinfo.mime || "" } className={ classes.icon } />
|
||||||
</div>
|
</div>
|
||||||
<aside className={ classes.asideColumn }>
|
<aside className={ classes.asideColumn }>
|
||||||
<Typography variant="h5" className={ classes.header }>{ fileinfo.filename }</Typography>
|
<Typography variant="h5" className={ classes.header }>{ fileinfo.filename }</Typography>
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { SubmissionStatus } from "@/state/reducer/submission";
|
||||||
|
|
||||||
export type Identifier = string;
|
export type Identifier = string;
|
||||||
|
|
||||||
export interface Identifiable {
|
export interface Identifiable {
|
||||||
@ -8,3 +10,7 @@ export type Multilingual<T> = {
|
|||||||
pl: T,
|
pl: T,
|
||||||
en: T
|
en: T
|
||||||
}
|
}
|
||||||
|
export interface Stateful {
|
||||||
|
comment: string;
|
||||||
|
state: SubmissionStatus;
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@ import { Moment } from "moment-timezone";
|
|||||||
import { Course } from "@/data/course";
|
import { Course } from "@/data/course";
|
||||||
import { Identifiable } from "@/data/common";
|
import { Identifiable } from "@/data/common";
|
||||||
import { InternshipProgramEntry, InternshipType } from "@/data/internship";
|
import { InternshipProgramEntry, InternshipType } from "@/data/internship";
|
||||||
|
import { ReportSchema } from "@/data/report";
|
||||||
|
|
||||||
export type Edition = {
|
export type Edition = {
|
||||||
course: Course;
|
course: Course;
|
||||||
@ -14,6 +15,7 @@ export type Edition = {
|
|||||||
maximumInternshipHours?: number;
|
maximumInternshipHours?: number;
|
||||||
program: InternshipProgramEntry[];
|
program: InternshipProgramEntry[];
|
||||||
types: InternshipType[];
|
types: InternshipType[];
|
||||||
|
schema: ReportSchema;
|
||||||
} & Identifiable
|
} & Identifiable
|
||||||
|
|
||||||
export type Deadlines = {
|
export type Deadlines = {
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { Multilingual } from "@/data/common";
|
import { Identifiable, Multilingual, Stateful } from "@/data/common";
|
||||||
|
|
||||||
interface PredefinedChoices {
|
interface PredefinedChoices {
|
||||||
choices: Multilingual<string>[];
|
choices: Multilingual<string>[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BaseFieldDefinition {
|
export interface BaseFieldDefinition extends Identifiable {
|
||||||
name: string;
|
|
||||||
description: Multilingual<string>;
|
description: Multilingual<string>;
|
||||||
label: Multilingual<string>;
|
label: Multilingual<string>;
|
||||||
}
|
}
|
||||||
@ -32,10 +31,11 @@ export type ReportFieldDefinition = TextFieldDefinition | MultiChoiceFieldDefini
|
|||||||
export type ReportFieldValue = TextFieldValue | MultiChoiceValue | SingleChoiceValue;
|
export type ReportFieldValue = TextFieldValue | MultiChoiceValue | SingleChoiceValue;
|
||||||
export type ReportFieldValues = { [field: string]: ReportFieldValue };
|
export type ReportFieldValues = { [field: string]: ReportFieldValue };
|
||||||
export type ReportSchema = ReportFieldDefinition[];
|
export type ReportSchema = ReportFieldDefinition[];
|
||||||
|
export type ReportFieldType = ReportFieldDefinition['type'];
|
||||||
|
|
||||||
export interface Report {
|
export interface Report extends Stateful {
|
||||||
fields: ReportFieldValues;
|
fields: ReportFieldValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const reportFieldTypes = ["short-text", "long-text", "checkbox", "radio", "select"];
|
export const reportFieldTypes: ReportFieldType[] = ["short-text", "long-text", "checkbox", "radio", "select"];
|
||||||
|
|
||||||
|
@ -23,11 +23,14 @@ import { TextField as TextFieldFormik } from "formik-material-ui";
|
|||||||
import { Field, Form, Formik, useFormik, useFormikContext } from "formik";
|
import { Field, Form, Formik, useFormik, useFormikContext } from "formik";
|
||||||
import { Multilingual } from "@/data";
|
import { Multilingual } from "@/data";
|
||||||
import { Transformer } from "@/serialization";
|
import { Transformer } from "@/serialization";
|
||||||
|
import api from "@/api";
|
||||||
|
|
||||||
export type ReportFieldProps<TField = ReportFieldDefinition> = {
|
export type ReportFieldProps<TField = ReportFieldDefinition> = {
|
||||||
field: TField;
|
field: TField;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const name = ({ id }: ReportFieldDefinition) => `field_${id}`;
|
||||||
|
|
||||||
export const CustomField = ({ field, ...props }: ReportFieldProps) => {
|
export const CustomField = ({ field, ...props }: ReportFieldProps) => {
|
||||||
switch (field.type) {
|
switch (field.type) {
|
||||||
case "short-text":
|
case "short-text":
|
||||||
@ -43,9 +46,10 @@ export const CustomField = ({ field, ...props }: ReportFieldProps) => {
|
|||||||
|
|
||||||
CustomField.Text = ({ field }: ReportFieldProps) => {
|
CustomField.Text = ({ field }: ReportFieldProps) => {
|
||||||
return <>
|
return <>
|
||||||
<Field label={ field.label.pl } name={ field.name }
|
<Field label={ field.label.pl } name={ name(field) }
|
||||||
fullWidth
|
fullWidth
|
||||||
rows={ field.type == "long-text" ? 4 : 1 } multiline={ field.type == "long-text" }
|
rows={ field.type == "long-text" ? 4 : 1 }
|
||||||
|
multiline={ field.type == "long-text" }
|
||||||
component={ TextFieldFormik }
|
component={ TextFieldFormik }
|
||||||
/>
|
/>
|
||||||
<Typography variant="caption" color="textSecondary" dangerouslySetInnerHTML={{ __html: field.description.pl }}/>
|
<Typography variant="caption" color="textSecondary" dangerouslySetInnerHTML={{ __html: field.description.pl }}/>
|
||||||
@ -54,14 +58,14 @@ CustomField.Text = ({ field }: ReportFieldProps) => {
|
|||||||
|
|
||||||
CustomField.Select = ({ field }: ReportFieldProps<SingleChoiceFieldDefinition>) => {
|
CustomField.Select = ({ field }: ReportFieldProps<SingleChoiceFieldDefinition>) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const id = `custom-field-${field.name}`;
|
const id = `custom-field-${field.id}`;
|
||||||
const { values, setFieldValue } = useFormikContext<any>();
|
const { values, setFieldValue } = useFormikContext<any>();
|
||||||
|
|
||||||
const value = values[field.name];
|
const value = values[name(field)];
|
||||||
|
|
||||||
return <FormControl variant="outlined">
|
return <FormControl variant="outlined">
|
||||||
<InputLabel htmlFor={id}>{ field.label.pl }</InputLabel>
|
<InputLabel htmlFor={id}>{ field.label.pl }</InputLabel>
|
||||||
<Select label={ field.label.pl } name={ field.name } id={id} value={ value } onChange={ ({ target }) => setFieldValue(field.name, target.value, false) }>
|
<Select label={ field.label.pl } name={ name(field) } id={id} value={ value } onChange={ ({ target }) => setFieldValue(name(field), target.value, false) }>
|
||||||
{ field.choices.map(choice => <MenuItem value={ choice as any }>{ choice.pl }</MenuItem>) }
|
{ field.choices.map(choice => <MenuItem value={ choice as any }>{ choice.pl }</MenuItem>) }
|
||||||
</Select>
|
</Select>
|
||||||
<Typography variant="caption" color="textSecondary" dangerouslySetInnerHTML={{ __html: field.description.pl }}/>
|
<Typography variant="caption" color="textSecondary" dangerouslySetInnerHTML={{ __html: field.description.pl }}/>
|
||||||
@ -72,17 +76,17 @@ CustomField.Choice = ({ field }: ReportFieldProps<SingleChoiceFieldDefinition |
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { values, setFieldValue } = useFormikContext<any>();
|
const { values, setFieldValue } = useFormikContext<any>();
|
||||||
|
|
||||||
const value = values[field.name];
|
const value = values[name(field)];
|
||||||
|
|
||||||
const isSelected = field.type == 'radio'
|
const isSelected = field.type == 'radio'
|
||||||
? (checked: Multilingual<string>) => value == checked
|
? (checked: Multilingual<string>) => value == checked
|
||||||
: (checked: Multilingual<string>) => (value || []).includes(checked)
|
: (checked: Multilingual<string>) => (value || []).includes(checked)
|
||||||
|
|
||||||
const handleChange = field.type == 'radio'
|
const handleChange = field.type == 'radio'
|
||||||
? (choice: Multilingual<string>) => () => setFieldValue(field.name, choice, false)
|
? (choice: Multilingual<string>) => () => setFieldValue(name(field), choice, false)
|
||||||
: (choice: Multilingual<string>) => () => {
|
: (choice: Multilingual<string>) => () => {
|
||||||
const current = value || [];
|
const current = value || [];
|
||||||
setFieldValue(field.name, !current.includes(choice) ? [ ...current, choice ] : current.filter((c: Multilingual<string>) => c != choice), false);
|
setFieldValue(name(field), !current.includes(choice) ? [ ...current, choice ] : current.filter((c: Multilingual<string>) => c != choice), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Component = field.type == 'radio' ? Radio : Checkbox;
|
const Component = field.type == 'radio' ? Radio : Checkbox;
|
||||||
@ -101,7 +105,7 @@ CustomField.Choice = ({ field }: ReportFieldProps<SingleChoiceFieldDefinition |
|
|||||||
|
|
||||||
export type ReportFormValues = ReportFieldValues;
|
export type ReportFormValues = ReportFieldValues;
|
||||||
|
|
||||||
const reportToFormValuesTransformer: Transformer<Report, ReportFormValues, { report: Report }> = {
|
const reportFormValuesTransformer: Transformer<Report, ReportFormValues, { report: Report }> = {
|
||||||
reverseTransform(subject: ReportFormValues, context: { report: Report }): Report {
|
reverseTransform(subject: ReportFormValues, context: { report: Report }): Report {
|
||||||
return { ...context.report, fields: subject };
|
return { ...context.report, fields: subject };
|
||||||
},
|
},
|
||||||
@ -115,9 +119,12 @@ export default function ReportForm() {
|
|||||||
const schema = sampleReportSchema;
|
const schema = sampleReportSchema;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const handleSubmit = async () => {};
|
const handleSubmit = async (values: ReportFormValues) => {
|
||||||
|
const result = reportFormValuesTransformer.reverseTransform(values);
|
||||||
|
await api.report.save(result);
|
||||||
|
};
|
||||||
|
|
||||||
return <Formik initialValues={ reportToFormValuesTransformer.transform(report) } onSubmit={ handleSubmit }>
|
return <Formik initialValues={ reportFormValuesTransformer.transform(report) } onSubmit={ handleSubmit }>
|
||||||
{ ({ submitForm }) => <Form>
|
{ ({ submitForm }) => <Form>
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
|
14
src/management/api/field.ts
Normal file
14
src/management/api/field.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { ReportFieldDefinition } from "@/data/report";
|
||||||
|
import { axios } from "@/api";
|
||||||
|
import { FieldDefinitionDTO, fieldDefinitionDtoTransformer } from "@/api/dto/edition";
|
||||||
|
|
||||||
|
const REPORT_FIELD_INDEX_ENDPOINT = "/management/report/fields"
|
||||||
|
|
||||||
|
export async function all(): Promise<ReportFieldDefinition[]> {
|
||||||
|
const result = await axios.get<FieldDefinitionDTO[]>(REPORT_FIELD_INDEX_ENDPOINT);
|
||||||
|
return (result.data || []).map(field => fieldDefinitionDtoTransformer.transform(field));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function save(field: ReportFieldDefinition) {
|
||||||
|
await axios.post(REPORT_FIELD_INDEX_ENDPOINT, fieldDefinitionDtoTransformer.reverseTransform(field));
|
||||||
|
}
|
@ -4,6 +4,7 @@ import * as type from "./type"
|
|||||||
import * as course from "./course"
|
import * as course from "./course"
|
||||||
import * as internship from "./internship"
|
import * as internship from "./internship"
|
||||||
import * as document from "./document"
|
import * as document from "./document"
|
||||||
|
import * as field from "./field"
|
||||||
|
|
||||||
export const api = {
|
export const api = {
|
||||||
edition,
|
edition,
|
||||||
@ -11,7 +12,8 @@ export const api = {
|
|||||||
type,
|
type,
|
||||||
course,
|
course,
|
||||||
internship,
|
internship,
|
||||||
document
|
document,
|
||||||
|
field
|
||||||
}
|
}
|
||||||
|
|
||||||
export default api;
|
export default api;
|
||||||
|
@ -3,7 +3,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { useAsync, useAsyncState } from "@/hooks";
|
import { useAsync, useAsyncState } from "@/hooks";
|
||||||
import { useSpacing } from "@/styles";
|
import { useSpacing } from "@/styles";
|
||||||
import api from "@/management/api";
|
import api from "@/management/api";
|
||||||
import { Box, Button, Container, IconButton, Typography } from "@material-ui/core";
|
import { Box, Button, Container, IconButton, Tooltip, Typography } from "@material-ui/core";
|
||||||
import MaterialTable, { Column } from "material-table";
|
import MaterialTable, { Column } from "material-table";
|
||||||
import { actionsColumn } from "@/management/common/helpers";
|
import { actionsColumn } from "@/management/common/helpers";
|
||||||
import { FileFind, Refresh, StickerCheckOutline, StickerRemoveOutline } from "mdi-material-ui";
|
import { FileFind, Refresh, StickerCheckOutline, StickerRemoveOutline } from "mdi-material-ui";
|
||||||
@ -46,7 +46,7 @@ export const InternshipManagement = ({ edition }: EditionManagementProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<IconButton onClick={ () => setOpen(true) }><StickerCheckOutline /></IconButton>
|
<Tooltip title={ t("translation:accept") as any }><IconButton onClick={ () => setOpen(true) }><StickerCheckOutline /></IconButton></Tooltip>
|
||||||
{ createPortal(
|
{ createPortal(
|
||||||
<AcceptSubmissionDialog onAccept={ handleSubmissionAccept } label="internship" open={ open } onClose={ () => setOpen(false) }/>,
|
<AcceptSubmissionDialog onAccept={ handleSubmissionAccept } label="internship" open={ open } onClose={ () => setOpen(false) }/>,
|
||||||
document.getElementById("modals") as Element,
|
document.getElementById("modals") as Element,
|
||||||
@ -64,7 +64,7 @@ export const InternshipManagement = ({ edition }: EditionManagementProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
<IconButton onClick={ () => setOpen(true) }><StickerRemoveOutline /></IconButton>
|
<Tooltip title={ t("translation:discard") as any }><IconButton onClick={ () => setOpen(true) }><StickerRemoveOutline /></IconButton></Tooltip>
|
||||||
{ createPortal(
|
{ createPortal(
|
||||||
<DiscardSubmissionDialog onDiscard={ handleSubmissionDiscard } label="internship" open={ open } onClose={ () => setOpen(false) }/>,
|
<DiscardSubmissionDialog onDiscard={ handleSubmissionDiscard } label="internship" open={ open } onClose={ () => setOpen(false) }/>,
|
||||||
document.getElementById("modals") as Element,
|
document.getElementById("modals") as Element,
|
||||||
|
@ -105,7 +105,7 @@ export const PlanManagement = ({ edition }: EditionManagementProps) => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("internship.column.status"),
|
title: t("internship.column.status"),
|
||||||
render: summary => <StateLabel state={ summary.ipp?.state } />
|
render: summary => <StateLabel state={ summary.ipp?.state || null } />
|
||||||
},
|
},
|
||||||
actionsColumn(internship => <>
|
actionsColumn(internship => <>
|
||||||
{ canAccept(internship.ipp) && <AcceptAction internship={ internship } /> }
|
{ canAccept(internship.ipp) && <AcceptAction internship={ internship } /> }
|
||||||
|
@ -47,9 +47,6 @@ export const EditionManagement = ({ edition }: EditionManagementProps) => {
|
|||||||
<Paper elevation={ 2 }>
|
<Paper elevation={ 2 }>
|
||||||
<Typography className={ classes.header }>{ t("edition.manage.internships") }</Typography>
|
<Typography className={ classes.header }>{ t("edition.manage.internships") }</Typography>
|
||||||
<Management.Menu>
|
<Management.Menu>
|
||||||
<ManagementLink icon={ <AccountMultiple/> } route={ route("management:edition_report_form", { edition: edition.id || "" }) }>
|
|
||||||
{ t("management:edition.students.title") }
|
|
||||||
</ManagementLink>
|
|
||||||
<ManagementLink icon={ <BriefcaseAccount/> } route={ route("management:edition_internships", { edition: edition.id || "" }) }>
|
<ManagementLink icon={ <BriefcaseAccount/> } route={ route("management:edition_internships", { edition: edition.id || "" }) }>
|
||||||
{ t("management:edition.internships.title") }
|
{ t("management:edition.internships.title") }
|
||||||
</ManagementLink>
|
</ManagementLink>
|
||||||
|
@ -4,8 +4,7 @@ import React from "react";
|
|||||||
import { Link as RouterLink } from "react-router-dom";
|
import { Link as RouterLink } from "react-router-dom";
|
||||||
import { route } from "@/routing";
|
import { route } from "@/routing";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { CalendarClock, FileCertificateOutline, FileDocumentMultipleOutline } from "mdi-material-ui";
|
import { CalendarClock, FileCertificateOutline, FileDocumentMultipleOutline, FormatPageBreak } from "mdi-material-ui";
|
||||||
|
|
||||||
|
|
||||||
export const ManagementLink = ({ icon, route, children }: ManagementLinkProps) =>
|
export const ManagementLink = ({ icon, route, children }: ManagementLinkProps) =>
|
||||||
<ListItem button component={ RouterLink } to={ route }>
|
<ListItem button component={ RouterLink } to={ route }>
|
||||||
@ -47,6 +46,9 @@ export const ManagementIndex = () => {
|
|||||||
<ManagementLink icon={ <FileCertificateOutline /> } route={ route("management:types") }>
|
<ManagementLink icon={ <FileCertificateOutline /> } route={ route("management:types") }>
|
||||||
{ t("management:type.index.title") }
|
{ t("management:type.index.title") }
|
||||||
</ManagementLink>
|
</ManagementLink>
|
||||||
|
<ManagementLink icon={ <FormatPageBreak/> } route={ route("management:report_fields") }>
|
||||||
|
{ t("management:edition.report-fields.title") }
|
||||||
|
</ManagementLink>
|
||||||
<ManagementLink icon={ <FileDocumentMultipleOutline /> } route={ route("management:static_pages") }>
|
<ManagementLink icon={ <FileDocumentMultipleOutline /> } route={ route("management:static_pages") }>
|
||||||
{ t("management:page.index.title") }
|
{ t("management:page.index.title") }
|
||||||
</ManagementLink>
|
</ManagementLink>
|
||||||
|
@ -7,7 +7,7 @@ import { Form, Formik } from "formik";
|
|||||||
import { Actions } from "@/components";
|
import { Actions } from "@/components";
|
||||||
import { Save } from "@material-ui/icons";
|
import { Save } from "@material-ui/icons";
|
||||||
import { Cancel } from "mdi-material-ui";
|
import { Cancel } from "mdi-material-ui";
|
||||||
import { FieldDefinitionForm, FieldDefinitionFormValues, fieldFormValuesTransformer, initialFieldFormValues } from "@/management/edition/report/fields/form";
|
import { FieldDefinitionForm, FieldDefinitionFormValues, fieldFormValuesTransformer, initialFieldFormValues } from "@/management/report/fields/form";
|
||||||
|
|
||||||
export type EditFieldDialogProps = {
|
export type EditFieldDialogProps = {
|
||||||
onSave?: (field: ReportFieldDefinition) => void;
|
onSave?: (field: ReportFieldDefinition) => void;
|
@ -11,14 +11,13 @@ import { Multilingual } from "@/data";
|
|||||||
import { Actions } from "@/components";
|
import { Actions } from "@/components";
|
||||||
import { Add } from "@material-ui/icons";
|
import { Add } from "@material-ui/icons";
|
||||||
import { TrashCan } from "mdi-material-ui";
|
import { TrashCan } from "mdi-material-ui";
|
||||||
import { FieldPreview } from "@/management/edition/report/fields/list";
|
import { FieldPreview } from "@/management/report/fields/list";
|
||||||
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
|
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
|
||||||
|
|
||||||
export type FieldDefinitionFormValues = ReportFieldDefinition | { type: string };
|
export type FieldDefinitionFormValues = ReportFieldDefinition | { type: string };
|
||||||
|
|
||||||
export const initialFieldFormValues: FieldDefinitionFormValues = {
|
export const initialFieldFormValues: FieldDefinitionFormValues = {
|
||||||
type: "short-text",
|
type: "short-text",
|
||||||
name: "",
|
|
||||||
description: {
|
description: {
|
||||||
pl: "",
|
pl: "",
|
||||||
en: "",
|
en: "",
|
||||||
@ -58,7 +57,6 @@ export function FieldDefinitionForm() {
|
|||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
return <div className={ spacing.vertical }>
|
return <div className={ spacing.vertical }>
|
||||||
<Field label={ t("report-field.field.name") } name="name" fullWidth component={ TextFieldFormik }/>
|
|
||||||
<FormControl variant="outlined">
|
<FormControl variant="outlined">
|
||||||
<InputLabel htmlFor="report-field-type">{ t("report-field.field.type") }</InputLabel>
|
<InputLabel htmlFor="report-field-type">{ t("report-field.field.type") }</InputLabel>
|
||||||
<Field
|
<Field
|
||||||
@ -81,7 +79,7 @@ export function FieldDefinitionForm() {
|
|||||||
<Typography variant="subtitle2">{ t("report-field.field.choices") }</Typography>
|
<Typography variant="subtitle2">{ t("report-field.field.choices") }</Typography>
|
||||||
<FieldArray name="choices" render={ helper => <>
|
<FieldArray name="choices" render={ helper => <>
|
||||||
{ values.choices.map((value: Multilingual<string>, index: number) => <Card>
|
{ values.choices.map((value: Multilingual<string>, index: number) => <Card>
|
||||||
<CardHeader subheader={ t("report-field.field.choice", { index }) } action={ <>
|
<CardHeader subheader={ t("report-field.field.choice", { index: index + 1 }) } action={ <>
|
||||||
<IconButton onClick={ () => helper.remove(index) }>
|
<IconButton onClick={ () => helper.remove(index) }>
|
||||||
<TrashCan />
|
<TrashCan />
|
||||||
</IconButton>
|
</IconButton>
|
@ -1,20 +1,24 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
import { Page } from "@/pages/base";
|
import { Page } from "@/pages/base";
|
||||||
import { Management } from "@/management/main";
|
import { Management } from "@/management/main";
|
||||||
import { Box, Container, IconButton, Tooltip, Typography } from "@material-ui/core";
|
import { Box, Button, Container, IconButton, Tooltip, Typography } from "@material-ui/core";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { sampleReportSchema } from "@/provider/dummy/report";
|
|
||||||
import MaterialTable, { Column } from "material-table";
|
import MaterialTable, { Column } from "material-table";
|
||||||
import { actionsColumn, fieldComparator, multilingualStringComparator } from "@/management/common/helpers";
|
import { actionsColumn, fieldComparator, multilingualStringComparator } from "@/management/common/helpers";
|
||||||
import { MultilingualCell } from "@/management/common/MultilangualCell";
|
import { MultilingualCell } from "@/management/common/MultilangualCell";
|
||||||
import { ReportFieldDefinition } from "@/data/report";
|
import { ReportFieldDefinition } from "@/data/report";
|
||||||
import { Formik } from "formik";
|
import { Formik } from "formik";
|
||||||
import { CustomField } from "@/forms/report";
|
import { CustomField } from "@/forms/report";
|
||||||
import { Edit } from "@material-ui/icons";
|
import { Add, Edit } from "@material-ui/icons";
|
||||||
import { createPortal } from "react-dom";
|
import { createPortal } from "react-dom";
|
||||||
import { createDeleteAction } from "@/management/common/DeleteResourceAction";
|
import { createDeleteAction } from "@/management/common/DeleteResourceAction";
|
||||||
import { EditFieldDefinitionDialog } from "@/management/edition/report/fields/edit";
|
import { EditFieldDefinitionDialog } from "@/management/report/fields/edit";
|
||||||
import { EditionManagement } from "../../manage";
|
import api from "@/management/api";
|
||||||
|
import { useAsync, useAsyncState } from "@/hooks";
|
||||||
|
import { Async } from "@/components/async";
|
||||||
|
import { Actions } from "@/components";
|
||||||
|
import { Refresh } from "mdi-material-ui";
|
||||||
|
import { useSpacing } from "@/styles";
|
||||||
|
|
||||||
const title = "edition.report-fields.title";
|
const title = "edition.report-fields.title";
|
||||||
|
|
||||||
@ -24,17 +28,42 @@ export const FieldPreview = ({ field }: { field: ReportFieldDefinition }) => {
|
|||||||
</Formik>
|
</Formik>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EditionReportFields = () => {
|
export const ReportFields = () => {
|
||||||
const { t } = useTranslation("management");
|
const { t } = useTranslation("management");
|
||||||
const schema = sampleReportSchema;
|
const [fields, setFieldsPromise] = useAsyncState<ReportFieldDefinition[]>();
|
||||||
|
|
||||||
|
const updateFieldList = () => {
|
||||||
|
setFieldsPromise(api.field.all());
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(updateFieldList, []);
|
||||||
|
|
||||||
const handleFieldDeletion = () => {}
|
const handleFieldDeletion = () => {}
|
||||||
|
|
||||||
|
const CreateFieldAction = () => {
|
||||||
|
const [ open, setOpen ] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const handleFieldCreation = async (value: ReportFieldDefinition) => {
|
||||||
|
await api.field.save(value);
|
||||||
|
setOpen(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<Button variant="contained" color="primary" startIcon={ <Add /> } onClick={ () => setOpen(true) }>{ t("create") }</Button>
|
||||||
|
{ open && createPortal(
|
||||||
|
<EditFieldDefinitionDialog open={ open } onSave={ handleFieldCreation } onClose={ () => setOpen(false) }/>,
|
||||||
|
document.getElementById("modals") as Element
|
||||||
|
) }
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
const DeleteFieldAction = createDeleteAction<ReportFieldDefinition>({ label: field => field.label.pl, onDelete: handleFieldDeletion })
|
const DeleteFieldAction = createDeleteAction<ReportFieldDefinition>({ label: field => field.label.pl, onDelete: handleFieldDeletion })
|
||||||
const EditFieldAction = ({ field }: { field: ReportFieldDefinition }) => {
|
const EditFieldAction = ({ field }: { field: ReportFieldDefinition }) => {
|
||||||
const [ open, setOpen ] = useState<boolean>(false);
|
const [ open, setOpen ] = useState<boolean>(false);
|
||||||
|
|
||||||
const handleFieldSave = async (field: ReportFieldDefinition) => {
|
const handleFieldSave = async (field: ReportFieldDefinition) => {
|
||||||
|
await api.field.save(field);
|
||||||
|
setOpen(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
return <>
|
||||||
@ -66,20 +95,28 @@ export const EditionReportFields = () => {
|
|||||||
</>),
|
</>),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const spacing = useSpacing(2);
|
||||||
|
|
||||||
return <Page>
|
return <Page>
|
||||||
<Page.Header maxWidth="lg">
|
<Page.Header maxWidth="lg">
|
||||||
<EditionManagement.Breadcrumbs>
|
<Management.Breadcrumbs>
|
||||||
<Typography color="textPrimary">{ t(title) }</Typography>
|
<Typography color="textPrimary">{ t(title) }</Typography>
|
||||||
</EditionManagement.Breadcrumbs>
|
</Management.Breadcrumbs>
|
||||||
<Page.Title>{ t(title) }</Page.Title>
|
<Page.Title>{ t(title) }</Page.Title>
|
||||||
</Page.Header>
|
</Page.Header>
|
||||||
<Container maxWidth="lg">
|
<Container maxWidth="lg" className={ spacing.vertical }>
|
||||||
<MaterialTable
|
<Actions>
|
||||||
columns={ columns }
|
<CreateFieldAction />
|
||||||
data={ schema }
|
<Button onClick={ updateFieldList } startIcon={ <Refresh /> }>{ t("refresh") }</Button>
|
||||||
title={ t(title) }
|
</Actions>
|
||||||
detailPanel={ field => <Box p={3}><FieldPreview field={ field } /></Box> }
|
<Async async={ fields }>
|
||||||
/>
|
{ fields => <MaterialTable
|
||||||
|
columns={ columns }
|
||||||
|
data={ fields }
|
||||||
|
title={ t(title) }
|
||||||
|
detailPanel={ field => <Box p={3}><FieldPreview field={ field } /></Box> }
|
||||||
|
/> }
|
||||||
|
</Async>
|
||||||
</Container>
|
</Container>
|
||||||
</Page>
|
</Page>
|
||||||
}
|
}
|
@ -6,17 +6,16 @@ import { ManagementIndex } from "@/management/main";
|
|||||||
import StaticPageManagement from "@/management/page/list";
|
import StaticPageManagement from "@/management/page/list";
|
||||||
import { InternshipTypeManagement } from "@/management/type/list";
|
import { InternshipTypeManagement } from "@/management/type/list";
|
||||||
import { EditionRouter, EditionManagement } from "@/management/edition/manage";
|
import { EditionRouter, EditionManagement } from "@/management/edition/manage";
|
||||||
import { EditionReportFields } from "@/management/edition/report/fields/list";
|
|
||||||
import { EditionSettings } from "@/management/edition/settings";
|
import { EditionSettings } from "@/management/edition/settings";
|
||||||
import { InternshipManagement } from "@/management/edition/internship/list";
|
import { InternshipManagement } from "@/management/edition/internship/list";
|
||||||
import { InternshipDetails } from "@/management/edition/internship/details";
|
import { InternshipDetails } from "@/management/edition/internship/details";
|
||||||
import { PlanManagement } from "@/management/edition/ipp/list";
|
import { PlanManagement } from "@/management/edition/ipp/list";
|
||||||
|
import { ReportFields } from "@/management/report/fields/list";
|
||||||
|
|
||||||
export const managementRoutes: Route[] = ([
|
export const managementRoutes: Route[] = ([
|
||||||
{ name: "index", path: "/", content: ManagementIndex, exact: true },
|
{ name: "index", path: "/", content: ManagementIndex, exact: true },
|
||||||
|
|
||||||
{ name: "edition_router", path: "/editions/:edition", content: EditionRouter },
|
{ name: "edition_router", path: "/editions/:edition", content: EditionRouter },
|
||||||
{ name: "edition_report_form", path: "/editions/:edition/report", content: EditionReportFields, tags: ["edition"] },
|
|
||||||
{ name: "edition_settings", path: "/editions/:edition/settings", content: EditionSettings, tags: ["edition"] },
|
{ name: "edition_settings", path: "/editions/:edition/settings", content: EditionSettings, tags: ["edition"] },
|
||||||
{ name: "edition_manage", path: "/editions/:edition", content: EditionManagement, tags: ["edition"], exact: true },
|
{ name: "edition_manage", path: "/editions/:edition", content: EditionManagement, tags: ["edition"], exact: true },
|
||||||
{ name: "edition_internship", path: "/editions/:edition/internships/:internship", content: InternshipDetails, tags: ["edition"] },
|
{ name: "edition_internship", path: "/editions/:edition/internships/:internship", content: InternshipDetails, tags: ["edition"] },
|
||||||
@ -24,6 +23,7 @@ export const managementRoutes: Route[] = ([
|
|||||||
{ name: "edition_ipp_index", path: "/editions/:edition/ipp", content: PlanManagement, tags: ["edition"] },
|
{ name: "edition_ipp_index", path: "/editions/:edition/ipp", content: PlanManagement, tags: ["edition"] },
|
||||||
{ name: "editions", path: "/editions", content: EditionsManagement },
|
{ name: "editions", path: "/editions", content: EditionsManagement },
|
||||||
|
|
||||||
|
{ name: "report_fields", path: "/fields", content: ReportFields },
|
||||||
{ name: "types", path: "/types", content: InternshipTypeManagement },
|
{ name: "types", path: "/types", content: InternshipTypeManagement },
|
||||||
{ name: "static_pages", path: "/static-pages", content: StaticPageManagement }
|
{ name: "static_pages", path: "/static-pages", content: StaticPageManagement }
|
||||||
] as Route[]).map(
|
] as Route[]).map(
|
||||||
|
@ -14,8 +14,8 @@ import { InsuranceState } from "@/state/reducer/insurance";
|
|||||||
import { InsuranceStep } from "@/pages/steps/insurance";
|
import { InsuranceStep } from "@/pages/steps/insurance";
|
||||||
import { StudentStep } from "@/pages/steps/student";
|
import { StudentStep } from "@/pages/steps/student";
|
||||||
import api from "@/api";
|
import api from "@/api";
|
||||||
import { AppDispatch, InternshipPlanActions, InternshipProposalActions, useDispatch } from "@/state/actions";
|
import { AppDispatch, InternshipPlanActions, InternshipProposalActions, InternshipReportActions, useDispatch } from "@/state/actions";
|
||||||
import { internshipRegistrationDtoTransformer } from "@/api/dto/internship-registration";
|
import { internshipDocumentDtoTransformer, internshipRegistrationDtoTransformer, internshipReportDtoTransformer } from "@/api/dto/internship-registration";
|
||||||
import { UploadType } from "@/api/upload";
|
import { UploadType } from "@/api/upload";
|
||||||
import { ReportStep } from "@/pages/steps/report";
|
import { ReportStep } from "@/pages/steps/report";
|
||||||
|
|
||||||
@ -30,18 +30,33 @@ export const updateInternshipInfo = async (dispatch: AppDispatch) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const plan = internship.documentation.find(doc => doc.type === UploadType.Ipp);
|
const plan = internship.documentation.find(doc => doc.type === UploadType.Ipp);
|
||||||
|
const report = internship.report;
|
||||||
|
|
||||||
if (plan) {
|
if (plan) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: InternshipPlanActions.Receive,
|
type: InternshipPlanActions.Receive,
|
||||||
document: plan,
|
document: internshipDocumentDtoTransformer.transform(plan),
|
||||||
state: plan.state,
|
state: plan.state,
|
||||||
|
comment: plan.changeStateComment,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: InternshipPlanActions.Reset,
|
type: InternshipPlanActions.Reset,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (report) {
|
||||||
|
dispatch({
|
||||||
|
type: InternshipReportActions.Receive,
|
||||||
|
report: internshipReportDtoTransformer.transform(report),
|
||||||
|
state: report.state,
|
||||||
|
comment: report.changeStateComment,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
dispatch({
|
||||||
|
type: InternshipReportActions.Reset,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MainPage = () => {
|
export const MainPage = () => {
|
||||||
|
@ -3,7 +3,7 @@ import { AppState } from "@/state/reducer";
|
|||||||
import { getSubmissionStatus, SubmissionState, SubmissionStatus } from "@/state/reducer/submission";
|
import { getSubmissionStatus, SubmissionState, SubmissionStatus } from "@/state/reducer/submission";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Box, Button, ButtonProps, StepProps } from "@material-ui/core";
|
import { Box, Button, ButtonProps, StepProps } from "@material-ui/core";
|
||||||
import { FileDownloadOutline, FileUploadOutline } from "mdi-material-ui/index";
|
import { FileUploadOutline } from "mdi-material-ui/index";
|
||||||
import { route } from "@/routing";
|
import { route } from "@/routing";
|
||||||
import { Link as RouterLink, useHistory } from "react-router-dom";
|
import { Link as RouterLink, useHistory } from "react-router-dom";
|
||||||
import { Actions, Step } from "@/components";
|
import { Actions, Step } from "@/components";
|
||||||
@ -15,7 +15,6 @@ import { useDeadlines } from "@/hooks";
|
|||||||
import { InternshipDocument } from "@/api/dto/internship-registration";
|
import { InternshipDocument } from "@/api/dto/internship-registration";
|
||||||
import { FileInfo } from "@/components/fileinfo";
|
import { FileInfo } from "@/components/fileinfo";
|
||||||
import { useSpacing } from "@/styles";
|
import { useSpacing } from "@/styles";
|
||||||
import { AcceptanceActions } from "@/components/acceptance-action";
|
|
||||||
import { InternshipPlanActions, useDispatch } from "@/state/actions";
|
import { InternshipPlanActions, useDispatch } from "@/state/actions";
|
||||||
|
|
||||||
const PlanActions = () => {
|
const PlanActions = () => {
|
||||||
@ -76,7 +75,7 @@ export const PlanComment = (props: HTMLProps<HTMLDivElement>) => {
|
|||||||
|
|
||||||
return comment ? <Alert severity={ declined ? "error" : "warning" } { ...props as any }>
|
return comment ? <Alert severity={ declined ? "error" : "warning" } { ...props as any }>
|
||||||
<AlertTitle>{ t('comments') }</AlertTitle>
|
<AlertTitle>{ t('comments') }</AlertTitle>
|
||||||
{ comment }
|
<div dangerouslySetInnerHTML={{ __html: comment }} />
|
||||||
</Alert> : null
|
</Alert> : null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Report, ReportSchema } from "@/data/report";
|
import { Report, ReportSchema } from "@/data/report";
|
||||||
|
import { Stateful } from "@/data";
|
||||||
|
|
||||||
const choices = [1, 2, 3, 4, 5].map(n => ({
|
const choices = [1, 2, 3, 4, 5].map(n => ({
|
||||||
pl: `Wybór ${n}`,
|
pl: `Wybór ${n}`,
|
||||||
@ -8,7 +9,7 @@ const choices = [1, 2, 3, 4, 5].map(n => ({
|
|||||||
export const sampleReportSchema: ReportSchema = [
|
export const sampleReportSchema: ReportSchema = [
|
||||||
{
|
{
|
||||||
type: "short-text",
|
type: "short-text",
|
||||||
name: "short",
|
id: "short",
|
||||||
description: {
|
description: {
|
||||||
en: "Text field, with <strong>HTML</strong> description",
|
en: "Text field, with <strong>HTML</strong> description",
|
||||||
pl: "Pole tekstowe, z opisem w formacie <strong>HTML</strong>"
|
pl: "Pole tekstowe, z opisem w formacie <strong>HTML</strong>"
|
||||||
@ -20,7 +21,7 @@ export const sampleReportSchema: ReportSchema = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "long-text",
|
type: "long-text",
|
||||||
name: "long",
|
id: "long",
|
||||||
description: {
|
description: {
|
||||||
en: "Long text field, with <strong>HTML</strong> description",
|
en: "Long text field, with <strong>HTML</strong> description",
|
||||||
pl: "Długie pole tekstowe, z opisem w formacie <strong>HTML</strong>"
|
pl: "Długie pole tekstowe, z opisem w formacie <strong>HTML</strong>"
|
||||||
@ -32,7 +33,7 @@ export const sampleReportSchema: ReportSchema = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "radio",
|
type: "radio",
|
||||||
name: "radio",
|
id: "radio",
|
||||||
description: {
|
description: {
|
||||||
en: "single choice field, with <strong>HTML</strong> description",
|
en: "single choice field, with <strong>HTML</strong> description",
|
||||||
pl: "Pole jednokrotnego wyboru, z opisem w formacie <strong>HTML</strong>"
|
pl: "Pole jednokrotnego wyboru, z opisem w formacie <strong>HTML</strong>"
|
||||||
@ -45,7 +46,7 @@ export const sampleReportSchema: ReportSchema = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: "select",
|
type: "select",
|
||||||
name: "select",
|
id: "select",
|
||||||
description: {
|
description: {
|
||||||
en: "select field, with <strong>HTML</strong> description",
|
en: "select field, with <strong>HTML</strong> description",
|
||||||
pl: "Pole jednokrotnego wyboru z selectboxem, z opisem w formacie <strong>HTML</strong>"
|
pl: "Pole jednokrotnego wyboru z selectboxem, z opisem w formacie <strong>HTML</strong>"
|
||||||
@ -57,8 +58,8 @@ export const sampleReportSchema: ReportSchema = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "multi",
|
|
||||||
type: "checkbox",
|
type: "checkbox",
|
||||||
|
id: "multi",
|
||||||
description: {
|
description: {
|
||||||
en: "Multiple choice field, with <strong>HTML</strong> description",
|
en: "Multiple choice field, with <strong>HTML</strong> description",
|
||||||
pl: "Pole wielokrotnego wyboru, z opisem w formacie <strong>HTML</strong>"
|
pl: "Pole wielokrotnego wyboru, z opisem w formacie <strong>HTML</strong>"
|
||||||
@ -73,8 +74,10 @@ export const sampleReportSchema: ReportSchema = [
|
|||||||
|
|
||||||
export const emptyReport: Report = {
|
export const emptyReport: Report = {
|
||||||
fields: {
|
fields: {
|
||||||
"short": "Testowa wartość",
|
"field_short": "Testowa wartość",
|
||||||
"select": choices[0],
|
"field_select": choices[0],
|
||||||
"multi": [ choices[1], choices[2] ],
|
"field_multi": [ choices[1], choices[2] ],
|
||||||
}
|
},
|
||||||
|
comment: "",
|
||||||
|
state: "draft",
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,7 @@ export interface ReceivePlanDeclineAction extends ReceiveSubmissionDeclineAction
|
|||||||
export interface ReceivePlanUpdateAction extends ReceiveSubmissionUpdateAction<InternshipPlanActions.Receive> {
|
export interface ReceivePlanUpdateAction extends ReceiveSubmissionUpdateAction<InternshipPlanActions.Receive> {
|
||||||
document: InternshipDocument;
|
document: InternshipDocument;
|
||||||
state: SubmissionState;
|
state: SubmissionState;
|
||||||
|
comment?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SavePlanAction extends SaveSubmissionAction<InternshipPlanActions.Save> {
|
export interface SavePlanAction extends SaveSubmissionAction<InternshipPlanActions.Save> {
|
||||||
|
@ -15,11 +15,15 @@ export enum InternshipReportActions {
|
|||||||
Approve = "RECEIVE_REPORT_APPROVE",
|
Approve = "RECEIVE_REPORT_APPROVE",
|
||||||
Decline = "RECEIVE_REPORT_DECLINE",
|
Decline = "RECEIVE_REPORT_DECLINE",
|
||||||
Receive = "RECEIVE_REPORT_STATE",
|
Receive = "RECEIVE_REPORT_STATE",
|
||||||
|
Reset = "RESET_REPORT",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendReportAction extends SendSubmissionAction<InternshipReportActions.Send> {
|
export interface SendReportAction extends SendSubmissionAction<InternshipReportActions.Send> {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ResetReportAction extends SendSubmissionAction<InternshipReportActions.Reset> {
|
||||||
|
}
|
||||||
|
|
||||||
export interface ReceiveReportApproveAction extends ReceiveSubmissionApproveAction<InternshipReportActions.Approve> {
|
export interface ReceiveReportApproveAction extends ReceiveSubmissionApproveAction<InternshipReportActions.Approve> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,6 +33,7 @@ export interface ReceiveReportDeclineAction extends ReceiveSubmissionDeclineActi
|
|||||||
export interface ReceiveReportUpdateAction extends ReceiveSubmissionUpdateAction<InternshipReportActions.Receive> {
|
export interface ReceiveReportUpdateAction extends ReceiveSubmissionUpdateAction<InternshipReportActions.Receive> {
|
||||||
report: Report;
|
report: Report;
|
||||||
state: SubmissionState,
|
state: SubmissionState,
|
||||||
|
comment: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SaveReportAction extends SaveSubmissionAction<InternshipReportActions.Save> {
|
export interface SaveReportAction extends SaveSubmissionAction<InternshipReportActions.Save> {
|
||||||
@ -38,6 +43,7 @@ export interface SaveReportAction extends SaveSubmissionAction<InternshipReportA
|
|||||||
export type InternshipReportAction
|
export type InternshipReportAction
|
||||||
= SendReportAction
|
= SendReportAction
|
||||||
| SaveReportAction
|
| SaveReportAction
|
||||||
|
| ResetReportAction
|
||||||
| ReceiveReportApproveAction
|
| ReceiveReportApproveAction
|
||||||
| ReceiveReportDeclineAction
|
| ReceiveReportDeclineAction
|
||||||
| ReceiveReportUpdateAction;
|
| ReceiveReportUpdateAction;
|
||||||
|
@ -54,6 +54,7 @@ const internshipPlanReducer = (state: InternshipPlanState = defaultInternshipPla
|
|||||||
ApiSubmissionState.Rejected,
|
ApiSubmissionState.Rejected,
|
||||||
ApiSubmissionState.Submitted
|
ApiSubmissionState.Submitted
|
||||||
].includes(action.state),
|
].includes(action.state),
|
||||||
|
comment: action.comment || null,
|
||||||
document: action.document,
|
document: action.document,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,8 @@ const internshipReportReducer = (state: InternshipReportState = defaultInternshi
|
|||||||
state = internshipReportSubmissionReducer(state, action);
|
state = internshipReportSubmissionReducer(state, action);
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
case InternshipReportActions.Reset:
|
||||||
|
return defaultInternshipReportState;
|
||||||
case InternshipReportActions.Save:
|
case InternshipReportActions.Save:
|
||||||
case InternshipReportActions.Send:
|
case InternshipReportActions.Send:
|
||||||
return {
|
return {
|
||||||
@ -57,6 +59,7 @@ const internshipReportReducer = (state: InternshipReportState = defaultInternshi
|
|||||||
ApiSubmissionState.Submitted
|
ApiSubmissionState.Submitted
|
||||||
].includes(action.state),
|
].includes(action.state),
|
||||||
report: reportSerializationTransformer.transform(action.report),
|
report: reportSerializationTransformer.transform(action.report),
|
||||||
|
comment: action.comment,
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
|
Loading…
Reference in New Issue
Block a user