Merge pull request 'Add mentor information to form' (#3) from feature_basic_form into master
This commit is contained in:
		
						commit
						94e33f4baa
					
				| @ -6,7 +6,7 @@ | |||||||
|     <meta name="theme-color" content="#000000" /> |     <meta name="theme-color" content="#000000" /> | ||||||
|     <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap&subset=latin,latin-ext" /> |     <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap&subset=latin,latin-ext" /> | ||||||
|     <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> |     <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> | ||||||
|     <title>React App</title> |     <title>Zgłoszenie praktyki studenckiej</title> | ||||||
|   </head> |   </head> | ||||||
|   <body> |   <body> | ||||||
|     <noscript>You need to enable JavaScript to run this app.</noscript> |     <noscript>You need to enable JavaScript to run this app.</noscript> | ||||||
|  | |||||||
| @ -3,4 +3,3 @@ export * from './company' | |||||||
| export * from './course' | export * from './course' | ||||||
| export * from './internship' | export * from './internship' | ||||||
| export * from './student' | export * from './student' | ||||||
| export { emptyInternship } from "@/provider/dummy/internship"; |  | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ import { Moment } from "moment"; | |||||||
| import { Identifiable } from "./common"; | import { Identifiable } from "./common"; | ||||||
| import { countWorkingWeeksInRange } from "@/utils/date"; | import { countWorkingWeeksInRange } from "@/utils/date"; | ||||||
| import { Student } from "@/data/student"; | import { Student } from "@/data/student"; | ||||||
|  | import { Company } from "@/data/company"; | ||||||
| 
 | 
 | ||||||
| export enum InternshipType { | export enum InternshipType { | ||||||
|     FreeInternship = "FreeInternship", |     FreeInternship = "FreeInternship", | ||||||
| @ -61,4 +62,13 @@ export interface Internship extends Identifiable { | |||||||
|     endDate: Moment; |     endDate: Moment; | ||||||
|     isAccepted: boolean; |     isAccepted: boolean; | ||||||
|     lengthInWeeks: number; |     lengthInWeeks: number; | ||||||
|  |     mentor: Mentor; | ||||||
|  |     company: Company; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export interface Mentor { | ||||||
|  |     name: string; | ||||||
|  |     surname: string; | ||||||
|  |     email: string; | ||||||
|  |     phone: string | null; | ||||||
| } | } | ||||||
|  | |||||||
| @ -3,7 +3,7 @@ import { Identifiable } from "./common"; | |||||||
| 
 | 
 | ||||||
| export type Semester = number; | export type Semester = number; | ||||||
| 
 | 
 | ||||||
| export interface Student extends Identifiable{ | export interface Student extends Identifiable { | ||||||
|     name: string; |     name: string; | ||||||
|     surname: string; |     surname: string; | ||||||
|     email: string; |     email: string; | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| import React, { ChangeEvent, HTMLProps, useMemo, useState } from "react"; | import React, { HTMLProps, useMemo, useState } from "react"; | ||||||
| import { | import { | ||||||
|     FormControl, |     FormControl, | ||||||
|     Grid, |     Grid, | ||||||
| @ -17,12 +17,13 @@ import { KeyboardDatePicker as DatePicker } from "@material-ui/pickers"; | |||||||
| import { CompanyForm } from "@/forms/company"; | import { CompanyForm } from "@/forms/company"; | ||||||
| import { StudentForm } from "@/forms/student"; | import { StudentForm } from "@/forms/student"; | ||||||
| import { sampleStudent } from "@/provider/dummy/student"; | import { sampleStudent } from "@/provider/dummy/student"; | ||||||
| import { Company, Course, emptyInternship, Internship, InternshipType, internshipTypeLabels } from "@/data"; | import { Course, Internship, InternshipType, internshipTypeLabels } from "@/data"; | ||||||
| import { Nullable } from "@/helpers"; | import { Nullable } from "@/helpers"; | ||||||
| import moment, { Moment } from "moment"; | import moment, { Moment } from "moment"; | ||||||
| import { computeWorkingHours } from "@/utils/date"; | import { computeWorkingHours } from "@/utils/date"; | ||||||
| import { Autocomplete } from "@material-ui/lab"; | import { Autocomplete } from "@material-ui/lab"; | ||||||
| import { formFieldProps } from "@/forms/helpers"; | import { formFieldProps } from "@/forms/helpers"; | ||||||
|  | import { emptyInternship } from "@/provider/dummy/internship"; | ||||||
| 
 | 
 | ||||||
| export type InternshipFormProps = {} | export type InternshipFormProps = {} | ||||||
| 
 | 
 | ||||||
| @ -150,7 +151,7 @@ export const InternshipForm: React.FunctionComponent<InternshipFormProps> = prop | |||||||
|             <Typography variant="h5" className="section-header">Czas trwania praktyki</Typography> |             <Typography variant="h5" className="section-header">Czas trwania praktyki</Typography> | ||||||
|             <InternshipDurationForm internship={ internship } onChange={ setInternship }/> |             <InternshipDurationForm internship={ internship } onChange={ setInternship }/> | ||||||
|             <Typography variant="h5" className="section-header">Miejsce odbywania praktyki</Typography> |             <Typography variant="h5" className="section-header">Miejsce odbywania praktyki</Typography> | ||||||
|             <CompanyForm/> |             <CompanyForm internship={ internship } onChange={ setInternship }/> | ||||||
|             <Button variant="contained" color="primary">Wyślij</Button> |             <Button variant="contained" color="primary">Wyślij</Button> | ||||||
|         </div> |         </div> | ||||||
|     ) |     ) | ||||||
|  | |||||||
| @ -1,11 +1,14 @@ | |||||||
| import React, { HTMLProps, useEffect, useMemo, useState } from "react"; | import React, { HTMLProps, useEffect, useMemo, useState } from "react"; | ||||||
| import { BranchOffice, Company, emptyAddress, emptyBranchOffice, emptyCompany, formatAddress } from "@/data"; | import { BranchOffice, Company, Course, emptyAddress, emptyBranchOffice, emptyCompany, formatAddress, Mentor } from "@/data"; | ||||||
| import { sampleCompanies } from "@/provider/dummy"; | import { sampleCompanies } from "@/provider/dummy"; | ||||||
| import { Autocomplete } from "@material-ui/lab"; | import { Alert, Autocomplete } from "@material-ui/lab"; | ||||||
| import { Grid, TextField, Typography } from "@material-ui/core"; | import { Button, Grid, TextField, Typography } from "@material-ui/core"; | ||||||
| import { formFieldProps } from "./helpers"; | import { BoundProperty, formFieldProps } from "./helpers"; | ||||||
|  | import { InternshipFormSectionProps } from "@/forms/Internship"; | ||||||
|  | import { sampleCourse } from "@/provider/dummy/student"; | ||||||
|  | import { emptyMentor } from "@/provider/dummy/internship"; | ||||||
| 
 | 
 | ||||||
| export type CompanyFormProps = {} | export type CompanyFormProps = {} & InternshipFormSectionProps; | ||||||
| 
 | 
 | ||||||
| export type BranchOfficeProps = { | export type BranchOfficeProps = { | ||||||
|     company: Company, |     company: Company, | ||||||
| @ -95,10 +98,38 @@ export const BranchForm: React.FC<BranchOfficeProps> = ({ company, disabled = fa | |||||||
|     ) |     ) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const CompanyForm: React.FunctionComponent<CompanyFormProps> = props => { | export const MentorForm = ({ mentor, onMentorChange }: BoundProperty<Mentor, 'onMentorChange', 'mentor'>) => { | ||||||
|  |     const fieldProps = formFieldProps(mentor, onMentorChange) | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |         <> | ||||||
|  |             <Grid container> | ||||||
|  |                 <Grid item md={6}> | ||||||
|  |                     <TextField label="Imię" fullWidth { ...fieldProps("name") }/> | ||||||
|  |                 </Grid> | ||||||
|  |                 <Grid item md={6}> | ||||||
|  |                     <TextField label="Nazwisko" value={ mentor.surname } fullWidth { ...fieldProps("surname") }/> | ||||||
|  |                 </Grid> | ||||||
|  |                 <Grid item md={8}> | ||||||
|  |                     <TextField label="E-mail" value={ mentor.email } fullWidth { ...fieldProps("email") }/> | ||||||
|  |                 </Grid> | ||||||
|  |                 <Grid item md={4}> | ||||||
|  |                     <TextField label="Nr telefonu" value={ mentor.phone } fullWidth { ...fieldProps("phone") }/> | ||||||
|  |                 </Grid> | ||||||
|  |             </Grid> | ||||||
|  |         </> | ||||||
|  |     ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export const CompanyForm: React.FunctionComponent<CompanyFormProps> = ({ internship, onChange }) => { | ||||||
|     const [company, setCompany] = useState<Company>(emptyCompany); |     const [company, setCompany] = useState<Company>(emptyCompany); | ||||||
|  |     const [mentor, setMentor] = useState<Mentor>(emptyMentor); | ||||||
|  | 
 | ||||||
|     const canEdit = useMemo(() => !company.id, [company.id]); |     const canEdit = useMemo(() => !company.id, [company.id]); | ||||||
| 
 | 
 | ||||||
|  |     useEffect(() => onChange({ ...internship, mentor }), [ mentor ]); | ||||||
|  |     useEffect(() => onChange({ ...internship, company }), [ company ]); | ||||||
|  | 
 | ||||||
|     const fieldProps = formFieldProps(company, setCompany) |     const fieldProps = formFieldProps(company, setCompany) | ||||||
| 
 | 
 | ||||||
|     const handleCompanyChange = (event: any, value: Company | string | null) => { |     const handleCompanyChange = (event: any, value: Company | string | null) => { | ||||||
| @ -133,6 +164,8 @@ export const CompanyForm: React.FunctionComponent<CompanyFormProps> = props => { | |||||||
|                 {/*    <TextField label={ "Url" } fullWidth { ...fieldProps("url") } disabled={ !canEdit }/>*/} |                 {/*    <TextField label={ "Url" } fullWidth { ...fieldProps("url") } disabled={ !canEdit }/>*/} | ||||||
|                 {/*</Grid>*/} |                 {/*</Grid>*/} | ||||||
|             </Grid> |             </Grid> | ||||||
|  |             <Typography variant="subtitle1" className="subsection-header">Zakładowy opiekun praktyki</Typography> | ||||||
|  |             <MentorForm mentor={ mentor } onMentorChange={ setMentor }/> | ||||||
|             <Typography variant="subtitle1" className="subsection-header">Oddział</Typography> |             <Typography variant="subtitle1" className="subsection-header">Oddział</Typography> | ||||||
|             <BranchForm company={ company }/> |             <BranchForm company={ company }/> | ||||||
|         </> |         </> | ||||||
|  | |||||||
| @ -2,22 +2,29 @@ import { DOMEvent } from "@/helpers"; | |||||||
| 
 | 
 | ||||||
| type UpdatingEvent = "onBlur" | "onChange" | "onInput"; | type UpdatingEvent = "onBlur" | "onChange" | "onInput"; | ||||||
| type FormFieldHelperOptions<T> = { | type FormFieldHelperOptions<T> = { | ||||||
|     event: UpdatingEvent |     event: UpdatingEvent, | ||||||
|  |     property: string, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function formFieldProps<T>(subject: T, update: (value: T) => void, options: Partial<FormFieldHelperOptions<T>> = {}) { | export function formFieldProps<T>(subject: T, update: (value: T) => void, options: Partial<FormFieldHelperOptions<T>> = {}) { | ||||||
|     const { |     const { | ||||||
|         event = "onChange" |         event = "onChange", | ||||||
|  |         property = "value", | ||||||
|     } = options; |     } = options; | ||||||
| 
 | 
 | ||||||
|     return <P extends keyof T, TArgs extends any[]>( |     return <P extends keyof T, TArgs extends any[]>( | ||||||
|         field: P, |         field: P, | ||||||
|         extractor: (...args: TArgs) => T[P] = ((event: DOMEvent<HTMLInputElement>) => event.target.value as unknown as T[P]) as any |         extractor: (...args: TArgs) => T[P] = ((event: DOMEvent<HTMLInputElement>) => event.target.value as unknown as T[P]) as any | ||||||
|     ) => ({ |     ) => ({ | ||||||
|         value: subject[field], |         [property]: subject[field], | ||||||
|         [event]: (...args: TArgs) => update({ |         [event]: (...args: TArgs) => update({ | ||||||
|             ...subject, |             ...subject, | ||||||
|             [field]: extractor(...args), |             [field]: extractor(...args), | ||||||
|         } as T) |         } as T) | ||||||
|     }) |     }) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | export type BoundProperty<T, TEvent extends string = 'onChange', TProperty extends string = 'value'> = | ||||||
|  |     { [property in TProperty]: T; } & | ||||||
|  |     { [event in TEvent]: (value: T) => void; } | ||||||
|  | |||||||
| @ -4,9 +4,8 @@ import { makeIdSequence } from "./helpers"; | |||||||
| const companySequence = makeIdSequence(); | const companySequence = makeIdSequence(); | ||||||
| const officeSequence = makeIdSequence(); | const officeSequence = makeIdSequence(); | ||||||
| 
 | 
 | ||||||
| export const sampleCompanies: Company[] = [ | export const sampleCompanies: Company[] = companySequence.assignIds([ | ||||||
|     { |     { | ||||||
|         id: companySequence(), |  | ||||||
|         name: "Intel", |         name: "Intel", | ||||||
|         url: "https://www.intel.com/content/www/us/en/jobs/locations/poland.html", |         url: "https://www.intel.com/content/www/us/en/jobs/locations/poland.html", | ||||||
|         nip: "9570752316", |         nip: "9570752316", | ||||||
| @ -22,7 +21,6 @@ export const sampleCompanies: Company[] = [ | |||||||
|         }] |         }] | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         id: companySequence(), |  | ||||||
|         name: "IHS Markit", |         name: "IHS Markit", | ||||||
|         url: "http://ihsgdansk.com/", |         url: "http://ihsgdansk.com/", | ||||||
|         nip: "5842068320", |         nip: "5842068320", | ||||||
| @ -38,12 +36,10 @@ export const sampleCompanies: Company[] = [ | |||||||
|         }] |         }] | ||||||
|     }, |     }, | ||||||
|     { |     { | ||||||
|         id: companySequence(), |  | ||||||
|         name: "Asseco Poland", |         name: "Asseco Poland", | ||||||
|         url: "http://pl.asseco.com/", |         url: "http://pl.asseco.com/", | ||||||
|         nip: "5842068320", |         nip: "5842068320", | ||||||
|         offices: [{ |         offices: officeSequence.assignIds([{ | ||||||
|             id: officeSequence(), |  | ||||||
|             address: { |             address: { | ||||||
|                 city: "Gdynia", |                 city: "Gdynia", | ||||||
|                 street: "ul. Podolska", |                 street: "ul. Podolska", | ||||||
| @ -52,7 +48,6 @@ export const sampleCompanies: Company[] = [ | |||||||
|                 country: "Poland" |                 country: "Poland" | ||||||
|             } |             } | ||||||
|         }, { |         }, { | ||||||
|             id: officeSequence(), |  | ||||||
|             address: { |             address: { | ||||||
|                 city: "Łódź", |                 city: "Łódź", | ||||||
|                 street: "al. Marszałka Józefa Piłsudskiego", |                 street: "al. Marszałka Józefa Piłsudskiego", | ||||||
| @ -61,7 +56,6 @@ export const sampleCompanies: Company[] = [ | |||||||
|                 country: "Poland" |                 country: "Poland" | ||||||
|             } |             } | ||||||
|         }, { |         }, { | ||||||
|             id: officeSequence(), |  | ||||||
|             address: { |             address: { | ||||||
|                 city: "Wrocław", |                 city: "Wrocław", | ||||||
|                 street: "Traugutta", |                 street: "Traugutta", | ||||||
| @ -69,6 +63,6 @@ export const sampleCompanies: Company[] = [ | |||||||
|                 postalCode: "50-449", |                 postalCode: "50-449", | ||||||
|                 country: "Poland" |                 country: "Poland" | ||||||
|             } |             } | ||||||
|         }] |         }]) | ||||||
|     } |     } | ||||||
| ] | ]) | ||||||
|  | |||||||
| @ -1,5 +1,12 @@ | |||||||
| import { Nullable } from "@/helpers"; | import { Nullable } from "@/helpers"; | ||||||
| import { Internship, InternshipType } from "@/data"; | import { emptyCompany, Internship, Mentor } from "@/data"; | ||||||
|  | 
 | ||||||
|  | export const emptyMentor: Mentor = { | ||||||
|  |     phone: null, | ||||||
|  |     email: "", | ||||||
|  |     name: "", | ||||||
|  |     surname: "" | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| export const emptyInternship: Nullable<Internship> = { | export const emptyInternship: Nullable<Internship> = { | ||||||
|     intern: null, |     intern: null, | ||||||
| @ -9,4 +16,6 @@ export const emptyInternship: Nullable<Internship> = { | |||||||
|     program: null, |     program: null, | ||||||
|     isAccepted: false, |     isAccepted: false, | ||||||
|     lengthInWeeks: 0, |     lengthInWeeks: 0, | ||||||
|  |     mentor: emptyMentor, | ||||||
|  |     company: emptyCompany, | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user