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