diff --git a/package.json b/package.json
index 705fa02..f1d1f0f 100644
--- a/package.json
+++ b/package.json
@@ -7,22 +7,32 @@
"@babel/preset-typescript": "^7.10.1",
"@date-io/moment": "^1.3.13",
"@material-ui/core": "^4.10.1",
+ "@material-ui/icons": "^4.9.1",
"@material-ui/lab": "^4.0.0-alpha.55",
"@material-ui/pickers": "^3.2.10",
+ "@types/classnames": "^2.2.10",
"@types/node": "^12.0.0",
"@types/react": "^16.9.0",
"@types/react-dom": "^16.9.0",
+ "@types/react-redux": "^7.1.9",
+ "@types/react-router-dom": "^5.1.5",
+ "@types/redux": "^3.6.0",
+ "@types/redux-persist": "^4.3.1",
"@typescript-eslint/eslint-plugin": "^2.10.0",
"@typescript-eslint/parser": "^2.10.0",
"babel-core": "^6.26.3",
"babel-loader": "^8.1.0",
"babel-plugin-import": "^1.13.0",
"babel-preset-react-app": "^9.1.2",
+ "classnames": "^2.2.6",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "3.4.2",
"date-holidays": "^1.5.3",
"file-loader": "4.3.0",
"html-webpack-plugin": "4.0.0-beta.11",
+ "i18next": "^19.6.0",
+ "i18next-browser-languagedetector": "^5.0.0",
+ "material-ui-dropzone": "^3.3.0",
"moment": "^2.26.0",
"node-sass": "^4.14.1",
"optimize-css-assets-webpack-plugin": "5.0.3",
@@ -35,6 +45,12 @@
"react-app-polyfill": "^1.0.6",
"react-dev-utils": "^10.2.1",
"react-dom": "^16.13.1",
+ "react-i18next": "^11.7.0",
+ "react-redux": "^7.2.0",
+ "react-router-dom": "^5.2.0",
+ "redux": "^4.0.5",
+ "redux-devtools-extension": "^2.13.8",
+ "redux-persist": "^6.0.0",
"sass-loader": "8.0.2",
"style-loader": "0.23.1",
"ts-loader": "^7.0.5",
@@ -43,7 +59,8 @@
"webpack": "4.42.0",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "3.10.3",
- "workbox-webpack-plugin": "4.3.1"
+ "workbox-webpack-plugin": "4.3.1",
+ "yaml-loader": "^0.6.0"
},
"scripts": {
"serve": "webpack-dev-server --mode development",
diff --git a/public/img/eti-logo.svg b/public/img/eti-logo.svg
new file mode 100644
index 0000000..c046c51
--- /dev/null
+++ b/public/img/eti-logo.svg
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/img/pg-logotyp.svg b/public/img/pg-logotyp.svg
new file mode 100644
index 0000000..3cf3f61
--- /dev/null
+++ b/public/img/pg-logotyp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/public/index.html b/public/index.html
index 6482fd8..ecae82c 100644
--- a/public/index.html
+++ b/public/index.html
@@ -4,9 +4,9 @@
-
-
+
Zgłoszenie praktyki studenckiej
+
You need to enable JavaScript to run this app.
diff --git a/src/app.tsx b/src/app.tsx
index 009dce1..0f42d36 100644
--- a/src/app.tsx
+++ b/src/app.tsx
@@ -1,40 +1,103 @@
-import React from 'react';
-import { Container, Typography } from "@material-ui/core";
-import { MuiThemeProvider as ThemeProvider, StylesProvider } from "@material-ui/core/styles";
-import { studentTheme } from "./ui/theme";
-import { InternshipForm } from "@/forms/Internship";
-import { MuiPickersUtilsProvider } from "@material-ui/pickers";
-import MomentUtils from "@date-io/moment";
-
-import "moment/locale/pl"
-moment.locale("pl")
-
+import React, { Dispatch, HTMLProps, useEffect } from 'react';
+import { Link, Route, Switch } from "react-router-dom"
+import moment from "moment";
+import { route, routes } from "@/routing";
+import { useDispatch, useSelector } from "react-redux";
+import { AppState } from "@/state/reducer";
+import { StudentAction, StudentActions } from "@/state/actions/student";
+import { sampleStudent } from "@/provider/dummy/student";
+import { Trans, useTranslation } from "react-i18next";
+import { Student } from "@/data";
import '@/styles/overrides.scss'
-import moment, { Moment } from "moment";
+import '@/styles/header.scss'
+import classNames from "classnames";
+import { EditionAction, EditionActions } from "@/state/actions/edition";
+import { sampleEdition } from "@/provider/dummy/edition";
+import { Edition } from "@/data/edition";
-class LocalizedMomentUtils extends MomentUtils {
- getDatePickerHeaderText(date: Moment): string {
- return this.format(date, "d MMM yyyy");
+const UserMenu = (props: HTMLProps) => {
+ const student = useSelector(state => state.student as Student);
+ const dispatch = useDispatch>();
+ const { t } = useTranslation();
+
+ const handleUserLogin = () => {
+ dispatch({
+ type: StudentActions.Login,
+ student: sampleStudent,
+ })
}
+
+ const handleUserLogout = () => {
+ dispatch({ type: StudentActions.Logout })
+ }
+
+ return
+ {
+ student ? <>
+ logged in as { { name: `${ student.name } ${ student.surname }` } }
+ { ' ' }
+ ( { t('logout') })
+ > : <>
+ { t('login') }
+ >
+ }
+ ;
+}
+
+const LanguageSwitcher = ({ className, ...props }: HTMLProps) => {
+ const { i18n } = useTranslation();
+
+ const handleLanguageChange = (language: string) => () => {
+ i18n.changeLanguage(language);
+ document.documentElement.lang = language;
+ moment.locale(language)
+ }
+
+ const isActive = (language: string) => language.toLowerCase() === i18n.language.toLowerCase();
+
+ return
+ { ['pl', 'en'].map(language =>
+
+ { language }
+
+ ) }
+
}
function App() {
- return (
-
-
-
-
-
- Zgłoszenie Praktyki
- UX Demo
+ const dispatch = useDispatch>();
+ const edition = useSelector(state => state.edition);
-
-
-
-
-
-
- );
+ useEffect(() => {
+ if (!edition) {
+ dispatch({ type: EditionActions.Set, edition: sampleEdition });
+ }
+ })
+
+ const isReady = !!edition;
+
+ return <>
+
+
+
+
+
+
+
+
+ { isReady && { routes.map(({ name, content, ...route }) => { content() } ) } }
+ >;
}
export default App;
diff --git a/src/components/actions.tsx b/src/components/actions.tsx
new file mode 100644
index 0000000..5fdb03d
--- /dev/null
+++ b/src/components/actions.tsx
@@ -0,0 +1,14 @@
+import React, { HTMLProps } from "react";
+import { makeStyles } from "@material-ui/core/styles";
+
+export const Actions = (props: HTMLProps) => {
+ const classes = makeStyles(theme => ({
+ root: {
+ "& > *": {
+ marginRight: theme.spacing(1)
+ }
+ }
+ }))();
+
+ return
+}
diff --git a/src/data/edition.ts b/src/data/edition.ts
new file mode 100644
index 0000000..8a29c94
--- /dev/null
+++ b/src/data/edition.ts
@@ -0,0 +1,21 @@
+import { Moment } from "moment";
+
+export type Edition = {
+ startDate: Moment;
+ endDate: Moment;
+ proposalDeadline: Moment;
+}
+
+export type Deadlines = {
+ personalData?: Moment;
+ proposal?: Moment;
+ personalPlan?: Moment;
+ report?: Moment;
+}
+
+export function getEditionDeadlines(edition: Edition): Deadlines {
+ return {
+ proposal: edition.proposalDeadline,
+ personalPlan: edition.proposalDeadline,
+ }
+}
diff --git a/src/data/internship.ts b/src/data/internship.ts
index b80258f..4961e27 100644
--- a/src/data/internship.ts
+++ b/src/data/internship.ts
@@ -1,6 +1,5 @@
import { Moment } from "moment";
import { Identifiable } from "./common";
-import { countWorkingWeeksInRange } from "@/utils/date";
import { Student } from "@/data/student";
import { Company } from "@/data/company";
diff --git a/src/data/student.ts b/src/data/student.ts
index 5fb3221..b8eabfc 100644
--- a/src/data/student.ts
+++ b/src/data/student.ts
@@ -11,3 +11,18 @@ export interface Student extends Identifiable {
semester: Semester;
course: Course;
}
+
+export function isStudentDataComplete(student: Student): boolean {
+ return getMissingStudentData(student).length === 0;
+}
+
+export function getMissingStudentData(student: Student): (keyof Student)[] {
+ return [
+ !!student.name || "name",
+ !!student.surname || "surname",
+ !!student.email || "email",
+ !!student.albumNumber || "albumNumber",
+ !!student.semester || "semester",
+ !!student.course || "course",
+ ].filter(x => x !== true) as (keyof Student)[];
+}
diff --git a/src/forms/Internship.tsx b/src/forms/Internship.tsx
index 56a5800..967b1b6 100644
--- a/src/forms/Internship.tsx
+++ b/src/forms/Internship.tsx
@@ -144,13 +144,13 @@ export const InternshipForm: React.FunctionComponent = prop
return (
- Dane osoby odbywającej praktykę
+ Dane osoby odbywającej praktykę
- Rodzaj i program praktyki
+ Rodzaj i program praktyki
- Czas trwania praktyki
+ Czas trwania praktyki
- Miejsce odbywania praktyki
+ Miejsce odbywania praktyki
Wyślij
diff --git a/src/i18n.ts b/src/i18n.ts
new file mode 100644
index 0000000..4f8c6a2
--- /dev/null
+++ b/src/i18n.ts
@@ -0,0 +1,33 @@
+import i18n from "i18next";
+import { initReactI18next } from "react-i18next";
+import I18nextBrowserLanguageDetector from "i18next-browser-languagedetector";
+
+import moment from "moment";
+
+import "moment/locale/pl"
+import "moment/locale/en-gb"
+
+const resources = {
+ en: {
+ translation: require('../translations/en.yaml'),
+ },
+ pl: {
+ translation: require('../translations/pl.yaml'),
+ }
+}
+
+i18n
+ .use(I18nextBrowserLanguageDetector)
+ .use(initReactI18next)
+ .init({
+ resources,
+ fallbackLng: "en",
+ interpolation: {
+ escapeValue: false
+ }
+ })
+
+document.documentElement.lang = i18n.language;
+moment.locale(i18n.language)
+
+export default i18n;
diff --git a/src/index.tsx b/src/index.tsx
index 902d328..2c53768 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,10 +1,38 @@
import React from 'react';
import ReactDOM from 'react-dom';
+import "./i18n"
import App from './app';
+import { Provider } from "react-redux";
+import store, { persistor } from "@/state/store";
+import { PersistGate } from "redux-persist/integration/react";
+import { MuiThemeProvider as ThemeProvider, StylesProvider } from "@material-ui/core/styles";
+import { MuiPickersUtilsProvider } from "@material-ui/pickers";
+import moment, { Moment } from "moment";
+import { studentTheme } from "@/ui/theme";
+import { BrowserRouter } from "react-router-dom";
+import MomentUtils from "@date-io/moment";
+
+class LocalizedMomentUtils extends MomentUtils {
+ getDatePickerHeaderText(date: Moment): string {
+ return this.format(date, "d MMM yyyy");
+ }
+}
ReactDOM.render(
-
+
+
+
+
+
+
+
+
+
+
+
+
+
,
document.getElementById('root')
);
diff --git a/src/pages/base.tsx b/src/pages/base.tsx
new file mode 100644
index 0000000..be27987
--- /dev/null
+++ b/src/pages/base.tsx
@@ -0,0 +1,33 @@
+import React, { HTMLProps, useEffect } from "react";
+import classNames from "classnames"
+import { Box, BoxProps, Breadcrumbs, BreadcrumbsProps, Container, Typography } from "@material-ui/core";
+import "@/styles/page.scss"
+
+export type PageProps = {
+ title?: string;
+} & BoxProps;
+
+export type PageHeaderProps = {
+ maxWidth?: "sm" | "md" | "lg" | false
+} & HTMLProps
+
+export const Page = ({ title, children, ...props }: PageProps) => {
+ useEffect(() => {
+ document.title = title ? title + " | Praktyka Studencka" : "Praktyka Studencka";
+ }, [ title ])
+
+ return
+ { children }
+
+}
+
+Page.Header = ({ children, maxWidth = false, ...props }: PageHeaderProps) =>
+
+
+Page.Title = ({ children }: HTMLProps) => { children }
+
+Page.Breadcrumbs = ({ children, ...props }: BreadcrumbsProps) => { children }
diff --git a/src/pages/errors/not-found.tsx b/src/pages/errors/not-found.tsx
new file mode 100644
index 0000000..0f6456b
--- /dev/null
+++ b/src/pages/errors/not-found.tsx
@@ -0,0 +1,22 @@
+import { Page } from "@/pages/base";
+import { Box, Button, Container, Divider, Typography } from "@material-ui/core";
+import { route } from "@/routing";
+import { Link as RouterLink } from "react-router-dom";
+import React from "react";
+
+export const NotFoundPage = () => {
+ return
+
+ 404
+ Strona nie została znaleziona
+
+
+
+
+
+ strona główna
+
+
+}
+
+export default NotFoundPage;
diff --git a/src/pages/index.ts b/src/pages/index.ts
new file mode 100644
index 0000000..538a1bd
--- /dev/null
+++ b/src/pages/index.ts
@@ -0,0 +1,4 @@
+export * from "./internship/proposal";
+export * from "./errors/not-found"
+export * from "./main"
+export { Actions } from "@/components/actions";
diff --git a/src/pages/internship/plan.tsx b/src/pages/internship/plan.tsx
new file mode 100644
index 0000000..992fd5c
--- /dev/null
+++ b/src/pages/internship/plan.tsx
@@ -0,0 +1,52 @@
+import { Page } from "@/pages/base";
+import { Button, Container, FormHelperText, Grid, Link, Typography } from "@material-ui/core";
+import { Link as RouterLink } from "react-router-dom";
+import { route } from "@/routing";
+import React from "react";
+import { useTranslation } from "react-i18next";
+import { DropzoneArea } from "material-ui-dropzone";
+import { Description as DescriptionIcon } from "@material-ui/icons";
+import { Actions } from "@/components/actions";
+
+export const SubmitPlanPage = () => {
+ const { t } = useTranslation();
+
+ return
+
+
+ { t('sections.my-internship.header') }
+ { t("steps.plan.submit") }
+
+ { t("steps.plan.submit") }
+
+
+
+
+ { t('forms.plan.instructions') }
+
+
+ }>
+ { t('steps.plan.template') }
+
+
+
+
+ { t('forms.plan.dropzone-help') }
+
+
+
+
+ { t('confirm') }
+
+
+
+ { t('go-back') }
+
+
+
+
+
+
+}
+
+export default SubmitPlanPage;
diff --git a/src/pages/internship/proposal.tsx b/src/pages/internship/proposal.tsx
new file mode 100644
index 0000000..00e233c
--- /dev/null
+++ b/src/pages/internship/proposal.tsx
@@ -0,0 +1,23 @@
+import { Page } from "@/pages/base";
+import { Container, Link, Typography } from "@material-ui/core";
+import { Link as RouterLink } from "react-router-dom";
+import { route } from "@/routing";
+import { InternshipForm } from "@/forms/Internship";
+import React from "react";
+
+export const InternshipProposalPage = () => {
+ return
+
+
+ Moja praktyka
+ Zgłoszenie praktyki
+
+ Zgłoszenie praktyki
+
+
+
+
+
+}
+
+export default InternshipProposalPage;
diff --git a/src/pages/main.tsx b/src/pages/main.tsx
new file mode 100644
index 0000000..0b773d9
--- /dev/null
+++ b/src/pages/main.tsx
@@ -0,0 +1,95 @@
+import React, { useMemo } from "react";
+import { Page } from "@/pages/base";
+import { Box, Button, Container, Step as StepperStep, StepContent, StepLabel, Stepper, StepProps as StepperStepProps, Typography } from "@material-ui/core";
+import { Link as RouterLink } from "react-router-dom";
+import { route } from "@/routing";
+import { useTranslation } from "react-i18next";
+import moment, { Moment } from "moment";
+import { useSelector } from "react-redux";
+import { AppState } from "@/state/reducer";
+import { getMissingStudentData, Student } from "@/data";
+import { Deadlines, Edition, getEditionDeadlines } from "@/data/edition";
+import { Description as DescriptionIcon } from "@material-ui/icons"
+import { Actions } from "@/components/actions";
+
+type StepProps = StepperStepProps & {
+ until?: Moment;
+ completedOn?: Moment;
+ label: string;
+}
+
+const now = moment();
+
+const Step = ({ until, label, completedOn, children, completed, ...props }: StepProps) => {
+ const { t } = useTranslation();
+
+ const isLate = useMemo(() => until?.isBefore(completedOn || now), [completedOn, until]);
+ const left = useMemo(() => moment.duration(now.diff(until)), [until]);
+
+ return
+
+ { label }
+ { until &&
+
+ { t('until', { date: until.format("DD MMMM YYYY") }) }
+ { isLate && - { t('late', { by: moment.duration(now.diff(until)).humanize() }) } }
+ { !isLate && !completed && - { t('left', { left: left.humanize() }) } }
+
+ }
+
+ { children && { children } }
+
+}
+
+export const MainPage = () => {
+ const { t } = useTranslation();
+
+ const student = useSelector(state => state.student);
+ const deadlines = useSelector(state => getEditionDeadlines(state.edition as Edition)); // edition cannot be null at this point
+
+ const missingStudentData = useMemo(() => student ? getMissingStudentData(student) : [], [student]);
+
+ return
+
+ { t("sections.my-internship.header") }
+
+
+ { missingStudentData.length > 0 && <>
+ { t('steps.personal-data.info') }
+
+
+ { missingStudentData.map(field => { t(`student.${ field }`) } ) }
+
+
+
+ { t('steps.personal-data.form') }
+
+ > }
+
+
+ { t('steps.internship-proposal.info') }
+
+
+ { t('steps.internship-proposal.form') }
+
+
+
+ { t('steps.plan.info') }
+
+
+
+ { t('steps.plan.submit') }
+
+ }>
+ { t('steps.plan.template') }
+
+
+
+
+
+
+
+
+
+}
diff --git a/src/provider/dummy/edition.ts b/src/provider/dummy/edition.ts
new file mode 100644
index 0000000..290a3ac
--- /dev/null
+++ b/src/provider/dummy/edition.ts
@@ -0,0 +1,8 @@
+import { Edition } from "@/data/edition";
+import moment from "moment";
+
+export const sampleEdition: Edition = {
+ startDate: moment("2020-07-01"),
+ endDate: moment("2020-09-30"),
+ proposalDeadline: moment("2020-07-31")
+}
diff --git a/src/routing.tsx b/src/routing.tsx
new file mode 100644
index 0000000..adb533a
--- /dev/null
+++ b/src/routing.tsx
@@ -0,0 +1,29 @@
+import React, { ReactComponentElement } from "react";
+import { MainPage } from "@/pages/main";
+import { RouteProps } from "react-router-dom";
+import { InternshipProposalPage } from "@/pages/internship/proposal";
+import { NotFoundPage } from "@/pages/errors/not-found";
+import SubmitPlanPage from "@/pages/internship/plan";
+
+type Route = {
+ name?: string;
+ content: () => ReactComponentElement,
+} & RouteProps;
+
+export const routes: Route[] = [
+ { name: "home", path: "/", exact: true, content: () => },
+
+ { name: "internship_proposal", path: "/internship/proposal", exact: true, content: () => },
+ { name: "internship_plan", path: "/internship/plan", exact: true, content: () => },
+
+ // fallback route for 404 pages
+ { name: "fallback", path: "*", content: () => }
+]
+
+const routeNameMap = new Map(routes.filter(({ name }) => !!name).map(({ name, path }) => [name, path instanceof Array ? path[0] : path])) as Map
+
+export function route(name: string, params: { [param: string]: string } = {}) {
+ const url = routeNameMap.get(name) || "";
+
+ return Object.entries(params).reduce((url, [name, value]) => url.replace(`:${ name }`, value), url);
+}
diff --git a/src/state/actions/base.ts b/src/state/actions/base.ts
new file mode 100644
index 0000000..42285e4
--- /dev/null
+++ b/src/state/actions/base.ts
@@ -0,0 +1,3 @@
+export interface Action {
+ readonly type: TType;
+}
diff --git a/src/state/actions/edition.ts b/src/state/actions/edition.ts
new file mode 100644
index 0000000..142220d
--- /dev/null
+++ b/src/state/actions/edition.ts
@@ -0,0 +1,13 @@
+import { Action } from "@/state/actions/base";
+import { Edition } from "@/data/edition";
+
+export enum EditionActions {
+ Set = 'SET',
+}
+
+export interface SetAction extends Action {
+ edition: Edition,
+}
+
+export type EditionAction = SetAction;
+
diff --git a/src/state/actions/index.ts b/src/state/actions/index.ts
new file mode 100644
index 0000000..e69de29
diff --git a/src/state/actions/student.ts b/src/state/actions/student.ts
new file mode 100644
index 0000000..29c6ae0
--- /dev/null
+++ b/src/state/actions/student.ts
@@ -0,0 +1,16 @@
+import { Action } from "@/state/actions/base";
+import { Student } from "@/data";
+
+export enum StudentActions {
+ Login = 'LOGIN',
+ Logout = 'LOGOUT'
+}
+
+export interface LoginAction extends Action {
+ student: Student
+}
+
+export type LogoutAction = Action;
+
+export type StudentAction = LoginAction | LogoutAction;
+
diff --git a/src/state/reducer/edition.ts b/src/state/reducer/edition.ts
new file mode 100644
index 0000000..ef696f9
--- /dev/null
+++ b/src/state/reducer/edition.ts
@@ -0,0 +1,17 @@
+import { Edition } from "@/data/edition";
+import { EditionAction, EditionActions } from "@/state/actions/edition";
+
+export type EditionState = Edition | null;
+
+const initialEditionState: EditionState = null;
+
+const editionReducer = (state: EditionState = initialEditionState, action: EditionAction): EditionState => {
+ switch (action.type) {
+ case EditionActions.Set:
+ return action.edition;
+ }
+
+ return state;
+}
+
+export default editionReducer;
diff --git a/src/state/reducer/index.ts b/src/state/reducer/index.ts
new file mode 100644
index 0000000..c839818
--- /dev/null
+++ b/src/state/reducer/index.ts
@@ -0,0 +1,13 @@
+import { combineReducers } from "redux";
+
+import studentReducer from "./student"
+import editionReducer from "@/state/reducer/edition";
+
+const rootReducer = combineReducers({
+ student: studentReducer,
+ edition: editionReducer,
+})
+
+export type AppState = ReturnType;
+
+export default rootReducer;
diff --git a/src/state/reducer/student.ts b/src/state/reducer/student.ts
new file mode 100644
index 0000000..687f308
--- /dev/null
+++ b/src/state/reducer/student.ts
@@ -0,0 +1,20 @@
+import { Student } from "@/data";
+import { StudentAction, StudentActions } from "@/state/actions/student";
+
+export type StudentState = Student | null;
+
+const initialStudentState: StudentState = null;
+
+const studentReducer = (state: StudentState = initialStudentState, action: StudentAction): StudentState => {
+ switch (action.type) {
+ case StudentActions.Login:
+ return action.student;
+
+ case StudentActions.Logout:
+ return null;
+ }
+
+ return state;
+}
+
+export default studentReducer;
diff --git a/src/state/store.ts b/src/state/store.ts
new file mode 100644
index 0000000..f35ec6d
--- /dev/null
+++ b/src/state/store.ts
@@ -0,0 +1,21 @@
+import { createStore } from "redux";
+import rootReducer from "@/state/reducer";
+import { devToolsEnhancer } from "redux-devtools-extension";
+import { persistReducer, persistStore } from "redux-persist"
+import sessionStorage from "redux-persist/lib/storage/session"
+
+const store = createStore(
+ persistReducer(
+ {
+ key: 'state',
+ storage: sessionStorage,
+ blacklist: ['edition']
+ },
+ rootReducer
+ ),
+ devToolsEnhancer({})
+);
+
+export const persistor = persistStore(store)
+
+export default store;
diff --git a/src/styles/_variables.scss b/src/styles/_variables.scss
new file mode 100644
index 0000000..520af2e
--- /dev/null
+++ b/src/styles/_variables.scss
@@ -0,0 +1,5 @@
+$brand: #043865;
+
+$main: #052f52;
+$main-dark: #072138;
+
diff --git a/src/styles/header.scss b/src/styles/header.scss
new file mode 100644
index 0000000..9750554
--- /dev/null
+++ b/src/styles/header.scss
@@ -0,0 +1,77 @@
+@import "variables";
+
+.header {
+ height: 110px;
+ background: $main;
+ display: flex;
+
+ color: white;
+}
+
+.header__logo {
+ width: 152px;
+ background: $brand;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ img {
+ max-width: 100px;
+ max-height: 72px;
+ }
+}
+
+.header__top {
+ background-color: $main-dark;
+ height: 38px;
+ width: 100%;
+ display: flex;
+ align-items: center;
+ font-size: 0.75rem;
+ color: #e4f1fe;
+ padding: 0 1rem;
+
+ a {
+ color: #e4f1fe
+ }
+
+ .header__divider {
+ margin: 0 1rem;
+ background: #274057;
+ width: 1px;
+ height: 60%;
+ }
+}
+
+.header__nav {
+ flex: 1 1 auto;
+}
+
+.header__top .header__menu {
+ margin-right: auto;
+}
+
+.header__language-switcher {
+ padding: 0;
+ display: flex;
+ text-transform: uppercase;
+
+ li {
+ list-style: none;
+
+ &:not(:last-child) {
+ margin-right: .5rem;
+ }
+
+ a {
+ padding: 7px;
+ display: block;
+ }
+ }
+}
+
+.language-switcher__language--active {
+ font-weight: bold;
+ cursor: default;
+ text-decoration: none;
+}
diff --git a/src/styles/overrides.scss b/src/styles/overrides.scss
index e143cac..08cb80e 100644
--- a/src/styles/overrides.scss
+++ b/src/styles/overrides.scss
@@ -11,6 +11,13 @@
margin-top: 1.5rem;
}
-#root {
- margin: 100px 0;
+html, body {
+ margin: 0;
+ padding: 0;
+
+ font-family: "Roboto", "Helvetica", "Arial", sans-serif;
+}
+
+* {
+ box-sizing: border-box;
}
diff --git a/src/styles/page.scss b/src/styles/page.scss
new file mode 100644
index 0000000..8b41597
--- /dev/null
+++ b/src/styles/page.scss
@@ -0,0 +1,14 @@
+@import "variables";
+
+.page__header {
+ background-color: #e9f0f5;
+ padding: 20px 0;
+ margin-bottom: 2rem;
+}
+
+.page__title {
+ color: $brand;
+ font-size: 3rem;
+ font-weight: 400;
+ line-height: 1.5;
+}
diff --git a/src/ui/theme.ts b/src/ui/theme.ts
index 31471dc..8f770f0 100644
--- a/src/ui/theme.ts
+++ b/src/ui/theme.ts
@@ -1,10 +1,34 @@
-import { createMuiTheme } from "@material-ui/core/styles";
+import { createMuiTheme, responsiveFontSizes } from "@material-ui/core/styles";
-export const studentTheme = createMuiTheme({
+export const studentTheme = responsiveFontSizes(createMuiTheme({
props: {
MuiGrid: {
spacing: 3,
xs: 12,
+ },
+ MuiContainer: {
+ maxWidth: "md"
}
- }
-})
+ },
+ palette: {
+ primary: {
+ main: "#043865",
+ dark: "#072138"
+ }
+ },
+ typography: {
+ h2: {
+ fontSize: "3rem",
+ fontWeight: 400,
+ color: "#043865",
+ },
+ h3: {
+ fontSize: "2.25rem",
+ lineHeight: "1.2",
+ },
+ h4: {
+ fontSize: "1.75rem"
+ },
+ },
+ spacing: 8
+}))
diff --git a/translations/en.yaml b/translations/en.yaml
new file mode 100644
index 0000000..ca1e2c6
--- /dev/null
+++ b/translations/en.yaml
@@ -0,0 +1,44 @@
+---
+login: login
+logout: logout
+logged-in-as: logged in as <1>{{ name }}1>
+
+until: until {{ date }}
+late: late by {{ by }}
+left: '{{ left }} left'
+
+dropzone: "Drag and drop a file here or click to choose"
+
+student:
+ name: first name
+ surname: last name
+ course: course
+ semester: semester
+ email: e-mail
+ albumNumber: album number
+
+sections:
+ my-internship:
+ header: "My internship"
+
+steps:
+ personal-data:
+ header: "Fill personal data"
+ info: >
+ 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.
+ internship-proposal:
+ header: "Internship proposal"
+ form: "Internship proposal form"
+ info: ""
+ plan:
+ header: "Individual Internship Plan"
+ info: ""
+ template: "Download template"
+ submit: "Submit Individual Internship Plan"
+ insurance:
+ header: "Insurance"
+ report:
+ header: "Internship report"
+ grade:
+ header: "Your grade"
diff --git a/translations/pl.yaml b/translations/pl.yaml
new file mode 100644
index 0000000..8b9e395
--- /dev/null
+++ b/translations/pl.yaml
@@ -0,0 +1,57 @@
+---
+login: zaloguj się
+logout: wyloguj się
+logged-in-as: zalogowany jako <1>{{ name }}1>
+
+until: do {{ date }}
+late: '{{ by }} spóźnienia'
+left: jeszcze {{ left }}
+
+confirm: zatwierdź
+go-back: wstecz
+
+dropzone: "Przeciągnij i upuść plik bądź kliknij, aby wybrać"
+
+sections:
+ my-internship:
+ header: "Moja praktyka"
+
+forms:
+ plan:
+ instructions: >
+ Wypełnij i zeskanuj Indywidualny Plan Praktyk a następnie wyślij go z pomocą tego formularza.
+ dropzone-help: Skan dokumentu w formacie PDF
+
+student:
+ name: imię
+ surname: mazwisko
+ course: kierunek
+ semester: semestr
+ email: adres e-mail
+ albumNumber: numer albumu
+
+steps:
+ personal-data:
+ header: "Uzupełnienie informacji"
+ info: >
+ Twój profil jest niekompletny. W celu kontynuacji praktyki musisz uzupełnić informacje podane poniżej. Jeżeli masz
+ problem z uzupełnieniem tych informacji - skontaktuj się z koordynatorem praktyk dla Twojego kierunku.
+ form: "Uzupełnij dane"
+ internship-proposal:
+ header: "Zgłoszenie praktyki"
+ info: >
+ Przed podjęciem praktyki należy ją zgłosić.
+ form: "Formularz zgłaszania praktyki"
+ plan:
+ header: "Indywidualny Program Praktyki"
+ info: ""
+ template: "Pobierz szablon"
+ submit: "Wyślij Indywidualny Plan Praktyki"
+ report:
+ header: "Raport z praktyki"
+ grade:
+ header: "Ocena z praktyki"
+ insurance:
+ header: "Ubezpieczenie NNW"
+
+contact-coordinator: "Skontaktuj się z koordynatorem"
diff --git a/webpack.config.js b/webpack.config.js
index 0c6a61f..6aeedda 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -34,6 +34,10 @@ const config = {
}, {
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: 'file-loader'
+ }, {
+ test: /\.ya?ml$/,
+ type: 'json',
+ use: 'yaml-loader'
}]
},
plugins: [
@@ -48,6 +52,7 @@ const config = {
port: 3000,
host: 'system-praktyk-front.localhost',
disableHostCheck: true,
+ historyApiFallback: true,
},
optimization: {
usedExports: true
diff --git a/yarn.lock b/yarn.lock
index 7316358..bad0fdf 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -919,13 +919,20 @@
dependencies:
regenerator-runtime "^0.13.4"
-"@babel/runtime@^7.0.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
+"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
version "7.10.2"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.2.tgz#d103f21f2602497d38348a32e008637d506db839"
integrity sha512-6sF3uQw2ivImfVIl62RZ7MXhO2tap69WeWK57vAaimT6AZbE4FbqjdEJIN1UqoD6wI6B+1n9UiagafH1sxjOtg==
dependencies:
regenerator-runtime "^0.13.4"
+"@babel/runtime@^7.10.1":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.4.tgz#a6724f1a6b8d2f6ea5236dbfe58c7d7ea9c5eb99"
+ integrity sha512-UpTN5yUJr9b4EX2CnGNWIvER7Ab83ibv0pcvvHc4UOdrBI5jb8bj+32cCwPX6xu0mt2daFNjYhoi+X7beH0RSw==
+ 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"
@@ -1036,6 +1043,13 @@
react-is "^16.8.0"
react-transition-group "^4.4.0"
+"@material-ui/icons@^4.9.1":
+ version "4.9.1"
+ resolved "https://registry.yarnpkg.com/@material-ui/icons/-/icons-4.9.1.tgz#fdeadf8cb3d89208945b33dbc50c7c616d0bd665"
+ integrity sha512-GBitL3oBWO0hzBhvA9KxqcowRUsA0qzwKkURyC8nppnC3fw54KPKZ+d4V1Eeg/UnDRSzDaI9nGCdel/eh9AQMg==
+ dependencies:
+ "@babel/runtime" "^7.4.4"
+
"@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"
@@ -1123,6 +1137,11 @@
resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a"
integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==
+"@types/classnames@^2.2.10":
+ version "2.2.10"
+ resolved "https://registry.yarnpkg.com/@types/classnames/-/classnames-2.2.10.tgz#cc658ca319b6355399efc1f5b9e818f1a24bf999"
+ integrity sha512-1UzDldn9GfYYEsWWnn/P4wkTlkZDH7lDb0wBMGbtIQc9zXEQq7FlKBdZUn6OBqD8sKZZ2RQO2mAjGpXiDGoRmQ==
+
"@types/eslint-visitor-keys@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
@@ -1136,6 +1155,19 @@
"@types/minimatch" "*"
"@types/node" "*"
+"@types/history@*":
+ version "4.7.6"
+ resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.6.tgz#ed8fc802c45b8e8f54419c2d054e55c9ea344356"
+ integrity sha512-GRTZLeLJ8ia00ZH8mxMO8t0aC9M1N9bN461Z2eaRurJo6Fpa+utgCwLzI4jQHcrdzuzp5WPN9jRwpsCQ1VhJ5w==
+
+"@types/hoist-non-react-statics@^3.3.0":
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f"
+ integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==
+ dependencies:
+ "@types/react" "*"
+ hoist-non-react-statics "^3.3.0"
+
"@types/json-schema@^7.0.3", "@types/json-schema@^7.0.4":
version "7.0.5"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd"
@@ -1178,6 +1210,33 @@
dependencies:
"@types/react" "*"
+"@types/react-redux@^7.1.9":
+ version "7.1.9"
+ resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.9.tgz#280c13565c9f13ceb727ec21e767abe0e9b4aec3"
+ integrity sha512-mpC0jqxhP4mhmOl3P4ipRsgTgbNofMRXJb08Ms6gekViLj61v1hOZEKWDCyWsdONr6EjEA6ZHXC446wdywDe0w==
+ dependencies:
+ "@types/hoist-non-react-statics" "^3.3.0"
+ "@types/react" "*"
+ hoist-non-react-statics "^3.3.0"
+ redux "^4.0.0"
+
+"@types/react-router-dom@^5.1.5":
+ version "5.1.5"
+ resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.1.5.tgz#7c334a2ea785dbad2b2dcdd83d2cf3d9973da090"
+ integrity sha512-ArBM4B1g3BWLGbaGvwBGO75GNFbLDUthrDojV2vHLih/Tq8M+tgvY1DSwkuNrPSwdp/GUL93WSEpTZs8nVyJLw==
+ dependencies:
+ "@types/history" "*"
+ "@types/react" "*"
+ "@types/react-router" "*"
+
+"@types/react-router@*":
+ version "5.1.8"
+ resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.8.tgz#4614e5ba7559657438e17766bb95ef6ed6acc3fa"
+ integrity sha512-HzOyJb+wFmyEhyfp4D4NYrumi+LQgQL/68HvJO+q6XtuHSDvw6Aqov7sCAhjbNq3bUPgPqbdvjXC5HeB2oEAPg==
+ dependencies:
+ "@types/history" "*"
+ "@types/react" "*"
+
"@types/react-transition-group@^4.2.0":
version "4.4.0"
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.0.tgz#882839db465df1320e4753e6e9f70ca7e9b4d46d"
@@ -1193,6 +1252,20 @@
"@types/prop-types" "*"
csstype "^2.2.0"
+"@types/redux-persist@^4.3.1":
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/@types/redux-persist/-/redux-persist-4.3.1.tgz#aa4c876859e0bea5155e5f7980e5b8c4699dc2e6"
+ integrity sha1-qkyHaFngvqUVXl95gOW4xGmdwuY=
+ dependencies:
+ redux-persist "*"
+
+"@types/redux@^3.6.0":
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/@types/redux/-/redux-3.6.0.tgz#f1ebe1e5411518072e4fdfca5c76e16e74c1399a"
+ integrity sha1-8evh5UEVGAcuT9/KXHbhbnTBOZo=
+ dependencies:
+ redux "*"
+
"@types/source-list-map@*":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9"
@@ -1703,6 +1776,11 @@ atob@^2.1.2:
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
+attr-accept@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.1.0.tgz#a231a854385d36ff7a99647bb77b33c8a5175aee"
+ integrity sha512-sLzVM3zCCmmDtDNhI0i96k6PUztkotSOXqE4kDGQt/6iDi5M+H0srjeF+QC6jN581l4X/Zq3Zu/tgcErEssavg==
+
autoprefixer@^9.6.1:
version "9.8.0"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.0.tgz#68e2d2bef7ba4c3a65436f662d0a56a741e56511"
@@ -2407,6 +2485,11 @@ class-utils@^0.3.5:
isobject "^3.0.0"
static-extend "^0.1.1"
+classnames@^2.2.6:
+ version "2.2.6"
+ resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
+ integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
+
clean-css@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78"
@@ -3722,6 +3805,13 @@ file-loader@4.3.0:
loader-utils "^1.2.3"
schema-utils "^2.5.0"
+file-selector@^0.1.12:
+ version "0.1.12"
+ resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-0.1.12.tgz#fe726547be219a787a9dcc640575a04a032b1fd0"
+ integrity sha512-Kx7RTzxyQipHuiqyZGf+Nz4vY9R1XGxuQl/hLoJwq+J4avk/9wxxgZyHKtbyIPJmbD4A66DWGYfyykWNpcYutQ==
+ dependencies:
+ tslib "^1.9.0"
+
file-uri-to-path@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
@@ -4240,6 +4330,18 @@ hex-color-regex@^1.1.0:
resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e"
integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==
+history@^4.9.0:
+ version "4.10.1"
+ resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3"
+ integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==
+ dependencies:
+ "@babel/runtime" "^7.1.2"
+ loose-envify "^1.2.0"
+ resolve-pathname "^3.0.0"
+ tiny-invariant "^1.0.2"
+ tiny-warning "^1.0.0"
+ value-equal "^1.0.1"
+
hmac-drbg@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
@@ -4249,7 +4351,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.1.0, 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==
@@ -4319,6 +4421,13 @@ html-minifier-terser@^5.0.1:
relateurl "^0.2.7"
terser "^4.6.3"
+html-parse-stringify2@2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/html-parse-stringify2/-/html-parse-stringify2-2.0.1.tgz#dc5670b7292ca158b7bc916c9a6735ac8872834a"
+ integrity sha1-3FZwtyksoVi3vJFsmmc1rIhyg0o=
+ dependencies:
+ void-elements "^2.0.1"
+
html-webpack-plugin@4.0.0-beta.11:
version "4.0.0-beta.11"
resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz#3059a69144b5aecef97708196ca32f9e68677715"
@@ -4423,6 +4532,20 @@ hyphenate-style-name@^1.0.3:
resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.3.tgz#097bb7fa0b8f1a9cf0bd5c734cf95899981a9b48"
integrity sha512-EcuixamT82oplpoJ2XU4pDtKGWQ7b00CD9f1ug9IaQ3p1bkHMiKCZ9ut9QDI6qsa6cpUuB+A/I+zLtdNK4n2DQ==
+i18next-browser-languagedetector@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-5.0.0.tgz#9e946ed2ea5514a636913fe020a32455e82946e3"
+ integrity sha512-ekeKbRvTOsSOABSEPHFqyb6Q37JagZXjkISgQKHP84t/VZRW/B3FMVz+tBNQDVdZLsEaOe8fuJpeZsw2TvWeVQ==
+ dependencies:
+ "@babel/runtime" "^7.5.5"
+
+i18next@^19.6.0:
+ version "19.6.0"
+ resolved "https://registry.yarnpkg.com/i18next/-/i18next-19.6.0.tgz#3881b8e476e494dcdadcc8983e594080417fd82e"
+ integrity sha512-t+pA7iN2WtwS1UQc4PFKHDIO4HYZIl2Wo8UC8gqt70Q1qY50FflAF5vV4IbQEqy4DuK3I9wv3BL1PMvkk238WA==
+ dependencies:
+ "@babel/runtime" "^7.10.1"
+
iconv-lite@0.4.24, iconv-lite@^0.4.24:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
@@ -4905,6 +5028,11 @@ is-wsl@^2.1.1:
dependencies:
is-docker "^2.0.0"
+isarray@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
+ integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
+
isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
@@ -5301,7 +5429,7 @@ loglevel@^1.6.6:
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.8.tgz#8a25fb75d092230ecd4457270d80b54e28011171"
integrity sha512-bsU7+gc9AJ2SqpzxwU3+1fedl8zAntbtC5XYlt3s2j1hJcn2PsXSmgN8TaLG/J1/2mod4+cE/3vNL70/c1RNCA==
-loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -5375,6 +5503,15 @@ map-visit@^1.0.0:
dependencies:
object-visit "^1.0.0"
+material-ui-dropzone@^3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/material-ui-dropzone/-/material-ui-dropzone-3.3.0.tgz#5adb64e7ad71953eb29c7d0616b0b693904eb412"
+ integrity sha512-PBOj5IiGbLxEgNybO28xo381/qe0tMF55U715xGs8XLoyfjOFIoC29u4UL3+SWPYsaP/JIFwR4JW+h32xHugIg==
+ dependencies:
+ "@babel/runtime" "^7.4.4"
+ clsx "^1.0.2"
+ react-dropzone "^10.2.1"
+
md5.js@^1.3.4:
version "1.3.5"
resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
@@ -5522,6 +5659,14 @@ mimic-fn@^2.0.0, mimic-fn@^2.1.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
+mini-create-react-context@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.0.tgz#df60501c83151db69e28eac0ef08b4002efab040"
+ integrity sha512-b0TytUgFSbgFJGzJqXPKCFCBWigAjpjo+Fl7Vf7ZbKRDptszpppKxXH6DRXEABZ/gcEQczeb0iZ7JvL8e8jjCA==
+ dependencies:
+ "@babel/runtime" "^7.5.5"
+ tiny-warning "^1.0.3"
+
minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
@@ -6220,6 +6365,13 @@ path-to-regexp@0.1.7:
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
+path-to-regexp@^1.7.0:
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a"
+ integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==
+ dependencies:
+ isarray "0.0.1"
+
path-type@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
@@ -7229,16 +7381,73 @@ react-dom@^16.13.1:
prop-types "^15.6.2"
scheduler "^0.19.1"
+react-dropzone@^10.2.1:
+ version "10.2.2"
+ resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-10.2.2.tgz#67b4db7459589a42c3b891a82eaf9ade7650b815"
+ integrity sha512-U5EKckXVt6IrEyhMMsgmHQiWTGLudhajPPG77KFSvgsMqNEHSyGpqWvOMc5+DhEah/vH4E1n+J5weBNLd5VtyA==
+ dependencies:
+ attr-accept "^2.0.0"
+ file-selector "^0.1.12"
+ prop-types "^15.7.2"
+
react-error-overlay@^6.0.7:
version "6.0.7"
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.7.tgz#1dcfb459ab671d53f660a991513cb2f0a0553108"
integrity sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA==
-react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1:
+react-i18next@^11.7.0:
+ version "11.7.0"
+ resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.7.0.tgz#f27c4c237a274e007a48ac1210db83e33719908b"
+ integrity sha512-8tvVkpuxQlubcszZON+jmoCgiA9gCZ74OAYli9KChPhETtq8pJsANBTe9KRLRLmX3ubumgvidURWr0VvKz1tww==
+ dependencies:
+ "@babel/runtime" "^7.3.1"
+ html-parse-stringify2 "2.0.1"
+
+react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1, react-is@^16.9.0:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
+react-redux@^7.2.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.0.tgz#f970f62192b3981642fec46fd0db18a074fe879d"
+ integrity sha512-EvCAZYGfOLqwV7gh849xy9/pt55rJXPwmYvI4lilPM5rUT/1NxuuN59ipdBksRVSvz0KInbPnp4IfoXJXCqiDA==
+ dependencies:
+ "@babel/runtime" "^7.5.5"
+ hoist-non-react-statics "^3.3.0"
+ loose-envify "^1.4.0"
+ prop-types "^15.7.2"
+ react-is "^16.9.0"
+
+react-router-dom@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662"
+ integrity sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA==
+ dependencies:
+ "@babel/runtime" "^7.1.2"
+ history "^4.9.0"
+ loose-envify "^1.3.1"
+ prop-types "^15.6.2"
+ react-router "5.2.0"
+ tiny-invariant "^1.0.2"
+ tiny-warning "^1.0.0"
+
+react-router@5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.0.tgz#424e75641ca8747fbf76e5ecca69781aa37ea293"
+ integrity sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw==
+ dependencies:
+ "@babel/runtime" "^7.1.2"
+ history "^4.9.0"
+ hoist-non-react-statics "^3.1.0"
+ loose-envify "^1.3.1"
+ mini-create-react-context "^0.4.0"
+ path-to-regexp "^1.7.0"
+ prop-types "^15.6.2"
+ react-is "^16.6.0"
+ tiny-invariant "^1.0.2"
+ tiny-warning "^1.0.0"
+
react-transition-group@^4.0.0, react-transition-group@^4.4.0:
version "4.4.1"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9"
@@ -7328,6 +7537,24 @@ redent@^1.0.0:
indent-string "^2.1.0"
strip-indent "^1.0.1"
+redux-devtools-extension@^2.13.8:
+ version "2.13.8"
+ resolved "https://registry.yarnpkg.com/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz#37b982688626e5e4993ff87220c9bbb7cd2d96e1"
+ integrity sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg==
+
+redux-persist@*, redux-persist@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/redux-persist/-/redux-persist-6.0.0.tgz#b4d2972f9859597c130d40d4b146fecdab51b3a8"
+ integrity sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==
+
+redux@*, redux@^4.0.0, redux@^4.0.5:
+ version "4.0.5"
+ resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f"
+ integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==
+ dependencies:
+ loose-envify "^1.4.0"
+ symbol-observable "^1.2.0"
+
regenerate-unicode-properties@^8.2.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec"
@@ -7512,6 +7739,11 @@ resolve-from@^4.0.0:
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+resolve-pathname@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd"
+ integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==
+
resolve-url@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
@@ -8307,6 +8539,11 @@ svgo@^1.0.0:
unquote "~1.1.1"
util.promisify "~1.0.0"
+symbol-observable@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
+ integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
+
tapable@^1.0.0, tapable@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
@@ -8380,7 +8617,12 @@ timsort@^0.3.0:
resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
-tiny-warning@^1.0.2:
+tiny-invariant@^1.0.2:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875"
+ integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw==
+
+tiny-warning@^1.0.0, tiny-warning@^1.0.2, tiny-warning@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
@@ -8724,6 +8966,11 @@ validate-npm-package-license@^3.0.1:
spdx-correct "^3.0.0"
spdx-expression-parse "^3.0.0"
+value-equal@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c"
+ integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==
+
vary@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
@@ -8748,6 +8995,11 @@ vm-browserify@^1.0.1:
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
+void-elements@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
+ integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=
+
watchpack-chokidar2@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz#9948a1866cbbd6cb824dea13a7ed691f6c8ddff0"
@@ -9128,7 +9380,15 @@ yallist@^3.0.2:
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
-yaml@^1.7.2:
+yaml-loader@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/yaml-loader/-/yaml-loader-0.6.0.tgz#fe1c48b9f4803dace55a59a1474e790ba6ab1b48"
+ integrity sha512-1bNiLelumURyj+zvVHOv8Y3dpCri0F2S+DCcmps0pA1zWRLjS+FhZQg4o3aUUDYESh73+pKZNI18bj7stpReow==
+ dependencies:
+ loader-utils "^1.4.0"
+ yaml "^1.8.3"
+
+yaml@^1.7.2, yaml@^1.8.3:
version "1.10.0"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e"
integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==