diff --git a/package.json b/package.json
index 290a8ba..83556ed 100644
--- a/package.json
+++ b/package.json
@@ -4,13 +4,16 @@
"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",
+ "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..1ec6596 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,25 +1,21 @@
import React from 'react';
-import logo from './logo.svg';
-import './App.css';
+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
new file mode 100644
index 0000000..5e6f2db
--- /dev/null
+++ b/src/data/company.ts
@@ -0,0 +1,41 @@
+import { Identifiable } from "./common";
+
+export interface Address {
+ street: string;
+ building: string;
+ city: string;
+ postalCode: string;
+ country: string;
+}
+
+export interface Company extends Identifiable {
+ name: string;
+ url?: string;
+ nip: string;
+ offices: BranchOffice[];
+}
+
+export interface BranchOffice extends Identifiable {
+ address: Address;
+}
+
+export const emptyCompany: Company = {
+ offices: [],
+ url: "",
+ name: "",
+ 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/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..78729e1
--- /dev/null
+++ b/src/forms/company.tsx
@@ -0,0 +1,139 @@
+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 { Grid, TextField, Typography } from "@material-ui/core";
+import { formFieldProps } from "./helpers";
+
+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 }
+
{ formatAddress(office.address) }
+
+)
+
+export const BranchForm: React.FC = ({ company, disabled = false }) => {
+ const [office, setOffice] = useState(emptyBranchOffice)
+
+ const canEdit = useMemo(() => !office.id && !disabled, [office.id, disabled]);
+
+ 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 (
+
+
+ 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
new file mode 100644
index 0000000..e128e6c
--- /dev/null
+++ b/src/helpers.ts
@@ -0,0 +1,5 @@
+export type Nullable = { [P in keyof T]: T[P] | null }
+
+export interface DOMEvent extends Event {
+ target: TTarget;
+}
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..be861f9
--- /dev/null
+++ b/src/provider/company.ts
@@ -0,0 +1,74 @@
+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",
+ building: "173",
+ postalCode: "80-298",
+ country: "Poland"
+ }
+ }]
+ },
+ {
+ id: companySequence(),
+ name: "IHS Markit",
+ url: "http://ihsgdansk.com/",
+ nip: "5842068320",
+ offices: [{
+ id: officeSequence(),
+ address: {
+ city: "Gdańsk",
+ street: "ul. Marynarki Polskiej",
+ building: "163",
+ postalCode: "80-868",
+ country: "Poland"
+ }
+ }]
+ },
+ {
+ id: companySequence(),
+ name: "Asseco Poland",
+ url: "http://pl.asseco.com/",
+ nip: "5842068320",
+ offices: [{
+ id: officeSequence(),
+ address: {
+ city: "Gdynia",
+ street: "ul. Podolska",
+ building: "21",
+ postalCode: "81-321",
+ country: "Poland"
+ }
+ }, {
+ id: officeSequence(),
+ address: {
+ city: "Łódź",
+ street: "al. Marszałka Józefa Piłsudskiego",
+ building: "85",
+ postalCode: "90-332",
+ country: "Poland"
+ }
+ }, {
+ id: officeSequence(),
+ address: {
+ city: "Wrocław",
+ street: "Traugutta",
+ building: "1/7",
+ postalCode: "50-449",
+ country: "Poland"
+ }
+ }]
+ }
+]
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/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/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 c32e217..1489c71 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"
@@ -7017,6 +7035,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"