From c7909388d15877b128774f4db611b30c3159ea8f Mon Sep 17 00:00:00 2001 From: Clement G Date: Sun, 5 Jan 2020 16:46:54 +0100 Subject: [PATCH] refactor(routes): use react-context to clarify and centralize the management of API routes #12 --- src/App.jsx | 17 ++-- src/AppContext.jsx | 19 ++++ src/Routes.jsx | 93 ++----------------- src/components/views/CreateElection.jsx | 14 +-- .../{CreateSuccess.js => CreateSuccess.jsx} | 10 +- src/components/views/Home.jsx | 3 + src/components/views/Result.jsx | 17 +++- ...UnknownElection.js => UnknownElection.jsx} | 2 + src/components/views/UnknownView.jsx | 2 + src/components/views/Vote.jsx | 19 +++- .../views/{VoteSuccess.js => VoteSuccess.jsx} | 6 +- 11 files changed, 88 insertions(+), 114 deletions(-) create mode 100644 src/AppContext.jsx rename src/components/views/{CreateSuccess.js => CreateSuccess.jsx} (93%) rename src/components/views/{UnknownElection.js => UnknownElection.jsx} (92%) rename src/components/views/{VoteSuccess.js => VoteSuccess.jsx} (85%) diff --git a/src/App.jsx b/src/App.jsx index c6253ea..abe0aff 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -4,16 +4,19 @@ import Routes from "./Routes"; import Header from "./components/layouts/Header"; import Footer from "./components/layouts/Footer"; +import AppContextProvider from "./AppContext"; function App() { return ( - -
-
- -
-
-
+ + +
+
+ +
+
+
+
); } diff --git a/src/AppContext.jsx b/src/AppContext.jsx new file mode 100644 index 0000000..3b7922b --- /dev/null +++ b/src/AppContext.jsx @@ -0,0 +1,19 @@ +import React, { createContext } from "react"; + +export const AppContext = createContext(); + +const AppContextProvider = ({ children }) => { + const defaultState = { + urlServer: process.env.REACT_APP_SERVER_URL, + routesServer: { + setElection: "election/", + getElection: "election/get/:slug", + getResultsElection: "election/results/:slug", + voteElection: "election/vote/:slug" + } + }; + return ( + {children} + ); +}; +export default AppContextProvider; diff --git a/src/Routes.jsx b/src/Routes.jsx index addc83d..a1b3167 100644 --- a/src/Routes.jsx +++ b/src/Routes.jsx @@ -10,96 +10,19 @@ import UnknownElection from "./components/views/UnknownElection"; import CreateSuccess from "./components/views/CreateSuccess"; import VoteSuccess from "./components/views/VoteSuccess"; -function Routes() { - const params = new URLSearchParams(window.location.search); - const urlServer = process.env.REACT_APP_SERVER_URL; - const routesServer = { - setElection: "election/", - getElection: "election/get/:slug", - getResultsElection: "election/results/:slug", - voteElection: "election/vote/:slug" - }; +function Routes() { return (
- ( - - )} - /> - ( - - )} - /> - ( - - )} - /> - ( - - )} - /> - ( - - )} - /> - ( - - )} - /> - /> - ( - - )} - /> + + + + + + +
); diff --git a/src/components/views/CreateElection.jsx b/src/components/views/CreateElection.jsx index 5eb250c..8a56181 100644 --- a/src/components/views/CreateElection.jsx +++ b/src/components/views/CreateElection.jsx @@ -37,6 +37,7 @@ import { import { grades } from "../../Util"; import { ReactMultiEmail, isEmail } from "react-multi-email"; import "react-multi-email/style.css"; +import { AppContext } from "../../AppContext"; const DragHandle = sortableHandle(({ children }) => ( {children} @@ -115,6 +116,7 @@ const SortableCandidatesContainer = sortableContainer(({ items, form }) => { }); class CreateElection extends Component { + static contextType = AppContext; constructor(props) { super(props); //default value : start now @@ -122,11 +124,11 @@ class CreateElection extends Component { const startedHour = startedAt.getHours(); //default value : finish in one week const finishedAt = new Date(startedAt.getTime() + 7 * 24 * 60 * 60 * 1000); - + const params = new URLSearchParams(window.location.search); this.state = { candidates: [{ label: "" }, { label: "" }], numCandidatesWithLabel: 0, - title: this.props.title, + title: params.get("title") ? params.get("title") : "A", isVisibleTipsDragAndDropCandidate: true, numGrades: 7, successCreate: false, @@ -163,7 +165,6 @@ class CreateElection extends Component { removeCandidate = index => { let candidates = this.state.candidates; candidates.splice(index, 1); - console.log(candidates.length); if (candidates.length === 0) { candidates = [{ label: "" }]; } @@ -215,8 +216,8 @@ class CreateElection extends Component { const { candidates, title, numGrades } = this.state; const endpoint = resolve( - this.props.urlServer, - this.props.routesServer.setElection + this.context.urlServer, + this.context.routesServer.setElection ); fetch(endpoint, { @@ -282,7 +283,6 @@ class CreateElection extends Component { render() { const { successCreate, redirectTo } = this.state; const { electorEmails } = this.state; - const params = new URLSearchParams(this.props.location.search); if (successCreate) return ; @@ -308,7 +308,7 @@ class CreateElection extends Component { id="title" innerRef={this.focusInput} autoFocus - defaultValue={this.props.title} + value={this.state.title} onChange={this.handleChangeTitle} maxLength="250" /> diff --git a/src/components/views/CreateSuccess.js b/src/components/views/CreateSuccess.jsx similarity index 93% rename from src/components/views/CreateSuccess.js rename to src/components/views/CreateSuccess.jsx index 0d91d1f..6ea14ac 100644 --- a/src/components/views/CreateSuccess.js +++ b/src/components/views/CreateSuccess.jsx @@ -4,11 +4,13 @@ import { Link } from "react-router-dom"; import { faCopy, faUsers } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import logoLine from "../../logos/logo-line-white.svg"; +import { AppContext } from "../../AppContext"; -class UnknownView extends Component { +class CreateSuccess extends Component { + static contextType = AppContext; constructor(props) { super(props); - const electionSlug = this.props.slug; + const electionSlug = this.props.match.params.slug; this.state = { urlOfVote: "https://" + window.location.hostname + "/vote/" + electionSlug, @@ -118,7 +120,7 @@ class UnknownView extends Component { - + Participer maintenant ! @@ -128,4 +130,4 @@ class UnknownView extends Component { ); } } -export default UnknownView; +export default CreateSuccess; diff --git a/src/components/views/Home.jsx b/src/components/views/Home.jsx index d342cad..031cb20 100644 --- a/src/components/views/Home.jsx +++ b/src/components/views/Home.jsx @@ -5,7 +5,9 @@ import { faRocket } from "@fortawesome/free-solid-svg-icons"; import { Redirect } from "react-router-dom"; import logoLine from "../../logos/logo-line-white.svg"; + class Home extends Component { + constructor(props) { super(props); this.state = { @@ -21,6 +23,7 @@ class Home extends Component { }; handleChangeTitle = event => { + //console.log(this.context.routesServer.setElection); this.setState({ title: event.target.value }); }; diff --git a/src/components/views/Result.jsx b/src/components/views/Result.jsx index 1e84210..2b44cbd 100644 --- a/src/components/views/Result.jsx +++ b/src/components/views/Result.jsx @@ -12,8 +12,10 @@ import { Table } from "reactstrap"; import { grades } from "../../Util"; +import { AppContext } from "../../AppContext"; class Result extends Component { + static contextType = AppContext; constructor(props) { super(props); this.state = { @@ -95,9 +97,13 @@ class Result extends Component { // FIXME we should better handling logs // get details of the election + const electionSlug = this.props.match.params.slug; const detailsEndpoint = resolve( - this.props.urlServer, - this.props.routesServer.getElection.replace(new RegExp(":slug","g"),(this.props.slug)) + this.context.urlServer, + this.context.routesServer.getElection.replace( + new RegExp(":slug", "g"), + electionSlug + ) ); fetch(detailsEndpoint) @@ -108,8 +114,11 @@ class Result extends Component { // get results of the election const resultsEndpoint = resolve( - this.props.urlServer, - this.props.routesServer.getResultsElection.replace(new RegExp(":slug","g"),(this.props.slug)) + this.context.urlServer, + this.context.routesServer.getResultsElection.replace( + new RegExp(":slug", "g"), + electionSlug + ) ); fetch(resultsEndpoint) diff --git a/src/components/views/UnknownElection.js b/src/components/views/UnknownElection.jsx similarity index 92% rename from src/components/views/UnknownElection.js rename to src/components/views/UnknownElection.jsx index 2fe4560..875231f 100644 --- a/src/components/views/UnknownElection.js +++ b/src/components/views/UnknownElection.jsx @@ -2,8 +2,10 @@ import React, { Component } from "react"; import { Col, Container, Row } from "reactstrap"; import logoLine from "../../logos/logo-line-white.svg"; import { Link } from "react-router-dom"; +import { AppContext } from "../../AppContext"; class UnknownElection extends Component { + static contextType = AppContext; constructor(props) { super(props); this.state = {}; diff --git a/src/components/views/UnknownView.jsx b/src/components/views/UnknownView.jsx index 7b2484b..c1753a2 100644 --- a/src/components/views/UnknownView.jsx +++ b/src/components/views/UnknownView.jsx @@ -2,8 +2,10 @@ import React, { Component } from "react"; import { Col, Container, Row } from "reactstrap"; import logoLine from "../../logos/logo-line-white.svg"; import { Link } from "react-router-dom"; +import { AppContext } from "../../AppContext"; class UnknownView extends Component { + static contextType = AppContext; constructor(props) { super(props); this.state = {}; diff --git a/src/components/views/Vote.jsx b/src/components/views/Vote.jsx index 28e1cc1..cf73e1a 100644 --- a/src/components/views/Vote.jsx +++ b/src/components/views/Vote.jsx @@ -6,8 +6,10 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faCheck } from "@fortawesome/free-solid-svg-icons"; import { resolve } from "url"; import { grades } from "../../Util"; +import { AppContext } from "../../AppContext"; class Vote extends Component { + static contextType = AppContext; constructor(props) { super(props); this.state = { @@ -89,9 +91,13 @@ class Vote extends Component { componentDidMount() { // FIXME we should better handling logs + const electionSlug = this.props.match.params.slug; const detailsEndpoint = resolve( - this.props.urlServer, - this.props.routesServer.getElection.replace(new RegExp(":slug","g"),(this.props.slug)) + this.context.urlServer, + this.context.routesServer.getElection.replace( + new RegExp(":slug", "g"), + electionSlug + ) ); fetch(detailsEndpoint) .then(this.handleErrors) @@ -123,10 +129,13 @@ class Vote extends Component { event.preventDefault(); const { ratedCandidates } = this.state; - const electionSlug = this.props.slug; + const electionSlug = this.props.match.params.slug; const endpoint = resolve( - this.props.urlServer, - this.props.routesServer.voteElection.replace(new RegExp(":slug","g"),(this.props.slug)) + this.context.urlServer, + this.context.routesServer.voteElection.replace( + new RegExp(":slug", "g"), + electionSlug + ) ); const gradesById = {}; diff --git a/src/components/views/VoteSuccess.js b/src/components/views/VoteSuccess.jsx similarity index 85% rename from src/components/views/VoteSuccess.js rename to src/components/views/VoteSuccess.jsx index f5ffe5f..fb5d9e2 100644 --- a/src/components/views/VoteSuccess.js +++ b/src/components/views/VoteSuccess.jsx @@ -2,8 +2,10 @@ import React, { Component } from "react"; import { Col, Container, Row } from "reactstrap"; import logoLine from "../../logos/logo-line-white.svg"; import { Link } from "react-router-dom"; +import { AppContext } from "../../AppContext"; -class UnknownView extends Component { +class VoteSuccess extends Component { + static contextType = AppContext; render() { return ( @@ -30,4 +32,4 @@ class UnknownView extends Component { ); } } -export default UnknownView; +export default VoteSuccess;