From 8eb9bcd72c08bf121b96ea23b1d371b435c7191f Mon Sep 17 00:00:00 2001
From: Julien Bouquillon
Date: Mon, 17 Sep 2018 17:30:19 +0200
Subject: [PATCH] feat: add server-side routing
---
pages/question.js | 53 +++++++++++++++
pages/theme.js | 128 ++++++++++++++++++++++++++++++++++++
routes.js | 10 ++-
src/search/Answer.js | 17 +++++
src/search/Search.js | 104 ++++++++++++++---------------
src/search/SearchAnswer.js | 25 +++----
src/search/SearchResults.js | 20 +++---
7 files changed, 277 insertions(+), 80 deletions(-)
create mode 100644 pages/question.js
create mode 100644 pages/theme.js
create mode 100644 src/search/Answer.js
diff --git a/pages/question.js b/pages/question.js
new file mode 100644
index 0000000000..438bbc2173
--- /dev/null
+++ b/pages/question.js
@@ -0,0 +1,53 @@
+import React from "react";
+import { withRouter } from "next/router";
+import Head from "next/head";
+import fetch from "isomorphic-unfetch";
+import { Container, Alert } from "@socialgouv/code-du-travail-ui";
+
+import Search from "../src/search/Search";
+import Answer from "../src/search/Answer";
+import api from "../conf/api.js";
+
+const BigError = ({ children }) => (
+
+ {children}
+
+);
+
+class Question extends React.Component {
+ static async getInitialProps({ res, query }) {
+ console.log("getInitialProps", query);
+ return await fetch(`${api.BASE_URL}/items/faq/${query.slug}`)
+ .then(r => r.json())
+ .then(data => ({
+ data
+ }))
+ .catch(e => {
+ console.log("e", e);
+ res.statusCode = 404;
+ throw e;
+ });
+ }
+
+ render() {
+ const { data } = this.props;
+ return (
+
+
+ {data._source.title}
+
+
+ {!data && Cette question n'a pas été trouvée }
+ {data && (
+
+ )}
+
+ );
+ }
+}
+
+export default withRouter(Question);
diff --git a/pages/theme.js b/pages/theme.js
new file mode 100644
index 0000000000..bb7e3ead5e
--- /dev/null
+++ b/pages/theme.js
@@ -0,0 +1,128 @@
+import React from "react";
+import { withRouter } from "next/router";
+import Head from "next/head";
+import { BreadCrumbs, Container, Alert } from "@socialgouv/code-du-travail-ui";
+
+import find from "unist-util-find";
+import parents from "unist-util-parents";
+
+import { Link } from "../routes";
+import Search from "../src/search/Search";
+import Categories from "../src/Categories";
+import themes from "../src/data/themes2";
+
+const BigError = ({ children }) => (
+
+);
+
+// check if node definition match given slug
+const slugMatch = (node, slug) =>
+ Array.isArray(node.slug) ? node.slug.join("/") === slug : node.slug === slug;
+
+// build list of parents data for the breadcrumbs
+const getParents = node => {
+ const p = [];
+ if (node.type !== "root") {
+ p.push(node);
+ }
+ let cur = node && node.parent;
+ while (cur) {
+ p.push(cur);
+ cur = cur.parent;
+ }
+ return p.reverse();
+};
+
+// return breadcrumbs components
+const getBreadcrumbs = parents =>
+ (parents &&
+ parents.map(
+ (parent, i) =>
+ i === 0 ? (
+
+ {parent.title}
+
+ ) : i === parents.length - 1 ? (
+ {parent.title}
+ ) : (
+
+ {parent.title}
+
+ )
+ )) ||
+ [];
+
+// Theme page
+class Theme extends React.Component {
+ static async getInitialProps({ res, query }) {
+ // build a unist tree from themes.json
+ const themeTree = parents({
+ type: "root",
+ title: "Thèmes",
+ children: themes
+ });
+ // get current theme
+ const theme =
+ find(themeTree, n => slugMatch(n, query.slug || "/")) || themeTree;
+
+ // get theme parents for breadcrumbs
+ const themeParents = getParents(theme);
+
+ if (!theme && res) {
+ res.statusCode = 404;
+ }
+ return { theme, parents: themeParents };
+ }
+
+ render() {
+ const { theme, parents } = this.props;
+ const breadCrumbs = getBreadcrumbs(parents);
+ return (
+
+
+ {theme && theme.title}
+
+
+
+ {!theme && Ce thème n'a pas été trouvé }
+ {(breadCrumbs &&
+ breadCrumbs.length && (
+
+
+
+ )) || (
+
+ Choisissez un thème :
+
+ )}
+ {(theme &&
+ theme.children &&
+ theme.children.length && (
+
+ )) || (
+
+ Aucun contenu actuellement disponible sur ce thème :/
+
+ )}
+
+
+ );
+ }
+}
+
+export default withRouter(Theme);
diff --git a/routes.js b/routes.js
index c78d450b4c..28bbff0234 100644
--- a/routes.js
+++ b/routes.js
@@ -5,6 +5,12 @@ module.exports = routes()
// - http://localhost:3000/
// - http://localhost:3000/?q=travail
// - http://localhost:3000/questions/Zm5o72QB0wLMRXWgrAhM
- .add("index", "/:type(questions)/:id")
- .add("explorer", "/explorer");
+ .add({ name: "question", page: "question", pattern: "/questions/:slug" })
+
+ .add({ name: "theme", page: "theme", pattern: "/themes/:slug+" }) // slug is an array of slugs
+ .add({ name: "themes", page: "theme", pattern: "/themes" })
+
+ .add({ name: "explorer", page: "explorer", pattern: "/explorer" })
+
+ .add({ name: "index", page: "index", pattern: "/" });
diff --git a/src/search/Answer.js b/src/search/Answer.js
new file mode 100644
index 0000000000..be47282550
--- /dev/null
+++ b/src/search/Answer.js
@@ -0,0 +1,17 @@
+import React from "react";
+
+import { Section } from "@socialgouv/code-du-travail-ui";
+
+const Answer = ({ title, html, footer }) => (
+
+);
+
+export default Answer;
diff --git a/src/search/Search.js b/src/search/Search.js
index 34e76ed577..b37fe199ea 100755
--- a/src/search/Search.js
+++ b/src/search/Search.js
@@ -1,14 +1,45 @@
import * as nodeUrl from "url";
import memoize from "memoize-state";
import React from "react";
-import { Router } from "../../routes";
import { withRouter } from "next/router";
+import { Alert, Section } from "@socialgouv/code-du-travail-ui";
-import Alert from "../common/Alert";
+import { Router } from "../../routes";
import api from "../../conf/api.js";
-import SearchAnswer from "./SearchAnswer";
import SearchResults from "./SearchResults";
-import Categories from "./Categories";
+
+const Disclaimer = () => (
+
+ Ce site est en cours de construction : les données qui s'y trouvent
+ peuvent être erronées ou imprécises.
+
+
+ L'ouverture officielle du site est prévue pour 2020.
+
+
+);
+
+const SearchForm = ({ query, onChange, onKeyDown, onSubmit }) => (
+
+);
class Search extends React.Component {
state = {
@@ -92,12 +123,13 @@ class Search extends React.Component {
render() {
const { data, error, pendingXHR, query } = this.state;
- const { router } = this.props;
+ // const { router } = this.props;
+ // console.log({ data, error, pendingXHR, query });
const xhrErrorJsx = error ? (
-
{error.message}
+
{error.message}
) : null;
@@ -108,63 +140,29 @@ class Search extends React.Component {
) : null;
- const showAnswer = router.query && router.query.type === "questions";
-
- let content = null;
- if (showAnswer) {
- content = ;
- } else {
- if (!data) {
- // No query.
- content = ;
- } else {
- content = ;
- }
- }
-
return (
-
-
+ {loadingJsx}
{xhrErrorJsx}
- {content}
+ {data && }
);
}
diff --git a/src/search/SearchAnswer.js b/src/search/SearchAnswer.js
index 4e0f9ed247..b5883980fd 100755
--- a/src/search/SearchAnswer.js
+++ b/src/search/SearchAnswer.js
@@ -2,8 +2,9 @@ import React from "react";
import Alert from "../common/Alert";
import api from "../../conf/api.js";
-import FeedbackForm from "../common/FeedbackForm.js";
-import SeeAlso from "../common/SeeAlso";
+import Answer from "./Answer";
+// import FeedbackForm from "../common/FeedbackForm.js";
+// import SeeAlso from "../common/SeeAlso";
// Display the details of a single result.
@@ -73,21 +74,11 @@ class SearchAnswer extends React.Component {
return (
-
-
-
+
);
}
diff --git a/src/search/SearchResults.js b/src/search/SearchResults.js
index 9c85e882db..cb3192dd3b 100755
--- a/src/search/SearchResults.js
+++ b/src/search/SearchResults.js
@@ -8,7 +8,9 @@ import { Link } from "../../routes";
const Results = ({ data }) => (
- {data.map(result => )}
+ {data.map(result => (
+
+ ))}
);
@@ -60,13 +62,15 @@ const ResultItem = ({ _id, _source, highlight }) => {
);
if (isInternal) {
- return (
-
-
- {body}
-
-
- );
+ if (_source.source === "faq") {
+ return (
+
+
+ {body}
+
+
+ );
+ }
}
return (