From 999cde6726b23bb1138bd6ed496f3e1c57ba9d11 Mon Sep 17 00:00:00 2001
From: Kacper Donat <kadet1090@gmail.com>
Date: Fri, 13 Nov 2020 23:57:33 +0100
Subject: [PATCH] Add static pages list

---
 package.json                      |  1 -
 src/api/page.ts                   |  2 +-
 src/app.tsx                       |  2 +-
 src/data/page.ts                  |  2 +
 src/management/api/dto/edition.ts |  9 ----
 src/management/api/index.ts       |  4 +-
 src/management/api/page.ts        | 12 +++++
 src/management/edition/list.tsx   | 16 ++++---
 src/management/main.tsx           | 51 +++++++++++++++++++++
 src/management/pages/list.tsx     | 76 +++++++++++++++++++++++++++++++
 src/management/routing.tsx        |  9 +++-
 translations/management.pl.yaml   | 12 ++++-
 translations/pl.yaml              |  1 +
 yarn.lock                         | 45 +-----------------
 14 files changed, 176 insertions(+), 66 deletions(-)
 delete mode 100644 src/management/api/dto/edition.ts
 create mode 100644 src/management/api/page.ts
 create mode 100644 src/management/main.tsx
 create mode 100644 src/management/pages/list.tsx

diff --git a/package.json b/package.json
index 43c30a5..2482de1 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,6 @@
     "@babel/preset-typescript": "^7.10.1",
     "@date-io/moment": "^1.3.13",
     "@material-ui/core": "^4.10.1",
-    "@material-ui/data-grid": "^4.0.0-alpha.9",
     "@material-ui/icons": "^4.9.1",
     "@material-ui/lab": "^4.0.0-alpha.55",
     "@material-ui/pickers": "^3.2.10",
diff --git a/src/api/page.ts b/src/api/page.ts
index 1a5cd02..a94def4 100644
--- a/src/api/page.ts
+++ b/src/api/page.ts
@@ -3,7 +3,7 @@ import { PageDTO, pageDtoTransformer } from "./dto/page"
 import { axios } from "@/api/index";
 import { prepare } from "@/routing";
 
-const STATIC_PAGE_ENDPOINT = "/staticPage/:slug"
+export const STATIC_PAGE_ENDPOINT = "/staticPage/:slug"
 
 export async function get(slug: string): Promise<Page> {
     const response = await axios.get<PageDTO>(prepare(STATIC_PAGE_ENDPOINT, { slug }))
diff --git a/src/app.tsx b/src/app.tsx
index 621b34a..95e05e1 100644
--- a/src/app.tsx
+++ b/src/app.tsx
@@ -104,7 +104,7 @@ function App() {
         <footer className="footer">
             <Container style={{ display: 'flex', alignItems: "center" }}>
                 <ul className="footer__menu">
-                    <li><Link to="/management">zarządzanie</Link></li>
+                    <li><Link to="/management">{ t("management") }</Link></li>
                 </ul>
                 <div className="footer__copyright">{ t('copyright', { date: moment() }) }</div>
             </Container>
diff --git a/src/data/page.ts b/src/data/page.ts
index ca7e3c9..e775e36 100644
--- a/src/data/page.ts
+++ b/src/data/page.ts
@@ -5,3 +5,5 @@ export interface Page extends Identifiable {
     content: Multilingual<string>;
     slug: string;
 }
+
+export default Page;
diff --git a/src/management/api/dto/edition.ts b/src/management/api/dto/edition.ts
deleted file mode 100644
index a12d5b1..0000000
--- a/src/management/api/dto/edition.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { Identifiable } from "@/data";
-import { CourseDTO } from "@/api/dto/course";
-
-export interface EditionDTO extends Identifiable {
-    editionStart: string;
-    editionFinish: string;
-    reportingStart: string;
-    course: CourseDTO;
-}
diff --git a/src/management/api/index.ts b/src/management/api/index.ts
index ea6d6a7..5a3e680 100644
--- a/src/management/api/index.ts
+++ b/src/management/api/index.ts
@@ -1,7 +1,9 @@
 import * as edition from "./edition"
+import * as page from "./page"
 
 export const api = {
-    edition
+    edition,
+    page
 }
 
 export default api;
diff --git a/src/management/api/page.ts b/src/management/api/page.ts
new file mode 100644
index 0000000..155d607
--- /dev/null
+++ b/src/management/api/page.ts
@@ -0,0 +1,12 @@
+import { Page } from "@/data/page";
+import pageDtoTransformer, { PageDTO } from "@/api/dto/page";
+import { axios } from "@/api";
+
+const STATIC_PAGE_INDEX_ENDPOINT = "/staticPage";
+
+export { get, STATIC_PAGE_ENDPOINT } from "@/api/page"
+
+export async function all(): Promise<Page[]> {
+    const response = await axios.get<PageDTO[]>(STATIC_PAGE_INDEX_ENDPOINT);
+    return response.data.map(dto => pageDtoTransformer.transform(dto));
+}
diff --git a/src/management/edition/list.tsx b/src/management/edition/list.tsx
index 4c53e0a..846ef35 100644
--- a/src/management/edition/list.tsx
+++ b/src/management/edition/list.tsx
@@ -4,10 +4,11 @@ import { useTranslation } from "react-i18next";
 import { useAsync } from "@/hooks";
 import api from "@/management/api";
 import { Async } from "@/components/async";
-import { Container } from "@material-ui/core";
+import { Container, Typography } from "@material-ui/core";
 import MaterialTable, { Action, Column } from "material-table";
 import { Edition } from "@/data/edition";
 import { Pencil } from "mdi-material-ui";
+import { Management } from "../main";
 
 export type EditionDetailsProps = {
     edition: string;
@@ -19,28 +20,28 @@ export function EditionDetails({ edition, ...props }: EditionDetailsProps) {
     return <Async async={ result }>{ edition => <pre>{ JSON.stringify(edition, null, 2) }</pre> }</Async>
 }
 
-export function ManagementEditionsList() {
+export function EditionsManagement() {
     const { t } = useTranslation("management");
     const editions = useAsync(useCallback(api.edition.all, []));
 
     const columns: Column<Edition>[] = [
         {
-            title: t("edition.fields.id"),
+            title: t("edition.field.id"),
             field: "id",
             cellStyle: { whiteSpace: "nowrap" }
         },
         {
-            title: t("edition.fields.start"),
+            title: t("edition.field.start"),
             render: edition => edition.startDate.format("DD.MM.yyyy"),
             customSort: (a, b) => b.startDate.unix() - a.startDate.unix(),
         },
         {
-            title: t("edition.fields.end"),
+            title: t("edition.field.end"),
             render: edition => edition.endDate.format("DD.MM.yyyy"),
             customSort: (a, b) => b.endDate.unix() - a.endDate.unix(),
         },
         {
-            title: t("edition.fields.course"),
+            title: t("edition.field.course"),
             customSort: (a, b) => a.course.name.localeCompare(b.course.name),
             render: edition => edition.course.name,
         },
@@ -55,6 +56,9 @@ export function ManagementEditionsList() {
 
     return <Page>
         <Page.Header maxWidth="lg">
+            <Management.Breadcrumbs>
+                <Typography color="textPrimary">{ t("edition.index.title") }</Typography>
+            </Management.Breadcrumbs>
             <Page.Title>{ t("edition.index.title") }</Page.Title>
         </Page.Header>
         <Container maxWidth="lg">
diff --git a/src/management/main.tsx b/src/management/main.tsx
new file mode 100644
index 0000000..fc91e9d
--- /dev/null
+++ b/src/management/main.tsx
@@ -0,0 +1,51 @@
+import { BreadcrumbsProps, Container, Link, List, ListItem, ListItemIcon, ListItemText, Paper } from "@material-ui/core";
+import { Page } from "@/pages/base";
+import React from "react";
+import { Link as RouterLink } from "react-router-dom";
+import { route } from "@/routing";
+import { useTranslation } from "react-i18next";
+import { CalendarClock, FileDocumentMultipleOutline } from "mdi-material-ui";
+
+export const Management = {
+    Breadcrumbs: ({ children, ...props }: BreadcrumbsProps) => {
+        const { t } = useTranslation();
+
+        return <Page.Breadcrumbs { ...props }>
+            <Link component={ RouterLink } to={ route("management:index") }>{ t("management:title") }</Link>
+            { children }
+        </Page.Breadcrumbs>;
+    }
+}
+
+type ManagementLinkProps = React.PropsWithChildren<{
+    icon: JSX.Element,
+    route: string,
+}>;
+
+const ManagementLink = ({ icon, route, children }: ManagementLinkProps) =>
+    <ListItem button component={ RouterLink } to={ route }>
+        <ListItemIcon>{ icon }</ListItemIcon>
+        <ListItemText>{ children }</ListItemText>
+    </ListItem>
+
+export const ManagementIndex = () => {
+    const { t } = useTranslation();
+
+    return <Page>
+        <Page.Header>
+            <Page.Title>{ t("management:title") }</Page.Title>
+        </Page.Header>
+        <Container>
+            <Paper elevation={ 2 }>
+                <List>
+                    <ManagementLink icon={ <CalendarClock /> } route={ route("management:editions") }>
+                        { t("management:edition.index.title") }
+                    </ManagementLink>
+                    <ManagementLink icon={ <FileDocumentMultipleOutline /> } route={ route("management:static_pages") }>
+                        { t("management:page.index.title") }
+                    </ManagementLink>
+                </List>
+            </Paper>
+        </Container>
+    </Page>
+}
diff --git a/src/management/pages/list.tsx b/src/management/pages/list.tsx
new file mode 100644
index 0000000..3a2648a
--- /dev/null
+++ b/src/management/pages/list.tsx
@@ -0,0 +1,76 @@
+import { Page } from "@/pages/base";
+import { Management } from "@/management/main";
+import { Box, Container, Typography } from "@material-ui/core";
+import React, { useCallback } from "react";
+import { useTranslation } from "react-i18next";
+import { useAsync } from "@/hooks";
+import api from "@/management/api";
+import { Async } from "@/components/async";
+import MaterialTable, { Action, Column } from "material-table";
+import { default as StaticPage } from "@/data/page";
+import { Edition } from "@/data/edition";
+import { Delete, Pencil } from "mdi-material-ui";
+
+export const StaticPageManagement = () => {
+    const { t } = useTranslation("management");
+    const pages = useAsync(useCallback(api.page.all, []));
+
+    const columns: Column<StaticPage>[] = [
+        {
+            render: page => page.title.pl,
+            title: t("page.field.title"),
+        },
+        {
+            field: "slug",
+            title: t("page.field.slug"),
+        },
+    ];
+
+    const actions: Action<StaticPage>[] = [
+        {
+            icon: () => <Pencil />,
+            onClick: () => {},
+        },
+        {
+            icon: () => <Delete />,
+            onClick: () => {},
+        },
+    ]
+
+    const PagePreview = ({ page }: { page: StaticPage }) =>
+        <>
+            <Box p={2}>
+                <Typography variant="subtitle2">Polski</Typography>
+                <Typography variant="h2">{ page.title.pl }</Typography>
+                <div dangerouslySetInnerHTML={{ __html: page.content.pl }} />
+            </Box>
+            <Box p={2}>
+                <Typography variant="subtitle2">English</Typography>
+                <Typography variant="h2">{ page.title.en }</Typography>
+                <div dangerouslySetInnerHTML={{ __html: page.content.en }} />
+            </Box>
+        </>
+
+    return <Page>
+        <Page.Header maxWidth="lg">
+            <Management.Breadcrumbs>
+                <Typography color="textPrimary">{ t("page.index.title") }</Typography>
+            </Management.Breadcrumbs>
+            <Page.Title>{ t("page.index.title") }</Page.Title>
+        </Page.Header>
+        <Container maxWidth="lg">
+            <Async async={ pages }>{
+                pages => <MaterialTable
+                    title={ t("page.index.title") }
+                    columns={ columns }
+                    actions={ actions }
+                    data={ pages }
+                    detailPanel={ page => <PagePreview page={ page } /> }
+                    options={{ actionsColumnIndex: -1 }}
+                />
+            }</Async>
+        </Container>
+    </Page>
+}
+
+export default StaticPageManagement;
diff --git a/src/management/routing.tsx b/src/management/routing.tsx
index 510d970..bbdc7b8 100644
--- a/src/management/routing.tsx
+++ b/src/management/routing.tsx
@@ -1,10 +1,15 @@
 import { Route } from "@/routing";
 import { isManagerMiddleware } from "@/management/middleware";
-import { ManagementEditionsList } from "@/management/edition/list";
+import { EditionsManagement } from "@/management/edition/list";
 import React from "react";
+import { ManagementIndex } from "@/management/main";
+import StaticPageManagement from "@/management/pages/list";
 
 export const managementRoutes: Route[] = ([
-    { name: "editions_index", path: "/editions", content: ManagementEditionsList }
+    { name: "index", path: "/", content: ManagementIndex, exact: true },
+
+    { name: "editions", path: "/editions", content: EditionsManagement },
+    { name: "static_pages", path: "/static-pages", content: StaticPageManagement }
 ] as Route[]).map(
     ({ name, path, middlewares = [], ...route }): Route => ({
         name: `management:${ name }`,
diff --git a/translations/management.pl.yaml b/translations/management.pl.yaml
index f90117a..83e57f7 100644
--- a/translations/management.pl.yaml
+++ b/translations/management.pl.yaml
@@ -1,8 +1,18 @@
+title: Zarządzanie
+
 edition:
   index:
     title: "Edycje praktyk"
-  fields:
+  field:
     id: Identyfikator
     start: Początek
     end: Koniec
     course: Kierunek
+
+page:
+  index:
+    title: Strony statyczne
+  field:
+    title: Tytuł
+    content: Treść
+    slug: Adres
diff --git a/translations/pl.yaml b/translations/pl.yaml
index 819cb77..020723c 100644
--- a/translations/pl.yaml
+++ b/translations/pl.yaml
@@ -223,3 +223,4 @@ validation:
 
 contact-coordinator: "Skontaktuj się z koordynatorem"
 download: "pobierz"
+management: "zarządzanie"
diff --git a/yarn.lock b/yarn.lock
index a27287f..5f3d70b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1072,16 +1072,6 @@
     react-is "^16.8.0"
     react-transition-group "^4.4.0"
 
-"@material-ui/data-grid@^4.0.0-alpha.9":
-  version "4.0.0-alpha.9"
-  resolved "https://registry.yarnpkg.com/@material-ui/data-grid/-/data-grid-4.0.0-alpha.9.tgz#a5f48550ea7c1ebdbcde9c7e0889ec9600473fec"
-  integrity sha512-2aXKQI6BH800i1AQzR3+p2eEET4ejVeGFlJQXBFvzBGodBW/AGfT2WsJGkmkriiVvD6jpsNsC5XF0HMAAcIFPA==
-  dependencies:
-    "@material-ui/utils" "^5.0.0-alpha.14"
-    prop-types "^15.7.2"
-    reselect "^4.0.0"
-    tslib "^2.0.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"
@@ -1158,17 +1148,6 @@
     prop-types "^15.7.2"
     react-is "^16.8.0"
 
-"@material-ui/utils@^5.0.0-alpha.14":
-  version "5.0.0-alpha.15"
-  resolved "https://registry.yarnpkg.com/@material-ui/utils/-/utils-5.0.0-alpha.15.tgz#b3ff9ae27f0b1ba60fe85ed318c49e4796d7eece"
-  integrity sha512-hxzqf4W7FVnVWB0x/+FKUwdcR3YUyoe7SeDBdsqPTkcUstU7RvrJztCAhybmeT3nTRQBd28HKGguM6oSCbboUw==
-  dependencies:
-    "@babel/runtime" "^7.4.4"
-    "@types/prop-types" "^15.7.3"
-    "@types/react-is" "^16.7.1 || ^17.0.0"
-    prop-types "^15.7.2"
-    react-is "^16.8.0 || ^17.0.0"
-
 "@mrmlnc/readdir-enhanced@^2.2.1":
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
@@ -1243,7 +1222,7 @@
   resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
   integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
 
-"@types/prop-types@*", "@types/prop-types@^15.7.3":
+"@types/prop-types@*":
   version "15.7.3"
   resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
   integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
@@ -1265,13 +1244,6 @@
   dependencies:
     "@types/react" "*"
 
-"@types/react-is@^16.7.1 || ^17.0.0":
-  version "16.7.1"
-  resolved "https://registry.yarnpkg.com/@types/react-is/-/react-is-16.7.1.tgz#d3f1c68c358c00ce116b55ef5410cf486dd08539"
-  integrity sha512-dMLFD2cCsxtDgMkTydQCM0PxDq8vwc6uN5M/jRktDfYvH3nQj6pjC9OrCXS2lKlYoYTNJorI/dI8x9dpLshexQ==
-  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"
@@ -7763,11 +7735,6 @@ react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.0, react-i
   resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
   integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
 
-"react-is@^16.8.0 || ^17.0.0":
-  version "17.0.1"
-  resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339"
-  integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==
-
 react-moment@^0.9.7:
   version "0.9.7"
   resolved "https://registry.yarnpkg.com/react-moment/-/react-moment-0.9.7.tgz#ca570466595b1aa4f7619e62da18b3bb2de8b6f3"
@@ -8095,11 +8062,6 @@ requires-port@^1.0.0:
   resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
   integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
 
-reselect@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.0.0.tgz#f2529830e5d3d0e021408b246a206ef4ea4437f7"
-  integrity sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA==
-
 resolve-cwd@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
@@ -9146,11 +9108,6 @@ tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0:
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
   integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
 
-tslib@^2.0.0:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.3.tgz#8e0741ac45fc0c226e58a17bfc3e64b9bc6ca61c"
-  integrity sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==
-
 tsutils@^3.17.1:
   version "3.17.1"
   resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"