From a3710d4b9b2f313bae7710fca1a4815763dcf416 Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Tue, 9 Jun 2020 23:52:14 +0200 Subject: [PATCH 1/2] Add basic datatypes and first form implementation --- package.json | 4 +++ src/App.css | 38 ---------------------- src/App.test.tsx | 9 ------ src/App.tsx | 23 ++++---------- src/data/company.ts | 27 ++++++++++++++++ src/data/internship.ts | 23 ++++++++++++++ src/forms/Internship.tsx | 22 +++++++++++++ src/forms/company.tsx | 69 ++++++++++++++++++++++++++++++++++++++++ src/helpers.ts | 1 + src/index.css | 13 -------- src/index.tsx | 1 - src/logo.svg | 7 ---- src/provider/company.ts | 62 ++++++++++++++++++++++++++++++++++++ src/setupTests.ts | 5 --- yarn.lock | 62 +++++++++++++++++++++++++++++++++++- 15 files changed, 275 insertions(+), 91 deletions(-) delete mode 100644 src/App.css delete mode 100644 src/App.test.tsx create mode 100644 src/data/company.ts create mode 100644 src/data/internship.ts create mode 100644 src/forms/Internship.tsx create mode 100644 src/forms/company.tsx create mode 100644 src/helpers.ts delete mode 100644 src/index.css delete mode 100644 src/logo.svg create mode 100644 src/provider/company.ts delete mode 100644 src/setupTests.ts diff --git a/package.json b/package.json index 290a8ba..d48b98e 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,17 @@ "private": true, "dependencies": { "@material-ui/core": "^4.10.1", + "@material-ui/lab": "^4.0.0-alpha.55", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^7.1.2", "@types/jest": "^24.0.0", + "@types/moment": "^2.13.0", "@types/node": "^12.0.0", "@types/react": "^16.9.0", "@types/react-dom": "^16.9.0", + "formik": "^2.1.4", + "moment": "^2.26.0", "react": "^16.13.1", "react-dom": "^16.13.1", "react-scripts": "3.4.1", diff --git a/src/App.css b/src/App.css deleted file mode 100644 index 74b5e05..0000000 --- a/src/App.css +++ /dev/null @@ -1,38 +0,0 @@ -.App { - text-align: center; -} - -.App-logo { - height: 40vmin; - pointer-events: none; -} - -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} diff --git a/src/App.test.tsx b/src/App.test.tsx deleted file mode 100644 index 4db7ebc..0000000 --- a/src/App.test.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import { render } from '@testing-library/react'; -import App from './App'; - -test('renders learn react link', () => { - const { getByText } = render(); - const linkElement = getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); -}); diff --git a/src/App.tsx b/src/App.tsx index d919f03..f6ed80e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,24 +1,13 @@ import React from 'react'; -import logo from './logo.svg'; -import './App.css'; +import { Container } from "@material-ui/core"; +import { CompanyForm } from "./forms/company"; function App() { return ( -
-
- logo -

- Edit src/App.tsx and save to reload. -

- - Learn React - System Praktyk - -
+
+ + +
); } diff --git a/src/data/company.ts b/src/data/company.ts new file mode 100644 index 0000000..c73333d --- /dev/null +++ b/src/data/company.ts @@ -0,0 +1,27 @@ +export interface Address { + street: string; + building: string; + city: string; + postalCode: string; + country: string; +} + +export interface Company { + name: string; + url?: string; + nip: string; + offices: BranchOffice[]; +} + +export interface BranchOffice { + address: Address; +} + +export const emptyCompany: Company = { + offices: [], + url: "", + name: "", + nip: "", +} + +export const formatAddress = ({ postalCode, building, street, city, country }: Address): string => `${street} ${building}, ${postalCode} ${city}, ${country}` diff --git a/src/data/internship.ts b/src/data/internship.ts new file mode 100644 index 0000000..03a557e --- /dev/null +++ b/src/data/internship.ts @@ -0,0 +1,23 @@ +import { Moment } from "moment"; +import { Nullable } from "../helpers"; + +export enum InternshipType { } +export enum InternshipProgram { } + +export interface Internship { + type: InternshipType; + program: InternshipProgram; + startDate: Moment; + endDate: Moment; + isAccepted: boolean; + lengthInWeeks: number; +} + +export const emptyInternship: Nullable = { + endDate: null, + startDate: null, + type: null, + program: null, + isAccepted: false, + lengthInWeeks: 0, +} diff --git a/src/forms/Internship.tsx b/src/forms/Internship.tsx new file mode 100644 index 0000000..e749b8d --- /dev/null +++ b/src/forms/Internship.tsx @@ -0,0 +1,22 @@ +import React from "react"; +import { useFormik } from "formik"; +import { emptyInternship, Internship } from "../data/internship"; +import { Nullable } from "../helpers"; +import { TextField } from "@material-ui/core"; + +export type InternshipFormProps = { + +} + +export const InternshipForm: React.FunctionComponent = props => { + const formik = useFormik>({ onSubmit: values => console.log(values), initialValues: emptyInternship }); + + const formikProps = (prop: keyof Internship) => ({ onChange: formik.handleChange, value: formik.values[prop], name: prop }) + + return ( +
+ +
+ ) +} + diff --git a/src/forms/company.tsx b/src/forms/company.tsx new file mode 100644 index 0000000..4ff47bf --- /dev/null +++ b/src/forms/company.tsx @@ -0,0 +1,69 @@ +import React, { HTMLProps, useState } from "react"; +import { useFormik } from "formik"; +import { Nullable } from "../helpers"; +import { formatAddress, Company, emptyCompany, BranchOffice } from "../data/company"; +import { sampleCompanies } from "../provider/company"; +import { Autocomplete } from "@material-ui/lab"; +import { Box, Grid, TextField, Typography } from "@material-ui/core"; + +export type CompanyFormProps = { + +} + +export const CompanyItem = ({ company, ...props }: { company: Company } & HTMLProps) => ( +
+
{ company.name }
+ NIP: { company.nip } +
+) + +export const OfficeItem = ({ office, ...props }: { office: BranchOffice } & HTMLProps) => ( +
+
{ office.address.city }, { office.address.street }
+ { formatAddress(office.address) } +
+) + +export const CompanyForm: React.FunctionComponent = props => { + const formik = useFormik>({ onSubmit: values => console.log(values), initialValues: emptyCompany }); + + const formikProps = (prop: keyof Company) => ({ onChange: formik.handleChange, value: formik.values[prop], name: prop }) + + const [company, setCompany] = useState(null); + + return ( + + + option.name } + renderOption={ company => } + renderInput={ props => } + onChange={ (ev, value: Company | null) => { + setCompany(value) + + formik.setFieldValue("name", value?.name || "") + formik.setFieldValue("url", value?.url || ""); + formik.setFieldValue("nip", value?.nip || ""); + } } + /> + + + + + + + + + + + office.address.city } + renderOption={ office => } + renderInput={ props => } + /> + + + ) +} + diff --git a/src/helpers.ts b/src/helpers.ts new file mode 100644 index 0000000..157ce58 --- /dev/null +++ b/src/helpers.ts @@ -0,0 +1 @@ +export type Nullable = { [P in keyof T]: T[P] | null } diff --git a/src/index.css b/src/index.css deleted file mode 100644 index ec2585e..0000000 --- a/src/index.css +++ /dev/null @@ -1,13 +0,0 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; -} diff --git a/src/index.tsx b/src/index.tsx index f5185c1..4146d1d 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,6 +1,5 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import './index.css'; import App from './App'; import * as serviceWorker from './serviceWorker'; diff --git a/src/logo.svg b/src/logo.svg deleted file mode 100644 index 6b60c10..0000000 --- a/src/logo.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/provider/company.ts b/src/provider/company.ts new file mode 100644 index 0000000..e0379f0 --- /dev/null +++ b/src/provider/company.ts @@ -0,0 +1,62 @@ +import { Company } from "../data/company"; + +export const sampleCompanies: Company[] = [ + { + name: "Intel", + url: "https://www.intel.com/content/www/us/en/jobs/locations/poland.html", + nip: "9570752316", + offices: [{ + address: { + city: "Gdańsk", + street: "ul. Słowackiego", + building: "173", + postalCode: "80-298", + country: "Poland" + } + }] + }, + { + name: "IHS Markit", + url: "http://ihsgdansk.com/", + nip: "5842068320", + offices: [{ + address: { + city: "Gdańsk", + street: "ul. Marynarki Polskiej", + building: "163", + postalCode: "80-868", + country: "Poland" + } + }] + }, + { + name: "Asseco Poland", + url: "http://pl.asseco.com/", + nip: "5842068320", + offices: [{ + address: { + city: "Gdynia", + street: "ul. Podolska", + building: "21", + postalCode: "81-321", + country: "Poland" + } + }, { + address: { + city: "Łódź", + street: "al. Marszałka Józefa Piłsudskiego", + building: "85", + postalCode: "90-332", + country: "Poland" + } + }, { + address: { + city: "Wrocław", + street: "Traugutta", + building: "1/7", + postalCode: "50-449", + country: "Poland" + } + }] + } +] diff --git a/src/setupTests.ts b/src/setupTests.ts deleted file mode 100644 index 74b1a27..0000000 --- a/src/setupTests.ts +++ /dev/null @@ -1,5 +0,0 @@ -// jest-dom adds custom jest matchers for asserting on DOM nodes. -// allows you to do things like: -// expect(element).toHaveTextContent(/react/i) -// learn more: https://github.com/testing-library/jest-dom -import '@testing-library/jest-dom/extend-expect'; diff --git a/yarn.lock b/yarn.lock index c32e217..b908545 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1309,6 +1309,17 @@ react-is "^16.8.0" react-transition-group "^4.4.0" +"@material-ui/lab@^4.0.0-alpha.55": + version "4.0.0-alpha.55" + resolved "https://registry.yarnpkg.com/@material-ui/lab/-/lab-4.0.0-alpha.55.tgz#82a850dc59654e04ee3a31be1b34eb3bf64d5585" + integrity sha512-mPHiS52Z1AT6NlWNp07xxTkoKGU3DZhoGdVtLKGy2+uMH5t4/UPtiZLRab7hR3hvuHvguxgV4tkBC9ww3xqUzA== + dependencies: + "@babel/runtime" "^7.4.4" + "@material-ui/utils" "^4.9.6" + clsx "^1.0.4" + prop-types "^15.7.2" + react-is "^16.8.0" + "@material-ui/styles@^4.10.0": version "4.10.0" resolved "https://registry.yarnpkg.com/@material-ui/styles/-/styles-4.10.0.tgz#2406dc23aa358217aa8cc772e6237bd7f0544071" @@ -1612,6 +1623,13 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== +"@types/moment@^2.13.0": + version "2.13.0" + resolved "https://registry.yarnpkg.com/@types/moment/-/moment-2.13.0.tgz#604ebd189bc3bc34a1548689404e61a2a4aac896" + integrity sha1-YE69GJvDvDShVIaJQE5hoqSqyJY= + dependencies: + moment "*" + "@types/node@*": version "13.9.2" resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.2.tgz#ace1880c03594cc3e80206d96847157d8e7fa349" @@ -3654,6 +3672,11 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +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: version "4.2.0" resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" @@ -4728,6 +4751,20 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" +formik@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/formik/-/formik-2.1.4.tgz#8deef07ec845ea98f75e03da4aad7aab4ac46570" + integrity sha512-oKz8S+yQBzuQVSEoxkqqJrKQS5XJASWGVn6mrs+oTWrBoHgByVwwI1qHiVc9GKDpZBU9vAxXYAKz2BvujlwunA== + 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: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" @@ -5084,7 +5121,7 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.3.2: +hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -6657,6 +6694,11 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +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: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" @@ -7017,6 +7059,11 @@ mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@~0.5.1: dependencies: minimist "^1.2.5" +moment@*, moment@^2.26.0: + version "2.26.0" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.26.0.tgz#5e1f82c6bafca6e83e808b30c8705eed0dcbd39a" + integrity sha512-oIixUO+OamkUkwjhAVE18rAMfRJNsNe/Stid/gwHSOfHrOtw9EhAY2AHvdKZ/k/MggcYELFCJz/Sn2pL8b8JMw== + move-concurrently@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" @@ -8785,6 +8832,11 @@ react-error-overlay@^6.0.7: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.7.tgz#1dcfb459ab671d53f660a991513cb2f0a0553108" 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-is@^16.12.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1, react-is@^16.8.4: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -9352,6 +9404,14 @@ saxes@^3.1.9: dependencies: xmlchars "^2.1.1" +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: version "0.19.1" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" -- 2.45.2 From ee44cbf2f7ef225051b53a3a137c480e3aae36ab Mon Sep 17 00:00:00 2001 From: Kacper Donat Date: Wed, 10 Jun 2020 23:47:07 +0200 Subject: [PATCH 2/2] Add basic company subform UX demo --- package.json | 1 - src/App.tsx | 19 +++-- src/data/common.ts | 3 + src/data/company.ts | 18 ++++- src/forms/company.tsx | 152 +++++++++++++++++++++++++++++----------- src/forms/helpers.ts | 20 ++++++ src/helpers.ts | 4 ++ src/provider/company.ts | 12 ++++ src/provider/helpers.ts | 4 ++ src/ui/theme.ts | 10 +++ yarn.lock | 39 +---------- 11 files changed, 194 insertions(+), 88 deletions(-) create mode 100644 src/data/common.ts create mode 100644 src/forms/helpers.ts create mode 100644 src/provider/helpers.ts create mode 100644 src/ui/theme.ts diff --git a/package.json b/package.json index d48b98e..83556ed 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,6 @@ "@types/node": "^12.0.0", "@types/react": "^16.9.0", "@types/react-dom": "^16.9.0", - "formik": "^2.1.4", "moment": "^2.26.0", "react": "^16.13.1", "react-dom": "^16.13.1", diff --git a/src/App.tsx b/src/App.tsx index f6ed80e..1ec6596 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,14 +1,21 @@ import React from 'react'; -import { Container } from "@material-ui/core"; +import { Container, ThemeProvider, Typography } from "@material-ui/core"; import { CompanyForm } from "./forms/company"; +import { studentTheme } from "./ui/theme"; function App() { return ( -
- - - -
+ +
+ + Zgłoszenie Praktyki + UX Demo + + Miejsce odbywania praktyki + + +
+
); } diff --git a/src/data/common.ts b/src/data/common.ts new file mode 100644 index 0000000..62671b8 --- /dev/null +++ b/src/data/common.ts @@ -0,0 +1,3 @@ +export interface Identifiable { + id?: string +} diff --git a/src/data/company.ts b/src/data/company.ts index c73333d..5e6f2db 100644 --- a/src/data/company.ts +++ b/src/data/company.ts @@ -1,3 +1,5 @@ +import { Identifiable } from "./common"; + export interface Address { street: string; building: string; @@ -6,14 +8,14 @@ export interface Address { country: string; } -export interface Company { +export interface Company extends Identifiable { name: string; url?: string; nip: string; offices: BranchOffice[]; } -export interface BranchOffice { +export interface BranchOffice extends Identifiable { address: Address; } @@ -24,4 +26,16 @@ export const emptyCompany: Company = { nip: "", } +export const emptyAddress: Address = { + street: "", + city: "", + country: "", + postalCode: "", + building: "" +} + +export const emptyBranchOffice: BranchOffice = { + address: emptyAddress, +} + export const formatAddress = ({ postalCode, building, street, city, country }: Address): string => `${street} ${building}, ${postalCode} ${city}, ${country}` diff --git a/src/forms/company.tsx b/src/forms/company.tsx index 4ff47bf..78729e1 100644 --- a/src/forms/company.tsx +++ b/src/forms/company.tsx @@ -1,69 +1,139 @@ -import React, { HTMLProps, useState } from "react"; -import { useFormik } from "formik"; -import { Nullable } from "../helpers"; -import { formatAddress, Company, emptyCompany, BranchOffice } from "../data/company"; +import React, { HTMLProps, useEffect, useMemo, useState } from "react"; +import { BranchOffice, Company, emptyAddress, emptyBranchOffice, emptyCompany, formatAddress } from "../data/company"; import { sampleCompanies } from "../provider/company"; import { Autocomplete } from "@material-ui/lab"; -import { Box, Grid, TextField, Typography } from "@material-ui/core"; +import { Grid, TextField, Typography } from "@material-ui/core"; +import { formFieldProps } from "./helpers"; -export type CompanyFormProps = { +export type CompanyFormProps = {} +export type BranchOfficeProps = { + company: Company, + disabled?: boolean } export const CompanyItem = ({ company, ...props }: { company: Company } & HTMLProps) => ( -
+
{ company.name }
NIP: { company.nip }
) export const OfficeItem = ({ office, ...props }: { office: BranchOffice } & HTMLProps) => ( -
-
{ office.address.city }, { office.address.street }
+
+
{ office.address.city }
{ formatAddress(office.address) }
) -export const CompanyForm: React.FunctionComponent = props => { - const formik = useFormik>({ onSubmit: values => console.log(values), initialValues: emptyCompany }); +export const BranchForm: React.FC = ({ company, disabled = false }) => { + const [office, setOffice] = useState(emptyBranchOffice) - const formikProps = (prop: keyof Company) => ({ onChange: formik.handleChange, value: formik.values[prop], name: prop }) + const canEdit = useMemo(() => !office.id && !disabled, [office.id, disabled]); - const [company, setCompany] = useState(null); + const fieldProps = formFieldProps(office.address, address => setOffice({ ...office, address })) + + const handleCityChange = (event: any, value: BranchOffice | string | null) => { + if (typeof value === "string") { + setOffice({ + ...emptyBranchOffice, + address: { + ...emptyAddress, + city: value, + } + }); + } else if (typeof value === "object" && value !== null) { + setOffice(value); + } else { + setOffice(emptyBranchOffice); + } + } + + const handleCityInput = (event: any, value: string) => { + const base = office.id ? emptyBranchOffice : office; + setOffice({ + ...base, + address: { + ...base.address, + city: value, + } + }) + } + + useEffect(() => void (office.id && setOffice(emptyBranchOffice)), [company]) return ( - - - option.name } - renderOption={ company => } - renderInput={ props => } - onChange={ (ev, value: Company | null) => { - setCompany(value) - - formik.setFieldValue("name", value?.name || "") - formik.setFieldValue("url", value?.url || ""); - formik.setFieldValue("nip", value?.nip || ""); - } } - /> - - - - - - - - - - + + office.address.city } - renderOption={ office => } - renderInput={ props => } + disabled={ disabled } + getOptionLabel={ office => typeof office == "string" ? office : office.address.city } + renderOption={ office => } + renderInput={ props => } + onChange={ handleCityChange } + onInputChange={ handleCityInput } + inputValue={ office.address.city } + value={ office.id ? office : null } + freeSolo /> + + + + + + + + + + + + ) } +export const CompanyForm: React.FunctionComponent = props => { + const [company, setCompany] = useState(emptyCompany); + const canEdit = useMemo(() => !company.id, [company.id]); + + const fieldProps = formFieldProps(company, setCompany) + + const handleCompanyChange = (event: any, value: Company | string | null) => { + if (typeof value === "string") { + setCompany({ + ...emptyCompany, + name: value, + }); + } else if (typeof value === "object" && value !== null) { + setCompany(value); + } else { + setCompany(emptyCompany); + } + } + + return ( + <> + + + option.name } + renderOption={ company => } + renderInput={ props => } + onChange={ handleCompanyChange } + freeSolo + /> + + + + + + + + + Oddział + + + ) +} + diff --git a/src/forms/helpers.ts b/src/forms/helpers.ts new file mode 100644 index 0000000..4fafb88 --- /dev/null +++ b/src/forms/helpers.ts @@ -0,0 +1,20 @@ +import { DOMEvent } from "../helpers"; + +type UpdatingEvent = "onBlur" | "onChange" | "onInput"; +type FormFieldHelperOptions = { + event: UpdatingEvent +} + +export function formFieldProps(subject: T, update: (value: T) => void, options: Partial> = {}) { + const { + event = "onChange" + } = options; + + return (field: keyof T) => ({ + value: subject[field], + [event]: (event: DOMEvent) => update({ + ...subject, + [field]: event.target.value, + } as T) + }) +} diff --git a/src/helpers.ts b/src/helpers.ts index 157ce58..e128e6c 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -1 +1,5 @@ export type Nullable = { [P in keyof T]: T[P] | null } + +export interface DOMEvent extends Event { + target: TTarget; +} diff --git a/src/provider/company.ts b/src/provider/company.ts index e0379f0..be861f9 100644 --- a/src/provider/company.ts +++ b/src/provider/company.ts @@ -1,11 +1,17 @@ import { Company } from "../data/company"; +import { makeIdSequence } from "./helpers"; + +const companySequence = makeIdSequence(); +const officeSequence = makeIdSequence(); export const sampleCompanies: Company[] = [ { + id: companySequence(), name: "Intel", url: "https://www.intel.com/content/www/us/en/jobs/locations/poland.html", nip: "9570752316", offices: [{ + id: officeSequence(), address: { city: "Gdańsk", street: "ul. Słowackiego", @@ -16,10 +22,12 @@ export const sampleCompanies: Company[] = [ }] }, { + id: companySequence(), name: "IHS Markit", url: "http://ihsgdansk.com/", nip: "5842068320", offices: [{ + id: officeSequence(), address: { city: "Gdańsk", street: "ul. Marynarki Polskiej", @@ -30,10 +38,12 @@ export const sampleCompanies: Company[] = [ }] }, { + id: companySequence(), name: "Asseco Poland", url: "http://pl.asseco.com/", nip: "5842068320", offices: [{ + id: officeSequence(), address: { city: "Gdynia", street: "ul. Podolska", @@ -42,6 +52,7 @@ export const sampleCompanies: Company[] = [ country: "Poland" } }, { + id: officeSequence(), address: { city: "Łódź", street: "al. Marszałka Józefa Piłsudskiego", @@ -50,6 +61,7 @@ export const sampleCompanies: Company[] = [ country: "Poland" } }, { + id: officeSequence(), address: { city: "Wrocław", street: "Traugutta", diff --git a/src/provider/helpers.ts b/src/provider/helpers.ts new file mode 100644 index 0000000..20b4496 --- /dev/null +++ b/src/provider/helpers.ts @@ -0,0 +1,4 @@ +export const makeIdSequence = (start: number = 1) => { + let i = start; + return () => i++; +} diff --git a/src/ui/theme.ts b/src/ui/theme.ts new file mode 100644 index 0000000..05e110a --- /dev/null +++ b/src/ui/theme.ts @@ -0,0 +1,10 @@ +import { createMuiTheme } from "@material-ui/core"; + +export const studentTheme = createMuiTheme({ + props: { + MuiGrid: { + spacing: 4, + xs: 12, + } + } +}) diff --git a/yarn.lock b/yarn.lock index b908545..1489c71 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3672,11 +3672,6 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= -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: version "4.2.0" resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" @@ -4751,20 +4746,6 @@ form-data@~2.3.2: combined-stream "^1.0.6" mime-types "^2.1.12" -formik@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/formik/-/formik-2.1.4.tgz#8deef07ec845ea98f75e03da4aad7aab4ac46570" - integrity sha512-oKz8S+yQBzuQVSEoxkqqJrKQS5XJASWGVn6mrs+oTWrBoHgByVwwI1qHiVc9GKDpZBU9vAxXYAKz2BvujlwunA== - 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: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" @@ -5121,7 +5102,7 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: +hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -6694,11 +6675,6 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" -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: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" @@ -8832,11 +8808,6 @@ react-error-overlay@^6.0.7: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.7.tgz#1dcfb459ab671d53f660a991513cb2f0a0553108" 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-is@^16.12.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1, react-is@^16.8.4: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -9404,14 +9375,6 @@ saxes@^3.1.9: dependencies: xmlchars "^2.1.1" -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: version "0.19.1" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" -- 2.45.2