feature_validation #10
@ -18,6 +18,7 @@
|
|||||||
"@types/react-router-dom": "^5.1.5",
|
"@types/react-router-dom": "^5.1.5",
|
||||||
"@types/redux": "^3.6.0",
|
"@types/redux": "^3.6.0",
|
||||||
"@types/redux-persist": "^4.3.1",
|
"@types/redux-persist": "^4.3.1",
|
||||||
|
"@types/yup": "^0.29.4",
|
||||||
"@typescript-eslint/eslint-plugin": "^2.10.0",
|
"@typescript-eslint/eslint-plugin": "^2.10.0",
|
||||||
"@typescript-eslint/parser": "^2.10.0",
|
"@typescript-eslint/parser": "^2.10.0",
|
||||||
"babel-core": "^6.26.3",
|
"babel-core": "^6.26.3",
|
||||||
@ -29,6 +30,8 @@
|
|||||||
"css-loader": "3.4.2",
|
"css-loader": "3.4.2",
|
||||||
"date-holidays": "^1.5.3",
|
"date-holidays": "^1.5.3",
|
||||||
"file-loader": "4.3.0",
|
"file-loader": "4.3.0",
|
||||||
|
"formik": "^2.1.5",
|
||||||
|
"formik-material-ui": "^3.0.0-alpha.0",
|
||||||
"html-webpack-plugin": "4.0.0-beta.11",
|
"html-webpack-plugin": "4.0.0-beta.11",
|
||||||
"i18next": "^19.6.0",
|
"i18next": "^19.6.0",
|
||||||
"i18next-browser-languagedetector": "^5.0.0",
|
"i18next-browser-languagedetector": "^5.0.0",
|
||||||
@ -62,7 +65,8 @@
|
|||||||
"webpack-cli": "^3.3.11",
|
"webpack-cli": "^3.3.11",
|
||||||
"webpack-dev-server": "3.10.3",
|
"webpack-dev-server": "3.10.3",
|
||||||
"workbox-webpack-plugin": "4.3.1",
|
"workbox-webpack-plugin": "4.3.1",
|
||||||
"yaml-loader": "^0.6.0"
|
"yaml-loader": "^0.6.0",
|
||||||
|
"yup": "^0.29.3"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "webpack-dev-server --mode development",
|
"serve": "webpack-dev-server --mode development",
|
||||||
|
@ -2,7 +2,7 @@ import React, { HTMLProps } from "react";
|
|||||||
import { useHorizontalSpacing } from "@/styles";
|
import { useHorizontalSpacing } from "@/styles";
|
||||||
|
|
||||||
export const Actions = (props: HTMLProps<HTMLDivElement>) => {
|
export const Actions = (props: HTMLProps<HTMLDivElement>) => {
|
||||||
const classes = useHorizontalSpacing(1);
|
const classes = useHorizontalSpacing(2);
|
||||||
|
|
||||||
return <div className={ classes.root } { ...props }/>
|
return <div className={ classes.root } { ...props } style={{ display: "flex", alignItems: "center" }}/>
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
import { Internship, internshipTypeLabels } from "@/data";
|
import { Internship, internshipTypeLabels } from "@/data";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Button, Paper, PaperProps, Typography, TypographyProps } from "@material-ui/core";
|
import { Paper, PaperProps, Typography, TypographyProps } from "@material-ui/core";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { createStyles, makeStyles } from "@material-ui/core/styles";
|
import { createStyles, makeStyles } from "@material-ui/core/styles";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { Link as RouterLink } from "react-router-dom";
|
|
||||||
import { route } from "@/routing";
|
|
||||||
import { Actions } from "@/components/actions";
|
|
||||||
import { useVerticalSpacing } from "@/styles";
|
import { useVerticalSpacing } from "@/styles";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
|
||||||
@ -36,7 +33,6 @@ export const ProposalPreview = ({ proposal }: ProposalPreviewProps) => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const classes = useVerticalSpacing(3);
|
const classes = useVerticalSpacing(3);
|
||||||
|
|
||||||
const duration = moment.duration(proposal.endDate.diff(proposal.startDate));
|
const duration = moment.duration(proposal.endDate.diff(proposal.startDate));
|
||||||
|
|
||||||
return <div className={ classNames("proposal", classes.root) }>
|
return <div className={ classNames("proposal", classes.root) }>
|
||||||
@ -74,9 +70,9 @@ export const ProposalPreview = ({ proposal }: ProposalPreviewProps) => {
|
|||||||
{ t('internship.date-range', { start: proposal.startDate, end: proposal.endDate }) }
|
{ t('internship.date-range', { start: proposal.startDate, end: proposal.endDate }) }
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography className="proposal__secondary">
|
<Typography className="proposal__secondary">
|
||||||
{ t('internship.duration', { duration }) }
|
{ t('internship.duration', { duration, count: Math.floor(duration.asWeeks()) }) }
|
||||||
{ ", " }
|
{ ", " }
|
||||||
{ t('internship.hours', { hours: proposal.hours }) }
|
{ t('internship.hours', { hours: proposal.hours, count: proposal.hours }) }
|
||||||
</Typography>
|
</Typography>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
@ -85,11 +81,5 @@ export const ProposalPreview = ({ proposal }: ProposalPreviewProps) => {
|
|||||||
<Typography className="proposal__primary">{ proposal.mentor.name } { proposal.mentor.surname }</Typography>
|
<Typography className="proposal__primary">{ proposal.mentor.name } { proposal.mentor.surname }</Typography>
|
||||||
<Typography className="proposal__secondary">{ proposal.mentor.email }, { proposal.mentor.phone }</Typography>
|
<Typography className="proposal__secondary">{ proposal.mentor.email }, { proposal.mentor.phone }</Typography>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
<Actions>
|
|
||||||
<Button component={ RouterLink } to={ route("home") } variant="contained" color="primary">
|
|
||||||
{ t('go-back') }
|
|
||||||
</Button>
|
|
||||||
</Actions>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
export type Identifier = string;
|
||||||
|
|
||||||
export interface Identifiable {
|
export interface Identifiable {
|
||||||
id?: string
|
id?: Identifier
|
||||||
}
|
}
|
||||||
|
@ -12,10 +12,10 @@ export interface Company extends Identifiable {
|
|||||||
name: string;
|
name: string;
|
||||||
url?: string;
|
url?: string;
|
||||||
nip: string;
|
nip: string;
|
||||||
offices: BranchOffice[];
|
offices: Office[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BranchOffice extends Identifiable {
|
export interface Office extends Identifiable {
|
||||||
address: Address;
|
address: Address;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ export const emptyAddress: Address = {
|
|||||||
building: ""
|
building: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
export const emptyBranchOffice: BranchOffice = {
|
export const emptyBranchOffice: Office = {
|
||||||
address: emptyAddress,
|
address: emptyAddress,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@ export type Edition = {
|
|||||||
startDate: Moment;
|
startDate: Moment;
|
||||||
endDate: Moment;
|
endDate: Moment;
|
||||||
proposalDeadline: Moment;
|
proposalDeadline: Moment;
|
||||||
|
minimumInternshipHours: number;
|
||||||
|
maximumInternshipHours?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Deadlines = {
|
export type Deadlines = {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Moment } from "moment";
|
import { Moment } from "moment";
|
||||||
import { Identifiable } from "./common";
|
import { Identifiable } from "./common";
|
||||||
import { Student } from "@/data/student";
|
import { Student } from "@/data/student";
|
||||||
import { BranchOffice, Company } from "@/data/company";
|
import { Company, Office } from "@/data/company";
|
||||||
|
|
||||||
export enum InternshipType {
|
export enum InternshipType {
|
||||||
FreeInternship = "FreeInternship",
|
FreeInternship = "FreeInternship",
|
||||||
@ -64,7 +64,7 @@ export interface Internship extends Identifiable {
|
|||||||
hours: number;
|
hours: number;
|
||||||
mentor: Mentor;
|
mentor: Mentor;
|
||||||
company: Company;
|
company: Company;
|
||||||
office: BranchOffice;
|
office: Office;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Plan extends Identifiable {
|
export interface Plan extends Identifiable {
|
||||||
|
@ -1,19 +1,12 @@
|
|||||||
import React, { HTMLProps, useMemo } from "react";
|
import React, { HTMLProps, useMemo } from "react";
|
||||||
import { BranchOffice, Company, emptyAddress, emptyBranchOffice, emptyCompany, formatAddress, Mentor } from "@/data";
|
import { Company, formatAddress, Office } from "@/data";
|
||||||
import { sampleCompanies } from "@/provider/dummy";
|
import { sampleCompanies } from "@/provider/dummy";
|
||||||
import { Autocomplete } from "@material-ui/lab";
|
import { Autocomplete } from "@material-ui/lab";
|
||||||
import { Grid, TextField, Typography } from "@material-ui/core";
|
import { Grid, TextField, Typography } from "@material-ui/core";
|
||||||
import { BoundProperty, formFieldProps } from "./helpers";
|
import { InternshipFormValues } from "@/forms/internship";
|
||||||
import { InternshipFormSectionProps } from "@/forms/internship";
|
import { useTranslation } from "react-i18next";
|
||||||
import { emptyMentor } from "@/provider/dummy/internship";
|
import { Field, useFormikContext } from "formik";
|
||||||
import { useProxyState } from "@/hooks";
|
import { TextField as TextFieldFormik } from "formik-material-ui"
|
||||||
|
|
||||||
export type CompanyFormProps = {} & InternshipFormSectionProps;
|
|
||||||
|
|
||||||
export type BranchOfficeProps = {
|
|
||||||
disabled?: boolean;
|
|
||||||
offices?: BranchOffice[];
|
|
||||||
} & BoundProperty<BranchOffice, "onChange", "value">
|
|
||||||
|
|
||||||
export const CompanyItem = ({ company, ...props }: { company: Company } & HTMLProps<any>) => (
|
export const CompanyItem = ({ company, ...props }: { company: Company } & HTMLProps<any>) => (
|
||||||
<div className="company-item" { ...props }>
|
<div className="company-item" { ...props }>
|
||||||
@ -22,42 +15,65 @@ export const CompanyItem = ({ company, ...props }: { company: Company } & HTMLPr
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
export const OfficeItem = ({ office, ...props }: { office: BranchOffice } & HTMLProps<any>) => (
|
export const OfficeItem = ({ office, ...props }: { office: Office } & HTMLProps<any>) => (
|
||||||
<div className="office-item" { ...props }>
|
<div className="office-item" { ...props }>
|
||||||
<div>{ office.address.city }</div>
|
<div>{ office.address.city }</div>
|
||||||
<Typography variant="caption">{ formatAddress(office.address) }</Typography>
|
<Typography variant="caption">{ formatAddress(office.address) }</Typography>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
export const BranchForm: React.FC<BranchOfficeProps> = ({ value: office, onChange: setOffice, offices = [], disabled = false }) => {
|
export const BranchForm: React.FC = () => {
|
||||||
const canEdit = useMemo(() => !office.id && !disabled, [office.id, disabled]);
|
const { values, errors, setValues, touched, setFieldTouched } = useFormikContext<InternshipFormValues>();
|
||||||
const fieldProps = formFieldProps(office.address, address => setOffice({ ...office, address }))
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const handleCityChange = (event: any, value: BranchOffice | string | null) => {
|
const disabled = useMemo(() => !values.companyName, [values.companyName]);
|
||||||
|
const offices = useMemo(() => values.company?.offices || [], [values.company]);
|
||||||
|
const canEdit = useMemo(() => !values.office && !disabled, [values.office, disabled]);
|
||||||
|
|
||||||
|
const handleCityChange = (event: any, value: Office | string | null) => {
|
||||||
if (typeof value === "string") {
|
if (typeof value === "string") {
|
||||||
setOffice({
|
setValues({
|
||||||
...emptyBranchOffice,
|
...values,
|
||||||
address: {
|
office: null,
|
||||||
...emptyAddress,
|
|
||||||
city: value,
|
city: value,
|
||||||
}
|
}, true);
|
||||||
});
|
|
||||||
} else if (typeof value === "object" && value !== null) {
|
} else if (typeof value === "object" && value !== null) {
|
||||||
setOffice(value);
|
const office = value as Office;
|
||||||
} else {
|
|
||||||
setOffice(emptyBranchOffice);
|
setValues({
|
||||||
|
...values,
|
||||||
|
office,
|
||||||
|
city: office.address.city,
|
||||||
|
country: office.address.country,
|
||||||
|
street: office.address.street,
|
||||||
|
building: office.address.building,
|
||||||
|
postalCode: office.address.postalCode,
|
||||||
|
}, true)
|
||||||
|
} else { // null
|
||||||
|
setValues({
|
||||||
|
...values,
|
||||||
|
office: null,
|
||||||
|
city: "",
|
||||||
|
country: "",
|
||||||
|
street: "",
|
||||||
|
building: "",
|
||||||
|
postalCode: "",
|
||||||
|
}, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleCityInput = (event: any, value: string) => {
|
const handleCityInput = (event: any, value: string) => {
|
||||||
const base = office.id ? emptyBranchOffice : office;
|
setValues( {
|
||||||
setOffice({
|
...values,
|
||||||
...base,
|
office: null,
|
||||||
address: {
|
...(values.office ? {
|
||||||
...base.address,
|
country: "",
|
||||||
|
street: "",
|
||||||
|
building: "",
|
||||||
|
postalCode: "",
|
||||||
|
} : { }),
|
||||||
city: value,
|
city: value,
|
||||||
}
|
}, true);
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -68,73 +84,89 @@ export const BranchForm: React.FC<BranchOfficeProps> = ({ value: office, onChang
|
|||||||
disabled={ disabled }
|
disabled={ disabled }
|
||||||
getOptionLabel={ office => typeof office == "string" ? office : office.address.city }
|
getOptionLabel={ office => typeof office == "string" ? office : office.address.city }
|
||||||
renderOption={ office => <OfficeItem office={ office }/> }
|
renderOption={ office => <OfficeItem office={ office }/> }
|
||||||
renderInput={ props => <TextField { ...props } label={ "Miasto" } fullWidth/> }
|
renderInput={
|
||||||
|
props =>
|
||||||
|
<TextField { ...props }
|
||||||
|
label={ t("forms.internship.fields.city") }
|
||||||
|
fullWidth
|
||||||
|
error={ touched.city && !!errors.city }
|
||||||
|
helperText={ touched.city && errors.city }
|
||||||
|
/>
|
||||||
|
}
|
||||||
onChange={ handleCityChange }
|
onChange={ handleCityChange }
|
||||||
onInputChange={ handleCityInput }
|
onInputChange={ handleCityInput }
|
||||||
inputValue={ office.address.city }
|
onBlur={ ev => setFieldTouched("city", true) }
|
||||||
value={ office.id ? office : null }
|
inputValue={ values.city }
|
||||||
|
value={ values.office ? values.office : null }
|
||||||
freeSolo
|
freeSolo
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={ 2 }>
|
<Grid item md={ 2 }>
|
||||||
<TextField label={ "Kod pocztowy" } fullWidth disabled={ !canEdit } { ...fieldProps("postalCode") }/>
|
<Field label={ t("forms.internship.fields.postal-code") } name="postalCode" fullWidth disabled={ !canEdit } component={ TextFieldFormik }/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={ 3 }>
|
<Grid item md={ 3 }>
|
||||||
<TextField label={ "Kraj" } fullWidth disabled={ !canEdit } { ...fieldProps("country") }/>
|
<Field label={ t("forms.internship.fields.country") } name="country" fullWidth disabled={ !canEdit } component={ TextFieldFormik }/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={ 10 }>
|
<Grid item md={ 10 }>
|
||||||
<TextField label={ "Ulica" } fullWidth disabled={ !canEdit } { ...fieldProps("street") }/>
|
<Field label={ t("forms.internship.fields.street") } name="street" fullWidth disabled={ !canEdit } component={ TextFieldFormik }/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={ 2 }>
|
<Grid item md={ 2 }>
|
||||||
<TextField label={ "Nr Budynku" } fullWidth disabled={ !canEdit } { ...fieldProps("building") }/>
|
<Field label={ t("forms.internship.fields.building") } name="building" fullWidth disabled={ !canEdit } component={ TextFieldFormik }/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MentorForm = ({ mentor, onMentorChange }: BoundProperty<Mentor, 'onMentorChange', 'mentor'>) => {
|
export const MentorForm = () => {
|
||||||
const fieldProps = formFieldProps(mentor, onMentorChange)
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item md={6}>
|
<Grid item md={ 6 }>
|
||||||
<TextField label="Imię" fullWidth { ...fieldProps("name") }/>
|
<Field name="mentorFirstName" label={ t("forms.internship.fields.first-name") } fullWidth component={ TextFieldFormik }/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={6}>
|
<Grid item md={ 6 }>
|
||||||
<TextField label="Nazwisko" value={ mentor.surname } fullWidth { ...fieldProps("surname") }/>
|
<Field name="mentorLastName" label={ t("forms.internship.fields.last-name") } fullWidth component={ TextFieldFormik }/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={8}>
|
<Grid item md={ 8 }>
|
||||||
<TextField label="E-mail" value={ mentor.email } fullWidth { ...fieldProps("email") }/>
|
<Field name="mentorEmail" label={ t("forms.internship.fields.e-mail") } fullWidth component={ TextFieldFormik }/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={4}>
|
<Grid item md={ 4 }>
|
||||||
<TextField label="Nr telefonu" value={ mentor.phone } fullWidth { ...fieldProps("phone") }/>
|
<Field name="mentorPhone" label={ t("forms.internship.fields.phone") } fullWidth component={ TextFieldFormik }/>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CompanyForm: React.FunctionComponent<CompanyFormProps> = ({ internship, onChange }) => {
|
export const CompanyForm: React.FunctionComponent = () => {
|
||||||
const [company, setCompany] = useProxyState<Company>(internship.company || emptyCompany, company => onChange({ ...internship, company }));
|
const { values, setValues, errors, touched, setFieldTouched } = useFormikContext<InternshipFormValues>();
|
||||||
const [mentor, setMentor] = useProxyState<Mentor>(internship.mentor || emptyMentor, mentor => onChange({ ...internship, mentor }));
|
const { t } = useTranslation();
|
||||||
const [office, setOffice] = useProxyState<BranchOffice>(internship.office || emptyBranchOffice, office => onChange({ ...internship, office }));
|
|
||||||
|
|
||||||
const canEdit = useMemo(() => !company.id, [company.id]);
|
const canEdit = useMemo(() => !values.company, [values.company]);
|
||||||
|
|
||||||
const fieldProps = formFieldProps(company, setCompany)
|
|
||||||
|
|
||||||
const handleCompanyChange = (event: any, value: Company | string | null) => {
|
const handleCompanyChange = (event: any, value: Company | string | null) => {
|
||||||
|
setFieldTouched("companyName", true);
|
||||||
|
|
||||||
if (typeof value === "string") {
|
if (typeof value === "string") {
|
||||||
setCompany({
|
setValues({
|
||||||
...emptyCompany,
|
...values,
|
||||||
name: value,
|
company: null,
|
||||||
});
|
companyName: value
|
||||||
|
}, true)
|
||||||
} else if (typeof value === "object" && value !== null) {
|
} else if (typeof value === "object" && value !== null) {
|
||||||
setCompany(value);
|
setValues({
|
||||||
|
...values,
|
||||||
|
company: value as Company,
|
||||||
|
companyName: value.name,
|
||||||
|
companyNip: value.nip,
|
||||||
|
}, true)
|
||||||
} else {
|
} else {
|
||||||
setCompany(emptyCompany);
|
setValues({
|
||||||
|
...values,
|
||||||
|
company: null,
|
||||||
|
companyName: "",
|
||||||
|
}, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,24 +175,22 @@ export const CompanyForm: React.FunctionComponent<CompanyFormProps> = ({ interns
|
|||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item>
|
<Grid item>
|
||||||
<Autocomplete options={ sampleCompanies }
|
<Autocomplete options={ sampleCompanies }
|
||||||
getOptionLabel={ option => option.name }
|
getOptionLabel={ option => typeof option === "string" ? option : option.name }
|
||||||
renderOption={ company => <CompanyItem company={ company }/> }
|
renderOption={ company => <CompanyItem company={ company }/> }
|
||||||
renderInput={ props => <TextField { ...props } label={ "Nazwa firmy" } fullWidth/> }
|
renderInput={ props => <TextField { ...props } label={ t("forms.internship.fields.company-name") } fullWidth
|
||||||
onChange={ handleCompanyChange } value={ company }
|
error={ touched.companyName && !!errors.companyName } helperText={ touched.companyName && errors.companyName }/> }
|
||||||
|
onChange={ handleCompanyChange } value={ values.company || values.companyName }
|
||||||
freeSolo
|
freeSolo
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={ 4 }>
|
<Grid item md={ 4 }>
|
||||||
<TextField label={ "NIP" } fullWidth { ...fieldProps("nip") } disabled={ !canEdit }/>
|
<Field label={ t("forms.internship.fields.nip") } fullWidth name="companyNip" disabled={ !canEdit } component={ TextFieldFormik }/>
|
||||||
</Grid>
|
</Grid>
|
||||||
{/*<Grid item md={ 8 }>*/}
|
|
||||||
{/* <TextField label={ "Url" } fullWidth { ...fieldProps("url") } disabled={ !canEdit }/>*/}
|
|
||||||
{/*</Grid>*/}
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Typography variant="subtitle1" className="subsection-header">Zakładowy opiekun praktyki</Typography>
|
<Typography variant="subtitle1" className="subsection-header">{ t("internship.mentor") }</Typography>
|
||||||
<MentorForm mentor={ mentor } onMentorChange={ setMentor }/>
|
<MentorForm/>
|
||||||
<Typography variant="subtitle1" className="subsection-header">Oddział</Typography>
|
<Typography variant="subtitle1" className="subsection-header">{ t("internship.office") }</Typography>
|
||||||
<BranchForm value={ office } onChange={ setOffice } offices={ company.offices } />
|
<BranchForm/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,28 +1,14 @@
|
|||||||
import React, { HTMLProps, useEffect, useMemo, useState } from "react";
|
import React, { HTMLProps, useMemo, useState } from "react";
|
||||||
import {
|
import { Button, Dialog, DialogActions, DialogContent, DialogContentText, Grid, TextField, Typography } from "@material-ui/core";
|
||||||
Button,
|
|
||||||
Dialog,
|
|
||||||
DialogActions,
|
|
||||||
DialogContent,
|
|
||||||
DialogContentText,
|
|
||||||
FormControl,
|
|
||||||
FormHelperText,
|
|
||||||
Grid,
|
|
||||||
Input,
|
|
||||||
InputLabel,
|
|
||||||
TextField,
|
|
||||||
Typography
|
|
||||||
} from "@material-ui/core";
|
|
||||||
import { KeyboardDatePicker as DatePicker } from "@material-ui/pickers";
|
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 { Course, Internship, InternshipType, internshipTypeLabels } from "@/data";
|
import { Company, Internship, InternshipType, internshipTypeLabels, Office, Student } 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 { emptyInternship } from "@/provider/dummy/internship";
|
import { emptyInternship } from "@/provider/dummy/internship";
|
||||||
import { InternshipProposalActions, useDispatch } from "@/state/actions";
|
import { InternshipProposalActions, useDispatch } from "@/state/actions";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@ -30,15 +16,61 @@ import { useSelector } from "react-redux";
|
|||||||
import { AppState } from "@/state/reducer";
|
import { AppState } from "@/state/reducer";
|
||||||
import { Link as RouterLink, useHistory } from "react-router-dom";
|
import { Link as RouterLink, useHistory } from "react-router-dom";
|
||||||
import { route } from "@/routing";
|
import { route } from "@/routing";
|
||||||
import { useProxyState } from "@/hooks";
|
|
||||||
import { getInternshipProposal } from "@/state/reducer/proposal";
|
import { getInternshipProposal } from "@/state/reducer/proposal";
|
||||||
import { Actions } from "@/components";
|
import { Actions } from "@/components";
|
||||||
|
import { Field, Form, Formik, useFormikContext } from "formik";
|
||||||
|
import * as Yup from "yup";
|
||||||
|
import { Transformer } from "@/serialization";
|
||||||
|
import { TextField as TextFieldFormik } from "formik-material-ui"
|
||||||
|
import { Edition } from "@/data/edition";
|
||||||
|
import { useUpdateEffect } from "@/hooks";
|
||||||
|
|
||||||
export type InternshipFormProps = {}
|
export type InternshipFormValues = {
|
||||||
|
startDate: Moment | null;
|
||||||
|
endDate: Moment | null;
|
||||||
|
hours: number | "";
|
||||||
|
workingHours: number;
|
||||||
|
companyName: string;
|
||||||
|
companyNip: string;
|
||||||
|
city: string;
|
||||||
|
postalCode: string;
|
||||||
|
country: string;
|
||||||
|
street: string;
|
||||||
|
building: string;
|
||||||
|
mentorFirstName: string;
|
||||||
|
mentorLastName: string;
|
||||||
|
mentorEmail: string;
|
||||||
|
mentorPhone: string;
|
||||||
|
kindOther: string | null;
|
||||||
|
|
||||||
export type InternshipFormSectionProps = {
|
// relations
|
||||||
internship: Nullable<Internship>,
|
kind: InternshipType | null;
|
||||||
onChange: (internship: Nullable<Internship>) => void,
|
company: Company | null;
|
||||||
|
office: Office | null;
|
||||||
|
student: Student;
|
||||||
|
}
|
||||||
|
|
||||||
|
const emptyInternshipValues: InternshipFormValues = {
|
||||||
|
building: "",
|
||||||
|
city: "",
|
||||||
|
company: null,
|
||||||
|
companyName: "",
|
||||||
|
companyNip: "",
|
||||||
|
country: "",
|
||||||
|
street: "",
|
||||||
|
endDate: null,
|
||||||
|
hours: "",
|
||||||
|
kind: null,
|
||||||
|
kindOther: "",
|
||||||
|
mentorEmail: "",
|
||||||
|
mentorFirstName: "",
|
||||||
|
mentorLastName: "",
|
||||||
|
mentorPhone: "",
|
||||||
|
office: null,
|
||||||
|
postalCode: "",
|
||||||
|
startDate: null,
|
||||||
|
student: sampleStudent,
|
||||||
|
workingHours: 40,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const InternshipTypeItem = ({ type, ...props }: { type: InternshipType } & HTMLProps<any>) => {
|
export const InternshipTypeItem = ({ type, ...props }: { type: InternshipType } & HTMLProps<any>) => {
|
||||||
@ -52,144 +84,250 @@ export const InternshipTypeItem = ({ type, ...props }: { type: InternshipType }
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const InternshipProgramForm = ({ internship, onChange }: InternshipFormSectionProps) => {
|
const InternshipProgramForm = () => {
|
||||||
const fieldProps = formFieldProps(internship, onChange);
|
const { t } = useTranslation();
|
||||||
|
const { values, handleBlur, setFieldValue, errors } = useFormikContext<InternshipFormValues>();
|
||||||
const course = internship.intern?.course as Course;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item md={ 4 }>
|
<Grid item md={ 4 }>
|
||||||
<Autocomplete renderInput={ props => <TextField { ...props } label="Rodzaj praktyki/umowy" fullWidth/> }
|
<Autocomplete renderInput={ props => <TextField { ...props } label={ t("forms.internship.fields.kind") } fullWidth error={ !!errors.kind } helperText={ errors.kind }/> }
|
||||||
getOptionLabel={ (option: InternshipType) => internshipTypeLabels[option].label }
|
getOptionLabel={ (option: InternshipType) => internshipTypeLabels[option].label }
|
||||||
renderOption={ (option: InternshipType) => <InternshipTypeItem type={ option }/> }
|
renderOption={ (option: InternshipType) => <InternshipTypeItem type={ option }/> }
|
||||||
options={ Object.values(InternshipType) as InternshipType[] }
|
options={ Object.values(InternshipType) as InternshipType[] }
|
||||||
disableClearable
|
disableClearable
|
||||||
{ ...fieldProps("type", (event, value) => value) as any }
|
value={ values.kind || undefined }
|
||||||
|
onChange={ (_, value) => setFieldValue("kind", value) }
|
||||||
|
onBlur={ handleBlur }
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={ 8 }>
|
<Grid item md={ 8 }>
|
||||||
{ internship.type === InternshipType.Other && <TextField label={ "Inny - Wprowadź" } fullWidth/> }
|
{
|
||||||
|
values.kind === InternshipType.Other &&
|
||||||
|
<Field label={ t("forms.internship.fields.kind-other") } name="kindOther" fullWidth component={ TextFieldFormik } />
|
||||||
|
}
|
||||||
</Grid>
|
</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>
|
</Grid>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const InternshipDurationForm = ({ internship, onChange }: InternshipFormSectionProps) => {
|
const InternshipDurationForm = () => {
|
||||||
const [startDate, setStartDate] = useProxyState<Moment | null>(internship.startDate, value => onChange({ ...internship, startDate: value }));
|
const { t } = useTranslation();
|
||||||
const [endDate, setEndDate] = useProxyState<Moment | null>(internship.endDate, value => onChange({ ...internship, endDate: value }));
|
const {
|
||||||
|
values: { startDate, endDate, workingHours },
|
||||||
|
errors,
|
||||||
|
touched,
|
||||||
|
setFieldTouched,
|
||||||
|
setFieldValue
|
||||||
|
} = useFormikContext<InternshipFormValues>();
|
||||||
|
|
||||||
const [overrideHours, setHoursOverride] = useState<number | null>(null)
|
const [overrideHours, setHoursOverride] = useState<number | null>(null)
|
||||||
const [workingHours, setWorkingHours] = useState<number>(40)
|
|
||||||
|
|
||||||
const computedHours = useMemo(() => startDate && endDate && computeWorkingHours(startDate, endDate, workingHours / 5), [startDate, endDate, workingHours]);
|
const computedHours = useMemo(() => startDate && endDate && computeWorkingHours(startDate, endDate, workingHours / 5), [startDate, endDate, workingHours]);
|
||||||
|
|
||||||
const hours = useMemo(() => overrideHours !== null ? overrideHours : computedHours || null, [overrideHours, computedHours]);
|
const hours = useMemo(() => overrideHours !== null ? overrideHours : computedHours || null, [overrideHours, computedHours]);
|
||||||
const weeks = useMemo(() => hours !== null ? Math.floor(hours / 40) : null, [hours]);
|
const weeks = useMemo(() => hours !== null ? Math.floor(hours / workingHours) : null, [ hours ]);
|
||||||
|
|
||||||
useEffect(() => onChange({ ...internship, hours }), [hours])
|
useUpdateEffect(() => {
|
||||||
|
setFieldTouched("hours", true);
|
||||||
|
setFieldValue("hours", hours, true);
|
||||||
|
}, [ hours ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item md={ 6 }>
|
<Grid item md={ 6 }>
|
||||||
<DatePicker value={ startDate } onChange={ setStartDate }
|
<DatePicker value={ startDate } onChange={ value => setFieldValue("startDate", value) }
|
||||||
format="DD MMMM yyyy"
|
format="DD MMMM yyyy"
|
||||||
clearable disableToolbar fullWidth
|
disableToolbar fullWidth
|
||||||
variant="inline" label={ "Data rozpoczęcia praktyki" }
|
variant="inline" label={ t("forms.internship.fields.start-date") }
|
||||||
|
minDate={ moment() }
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={ 6 }>
|
<Grid item md={ 6 }>
|
||||||
<DatePicker value={ endDate } onChange={ setEndDate }
|
<DatePicker value={ endDate } onChange={ value => setFieldValue("endDate", value) }
|
||||||
format="DD MMMM yyyy"
|
format="DD MMMM yyyy"
|
||||||
clearable disableToolbar fullWidth
|
disableToolbar fullWidth
|
||||||
variant="inline" label={ "Data zakończenia praktyki" }
|
variant="inline" label={ t("forms.internship.fields.end-date") }
|
||||||
minDate={ startDate || moment() }
|
minDate={ startDate || moment() }
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={ 4 }>
|
<Grid item md={ 4 }>
|
||||||
<FormControl fullWidth>
|
<Field component={ TextFieldFormik }
|
||||||
<InputLabel>Wymiar etatu</InputLabel>
|
name="workingHours"
|
||||||
<Input value={ workingHours }
|
label={ t("forms.internship.fields.working-hours") }
|
||||||
onChange={ ev => setWorkingHours(parseInt(ev.target.value) || 0) }
|
helperText={ t("forms.internship.help.working-hours") }
|
||||||
fullWidth
|
fullWidth
|
||||||
/>
|
/>
|
||||||
<FormHelperText>Liczba godzin w tygodniu roboczym</FormHelperText>
|
|
||||||
</FormControl>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={ 4 }>
|
<Grid item md={ 4 }>
|
||||||
<FormControl fullWidth>
|
<TextField fullWidth
|
||||||
<InputLabel>Łączna liczba godzin</InputLabel>
|
label={ t("forms.internship.fields.total-hours") }
|
||||||
<Input value={ hours || "" }
|
error={ !!errors.hours && touched.hours }
|
||||||
|
helperText={ touched.hours && errors.hours }
|
||||||
|
value={ hours || "" }
|
||||||
onChange={ ev => setHoursOverride(parseInt(ev.target.value) || 0) }
|
onChange={ ev => setHoursOverride(parseInt(ev.target.value) || 0) }
|
||||||
fullWidth
|
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={ 4 }>
|
<Grid item md={ 4 }>
|
||||||
<FormControl fullWidth>
|
<TextField fullWidth label={ t("forms.internship.fields.weeks") }
|
||||||
<InputLabel>Liczba tygodni</InputLabel>
|
value={ weeks || "" }
|
||||||
<Input value={ weeks || "" }
|
|
||||||
disabled
|
disabled
|
||||||
fullWidth
|
helperText={ t("forms.internship.help.weeks") }
|
||||||
/>
|
/>
|
||||||
<FormHelperText>Wyliczona automatycznie</FormHelperText>
|
|
||||||
</FormControl>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const InternshipForm: React.FunctionComponent<InternshipFormProps> = props => {
|
type InternshipConverterContext = {
|
||||||
const initialInternshipState = useSelector<AppState, Nullable<Internship>>(state => getInternshipProposal(state.proposal) || {
|
internship: Internship,
|
||||||
|
}
|
||||||
|
|
||||||
|
const converter: Transformer<Nullable<Internship>, InternshipFormValues, InternshipConverterContext> = {
|
||||||
|
transform(internship: Nullable<Internship>): InternshipFormValues {
|
||||||
|
return {
|
||||||
|
student: internship.intern as Student,
|
||||||
|
kind: internship.type,
|
||||||
|
kindOther: "",
|
||||||
|
startDate: internship.startDate,
|
||||||
|
endDate: internship.endDate,
|
||||||
|
hours: internship.hours || "",
|
||||||
|
building: internship.office?.address?.building || "",
|
||||||
|
office: internship.office,
|
||||||
|
city: internship.office?.address?.city || "",
|
||||||
|
postalCode: internship.office?.address?.postalCode || "",
|
||||||
|
street: internship.office?.address?.street || "",
|
||||||
|
country: internship.office?.address?.country || "",
|
||||||
|
company: internship.company,
|
||||||
|
companyName: internship.company?.name || "",
|
||||||
|
companyNip: internship.company?.nip || "",
|
||||||
|
mentorEmail: internship.mentor?.email || "",
|
||||||
|
mentorFirstName: internship.mentor?.name || "",
|
||||||
|
mentorLastName: internship.mentor?.surname || "",
|
||||||
|
mentorPhone: internship.mentor?.phone || "",
|
||||||
|
workingHours: 40,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
reverseTransform(form: InternshipFormValues, context: InternshipConverterContext): Nullable<Internship> {
|
||||||
|
return {
|
||||||
|
...context.internship,
|
||||||
|
startDate: form.startDate as Moment,
|
||||||
|
endDate: form.endDate as Moment,
|
||||||
|
office: form.office || {
|
||||||
|
address: {
|
||||||
|
street: form.street,
|
||||||
|
postalCode: form.postalCode,
|
||||||
|
country: form.country,
|
||||||
|
city: form.city,
|
||||||
|
building: form.building,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mentor: {
|
||||||
|
surname: form.mentorLastName,
|
||||||
|
name: form.mentorFirstName,
|
||||||
|
email: form.mentorEmail,
|
||||||
|
phone: form.mentorPhone,
|
||||||
|
},
|
||||||
|
company: form.company || {
|
||||||
|
name: form.companyName,
|
||||||
|
nip: form.companyNip,
|
||||||
|
offices: [],
|
||||||
|
},
|
||||||
|
hours: form.hours as number,
|
||||||
|
type: form.kind as InternshipType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const InternshipForm: React.FunctionComponent = () => {
|
||||||
|
const initialInternship = useSelector<AppState, Nullable<Internship>>(state => getInternshipProposal(state.proposal) || {
|
||||||
...emptyInternship,
|
...emptyInternship,
|
||||||
|
office: null,
|
||||||
|
company: null,
|
||||||
|
mentor: null,
|
||||||
intern: sampleStudent
|
intern: sampleStudent
|
||||||
});
|
});
|
||||||
|
|
||||||
const [internship, setInternship] = useState<Nullable<Internship>>(initialInternshipState)
|
const edition = useSelector<AppState, Edition>(state => state.edition as Edition);
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
const [confirmDialogOpen, setConfirmDialogOpen] = useState<boolean>(false);
|
const [confirmDialogOpen, setConfirmDialogOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const validationSchema = Yup.object<Partial<InternshipFormValues>>({
|
||||||
|
mentorFirstName: Yup.string().required(t("validation.required")),
|
||||||
|
mentorLastName: Yup.string().required(t("validation.required")),
|
||||||
|
mentorEmail: Yup.string()
|
||||||
|
.required(t("validation.required"))
|
||||||
|
.email(t("validation.email")),
|
||||||
|
mentorPhone: Yup.string()
|
||||||
|
.required(t("validation.required"))
|
||||||
|
.matches(/^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\s\./0-9]*$/, t("validation.phone")),
|
||||||
|
hours: Yup.number()
|
||||||
|
.min(edition.minimumInternshipHours, t("validation.internship.minimum-hours", { hours: edition.minimumInternshipHours })),
|
||||||
|
companyName: Yup.string().when("company", {
|
||||||
|
is: null,
|
||||||
|
then: Yup.string().required(t("validation.required"))
|
||||||
|
}),
|
||||||
|
companyNip: Yup.string().when("company", {
|
||||||
|
is: null,
|
||||||
|
then: Yup.string()
|
||||||
|
.required(t("validation.required"))
|
||||||
|
}),
|
||||||
|
street: Yup.string().required(t("validation.required")),
|
||||||
|
country: Yup.string().required(t("validation.required")),
|
||||||
|
city: Yup.string().required(t("validation.required")),
|
||||||
|
postalCode: Yup.string().required(t("validation.required")),
|
||||||
|
building: Yup.string().required(t("validation.required")),
|
||||||
|
kindOther: Yup.string().when("kind", {
|
||||||
|
is: (values: InternshipFormValues) => values?.kind !== InternshipType.Other,
|
||||||
|
then: Yup.string().required(t("validation.required"))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const values = converter.transform(initialInternship);
|
||||||
|
|
||||||
|
const handleSubmit = (values: InternshipFormValues) => {
|
||||||
setConfirmDialogOpen(false);
|
setConfirmDialogOpen(false);
|
||||||
|
|
||||||
dispatch({ type: InternshipProposalActions.Send, internship: internship as Internship });
|
dispatch({
|
||||||
|
type: InternshipProposalActions.Send,
|
||||||
|
internship: converter.reverseTransform(values, {
|
||||||
|
internship: initialInternship as Internship,
|
||||||
|
}) as Internship
|
||||||
|
});
|
||||||
|
|
||||||
history.push(route("home"))
|
history.push(route("home"))
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSubmitConfirmation = () => {
|
const InnerForm = () => {
|
||||||
|
const { submitForm, validateForm } = useFormikContext();
|
||||||
|
|
||||||
|
const handleSubmitConfirmation = async () => {
|
||||||
|
const errors = await validateForm();
|
||||||
|
|
||||||
|
if (Object.keys(errors).length == 0) {
|
||||||
setConfirmDialogOpen(true);
|
setConfirmDialogOpen(true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
setConfirmDialogOpen(false);
|
setConfirmDialogOpen(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return <Form>
|
||||||
<div className="internship-form">
|
|
||||||
<Typography variant="h3" className="section-header">{ t('internship.sections.intern-info') }</Typography>
|
<Typography variant="h3" className="section-header">{ t('internship.sections.intern-info') }</Typography>
|
||||||
<StudentForm student={ sampleStudent }/>
|
<StudentForm />
|
||||||
<Typography variant="h3" className="section-header">{ t('internship.sections.kind' )}</Typography>
|
<Typography variant="h3" className="section-header">{ t('internship.sections.kind' )}</Typography>
|
||||||
<InternshipProgramForm internship={ internship } onChange={ setInternship }/>
|
<InternshipProgramForm />
|
||||||
<Typography variant="h3" className="section-header">{ t('internship.sections.duration') }</Typography>
|
<Typography variant="h3" className="section-header">{ t('internship.sections.duration') }</Typography>
|
||||||
<InternshipDurationForm internship={ internship } onChange={ setInternship }/>
|
<InternshipDurationForm />
|
||||||
<Typography variant="h3" className="section-header">{ t('internship.sections.place') }</Typography>
|
<Typography variant="h3" className="section-header">{ t('internship.sections.place') }</Typography>
|
||||||
<CompanyForm internship={ internship } onChange={ setInternship }/>
|
<CompanyForm />
|
||||||
<Actions>
|
<Actions>
|
||||||
<Button variant="contained" color="primary" onClick={ handleSubmitConfirmation }>{ t("confirm") }</Button>
|
<Button variant="contained" color="primary" onClick={ handleSubmitConfirmation }>{ t("confirm") }</Button>
|
||||||
|
|
||||||
@ -204,10 +342,21 @@ export const InternshipForm: React.FunctionComponent<InternshipFormProps> = prop
|
|||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={ handleCancel }>{ t('cancel') }</Button>
|
<Button onClick={ handleCancel }>{ t('cancel') }</Button>
|
||||||
<Button color="primary" autoFocus onClick={ handleSubmit }>{ t('confirm') }</Button>
|
<Button color="primary" autoFocus onClick={ submitForm }>{ t('confirm') }</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
</div>
|
</Form>
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Formik initialValues={ values }
|
||||||
|
onSubmit={ handleSubmit }
|
||||||
|
validationSchema={ validationSchema }
|
||||||
|
validateOnChange={ false }
|
||||||
|
validateOnBlur={ true }
|
||||||
|
>
|
||||||
|
<InnerForm />
|
||||||
|
</Formik>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,37 +1,38 @@
|
|||||||
import { Course, Student } from "@/data";
|
import { Course } from "@/data";
|
||||||
import { Button, Grid, TextField } from "@material-ui/core";
|
import { Button, Grid, TextField } from "@material-ui/core";
|
||||||
import { Alert, Autocomplete } from "@material-ui/lab";
|
import { Alert, Autocomplete } from "@material-ui/lab";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { sampleCourse } from "@/provider/dummy/student";
|
import { sampleCourse } from "@/provider/dummy/student";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useFormikContext } from "formik";
|
||||||
|
import { InternshipFormValues } from "@/forms/internship";
|
||||||
|
|
||||||
type StudentFormProps = {
|
export const StudentForm = () => {
|
||||||
student: Student
|
const { t } = useTranslation();
|
||||||
}
|
const { values: { student } } = useFormikContext<InternshipFormValues>();
|
||||||
|
|
||||||
export const StudentForm = ({ student }: StudentFormProps) => {
|
return <>
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item md={4}>
|
<Grid item md={4}>
|
||||||
<TextField label="Imię" value={ student.name } disabled fullWidth/>
|
<TextField label={ t("forms.internship.fields.first-name") } value={ student.name } disabled fullWidth/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={4}>
|
<Grid item md={4}>
|
||||||
<TextField label="Nazwisko" value={ student.surname } disabled fullWidth/>
|
<TextField label={ t("forms.internship.fields.last-name") } value={ student.surname } disabled fullWidth/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={4}>
|
<Grid item md={4}>
|
||||||
<TextField label="Nr Indeksu" value={ student.albumNumber } disabled fullWidth/>
|
<TextField label={ t("forms.internship.fields.album") } value={ student.albumNumber } disabled fullWidth/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={9}>
|
<Grid item md={9}>
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
getOptionLabel={ (course: Course) => course.name }
|
getOptionLabel={ (course: Course) => course.name }
|
||||||
renderInput={ props => <TextField { ...props } label={ "Kierunek" } fullWidth/> }
|
renderInput={ props => <TextField { ...props } label={ t("forms.internship.fields.course") } fullWidth/> }
|
||||||
options={[ sampleCourse ]}
|
options={[ sampleCourse ]}
|
||||||
value={ student.course }
|
value={ student.course }
|
||||||
disabled
|
disabled
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item md={3}>
|
<Grid item md={3}>
|
||||||
<TextField label="Semestr" value={ student.semester } disabled fullWidth/>
|
<TextField label={ t("forms.internship.fields.semester") } value={ student.semester } disabled fullWidth/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item>
|
<Grid item>
|
||||||
<Alert severity="warning" action={ <Button color="inherit" size="small">skontaktuj się z opiekunem</Button> }>
|
<Alert severity="warning" action={ <Button color="inherit" size="small">skontaktuj się z opiekunem</Button> }>
|
||||||
@ -39,6 +40,5 @@ export const StudentForm = ({ student }: StudentFormProps) => {
|
|||||||
</Alert>
|
</Alert>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</>
|
</>;
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
@ -1 +1,2 @@
|
|||||||
export * from "./useProxyState"
|
export * from "./useProxyState"
|
||||||
|
export * from "./useUpdateEffect"
|
||||||
|
15
src/hooks/useUpdateEffect.ts
Normal file
15
src/hooks/useUpdateEffect.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { DependencyList, EffectCallback, useEffect, useRef } from "react";
|
||||||
|
|
||||||
|
export const useUpdateEffect = (effect: EffectCallback, dependencies: DependencyList) => {
|
||||||
|
const flag = useRef<boolean>(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (flag.current) {
|
||||||
|
effect();
|
||||||
|
} else {
|
||||||
|
flag.current = true;
|
||||||
|
}
|
||||||
|
}, dependencies)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useUpdateEffect;
|
@ -4,7 +4,7 @@ import I18nextBrowserLanguageDetector from "i18next-browser-languagedetector";
|
|||||||
|
|
||||||
import "moment/locale/pl"
|
import "moment/locale/pl"
|
||||||
import "moment/locale/en-gb"
|
import "moment/locale/en-gb"
|
||||||
import moment, { isDuration, isMoment } from "moment";
|
import moment, { isDuration, isMoment, unitOfTime } from "moment";
|
||||||
import { convertToRoman } from "@/utils/numbers";
|
import { convertToRoman } from "@/utils/numbers";
|
||||||
|
|
||||||
const resources = {
|
const resources = {
|
||||||
@ -22,6 +22,7 @@ i18n
|
|||||||
.init({
|
.init({
|
||||||
resources,
|
resources,
|
||||||
fallbackLng: "pl",
|
fallbackLng: "pl",
|
||||||
|
compatibilityJSON: "v3",
|
||||||
interpolation: {
|
interpolation: {
|
||||||
escapeValue: false,
|
escapeValue: false,
|
||||||
format: (value, format, lng) => {
|
format: (value, format, lng) => {
|
||||||
@ -34,7 +35,11 @@ i18n
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isDuration(value)) {
|
if (isDuration(value)) {
|
||||||
|
if (format === "humanize") {
|
||||||
return value.locale(lng || "pl").humanize();
|
return value.locale(lng || "pl").humanize();
|
||||||
|
} else {
|
||||||
|
return Math.floor(value.locale(lng || "pl").as(format as unitOfTime.Base));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
|
@ -12,7 +12,7 @@ export const SubmitPlanPage = () => {
|
|||||||
return <Page title={ t("steps.plan.submit") }>
|
return <Page title={ t("steps.plan.submit") }>
|
||||||
<Page.Header maxWidth="md">
|
<Page.Header maxWidth="md">
|
||||||
<Page.Breadcrumbs>
|
<Page.Breadcrumbs>
|
||||||
<Link component={ RouterLink } to={ route("home") }>{ t('sections.my-internship.header') }</Link>
|
<Link component={ RouterLink } to={ route("home") }>{ t('pages.my-internship.header') }</Link>
|
||||||
<Typography color="textPrimary">{ t("steps.plan.submit") }</Typography>
|
<Typography color="textPrimary">{ t("steps.plan.submit") }</Typography>
|
||||||
</Page.Breadcrumbs>
|
</Page.Breadcrumbs>
|
||||||
<Page.Title>{ t("steps.plan.submit") }</Page.Title>
|
<Page.Title>{ t("steps.plan.submit") }</Page.Title>
|
||||||
|
@ -1,9 +1,22 @@
|
|||||||
import { Page } from "@/pages/base";
|
import { Page } from "@/pages/base";
|
||||||
import { Container, Link, Typography } from "@material-ui/core";
|
import {
|
||||||
import { Link as RouterLink } from "react-router-dom";
|
Button,
|
||||||
|
ButtonGroup,
|
||||||
|
Container,
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogTitle,
|
||||||
|
Link,
|
||||||
|
Menu,
|
||||||
|
MenuItem,
|
||||||
|
TextField,
|
||||||
|
Typography
|
||||||
|
} from "@material-ui/core";
|
||||||
|
import { Link as RouterLink, useHistory } from "react-router-dom";
|
||||||
import { route } from "@/routing";
|
import { route } from "@/routing";
|
||||||
import { InternshipForm } from "@/forms/internship";
|
import { InternshipForm } from "@/forms/internship";
|
||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import { ProposalComment } from "@/pages/steps/proposal";
|
import { ProposalComment } from "@/pages/steps/proposal";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { ProposalPreview } from "@/components/proposalPreview";
|
import { ProposalPreview } from "@/components/proposalPreview";
|
||||||
@ -11,15 +24,21 @@ import { useSelector } from "react-redux";
|
|||||||
import { Internship } from "@/data";
|
import { Internship } from "@/data";
|
||||||
import { AppState } from "@/state/reducer";
|
import { AppState } from "@/state/reducer";
|
||||||
import { internshipSerializationTransformer } from "@/serialization";
|
import { internshipSerializationTransformer } from "@/serialization";
|
||||||
|
import { Actions } from "@/components";
|
||||||
|
import { InternshipProposalActions, useDispatch } from "@/state/actions";
|
||||||
|
import { MenuDown, StickerCheckOutline, StickerRemoveOutline } from "mdi-material-ui/index";
|
||||||
|
import { useVerticalSpacing } from "@/styles";
|
||||||
|
|
||||||
export const InternshipProposalFormPage = () => {
|
export const InternshipProposalFormPage = () => {
|
||||||
return <Page title="Zgłoszenie praktyki">
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return <Page title={ t("pages.proposal-form.header") }>
|
||||||
<Page.Header maxWidth="md">
|
<Page.Header maxWidth="md">
|
||||||
<Page.Breadcrumbs>
|
<Page.Breadcrumbs>
|
||||||
<Link component={ RouterLink } to={ route("home") }>Moja praktyka</Link>
|
<Link component={ RouterLink } to={ route("home") }>{ t("pages.my-internship.header") }</Link>
|
||||||
<Typography color="textPrimary">Zgłoszenie praktyki</Typography>
|
<Typography color="textPrimary">{ t("pages.proposal-form.header") }</Typography>
|
||||||
</Page.Breadcrumbs>
|
</Page.Breadcrumbs>
|
||||||
<Page.Title>Zgłoszenie praktyki</Page.Title>
|
<Page.Title>{ t("pages.proposal-form.header") }</Page.Title>
|
||||||
</Page.Header>
|
</Page.Header>
|
||||||
<Container maxWidth={ "md" }>
|
<Container maxWidth={ "md" }>
|
||||||
<ProposalComment />
|
<ProposalComment />
|
||||||
@ -32,6 +51,57 @@ export const InternshipProposalPreviewPage = () => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const proposal = useSelector<AppState, Internship | null>(state => state.proposal.proposal && internshipSerializationTransformer.reverseTransform(state.proposal.proposal));
|
const proposal = useSelector<AppState, Internship | null>(state => state.proposal.proposal && internshipSerializationTransformer.reverseTransform(state.proposal.proposal));
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const history = useHistory();
|
||||||
|
|
||||||
|
const [isDiscardModalOpen, setDiscardModelOpen] = useState<boolean>(false);
|
||||||
|
const [isAcceptModalOpen, setAcceptModelOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const [comment, setComment] = useState<string>("");
|
||||||
|
const [menuAnchor, setMenuAnchor] = useState<null | HTMLElement>(null);
|
||||||
|
|
||||||
|
const handleAccept = () => {
|
||||||
|
dispatch({ type: InternshipProposalActions.Approve, comment });
|
||||||
|
history.push(route("home"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDiscard = () => {
|
||||||
|
dispatch({ type: InternshipProposalActions.Decline, comment });
|
||||||
|
history.push(route("home"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAcceptModalClose = () => {
|
||||||
|
setAcceptModelOpen(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDiscardModalClose = () => {
|
||||||
|
setDiscardModelOpen(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDiscardAction = () => {
|
||||||
|
setDiscardModelOpen(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAcceptMenuOpen = (ev: React.MouseEvent<HTMLElement>) => {
|
||||||
|
setMenuAnchor(ev.currentTarget);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAcceptMenuClose = () => {
|
||||||
|
setMenuAnchor(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAcceptWithComment = () => {
|
||||||
|
setAcceptModelOpen(true);
|
||||||
|
setMenuAnchor(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAcceptWithoutComment = () => {
|
||||||
|
dispatch({ type: InternshipProposalActions.Approve, comment: null });
|
||||||
|
history.push(route("home"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const classes = useVerticalSpacing(3);
|
||||||
|
|
||||||
return <Page title={ t("") }>
|
return <Page title={ t("") }>
|
||||||
<Page.Header maxWidth="md">
|
<Page.Header maxWidth="md">
|
||||||
<Page.Breadcrumbs>
|
<Page.Breadcrumbs>
|
||||||
@ -40,10 +110,64 @@ export const InternshipProposalPreviewPage = () => {
|
|||||||
</Page.Breadcrumbs>
|
</Page.Breadcrumbs>
|
||||||
<Page.Title>Moje zgłoszenie</Page.Title>
|
<Page.Title>Moje zgłoszenie</Page.Title>
|
||||||
</Page.Header>
|
</Page.Header>
|
||||||
<Container maxWidth={ "md" }>
|
<Container maxWidth={ "md" } className={ classes.root }>
|
||||||
<ProposalComment />
|
<ProposalComment />
|
||||||
{ proposal && <ProposalPreview proposal={ proposal } /> }
|
{ proposal && <ProposalPreview proposal={ proposal } /> }
|
||||||
|
|
||||||
|
<Actions>
|
||||||
|
<Button component={ RouterLink } to={ route("home") } variant="contained" color="primary">
|
||||||
|
{ t('go-back') }
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<ButtonGroup color="primary" variant="contained">
|
||||||
|
<Button onClick={ handleAcceptWithoutComment } startIcon={ <StickerCheckOutline /> }>
|
||||||
|
{ t('accept-without-comments') }
|
||||||
|
</Button>
|
||||||
|
<Button size="small" onClick={ handleAcceptMenuOpen }><MenuDown /></Button>
|
||||||
|
</ButtonGroup>
|
||||||
|
|
||||||
|
<Menu open={ !!menuAnchor } anchorEl={ menuAnchor } onClose={ handleAcceptMenuClose }>
|
||||||
|
<MenuItem onClick={ handleAcceptWithoutComment }>{ t("accept-without-comments") }</MenuItem>
|
||||||
|
<MenuItem onClick={ handleAcceptWithComment }>{ t("accept-with-comments") }</MenuItem>
|
||||||
|
</Menu>
|
||||||
|
|
||||||
|
<Button onClick={ handleDiscardAction } color="secondary" startIcon={ <StickerRemoveOutline /> }>
|
||||||
|
{ t('discard') }
|
||||||
|
</Button>
|
||||||
|
</Actions>
|
||||||
</Container>
|
</Container>
|
||||||
|
<Dialog open={ isDiscardModalOpen } onClose={ handleDiscardModalClose } maxWidth="md">
|
||||||
|
<DialogTitle>{ t("internship.discard.title") }</DialogTitle>
|
||||||
|
<DialogContent className={ classes.root }>
|
||||||
|
<Typography variant="body1">{ t("internship.discard.info") }</Typography>
|
||||||
|
<TextField multiline value={ comment } onChange={ ev => setComment(ev.target.value) } fullWidth label={ t("comments") } rows={3}/>
|
||||||
|
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={ handleDiscardModalClose }>
|
||||||
|
{ t('cancel') }
|
||||||
|
</Button>
|
||||||
|
<Button onClick={ handleDiscard } color="primary" variant="contained">
|
||||||
|
{ t('confirm') }
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
<Dialog open={ isAcceptModalOpen } onClose={ handleAcceptModalClose } maxWidth="md">
|
||||||
|
<DialogTitle>{ t("internship.accept.title") }</DialogTitle>
|
||||||
|
<DialogContent className={ classes.root }>
|
||||||
|
<Typography variant="body1">{ t("internship.accept.info") }</Typography>
|
||||||
|
<TextField multiline value={ comment } onChange={ ev => setComment(ev.target.value) } fullWidth label={ t("comments") }/>
|
||||||
|
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={ handleAcceptModalClose }>
|
||||||
|
{ t('cancel') }
|
||||||
|
</Button>
|
||||||
|
<Button onClick={ handleAccept } color="primary" variant="contained">
|
||||||
|
{ t('confirm') }
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
</Page>
|
</Page>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ export const MainPage = () => {
|
|||||||
|
|
||||||
return <Page my={ 6 }>
|
return <Page my={ 6 }>
|
||||||
<Container>
|
<Container>
|
||||||
<Typography variant="h2">{ t("sections.my-internship.header") }</Typography>
|
<Typography variant="h2">{ t("pages.my-internship.header") }</Typography>
|
||||||
<Stepper orientation="vertical" nonLinear>
|
<Stepper orientation="vertical" nonLinear>
|
||||||
<Step label={ t('steps.personal-data.header') } completed={ missingStudentData.length === 0 } until={ deadlines.personalData }>
|
<Step label={ t('steps.personal-data.header') } completed={ missingStudentData.length === 0 } until={ deadlines.personalData }>
|
||||||
{ missingStudentData.length > 0 && <>
|
{ missingStudentData.length > 0 && <>
|
||||||
|
@ -4,5 +4,6 @@ import moment from "moment";
|
|||||||
export const sampleEdition: Edition = {
|
export const sampleEdition: Edition = {
|
||||||
startDate: moment("2020-07-01"),
|
startDate: moment("2020-07-01"),
|
||||||
endDate: moment("2020-09-30"),
|
endDate: moment("2020-09-30"),
|
||||||
proposalDeadline: moment("2020-07-31")
|
proposalDeadline: moment("2020-07-31"),
|
||||||
|
minimumInternshipHours: 40,
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,9 @@ type Simplify<T> = string |
|
|||||||
T extends Object ? Serializable<T> : any;
|
T extends Object ? Serializable<T> : any;
|
||||||
|
|
||||||
export type Serializable<T> = { [K in keyof T]: Simplify<T[K]> }
|
export type Serializable<T> = { [K in keyof T]: Simplify<T[K]> }
|
||||||
export type Transformer<TFrom, TResult> = {
|
export type Transformer<TFrom, TResult, TContext = never> = {
|
||||||
transform(subject: TFrom): TResult;
|
transform(subject: TFrom, context?: TContext): TResult;
|
||||||
reverseTransform(subject: TResult): TFrom;
|
reverseTransform(subject: TResult, context?: TContext): TFrom;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SerializationTransformer<T, TSerialized = Serializable<T>> = Transformer<T, TSerialized>
|
export type SerializationTransformer<T, TSerialized = Serializable<T>> = Transformer<T, TSerialized>
|
||||||
|
@ -8,6 +8,9 @@ export const studentTheme = responsiveFontSizes(createMuiTheme({
|
|||||||
},
|
},
|
||||||
MuiContainer: {
|
MuiContainer: {
|
||||||
maxWidth: "md"
|
maxWidth: "md"
|
||||||
|
},
|
||||||
|
MuiTextField: {
|
||||||
|
variant: "outlined",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
palette: {
|
palette: {
|
||||||
|
@ -11,6 +11,41 @@ left: '{{ left, humanize }} left'
|
|||||||
|
|
||||||
dropzone: "Drag and drop a file here or click to choose"
|
dropzone: "Drag and drop a file here or click to choose"
|
||||||
|
|
||||||
|
forms:
|
||||||
|
internship:
|
||||||
|
fields:
|
||||||
|
start-date: Internship start date
|
||||||
|
end-date: Internship end date
|
||||||
|
working-hours: Working time
|
||||||
|
total-hours: Total hours
|
||||||
|
weeks: Total weeks
|
||||||
|
first-name: First name
|
||||||
|
last-name: Last name
|
||||||
|
album: Album number
|
||||||
|
course: Course
|
||||||
|
semester: Semester
|
||||||
|
kind: Contract type
|
||||||
|
kind-other: Other - please fill
|
||||||
|
company-name: Company name
|
||||||
|
nip: NIP
|
||||||
|
e-mail: e-mail address
|
||||||
|
phone: Phone number
|
||||||
|
city: City
|
||||||
|
postal-code: Postal code
|
||||||
|
country: Country
|
||||||
|
street: Street
|
||||||
|
building: Building
|
||||||
|
help:
|
||||||
|
weeks: Calculated automatically
|
||||||
|
working-hours: Total working hours in working week
|
||||||
|
send-confirmation: >
|
||||||
|
Po wysłaniu zgłoszenia nie będzie możliwości jego zmiany do czasu zweryfikowania go przez pełnomocnika ds. Twojego
|
||||||
|
kierunku. Czy na pewno chcesz wysłać zgłoszenie praktyki w tej formie?
|
||||||
|
plan:
|
||||||
|
instructions: >
|
||||||
|
Wypełnij i zeskanuj Indywidualny program Praktyk a następnie wyślij go z pomocą tego formularza. <więcej informacji>
|
||||||
|
dropzone-help: Skan dokumentu w formacie PDF
|
||||||
|
|
||||||
student:
|
student:
|
||||||
name: first name
|
name: first name
|
||||||
surname: last name
|
surname: last name
|
||||||
@ -19,7 +54,41 @@ student:
|
|||||||
email: e-mail
|
email: e-mail
|
||||||
albumNumber: album number
|
albumNumber: album number
|
||||||
|
|
||||||
sections:
|
internship:
|
||||||
|
intern:
|
||||||
|
semester: semesetr {{ semester, roman }}
|
||||||
|
album: "album number {{ album }}"
|
||||||
|
date-range: "{{ start, DD MMMM YYYY }} - {{ end, DD MMMM YYYY }}"
|
||||||
|
duration: "{{ duration, weeks }} week"
|
||||||
|
duration_plural: "{{ duration, weeks }} weeks"
|
||||||
|
hours: "{{ hours }} hour"
|
||||||
|
hours_plural: "{{ hours }} hours"
|
||||||
|
office: "Office / Address"
|
||||||
|
mentor: "Internship mentor"
|
||||||
|
address:
|
||||||
|
city: "{{ city }}, {{ country }}"
|
||||||
|
street: "{{ postalCode }}, {{ street }} {{ building }}"
|
||||||
|
sections:
|
||||||
|
intern-info: "Intern personal data"
|
||||||
|
duration: "Internship duration"
|
||||||
|
place: "Internship place"
|
||||||
|
kind: "Contract and programme"
|
||||||
|
mentor: "Internship mentor"
|
||||||
|
discard:
|
||||||
|
title: "Discard internship proposal"
|
||||||
|
info: "This comments will be presented to student in order to fix errors."
|
||||||
|
accept:
|
||||||
|
title: "Accept internship proposal"
|
||||||
|
info: "This comments will be presented to student."
|
||||||
|
|
||||||
|
submission:
|
||||||
|
status:
|
||||||
|
awaiting: "sent, awaiting verification"
|
||||||
|
accepted: "accepted"
|
||||||
|
declined: "needs correction"
|
||||||
|
draft: "draft"
|
||||||
|
|
||||||
|
pages:
|
||||||
my-internship:
|
my-internship:
|
||||||
header: "My internship"
|
header: "My internship"
|
||||||
|
|
||||||
@ -29,10 +98,22 @@ steps:
|
|||||||
info: >
|
info: >
|
||||||
Your profile is incomplete. In order to continue your internship you have to supply information given below. In
|
Your profile is incomplete. In order to continue your internship you have to supply information given below. In
|
||||||
case of problem with providing those information - please contact with your internship coordinator of your course.
|
case of problem with providing those information - please contact with your internship coordinator of your course.
|
||||||
|
form: "Add missing data"
|
||||||
internship-proposal:
|
internship-proposal:
|
||||||
header: "Internship proposal"
|
header: "Internship proposal"
|
||||||
form: "Internship proposal form"
|
form: "Internship proposal form"
|
||||||
info: ""
|
info:
|
||||||
|
draft: >
|
||||||
|
Przed podjęciem praktyki należy ją zgłosić. (TODO)
|
||||||
|
awaiting: >
|
||||||
|
Twoje zgłoszenie musi zostać zweryfikowane i zatwierdzone. Po weryfikacji zostaniesz poinformowany o
|
||||||
|
akceptacji bądź konieczności wprowadzenia zmian.
|
||||||
|
accepted: >
|
||||||
|
Twoje zgłoszenie zostało zweryfikowane i zaakceptowane.
|
||||||
|
declined: >
|
||||||
|
Twoje zgłoszenie zostało zweryfikowane i odrzucone. Popraw zgłoszone uwagi i wyślij zgłoszenie ponownie. W razie
|
||||||
|
pytań możesz również skontaktować się z pełnomocnikiem ds. praktyk Twojego kierunku.
|
||||||
|
action: "Send internship proposal"
|
||||||
plan:
|
plan:
|
||||||
header: "Individual Internship Plan"
|
header: "Individual Internship Plan"
|
||||||
info: ""
|
info: ""
|
||||||
|
@ -20,15 +20,46 @@ comments: Zgłoszone uwagi
|
|||||||
send-again: wyślij ponownie
|
send-again: wyślij ponownie
|
||||||
cancel: anuluj
|
cancel: anuluj
|
||||||
|
|
||||||
|
accept: zaakceptuj
|
||||||
|
accept-with-comments: zaakceptuj z uwagami
|
||||||
|
accept-without-comments: zaakceptuj bez uwag
|
||||||
|
discard: zgłoś uwagi
|
||||||
|
|
||||||
dropzone: "Przeciągnij i upuść plik bądź kliknij, aby wybrać"
|
dropzone: "Przeciągnij i upuść plik bądź kliknij, aby wybrać"
|
||||||
|
|
||||||
sections:
|
pages:
|
||||||
my-internship:
|
my-internship:
|
||||||
header: "Moja praktyka"
|
header: "Moja praktyka"
|
||||||
|
proposal-form:
|
||||||
|
header: "Propose internship"
|
||||||
|
|
||||||
forms:
|
forms:
|
||||||
internship:
|
internship:
|
||||||
|
fields:
|
||||||
|
start-date: Data rozpoczęcia praktyki
|
||||||
|
end-date: Data zakończenia praktyki
|
||||||
|
working-hours: Wymiar etatu
|
||||||
|
total-hours: Łączna liczba godzin
|
||||||
|
weeks: Liczba tygodni
|
||||||
|
first-name: Imię
|
||||||
|
last-name: Nazwisko
|
||||||
|
album: Numer albumu
|
||||||
|
course: Kierunek
|
||||||
|
semester: Semestr
|
||||||
|
kind: Rodzaj praktyki/umowy
|
||||||
|
kind-other: Inny - wprowadź
|
||||||
|
company-name: Nazwa firmy
|
||||||
|
nip: NIP
|
||||||
|
e-mail: Kontaktowy adres e-mail
|
||||||
|
phone: Numer telefonu
|
||||||
|
city: Miasto
|
||||||
|
postal-code: Kod pocztowy
|
||||||
|
country: Kraj
|
||||||
|
street: Ulica
|
||||||
|
building: Nr budynku
|
||||||
|
help:
|
||||||
|
weeks: Wartość wyliczana automatycznie
|
||||||
|
working-hours: Liczba godzin w tygodniu roboczym
|
||||||
send-confirmation: >
|
send-confirmation: >
|
||||||
Po wysłaniu zgłoszenia nie będzie możliwości jego zmiany do czasu zweryfikowania go przez pełnomocnika ds. Twojego
|
Po wysłaniu zgłoszenia nie będzie możliwości jego zmiany do czasu zweryfikowania go przez pełnomocnika ds. Twojego
|
||||||
kierunku. Czy na pewno chcesz wysłać zgłoszenie praktyki w tej formie?
|
kierunku. Czy na pewno chcesz wysłać zgłoszenie praktyki w tej formie?
|
||||||
@ -57,9 +88,14 @@ internship:
|
|||||||
semester: semestr {{ semester, roman }}
|
semester: semestr {{ semester, roman }}
|
||||||
album: "numer albumu {{ album }}"
|
album: "numer albumu {{ album }}"
|
||||||
date-range: "{{ start, DD MMMM YYYY }} - {{ end, DD MMMM YYYY }}"
|
date-range: "{{ start, DD MMMM YYYY }} - {{ end, DD MMMM YYYY }}"
|
||||||
duration: "{{ duration, humanize }}"
|
duration_2: "{{ duration, weeks }} tygodni"
|
||||||
hours: "{{ hours }} godzin"
|
duration_0: "{{ duration, weeks }} tydzień"
|
||||||
|
duration_1: "{{ duration, weeks }} tygodnie"
|
||||||
|
hours_2: "{{ hours }} godzin"
|
||||||
|
hours_0: "{{ hours }} godzina"
|
||||||
|
hours_1: "{{ hours }} godziny"
|
||||||
office: "Oddział / adres"
|
office: "Oddział / adres"
|
||||||
|
mentor: "Zakładowy opiekun praktyki"
|
||||||
address:
|
address:
|
||||||
city: "{{ city }}, {{ country }}"
|
city: "{{ city }}, {{ country }}"
|
||||||
street: "{{ postalCode }}, {{ street }} {{ building }}"
|
street: "{{ postalCode }}, {{ street }} {{ building }}"
|
||||||
@ -69,7 +105,12 @@ internship:
|
|||||||
place: "Miejsce odbywania praktyki"
|
place: "Miejsce odbywania praktyki"
|
||||||
kind: "Rodzaj i program praktyki"
|
kind: "Rodzaj i program praktyki"
|
||||||
mentor: "Zakładowy opiekun praktyki"
|
mentor: "Zakładowy opiekun praktyki"
|
||||||
|
discard:
|
||||||
|
title: "Odrzuć zgłoszenie praktyki"
|
||||||
|
info: "Poniższa informacja zostanie przekazana praktykantowi w celu poprawy zgłoszenia."
|
||||||
|
accept:
|
||||||
|
title: "Zaakceptuj zgłoszenie praktyki"
|
||||||
|
info: "Poniższa informacja zostanie przekazana praktykantowi."
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
personal-data:
|
personal-data:
|
||||||
@ -118,4 +159,11 @@ steps:
|
|||||||
instructions: >
|
instructions: >
|
||||||
papierki do podpisania...
|
papierki do podpisania...
|
||||||
|
|
||||||
|
validation:
|
||||||
|
required: "To pole jest wymagane"
|
||||||
|
email: "Wprowadź poprawny adres e-mail"
|
||||||
|
phone: "Wprowadź poprawny numer telefonu"
|
||||||
|
internship:
|
||||||
|
minimum-hours: "Minimalna liczba godzin wynosi {{ hours }}"
|
||||||
|
|
||||||
contact-coordinator: "Skontaktuj się z koordynatorem"
|
contact-coordinator: "Skontaktuj się z koordynatorem"
|
||||||
|
87
yarn.lock
87
yarn.lock
@ -933,6 +933,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
regenerator-runtime "^0.13.4"
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
|
"@babel/runtime@^7.10.5":
|
||||||
|
version "7.11.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
|
||||||
|
integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
|
||||||
|
dependencies:
|
||||||
|
regenerator-runtime "^0.13.4"
|
||||||
|
|
||||||
"@babel/template@^7.10.1", "@babel/template@^7.8.6":
|
"@babel/template@^7.10.1", "@babel/template@^7.8.6":
|
||||||
version "7.10.1"
|
version "7.10.1"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811"
|
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811"
|
||||||
@ -1311,6 +1318,11 @@
|
|||||||
"@types/webpack-sources" "*"
|
"@types/webpack-sources" "*"
|
||||||
source-map "^0.6.0"
|
source-map "^0.6.0"
|
||||||
|
|
||||||
|
"@types/yup@^0.29.4":
|
||||||
|
version "0.29.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.29.4.tgz#f7b1f9978180d5155663c1cd0ecdc41a72c23d81"
|
||||||
|
integrity sha512-OQ7gZRQb7eSbGu5h57tbK67sgX8UH5wbuqPORTFBG7qiBtOkEf1dXAr0QULyHIeRwaGLPYxPXiQru+40ClR6ng==
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin@^2.10.0":
|
"@typescript-eslint/eslint-plugin@^2.10.0":
|
||||||
version "2.34.0"
|
version "2.34.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz#6f8ce8a46c7dea4a6f1d171d2bb8fbae6dac2be9"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz#6f8ce8a46c7dea4a6f1d171d2bb8fbae6dac2be9"
|
||||||
@ -3170,6 +3182,11 @@ deep-equal@^1.0.1:
|
|||||||
object-keys "^1.1.1"
|
object-keys "^1.1.1"
|
||||||
regexp.prototype.flags "^1.2.0"
|
regexp.prototype.flags "^1.2.0"
|
||||||
|
|
||||||
|
deepmerge@^2.1.1:
|
||||||
|
version "2.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170"
|
||||||
|
integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==
|
||||||
|
|
||||||
default-gateway@^4.2.0:
|
default-gateway@^4.2.0:
|
||||||
version "4.2.0"
|
version "4.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b"
|
resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b"
|
||||||
@ -3914,6 +3931,11 @@ flush-write-stream@^1.0.0:
|
|||||||
inherits "^2.0.3"
|
inherits "^2.0.3"
|
||||||
readable-stream "^2.3.6"
|
readable-stream "^2.3.6"
|
||||||
|
|
||||||
|
fn-name@~3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-3.0.0.tgz#0596707f635929634d791f452309ab41558e3c5c"
|
||||||
|
integrity sha512-eNMNr5exLoavuAMhIUVsOKF79SWd/zG104ef6sxBTSw+cZc6BXdQXDvYcGvp0VbxVVSp1XDUNoz7mg1xMtSznA==
|
||||||
|
|
||||||
follow-redirects@^1.0.0:
|
follow-redirects@^1.0.0:
|
||||||
version "1.11.0"
|
version "1.11.0"
|
||||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.11.0.tgz#afa14f08ba12a52963140fe43212658897bc0ecb"
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.11.0.tgz#afa14f08ba12a52963140fe43212658897bc0ecb"
|
||||||
@ -3954,6 +3976,25 @@ form-data@~2.3.2:
|
|||||||
combined-stream "^1.0.6"
|
combined-stream "^1.0.6"
|
||||||
mime-types "^2.1.12"
|
mime-types "^2.1.12"
|
||||||
|
|
||||||
|
formik-material-ui@^3.0.0-alpha.0:
|
||||||
|
version "3.0.0-alpha.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/formik-material-ui/-/formik-material-ui-3.0.0-alpha.0.tgz#4020b5cbd9e431406fb275a317cdce95ad398545"
|
||||||
|
integrity sha512-N9JcSngi4nWaKN67sN1M3ILXgz0fLCdoMhHHecrZC3NeR+C5lWWAUuAcjGZWNj+z87Qt7NW8VXlxSnGxGus8Uw==
|
||||||
|
|
||||||
|
formik@^2.1.5:
|
||||||
|
version "2.1.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/formik/-/formik-2.1.5.tgz#de5bbbe35543fa6d049fe96b8ee329d6cd6892b8"
|
||||||
|
integrity sha512-bWpo3PiqVDYslvrRjTq0Isrm0mFXHiO33D8MS6t6dWcqSFGeYF52nlpCM2xwOJ6tRVRznDkL+zz/iHPL4LDuvQ==
|
||||||
|
dependencies:
|
||||||
|
deepmerge "^2.1.1"
|
||||||
|
hoist-non-react-statics "^3.3.0"
|
||||||
|
lodash "^4.17.14"
|
||||||
|
lodash-es "^4.17.14"
|
||||||
|
react-fast-compare "^2.0.1"
|
||||||
|
scheduler "^0.18.0"
|
||||||
|
tiny-warning "^1.0.2"
|
||||||
|
tslib "^1.10.0"
|
||||||
|
|
||||||
forwarded@~0.1.2:
|
forwarded@~0.1.2:
|
||||||
version "0.1.2"
|
version "0.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
|
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
|
||||||
@ -5364,6 +5405,11 @@ locate-path@^5.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
p-locate "^4.1.0"
|
p-locate "^4.1.0"
|
||||||
|
|
||||||
|
lodash-es@^4.17.11, lodash-es@^4.17.14:
|
||||||
|
version "4.17.15"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.15.tgz#21bd96839354412f23d7a10340e5eac6ee455d78"
|
||||||
|
integrity sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==
|
||||||
|
|
||||||
lodash._reinterpolate@^3.0.0:
|
lodash._reinterpolate@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
|
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
|
||||||
@ -7192,6 +7238,11 @@ prop-types@^15.6.2, prop-types@^15.7.2:
|
|||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
react-is "^16.8.1"
|
react-is "^16.8.1"
|
||||||
|
|
||||||
|
property-expr@^2.0.2:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.2.tgz#fff2a43919135553a3bc2fdd94bdb841965b2330"
|
||||||
|
integrity sha512-bc/5ggaYZxNkFKj374aLbEDqVADdYaLcFo8XBkishUWbaAdjlphaBFns9TvRA2pUseVL/wMFmui9X3IdNDU37g==
|
||||||
|
|
||||||
proxy-addr@~2.0.5:
|
proxy-addr@~2.0.5:
|
||||||
version "2.0.6"
|
version "2.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf"
|
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf"
|
||||||
@ -7400,6 +7451,11 @@ react-error-overlay@^6.0.7:
|
|||||||
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.7.tgz#1dcfb459ab671d53f660a991513cb2f0a0553108"
|
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.7.tgz#1dcfb459ab671d53f660a991513cb2f0a0553108"
|
||||||
integrity sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA==
|
integrity sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA==
|
||||||
|
|
||||||
|
react-fast-compare@^2.0.1:
|
||||||
|
version "2.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9"
|
||||||
|
integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==
|
||||||
|
|
||||||
react-i18next@^11.7.0:
|
react-i18next@^11.7.0:
|
||||||
version "11.7.0"
|
version "11.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.7.0.tgz#f27c4c237a274e007a48ac1210db83e33719908b"
|
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.7.0.tgz#f27c4c237a274e007a48ac1210db83e33719908b"
|
||||||
@ -7888,6 +7944,14 @@ sax@~1.2.4:
|
|||||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||||
|
|
||||||
|
scheduler@^0.18.0:
|
||||||
|
version "0.18.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.18.0.tgz#5901ad6659bc1d8f3fdaf36eb7a67b0d6746b1c4"
|
||||||
|
integrity sha512-agTSHR1Nbfi6ulI0kYNK0203joW2Y5W4po4l+v03tOoiJKpTBbxpNhWDvqc/4IcOw+KLmSiQLTasZ4cab2/UWQ==
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.1.0"
|
||||||
|
object-assign "^4.1.1"
|
||||||
|
|
||||||
scheduler@^0.19.1:
|
scheduler@^0.19.1:
|
||||||
version "0.19.1"
|
version "0.19.1"
|
||||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196"
|
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196"
|
||||||
@ -8554,6 +8618,11 @@ symbol-observable@^1.2.0:
|
|||||||
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
|
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
|
||||||
integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
|
integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
|
||||||
|
|
||||||
|
synchronous-promise@^2.0.13:
|
||||||
|
version "2.0.13"
|
||||||
|
resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.13.tgz#9d8c165ddee69c5a6542862b405bc50095926702"
|
||||||
|
integrity sha512-R9N6uDkVsghHePKh1TEqbnLddO2IY25OcsksyFp/qBe7XYd0PVbKEWxhcdMhpLzE1I6skj5l4aEZ3CRxcbArlA==
|
||||||
|
|
||||||
tapable@^1.0.0, tapable@^1.1.3:
|
tapable@^1.0.0, tapable@^1.1.3:
|
||||||
version "1.1.3"
|
version "1.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
|
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
|
||||||
@ -8696,6 +8765,11 @@ toidentifier@1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
|
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
|
||||||
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
|
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
|
||||||
|
|
||||||
|
toposort@^2.0.2:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330"
|
||||||
|
integrity sha1-riF2gXXRVZ1IvvNUILL0li8JwzA=
|
||||||
|
|
||||||
tough-cookie@~2.5.0:
|
tough-cookie@~2.5.0:
|
||||||
version "2.5.0"
|
version "2.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
|
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
|
||||||
@ -9469,3 +9543,16 @@ yargs@^13.3.2:
|
|||||||
which-module "^2.0.0"
|
which-module "^2.0.0"
|
||||||
y18n "^4.0.0"
|
y18n "^4.0.0"
|
||||||
yargs-parser "^13.1.2"
|
yargs-parser "^13.1.2"
|
||||||
|
|
||||||
|
yup@^0.29.3:
|
||||||
|
version "0.29.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/yup/-/yup-0.29.3.tgz#69a30fd3f1c19f5d9e31b1cf1c2b851ce8045fea"
|
||||||
|
integrity sha512-RNUGiZ/sQ37CkhzKFoedkeMfJM0vNQyaz+wRZJzxdKE7VfDeVKH8bb4rr7XhRLbHJz5hSjoDNwMEIaKhuMZ8gQ==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.10.5"
|
||||||
|
fn-name "~3.0.0"
|
||||||
|
lodash "^4.17.15"
|
||||||
|
lodash-es "^4.17.11"
|
||||||
|
property-expr "^2.0.2"
|
||||||
|
synchronous-promise "^2.0.13"
|
||||||
|
toposort "^2.0.2"
|
||||||
|
Loading…
Reference in New Issue
Block a user