Fix multiple issues with forms

This commit is contained in:
Kacper Donat 2020-10-18 13:48:05 +02:00
parent 263be22901
commit 5879efc978
12 changed files with 96 additions and 35 deletions

View File

@ -1,4 +1,4 @@
import { Company, Identifiable, Internship, Mentor, Office } from "@/data"; import { Address, Company, Identifiable, Internship, Mentor, Office } from "@/data";
import { momentSerializationTransformer, OneWayTransformer } from "@/serialization"; import { momentSerializationTransformer, OneWayTransformer } from "@/serialization";
import { Nullable } from "@/helpers"; import { Nullable } from "@/helpers";
import { MentorDTO, mentorDtoTransformer } from "@/api/dto/mentor"; import { MentorDTO, mentorDtoTransformer } from "@/api/dto/mentor";
@ -7,24 +7,34 @@ import { Moment } from "moment";
import { sampleStudent } from "@/provider/dummy"; import { sampleStudent } from "@/provider/dummy";
export enum SubmissionState { export enum SubmissionState {
Draft, Draft = "Draft",
Submitted, Submitted = "Submitted",
Accepted, Accepted = "Accepted",
Rejected, Rejected = "Rejected",
Archival, Archival = "Archival",
}
export interface NewBranchOffice extends Address {
} }
export interface InternshipRegistrationUpdateCompany { export interface InternshipRegistrationUpdateCompany {
id: string, id: string,
branchOffice: Identifiable, branchOffice: Identifiable | NewBranchOffice,
}
export interface NewCompany {
nip: string;
name: string;
branchOffice: NewBranchOffice | null;
} }
export interface InternshipRegistrationUpdate { export interface InternshipRegistrationUpdate {
company: InternshipRegistrationUpdateCompany, company: InternshipRegistrationUpdateCompany | NewCompany,
start: string, start: string,
end: string, end: string,
type: number, type: number,
mentor: MentorDTO, mentor: MentorDTO,
hours: number,
} }
export interface InternshipRegistrationDTO extends Identifiable { export interface InternshipRegistrationDTO extends Identifiable {
@ -35,8 +45,11 @@ export interface InternshipRegistrationDTO extends Identifiable {
mentor: MentorDTO, mentor: MentorDTO,
company: Company, company: Company,
branchAddress: Office, branchAddress: Office,
declaredHours: number,
} }
const reference = (subject: Identifiable | null): Identifiable | null => subject && { id: subject.id };
export interface InternshipInfoDTO { export interface InternshipInfoDTO {
internshipRegistration: InternshipRegistrationDTO; internshipRegistration: InternshipRegistrationDTO;
} }
@ -48,12 +61,17 @@ export const internshipRegistrationUpdateTransformer: OneWayTransformer<Nullable
end: subject?.endDate?.toISOString() || null, end: subject?.endDate?.toISOString() || null,
type: parseInt(subject?.type?.id || "0"), type: parseInt(subject?.type?.id || "0"),
mentor: mentorDtoTransformer.reverseTransform(subject.mentor as Mentor), mentor: mentorDtoTransformer.reverseTransform(subject.mentor as Mentor),
company: { company: subject?.company?.id ? {
id: subject?.company?.id as string, id: subject?.company?.id as string,
branchOffice: { branchOffice: subject?.office?.id
id: subject?.office?.id ? reference(subject?.office) as Identifiable
}, : subject?.office?.address as NewBranchOffice,
} } : {
name: subject?.company?.name as string,
nip: subject?.company?.nip as string,
branchOffice: subject?.office?.address as NewBranchOffice
},
hours: subject?.hours,
} }
} }
} }
@ -68,7 +86,7 @@ export const internshipRegistrationDtoTransformer: OneWayTransformer<InternshipR
startDate: momentSerializationTransformer.reverseTransform(dto.start) as Moment, startDate: momentSerializationTransformer.reverseTransform(dto.start) as Moment,
endDate: momentSerializationTransformer.reverseTransform(dto.end) as Moment, endDate: momentSerializationTransformer.reverseTransform(dto.end) as Moment,
type: internshipTypeDtoTransformer.transform(dto.type), type: internshipTypeDtoTransformer.transform(dto.type),
hours: 0, hours: dto.declaredHours,
isAccepted: dto.state === SubmissionState.Accepted, isAccepted: dto.state === SubmissionState.Accepted,
lengthInWeeks: 0, lengthInWeeks: 0,
program: [], program: [],

View File

@ -10,6 +10,7 @@ import * as student from "./student";
import * as type from "./type"; 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";
export const axios = Axios.create({ export const axios = Axios.create({
baseURL: process.env.API_BASE_URL || "https://system-praktyk.stg.kadet.net/api/", baseURL: process.env.API_BASE_URL || "https://system-praktyk.stg.kadet.net/api/",
@ -40,6 +41,7 @@ const api = {
type, type,
companies, companies,
internship, internship,
upload
} }
export default api; export default api;

View File

@ -2,10 +2,11 @@ import { InternshipInfoDTO, InternshipRegistrationUpdate } from "@/api/dto/inter
import { axios } from "@/api/index"; import { axios } from "@/api/index";
import { Nullable } from "@/helpers"; import { Nullable } from "@/helpers";
const INTERNSHIP_ENDPOINT = '/internshipRegistration'; const INTERNSHIP_REGISTRATION_ENDPOINT = '/internshipRegistration';
const INTERNSHIP_ENDPOINT = '/internship';
export async function update(internship: Nullable<InternshipRegistrationUpdate>): Promise<boolean> { export async function update(internship: Nullable<InternshipRegistrationUpdate>): Promise<boolean> {
const response = await axios.put(INTERNSHIP_ENDPOINT, internship); const response = await axios.put(INTERNSHIP_REGISTRATION_ENDPOINT, internship);
return true; return true;
} }

23
src/api/upload.ts Normal file
View File

@ -0,0 +1,23 @@
import { Identifiable } from "@/data";
import { axios } from "@/api/index";
export enum UploadType {
Ipp = "IppScan",
DeanConsent = "DeanConsent",
Insurance = "NnwInsurance",
}
const CREATE_DOCUMENT_ENDPOINT = '/document';
const DOCUMENT_UPLOAD_ENDPOINT = '/document/:id/scan';
interface Document extends Identifiable {
description?: string;
type: UploadType;
}
export async function create(type: UploadType, content: File)
{
const response = await axios.post<Document>(CREATE_DOCUMENT_ENDPOINT, { type });
console.log(response.data);
}

View File

@ -103,7 +103,7 @@ export const BranchForm: React.FC = () => {
onInputChange={ handleCityInput } onInputChange={ handleCityInput }
onBlur={ ev => setFieldTouched("city", true) } onBlur={ ev => setFieldTouched("city", true) }
inputValue={ values.city } inputValue={ values.city }
value={ values.office ? values.office : null } value={ values.office ? values.office : values.city }
freeSolo freeSolo
/> />
</Grid> </Grid>
@ -155,9 +155,15 @@ export const CompanyForm: React.FunctionComponent = () => {
const canEdit = useMemo(() => !values.company, [values.company]); const canEdit = useMemo(() => !values.company, [values.company]);
useEffect(() => { useEffect(() => {
if (!input || values.companyName == input) {
return;
}
(async () => { (async () => {
setCompanies(await api.companies.search(input)); setCompanies(await api.companies.search(input));
})() })()
setValues({ ...values, company: null, companyName: input }, true)
}, [ input ]); }, [ input ]);
const handleCompanyChange = (event: any, value: Company | string | null) => { const handleCompanyChange = (event: any, value: Company | string | null) => {
@ -194,7 +200,9 @@ export const CompanyForm: React.FunctionComponent = () => {
renderOption={ company => <CompanyItem company={ company }/> } renderOption={ company => <CompanyItem company={ company }/> }
renderInput={ props => <TextField { ...props } label={ t("forms.internship.fields.company-name") } fullWidth renderInput={ props => <TextField { ...props } label={ t("forms.internship.fields.company-name") } fullWidth
error={ touched.companyName && !!errors.companyName } helperText={ touched.companyName && errors.companyName }/> } error={ touched.companyName && !!errors.companyName } helperText={ touched.companyName && errors.companyName }/> }
onChange={ handleCompanyChange } value={ values.company || values.companyName } onChange={ handleCompanyChange }
value={ values.company || values.companyName }
inputValue={ input }
freeSolo freeSolo
onInputChange={ (_, value) => setInput(value) } onInputChange={ (_, value) => setInput(value) }
/> />

View File

@ -97,7 +97,7 @@ const InternshipProgramForm = () => {
renderOption={ (option: InternshipType) => <InternshipTypeItem internshipType={ option }/> } renderOption={ (option: InternshipType) => <InternshipTypeItem internshipType={ option }/> }
options={ types } options={ types }
disableClearable disableClearable
value={ values.kind || undefined } value={ values.kind || null as any }
onChange={ (_, value) => setFieldValue("kind", value) } onChange={ (_, value) => setFieldValue("kind", value) }
onBlur={ handleBlur } onBlur={ handleBlur }
/> />
@ -234,7 +234,7 @@ const converter: Transformer<Nullable<Internship>, InternshipFormValues, Interns
nip: form.companyNip, nip: form.companyNip,
offices: [], offices: [],
}, },
hours: form.hours as number, hours: form.hours ? form.hours : 0,
type: form.kind as InternshipType, type: form.kind as InternshipType,
} }
} }
@ -299,6 +299,8 @@ export const InternshipForm: React.FunctionComponent = () => {
const internship = converter.reverseTransform(values, { internship: initialInternship as Internship }); const internship = converter.reverseTransform(values, { internship: initialInternship as Internship });
const update = internshipRegistrationUpdateTransformer.transform(internship); const update = internshipRegistrationUpdateTransformer.transform(internship);
console.log(update);
api.internship.update(update); api.internship.update(update);
// history.push(route("home")) // history.push(route("home"))
@ -308,8 +310,8 @@ export const InternshipForm: React.FunctionComponent = () => {
const { submitForm, validateForm } = useFormikContext(); const { submitForm, validateForm } = useFormikContext();
const handleSubmitConfirmation = async () => { const handleSubmitConfirmation = async () => {
const errors = await validateForm(); // const errors = await validateForm();
const errors = {};
if (Object.keys(errors).length == 0) { if (Object.keys(errors).length == 0) {
setConfirmDialogOpen(true); setConfirmDialogOpen(true);
} else { } else {

View File

@ -7,7 +7,9 @@ import { route } from "@/routing";
import React, { useState } from "react"; import React, { useState } from "react";
import { Plan } from "@/data"; import { Plan } from "@/data";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { InternshipPlanActions, useDispatch } from "@/state/actions"; import { useDispatch } from "@/state/actions";
import { UploadType } from "@/api/upload";
import api from "@/api";
export const PlanForm = () => { export const PlanForm = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -18,7 +20,8 @@ export const PlanForm = () => {
const history = useHistory(); const history = useHistory();
const handleSubmit = () => { const handleSubmit = () => {
dispatch({ type: InternshipPlanActions.Send, plan }); api.upload.create(UploadType.Ipp, null as any);
// dispatch({ type: InternshipPlanActions.Send, plan });
history.push(route("home")) history.push(route("home"))
} }

View File

@ -33,7 +33,7 @@ export const StudentForm = () => {
/> />
</Grid> </Grid>
<Grid item md={3}> <Grid item md={3}>
<TextField label={ t("forms.internship.fields.semester") } value={ student.semester } disabled fullWidth/> <TextField label={ t("forms.internship.fields.semester") } value={ student.semester || "" } disabled fullWidth/>
</Grid> </Grid>
<Grid item> <Grid item>
<Alert severity="warning" action={ <Button color="inherit" size="small">skontaktuj się z opiekunem</Button> }> <Alert severity="warning" action={ <Button color="inherit" size="small">skontaktuj się z opiekunem</Button> }>

View File

@ -5,21 +5,21 @@ import { Redirect } from "react-router-dom";
import React from "react"; import React from "react";
import { UserState } from "@/state/reducer/user"; import { UserState } from "@/state/reducer/user";
export const isReadyMiddleware: Middleware<any, any> = next => isLoggedInMiddleware(() => { export const isReadyMiddleware: Middleware<any, any> = Next => isLoggedInMiddleware(() => {
const ready = useSelector(isReady); const ready = useSelector(isReady);
if (ready) { if (ready) {
return <>{ next() }</>; return <Next />;
} }
return <Redirect to={ route("edition_pick") } />; return <Redirect to={ route("edition_pick") } />;
}) })
export const isLoggedInMiddleware: Middleware<any, any> = next => { export const isLoggedInMiddleware: Middleware<any, any> = Next => {
const user = useSelector<AppState>(state => state.user) as UserState; const user = useSelector<AppState>(state => state.user) as UserState;
if (user.loggedIn) { if (user.loggedIn) {
return <>{ next() }</>; return <Next />;
} }
return <Redirect to={ route("user_login") } />; return <Redirect to={ route("user_login") } />;

View File

@ -115,10 +115,6 @@ export const InternshipProposalPreviewPage = () => {
{ proposal && <ProposalPreview proposal={ proposal } /> } { proposal && <ProposalPreview proposal={ proposal } /> }
<Actions> <Actions>
<Button component={ RouterLink } to={ route("home") } variant="contained" color="primary">
{ t('go-back') }
</Button>
<ButtonGroup color="primary" variant="contained"> <ButtonGroup color="primary" variant="contained">
<Button onClick={ handleAcceptWithoutComment } startIcon={ <StickerCheckOutline /> }> <Button onClick={ handleAcceptWithoutComment } startIcon={ <StickerCheckOutline /> }>
{ t('accept-without-comments') } { t('accept-without-comments') }
@ -134,6 +130,10 @@ export const InternshipProposalPreviewPage = () => {
<Button onClick={ handleDiscardAction } color="secondary" startIcon={ <StickerRemoveOutline /> }> <Button onClick={ handleDiscardAction } color="secondary" startIcon={ <StickerRemoveOutline /> }>
{ t('discard') } { t('discard') }
</Button> </Button>
<Button component={ RouterLink } to={ route("home") }>
{ t('go-back') }
</Button>
</Actions> </Actions>
</Container> </Container>
<Dialog open={ isDiscardModalOpen } onClose={ handleDiscardModalClose } maxWidth="md"> <Dialog open={ isDiscardModalOpen } onClose={ handleDiscardModalClose } maxWidth="md">

View File

@ -47,7 +47,7 @@ export const UserProfilePage = () => {
</Box> </Box>
</Paper> </Paper>
<Actions> <Actions>
<Button variant="contained" component={ RouterLink } to={ route("home") }> <Button component={ RouterLink } to={ route("home") }>
{ t('go-back') } { t('go-back') }
</Button> </Button>
</Actions> </Actions>

View File

@ -1,15 +1,19 @@
import { Edition } from "@/data/edition"; import { Edition } from "@/data/edition";
import { EditionAction, EditionActions } from "@/state/actions/edition"; import { EditionAction, EditionActions } from "@/state/actions/edition";
import { editionSerializationTransformer, Serializable } from "@/serialization"; import { editionSerializationTransformer, Serializable } from "@/serialization";
import { LoginAction, LogoutAction, UserActions } from "@/state/actions";
export type EditionState = Serializable<Edition> | null; export type EditionState = Serializable<Edition> | null;
const initialEditionState: EditionState = null; const initialEditionState: EditionState = null;
const editionReducer = (state: EditionState = initialEditionState, action: EditionAction): EditionState => { const editionReducer = (state: EditionState = initialEditionState, action: EditionAction | LogoutAction | LoginAction): EditionState => {
switch (action.type) { switch (action.type) {
case EditionActions.Set: case EditionActions.Set:
return editionSerializationTransformer.transform(action.edition); return editionSerializationTransformer.transform(action.edition);
case UserActions.Login:
case UserActions.Logout:
return initialEditionState;
} }
return state; return state;