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