Add internship type and program form section
This commit is contained in:
		
							parent
							
								
									8eae385d03
								
							
						
					
					
						commit
						48d2983e01
					
				| @ -26,7 +26,7 @@ function App() { | |||||||
|                   <div className="app"> |                   <div className="app"> | ||||||
|                       <Container maxWidth={"md"}> |                       <Container maxWidth={"md"}> | ||||||
|                           <Typography variant="h3">Zgłoszenie Praktyki</Typography> |                           <Typography variant="h3">Zgłoszenie Praktyki</Typography> | ||||||
|                           <Typography variant="subtitle1" style={{ marginBottom: '100px' }}>UX Demo</Typography> |                           <Typography variant="subtitle1">UX Demo</Typography> | ||||||
| 
 | 
 | ||||||
|                           <InternshipForm /> |                           <InternshipForm /> | ||||||
|                       </Container> |                       </Container> | ||||||
|  | |||||||
| @ -1,6 +1,7 @@ | |||||||
| import { Moment } from "moment"; | 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"; | ||||||
| 
 | 
 | ||||||
| export enum InternshipType { | export enum InternshipType { | ||||||
|     FreeInternship = "FreeInternship", |     FreeInternship = "FreeInternship", | ||||||
| @ -14,11 +15,46 @@ export enum InternshipType { | |||||||
|     Other = "Other", |     Other = "Other", | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export const internshipTypeLabels: { [type in InternshipType]: { label: string, description?: string } } = { | ||||||
|  |     [InternshipType.FreeInternship]: { | ||||||
|  |         label: "Umowa o organizację praktyki", | ||||||
|  |         description: "Praktyka bezpłatna" | ||||||
|  |     }, | ||||||
|  |     [InternshipType.GraduateInternship]: { | ||||||
|  |         label: "Umowa o praktykę absolwencką" | ||||||
|  |     }, | ||||||
|  |     [InternshipType.FreeApprenticeship]: { | ||||||
|  |         label: "Umowa o staż bezpłatny" | ||||||
|  |     }, | ||||||
|  |     [InternshipType.PaidApprenticeship]: { | ||||||
|  |         label: "Umowa o staż płatny", | ||||||
|  |         description: "np. przemysłowy" | ||||||
|  |     }, | ||||||
|  |     [InternshipType.ForeignInternship]: { | ||||||
|  |         label: "Praktyka zagraniczna", | ||||||
|  |         description: "np. IAESTE, ERASMUS" | ||||||
|  |     }, | ||||||
|  |     [InternshipType.UOP]: { | ||||||
|  |         label: "Umowa o pracę" | ||||||
|  |     }, | ||||||
|  |     [InternshipType.UD]: { | ||||||
|  |         label: "Umowa o dzieło (w tym B2B)" | ||||||
|  |     }, | ||||||
|  |     [InternshipType.UZ]: { | ||||||
|  |         label: "Umowa o zlecenie (w tym B2B)" | ||||||
|  |     }, | ||||||
|  |     [InternshipType.Other]: { | ||||||
|  |         label: "Inna", | ||||||
|  |         description: "Należy wprowadzić samodzielnie" | ||||||
|  |     }, | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export interface InternshipProgramEntry extends Identifiable { | export interface InternshipProgramEntry extends Identifiable { | ||||||
|     description: string; |     description: string; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface Internship extends Identifiable { | export interface Internship extends Identifiable { | ||||||
|  |     intern: Student, | ||||||
|     type: InternshipType; |     type: InternshipType; | ||||||
|     program: InternshipProgramEntry[]; |     program: InternshipProgramEntry[]; | ||||||
|     startDate: Moment; |     startDate: Moment; | ||||||
|  | |||||||
| @ -1,21 +1,83 @@ | |||||||
| import React, { ChangeEvent, useMemo, useState } from "react"; | import React, { ChangeEvent, HTMLProps, useMemo, useState } from "react"; | ||||||
| import { FormControl, Grid, Input, InputLabel, Typography, FormHelperText } from "@material-ui/core"; | import { | ||||||
| import { DatePicker } from "@material-ui/pickers"; |     FormControl, | ||||||
|  |     Grid, | ||||||
|  |     Input, | ||||||
|  |     InputLabel, | ||||||
|  |     Typography, | ||||||
|  |     FormHelperText, | ||||||
|  |     TextField, | ||||||
|  |     FormGroup, | ||||||
|  |     FormControlLabel, | ||||||
|  |     Checkbox, | ||||||
|  |     FormLabel, | ||||||
|  |     Button | ||||||
|  | } from "@material-ui/core"; | ||||||
|  | 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 { emptyInternship, Internship } from "@/data"; | import { Company, Course, emptyInternship, 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 { formFieldProps } from "@/forms/helpers"; | ||||||
| 
 | 
 | ||||||
| export type InternshipFormProps = {} | export type InternshipFormProps = {} | ||||||
| 
 | 
 | ||||||
| export type InternshipDetailsFormProps = { | export type InternshipFormSectionProps = { | ||||||
|     internship: Nullable<Internship> |     internship: Nullable<Internship>, | ||||||
|  |     onChange: (internship: Nullable<Internship>) => void, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const InternshipDurationForm = ({ internship }: InternshipDetailsFormProps) => { | export const InternshipTypeItem = ({ type, ...props }: { type: InternshipType } & HTMLProps<any>) => { | ||||||
|  |     const info = internshipTypeLabels[type]; | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |         <div className="internship=type-item" { ...props }> | ||||||
|  |             <div>{ info.label }</div> | ||||||
|  |             { info.description && <Typography variant="caption">{ info.description }</Typography> } | ||||||
|  |         </div> | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const InternshipProgramForm = ({ internship, onChange }: InternshipFormSectionProps) => { | ||||||
|  |     const fieldProps = formFieldProps(internship, onChange); | ||||||
|  | 
 | ||||||
|  |     const course = internship.intern?.course as Course; | ||||||
|  | 
 | ||||||
|  |     return ( | ||||||
|  |         <Grid container> | ||||||
|  |             <Grid item md={4}> | ||||||
|  |                 <Autocomplete renderInput={ props => <TextField { ...props } label="Rodzaj praktyki/umowy" fullWidth/> } | ||||||
|  |                               getOptionLabel={ (option: InternshipType) => internshipTypeLabels[option].label } | ||||||
|  |                               renderOption={ (option: InternshipType) => <InternshipTypeItem type={ option } /> } | ||||||
|  |                               options={ Object.values(InternshipType) as InternshipType[] } | ||||||
|  |                               disableClearable | ||||||
|  |                               { ...fieldProps("type", (event, value) => value) as any } | ||||||
|  |                 /> | ||||||
|  |             </Grid> | ||||||
|  |             <Grid item md={8}> | ||||||
|  |                 { internship.type === InternshipType.Other && <TextField label={"Inny - Wprowadź"} fullWidth/> } | ||||||
|  |             </Grid> | ||||||
|  |             <Grid item> | ||||||
|  |                 <FormGroup> | ||||||
|  |                     <FormLabel component="legend" className="subsection-header">Realizowane punkty programu praktyk (minimum 3)</FormLabel> | ||||||
|  |                     { course.possibleProgramEntries.map(entry => { | ||||||
|  |                         return ( | ||||||
|  |                             <FormControlLabel label={ entry.description } key={ entry.id } | ||||||
|  |                                               control={ <Checkbox /> } | ||||||
|  |                             /> | ||||||
|  |                         ) | ||||||
|  |                     }) } | ||||||
|  |                 </FormGroup> | ||||||
|  |             </Grid> | ||||||
|  |         </Grid> | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const InternshipDurationForm = ({ internship }: InternshipFormSectionProps) => { | ||||||
|     const [startDate, setStartDate] = useState<Moment | null>(internship.startDate); |     const [startDate, setStartDate] = useState<Moment | null>(internship.startDate); | ||||||
|     const [endDate, setEndDate] = useState<Moment | null>(internship.endDate); |     const [endDate, setEndDate] = useState<Moment | null>(internship.endDate); | ||||||
|     const [overrideHours, setHoursOverride] = useState<number | null>(null) |     const [overrideHours, setHoursOverride] = useState<number | null>(null) | ||||||
| @ -28,18 +90,21 @@ const InternshipDurationForm = ({ internship }: InternshipDetailsFormProps) => { | |||||||
| 
 | 
 | ||||||
|     return ( |     return ( | ||||||
|         <Grid container> |         <Grid container> | ||||||
|             <Grid item md={ 4 }> |             <Grid item md={ 6 }> | ||||||
|                 <DatePicker value={ startDate } onChange={ setStartDate } clearable variant="inline" label={ "Data rozpoczęcia praktyki" } disableToolbar |                 <DatePicker value={ startDate } onChange={ setStartDate } | ||||||
|                             fullWidth/> |                             format="DD MMMM yyyy" | ||||||
|  |                             clearable disableToolbar fullWidth | ||||||
|  |                             variant="inline" label={ "Data rozpoczęcia praktyki" } | ||||||
|  |                 /> | ||||||
|             </Grid> |             </Grid> | ||||||
|             <Grid item md={ 4 }> |             <Grid item md={ 6 }> | ||||||
|                 <DatePicker value={ endDate } onChange={ setEndDate } |                 <DatePicker value={ endDate } onChange={ setEndDate } | ||||||
|  |                             format="DD MMMM yyyy" | ||||||
|                             clearable disableToolbar fullWidth |                             clearable disableToolbar fullWidth | ||||||
|                             variant="inline" label={ "Data zakończenia praktyki" } |                             variant="inline" label={ "Data zakończenia praktyki" } | ||||||
|                             minDate={ startDate || moment() } |                             minDate={ startDate || moment() } | ||||||
|                 /> |                 /> | ||||||
|             </Grid> |             </Grid> | ||||||
|             <Grid item md={ 4 }/> |  | ||||||
|             <Grid item md={ 4 }> |             <Grid item md={ 4 }> | ||||||
|                 <FormControl fullWidth> |                 <FormControl fullWidth> | ||||||
|                     <InputLabel>Wymiar etatu</InputLabel> |                     <InputLabel>Wymiar etatu</InputLabel> | ||||||
| @ -66,6 +131,7 @@ const InternshipDurationForm = ({ internship }: InternshipDetailsFormProps) => { | |||||||
|                            disabled |                            disabled | ||||||
|                            fullWidth |                            fullWidth | ||||||
|                     /> |                     /> | ||||||
|  |                     <FormHelperText>Wyliczona automatycznie</FormHelperText> | ||||||
|                 </FormControl> |                 </FormControl> | ||||||
|             </Grid> |             </Grid> | ||||||
|         </Grid> |         </Grid> | ||||||
| @ -73,16 +139,19 @@ const InternshipDurationForm = ({ internship }: InternshipDetailsFormProps) => { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const InternshipForm: React.FunctionComponent<InternshipFormProps> = props => { | export const InternshipForm: React.FunctionComponent<InternshipFormProps> = props => { | ||||||
|     const [internship, setInternship] = useState<Nullable<Internship>>(emptyInternship) |     const [internship, setInternship] = useState<Nullable<Internship>>({ ...emptyInternship, intern: sampleStudent }) | ||||||
| 
 | 
 | ||||||
|     return ( |     return ( | ||||||
|         <div className="internship-form"> |         <div className="internship-form"> | ||||||
|             <Typography variant="h5">Dane osoby odbywającej praktykę</Typography> |             <Typography variant="h5" className="section-header">Dane osoby odbywającej praktykę</Typography> | ||||||
|             <StudentForm student={ sampleStudent }/> |             <StudentForm student={ sampleStudent }/> | ||||||
|             <Typography variant="h5" style={ { marginTop: "1rem" } }>Czas trwania praktyki</Typography> |             <Typography variant="h5" className="section-header">Rodzaj i program praktyki</Typography> | ||||||
|             <InternshipDurationForm internship={ internship }/> |             <InternshipProgramForm internship={ internship } onChange={ setInternship }/> | ||||||
|             <Typography variant="h5" style={ { marginTop: "1rem" } }>Miejsce odbywania praktyki</Typography> |             <Typography variant="h5" className="section-header">Czas trwania praktyki</Typography> | ||||||
|  |             <InternshipDurationForm internship={ internship } onChange={ setInternship }/> | ||||||
|  |             <Typography variant="h5" className="section-header">Miejsce odbywania praktyki</Typography> | ||||||
|             <CompanyForm/> |             <CompanyForm/> | ||||||
|  |             <Button variant="contained" color="primary">Wyślij</Button> | ||||||
|         </div> |         </div> | ||||||
|     ) |     ) | ||||||
| } | } | ||||||
|  | |||||||
| @ -129,11 +129,11 @@ export const CompanyForm: React.FunctionComponent<CompanyFormProps> = props => { | |||||||
|                 <Grid item md={ 4 }> |                 <Grid item md={ 4 }> | ||||||
|                     <TextField label={ "NIP" } fullWidth { ...fieldProps("nip") } disabled={ !canEdit }/> |                     <TextField label={ "NIP" } fullWidth { ...fieldProps("nip") } disabled={ !canEdit }/> | ||||||
|                 </Grid> |                 </Grid> | ||||||
|                 <Grid item md={ 8 }> |                 {/*<Grid item md={ 8 }>*/} | ||||||
|                     <TextField label={ "Url" } fullWidth { ...fieldProps("url") } disabled={ !canEdit }/> |                 {/*    <TextField label={ "Url" } fullWidth { ...fieldProps("url") } disabled={ !canEdit }/>*/} | ||||||
|                 </Grid> |                 {/*</Grid>*/} | ||||||
|             </Grid> |             </Grid> | ||||||
|             <Typography variant="subtitle1">Oddział</Typography> |             <Typography variant="subtitle1" className="subsection-header">Oddział</Typography> | ||||||
|             <BranchForm company={ company }/> |             <BranchForm company={ company }/> | ||||||
|         </> |         </> | ||||||
|     ) |     ) | ||||||
|  | |||||||
| @ -10,11 +10,14 @@ export function formFieldProps<T>(subject: T, update: (value: T) => void, option | |||||||
|         event = "onChange" |         event = "onChange" | ||||||
|     } = options; |     } = options; | ||||||
| 
 | 
 | ||||||
|     return (field: keyof T) => ({ |     return <P extends keyof T, TArgs extends any[]>( | ||||||
|  |         field: P, | ||||||
|  |         extractor: (...args: TArgs) => T[P] = ((event: DOMEvent<HTMLInputElement>) => event.target.value as unknown as T[P]) as any | ||||||
|  |     ) => ({ | ||||||
|         value: subject[field], |         value: subject[field], | ||||||
|         [event]: (event: DOMEvent<HTMLInputElement>) => update({ |         [event]: (...args: TArgs) => update({ | ||||||
|             ...subject, |             ...subject, | ||||||
|             [field]: event.target.value, |             [field]: extractor(...args), | ||||||
|         } as T) |         } as T) | ||||||
|     }) |     }) | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,7 +1,8 @@ | |||||||
| import { Nullable } from "@/helpers"; | import { Nullable } from "@/helpers"; | ||||||
| import { Internship } from "@/data"; | import { Internship, InternshipType } from "@/data"; | ||||||
| 
 | 
 | ||||||
| export const emptyInternship: Nullable<Internship> = { | export const emptyInternship: Nullable<Internship> = { | ||||||
|  |     intern: null, | ||||||
|     endDate: null, |     endDate: null, | ||||||
|     startDate: null, |     startDate: null, | ||||||
|     type: null, |     type: null, | ||||||
|  | |||||||
| @ -35,5 +35,5 @@ export const sampleStudent: Student = { | |||||||
|     albumNumber: "123456", |     albumNumber: "123456", | ||||||
|     email: "s123456@student.pg.edu.pl", |     email: "s123456@student.pg.edu.pl", | ||||||
|     course: sampleCourse, |     course: sampleCourse, | ||||||
|     semester: 4, |     semester: 6, | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,3 +1,16 @@ | |||||||
| .MuiGrid-container { | .MuiGrid-container { | ||||||
|   margin-bottom: 0; |   margin-bottom: 0; | ||||||
|  |   margin-top: 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .section-header { | ||||||
|  |   margin-top: 2.5rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | .subsection-header { | ||||||
|  |   margin-top: 1.5rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #root { | ||||||
|  |   margin: 100px 0; | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user