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"> | ||||
|                       <Container maxWidth={"md"}> | ||||
|                           <Typography variant="h3">Zgłoszenie Praktyki</Typography> | ||||
|                           <Typography variant="subtitle1" style={{ marginBottom: '100px' }}>UX Demo</Typography> | ||||
|                           <Typography variant="subtitle1">UX Demo</Typography> | ||||
| 
 | ||||
|                           <InternshipForm /> | ||||
|                       </Container> | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| import { Moment } from "moment"; | ||||
| import { Identifiable } from "./common"; | ||||
| import { countWorkingWeeksInRange } from "@/utils/date"; | ||||
| import { Student } from "@/data/student"; | ||||
| 
 | ||||
| export enum InternshipType { | ||||
|     FreeInternship = "FreeInternship", | ||||
| @ -14,11 +15,46 @@ export enum InternshipType { | ||||
|     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 { | ||||
|     description: string; | ||||
| } | ||||
| 
 | ||||
| export interface Internship extends Identifiable { | ||||
|     intern: Student, | ||||
|     type: InternshipType; | ||||
|     program: InternshipProgramEntry[]; | ||||
|     startDate: Moment; | ||||
|  | ||||
| @ -1,21 +1,83 @@ | ||||
| import React, { ChangeEvent, useMemo, useState } from "react"; | ||||
| import { FormControl, Grid, Input, InputLabel, Typography, FormHelperText } from "@material-ui/core"; | ||||
| import { DatePicker } from "@material-ui/pickers"; | ||||
| import React, { ChangeEvent, HTMLProps, useMemo, useState } from "react"; | ||||
| import { | ||||
|     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 { StudentForm } from "@/forms/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 moment, { Moment } from "moment"; | ||||
| import { computeWorkingHours } from "@/utils/date"; | ||||
| import { Autocomplete } from "@material-ui/lab"; | ||||
| import { formFieldProps } from "@/forms/helpers"; | ||||
| 
 | ||||
| export type InternshipFormProps = {} | ||||
| 
 | ||||
| export type InternshipDetailsFormProps = { | ||||
|     internship: Nullable<Internship> | ||||
| export type InternshipFormSectionProps = { | ||||
|     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 [endDate, setEndDate] = useState<Moment | null>(internship.endDate); | ||||
|     const [overrideHours, setHoursOverride] = useState<number | null>(null) | ||||
| @ -28,18 +90,21 @@ const InternshipDurationForm = ({ internship }: InternshipDetailsFormProps) => { | ||||
| 
 | ||||
|     return ( | ||||
|         <Grid container> | ||||
|             <Grid item md={ 4 }> | ||||
|                 <DatePicker value={ startDate } onChange={ setStartDate } clearable variant="inline" label={ "Data rozpoczęcia praktyki" } disableToolbar | ||||
|                             fullWidth/> | ||||
|             <Grid item md={ 6 }> | ||||
|                 <DatePicker value={ startDate } onChange={ setStartDate } | ||||
|                             format="DD MMMM yyyy" | ||||
|                             clearable disableToolbar fullWidth | ||||
|                             variant="inline" label={ "Data rozpoczęcia praktyki" } | ||||
|                 /> | ||||
|             </Grid> | ||||
|             <Grid item md={ 4 }> | ||||
|             <Grid item md={ 6 }> | ||||
|                 <DatePicker value={ endDate } onChange={ setEndDate } | ||||
|                             format="DD MMMM yyyy" | ||||
|                             clearable disableToolbar fullWidth | ||||
|                             variant="inline" label={ "Data zakończenia praktyki" } | ||||
|                             minDate={ startDate || moment() } | ||||
|                 /> | ||||
|             </Grid> | ||||
|             <Grid item md={ 4 }/> | ||||
|             <Grid item md={ 4 }> | ||||
|                 <FormControl fullWidth> | ||||
|                     <InputLabel>Wymiar etatu</InputLabel> | ||||
| @ -66,6 +131,7 @@ const InternshipDurationForm = ({ internship }: InternshipDetailsFormProps) => { | ||||
|                            disabled | ||||
|                            fullWidth | ||||
|                     /> | ||||
|                     <FormHelperText>Wyliczona automatycznie</FormHelperText> | ||||
|                 </FormControl> | ||||
|             </Grid> | ||||
|         </Grid> | ||||
| @ -73,16 +139,19 @@ const InternshipDurationForm = ({ internship }: InternshipDetailsFormProps) => { | ||||
| } | ||||
| 
 | ||||
| export const InternshipForm: React.FunctionComponent<InternshipFormProps> = props => { | ||||
|     const [internship, setInternship] = useState<Nullable<Internship>>(emptyInternship) | ||||
|     const [internship, setInternship] = useState<Nullable<Internship>>({ ...emptyInternship, intern: sampleStudent }) | ||||
| 
 | ||||
|     return ( | ||||
|         <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 }/> | ||||
|             <Typography variant="h5" style={ { marginTop: "1rem" } }>Czas trwania praktyki</Typography> | ||||
|             <InternshipDurationForm internship={ internship }/> | ||||
|             <Typography variant="h5" style={ { marginTop: "1rem" } }>Miejsce odbywania praktyki</Typography> | ||||
|             <Typography variant="h5" className="section-header">Rodzaj i program praktyki</Typography> | ||||
|             <InternshipProgramForm internship={ internship } onChange={ setInternship }/> | ||||
|             <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/> | ||||
|             <Button variant="contained" color="primary">Wyślij</Button> | ||||
|         </div> | ||||
|     ) | ||||
| } | ||||
|  | ||||
| @ -129,11 +129,11 @@ export const CompanyForm: React.FunctionComponent<CompanyFormProps> = props => { | ||||
|                 <Grid item md={ 4 }> | ||||
|                     <TextField label={ "NIP" } fullWidth { ...fieldProps("nip") } disabled={ !canEdit }/> | ||||
|                 </Grid> | ||||
|                 <Grid item md={ 8 }> | ||||
|                     <TextField label={ "Url" } fullWidth { ...fieldProps("url") } disabled={ !canEdit }/> | ||||
|                 {/*<Grid item md={ 8 }>*/} | ||||
|                 {/*    <TextField label={ "Url" } fullWidth { ...fieldProps("url") } disabled={ !canEdit }/>*/} | ||||
|                 {/*</Grid>*/} | ||||
|             </Grid> | ||||
|             </Grid> | ||||
|             <Typography variant="subtitle1">Oddział</Typography> | ||||
|             <Typography variant="subtitle1" className="subsection-header">Oddział</Typography> | ||||
|             <BranchForm company={ company }/> | ||||
|         </> | ||||
|     ) | ||||
|  | ||||
| @ -10,11 +10,14 @@ export function formFieldProps<T>(subject: T, update: (value: T) => void, option | ||||
|         event = "onChange" | ||||
|     } = 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], | ||||
|         [event]: (event: DOMEvent<HTMLInputElement>) => update({ | ||||
|         [event]: (...args: TArgs) => update({ | ||||
|             ...subject, | ||||
|             [field]: event.target.value, | ||||
|             [field]: extractor(...args), | ||||
|         } as T) | ||||
|     }) | ||||
| } | ||||
|  | ||||
| @ -1,7 +1,8 @@ | ||||
| import { Nullable } from "@/helpers"; | ||||
| import { Internship } from "@/data"; | ||||
| import { Internship, InternshipType } from "@/data"; | ||||
| 
 | ||||
| export const emptyInternship: Nullable<Internship> = { | ||||
|     intern: null, | ||||
|     endDate: null, | ||||
|     startDate: null, | ||||
|     type: null, | ||||
|  | ||||
| @ -35,5 +35,5 @@ export const sampleStudent: Student = { | ||||
|     albumNumber: "123456", | ||||
|     email: "s123456@student.pg.edu.pl", | ||||
|     course: sampleCourse, | ||||
|     semester: 4, | ||||
|     semester: 6, | ||||
| } | ||||
|  | ||||
| @ -1,3 +1,16 @@ | ||||
| .MuiGrid-container { | ||||
|   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