diff --git a/package.json b/package.json index 4b1d642..c5eba09 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "@types/react-router-dom": "^5.1.5", "@types/redux": "^3.6.0", "@types/redux-persist": "^4.3.1", + "@types/yup": "^0.29.4", "@typescript-eslint/eslint-plugin": "^2.10.0", "@typescript-eslint/parser": "^2.10.0", "babel-core": "^6.26.3", @@ -30,6 +31,7 @@ "date-holidays": "^1.5.3", "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", "i18next": "^19.6.0", "i18next-browser-languagedetector": "^5.0.0", @@ -63,7 +65,8 @@ "webpack-cli": "^3.3.11", "webpack-dev-server": "3.10.3", "workbox-webpack-plugin": "4.3.1", - "yaml-loader": "^0.6.0" + "yaml-loader": "^0.6.0", + "yup": "^0.29.3" }, "scripts": { "serve": "webpack-dev-server --mode development", diff --git a/src/data/common.ts b/src/data/common.ts index 62671b8..5a735c4 100644 --- a/src/data/common.ts +++ b/src/data/common.ts @@ -1,3 +1,5 @@ +export type Identifier = string; + export interface Identifiable { - id?: string + id?: Identifier } diff --git a/src/forms/company.tsx b/src/forms/company.tsx index d18ddcc..4cfd2b8 100644 --- a/src/forms/company.tsx +++ b/src/forms/company.tsx @@ -8,6 +8,8 @@ import { InternshipFormSectionProps } from "@/forms/internship"; import { emptyMentor } from "@/provider/dummy/internship"; import { useProxyState } from "@/hooks"; import { useTranslation } from "react-i18next"; +import { Field } from "formik"; +import { TextField as TextFieldFormik } from "formik-material-ui" export type CompanyFormProps = {} & InternshipFormSectionProps; @@ -95,27 +97,24 @@ export const BranchForm: React.FC = ({ value: office, onChang ) } -export const MentorForm = ({ mentor, onMentorChange }: BoundProperty) => { - const fieldProps = formFieldProps(mentor, onMentorChange) +export const MentorForm = () => { const { t } = useTranslation(); return ( - <> - - - - - - - - - - - - - + + + - + + + + + + + + + + ); } @@ -162,7 +161,7 @@ export const CompanyForm: React.FunctionComponent = ({ interns {/**/} { t("internship.mentor") } - + { t("internship.office") } diff --git a/src/forms/internship.tsx b/src/forms/internship.tsx index a6c5e3a..7b487eb 100644 --- a/src/forms/internship.tsx +++ b/src/forms/internship.tsx @@ -4,7 +4,7 @@ import { KeyboardDatePicker as DatePicker } from "@material-ui/pickers"; import { CompanyForm } from "@/forms/company"; import { StudentForm } from "@/forms/student"; import { sampleStudent } from "@/provider/dummy/student"; -import { Internship, InternshipType, internshipTypeLabels } from "@/data"; +import { BranchOffice, Company, Internship, InternshipType, internshipTypeLabels, Student } from "@/data"; import { Nullable } from "@/helpers"; import moment, { Moment } from "moment"; import { computeWorkingHours } from "@/utils/date"; @@ -20,6 +20,8 @@ import { route } from "@/routing"; import { useProxyState } from "@/hooks"; import { getInternshipProposal } from "@/state/reducer/proposal"; import { Actions } from "@/components"; +import { Form, Formik } from "formik"; +import * as Yup from "yup"; export type InternshipFormProps = {} @@ -28,6 +30,50 @@ export type InternshipFormSectionProps = { onChange: (internship: Nullable) => void, } +export type InternshipFormState = { + startDate: Moment | null; + endDate: Moment | null; + hours: number | null; + companyName: string; + companyNip: string; + city: string; + postalCode: string; + country: string; + building: string; + mentorFirstName: string; + mentorLastName: string; + mentorEmail: string; + mentorPhone: string; + kindOther: string | null; + + // relations + kind: InternshipType | null; + company: Company | null; + office: BranchOffice | null; + student: Student | null; +} + +const emptyInternshipValues: InternshipFormState = { + building: "", + city: "", + company: null, + companyName: "", + companyNip: "", + country: "", + endDate: null, + hours: null, + kind: null, + kindOther: "", + mentorEmail: "", + mentorFirstName: "", + mentorLastName: "", + mentorPhone: "", + office: null, + postalCode: "", + startDate: null, + student: null +} + export const InternshipTypeItem = ({ type, ...props }: { type: InternshipType } & HTMLProps) => { const info = internshipTypeLabels[type]; @@ -158,34 +204,50 @@ export const InternshipForm: React.FunctionComponent = prop setConfirmDialogOpen(false); } + const validationSchema = Yup.object>({ + 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(40, t("validation.internship.minimum-hours")) // todo: take it from edition + }) + return ( -
- { t('internship.sections.intern-info') } - - { t('internship.sections.kind' )} - - { t('internship.sections.duration') } - - { t('internship.sections.place') } - - - + console.log(values) } + validationSchema={ validationSchema } validateOnChange={ false } validateOnBlur={ true }> + { formik =>
+ { t('internship.sections.intern-info') } + + { t('internship.sections.kind' )} + + { t('internship.sections.duration') } + + { t('internship.sections.place') } + + + - - + + - - - { t('forms.internship.send-confirmation') } - - - - - - -
+ + + { t('forms.internship.send-confirmation') } + + + + + + + } + ) } diff --git a/translations/pl.yaml b/translations/pl.yaml index a82d788..8fc6115 100644 --- a/translations/pl.yaml +++ b/translations/pl.yaml @@ -159,4 +159,9 @@ steps: instructions: > papierki do podpisania... +validation: + required: "To pole jest wymagane" + email: "Wprowadź poprawny adres e-mail" + phone: "Wprowadź poprawny numer telefonu" + contact-coordinator: "Skontaktuj się z koordynatorem" diff --git a/yarn.lock b/yarn.lock index 4ed4f49..634fa14 100644 --- a/yarn.lock +++ b/yarn.lock @@ -933,6 +933,13 @@ dependencies: 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": version "7.10.1" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.1.tgz#e167154a94cb5f14b28dc58f5356d2162f539811" @@ -1311,6 +1318,11 @@ "@types/webpack-sources" "*" 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": version "2.34.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz#6f8ce8a46c7dea4a6f1d171d2bb8fbae6dac2be9" @@ -3919,6 +3931,11 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" 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: version "1.11.0" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.11.0.tgz#afa14f08ba12a52963140fe43212658897bc0ecb" @@ -3959,6 +3976,11 @@ form-data@~2.3.2: combined-stream "^1.0.6" 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" @@ -5383,7 +5405,7 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" -lodash-es@^4.17.14: +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== @@ -7216,6 +7238,11 @@ prop-types@^15.6.2, prop-types@^15.7.2: object-assign "^4.1.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: version "2.0.6" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" @@ -8591,6 +8618,11 @@ symbol-observable@^1.2.0: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" 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: version "1.1.3" resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" @@ -8733,6 +8765,11 @@ toidentifier@1.0.0: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" 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: version "2.5.0" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" @@ -9506,3 +9543,16 @@ yargs@^13.3.2: which-module "^2.0.0" y18n "^4.0.0" 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"