fix: build works

pull/89/head
Pierre-Louis Guhur 1 year ago
parent bf22ec4c67
commit f05b668a5d

@ -3,7 +3,7 @@
*/
import {createContext, useContext, useReducer, useEffect} from 'react';
import {useRouter} from "next/router";
import {DEFAULT_NUM_GRADES} from '@services/constants';
import {DEFAULT_GRADES} from '@services/constants';
// Store data about an election
const ElectionContext = createContext(null);
@ -115,7 +115,7 @@ const initialElection = {
title: "",
description: "",
candidates: [{...defaultCandidate}, {...defaultCandidate}],
grades: DEFAULT_NUM_GRADES,
grades: DEFAULT_GRADES,
isTimeLimited: false,
isRandomOrder: false,
restrictResult: true,

281
package-lock.json generated

@ -20,6 +20,7 @@
"clipboard": "^2.0.10",
"dotenv": "^8.6.0",
"eslint-config-next": "^13.0.0",
"framer-motion": "^7.6.4",
"highcharts-react-official": "^3.1.0",
"i18next": "^22.0.3",
"mailgun.js": "^3.3.2",
@ -30,6 +31,7 @@
"react-dom": "^18.2.0",
"react-flags-select": "^2.2.3",
"react-i18next": "^12.0.0",
"react-toastify": "^9.1.0",
"reactstrap": "^9.1.4",
"sass": "^1.32.13"
},
@ -226,6 +228,21 @@
"node": ">=6.9.0"
}
},
"node_modules/@emotion/is-prop-valid": {
"version": "0.8.8",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
"integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
"optional": true,
"dependencies": {
"@emotion/memoize": "0.7.4"
}
},
"node_modules/@emotion/memoize": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
"optional": true
},
"node_modules/@eslint/eslintrc": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz",
@ -400,6 +417,64 @@
"@jridgewell/sourcemap-codec": "1.4.14"
}
},
"node_modules/@motionone/animation": {
"version": "10.14.0",
"resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.14.0.tgz",
"integrity": "sha512-h+1sdyBP8vbxEBW5gPFDnj+m2DCqdlAuf2g6Iafb1lcMnqjsRXWlPw1AXgvUMXmreyhqmPbJqoNfIKdytampRQ==",
"dependencies": {
"@motionone/easing": "^10.14.0",
"@motionone/types": "^10.14.0",
"@motionone/utils": "^10.14.0",
"tslib": "^2.3.1"
}
},
"node_modules/@motionone/dom": {
"version": "10.13.1",
"resolved": "https://registry.npmjs.org/@motionone/dom/-/dom-10.13.1.tgz",
"integrity": "sha512-zjfX+AGMIt/fIqd/SL1Lj93S6AiJsEA3oc5M9VkUr+Gz+juRmYN1vfvZd6MvEkSqEjwPQgcjN7rGZHrDB9APfQ==",
"dependencies": {
"@motionone/animation": "^10.13.1",
"@motionone/generators": "^10.13.1",
"@motionone/types": "^10.13.0",
"@motionone/utils": "^10.13.1",
"hey-listen": "^1.0.8",
"tslib": "^2.3.1"
}
},
"node_modules/@motionone/easing": {
"version": "10.14.0",
"resolved": "https://registry.npmjs.org/@motionone/easing/-/easing-10.14.0.tgz",
"integrity": "sha512-2vUBdH9uWTlRbuErhcsMmt1jvMTTqvGmn9fHq8FleFDXBlHFs5jZzHJT9iw+4kR1h6a4SZQuCf72b9ji92qNYA==",
"dependencies": {
"@motionone/utils": "^10.14.0",
"tslib": "^2.3.1"
}
},
"node_modules/@motionone/generators": {
"version": "10.14.0",
"resolved": "https://registry.npmjs.org/@motionone/generators/-/generators-10.14.0.tgz",
"integrity": "sha512-6kRHezoFfIjFN7pPpaxmkdZXD36tQNcyJe3nwVqwJ+ZfC0e3rFmszR8kp9DEVFs9QL/akWjuGPSLBI1tvz+Vjg==",
"dependencies": {
"@motionone/types": "^10.14.0",
"@motionone/utils": "^10.14.0",
"tslib": "^2.3.1"
}
},
"node_modules/@motionone/types": {
"version": "10.14.0",
"resolved": "https://registry.npmjs.org/@motionone/types/-/types-10.14.0.tgz",
"integrity": "sha512-3bNWyYBHtVd27KncnJLhksMFQ5o2MSdk1cA/IZqsHtA9DnRM1SYgN01CTcJ8Iw8pCXF5Ocp34tyAjY7WRpOJJQ=="
},
"node_modules/@motionone/utils": {
"version": "10.14.0",
"resolved": "https://registry.npmjs.org/@motionone/utils/-/utils-10.14.0.tgz",
"integrity": "sha512-sLWBLPzRqkxmOTRzSaD3LFQXCPHvDzyHJ1a3VP9PRzBxyVd2pv51/gMOsdAcxQ9n+MIeGJnxzXBYplUHKj4jkw==",
"dependencies": {
"@motionone/types": "^10.14.0",
"hey-listen": "^1.0.8",
"tslib": "^2.3.1"
}
},
"node_modules/@next/env": {
"version": "13.0.0",
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.0.0.tgz",
@ -1189,6 +1264,14 @@
"node": ">=6"
}
},
"node_modules/clsx": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
"engines": {
"node": ">=6"
}
},
"node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@ -2040,6 +2123,34 @@
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ=="
},
"node_modules/framer-motion": {
"version": "7.6.4",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-7.6.4.tgz",
"integrity": "sha512-Ac3Bl9M45fS8A0ibOUnYMSCfjaCrFfWT0uh0/MZVm/DGWcr5IsRRinWRiVGABA9RGJgn4THehqcn235JVQkucQ==",
"dependencies": {
"@motionone/dom": "10.13.1",
"framesync": "6.1.2",
"hey-listen": "^1.0.8",
"popmotion": "11.0.5",
"style-value-types": "5.1.2",
"tslib": "2.4.0"
},
"optionalDependencies": {
"@emotion/is-prop-valid": "^0.8.2"
},
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
},
"node_modules/framesync": {
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/framesync/-/framesync-6.1.2.tgz",
"integrity": "sha512-jBTqhX6KaQVDyus8muwZbBeGGP0XgujBRbQ7gM7BRdS3CadCZIHiawyzYLnafYcvZIh5j8WE7cxZKFn7dXhu9g==",
"dependencies": {
"tslib": "2.4.0"
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -2249,6 +2360,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hey-listen": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
"integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
},
"node_modules/highcharts": {
"version": "10.2.1",
"resolved": "https://registry.npmjs.org/highcharts/-/highcharts-10.2.1.tgz",
@ -3198,6 +3314,17 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/popmotion": {
"version": "11.0.5",
"resolved": "https://registry.npmjs.org/popmotion/-/popmotion-11.0.5.tgz",
"integrity": "sha512-la8gPM1WYeFznb/JqF4GiTkRRPZsfaj2+kCxqQgr2MJylMmIKUwBfWW8Wa5fml/8gmtlD5yI01MP1QCZPWmppA==",
"dependencies": {
"framesync": "6.1.2",
"hey-listen": "^1.0.8",
"style-value-types": "5.1.2",
"tslib": "2.4.0"
}
},
"node_modules/postcss": {
"version": "8.4.14",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
@ -3356,6 +3483,18 @@
"react-dom": "^16.8.0 || ^17 || ^18"
}
},
"node_modules/react-toastify": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.0.tgz",
"integrity": "sha512-63i/5SROvfYz9yzdkmxIrpndtggTdif/5ZpswY3VH+s2/S1Hxo/hiv+oGXnPH6UO2pJBOgfcLNeyVh7okRmnhg==",
"dependencies": {
"clsx": "^1.1.1"
},
"peerDependencies": {
"react": ">=16",
"react-dom": ">=16"
}
},
"node_modules/react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
@ -3683,6 +3822,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/style-value-types": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-5.1.2.tgz",
"integrity": "sha512-Vs9fNreYF9j6W2VvuDTP7kepALi7sk0xtk2Tu8Yxi9UoajJdEVpNpCov0HsLTqXvNGKX+Uv09pkozVITi1jf3Q==",
"dependencies": {
"hey-listen": "^1.0.8",
"tslib": "2.4.0"
}
},
"node_modules/styled-jsx": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.0.tgz",
@ -4126,6 +4274,21 @@
"to-fast-properties": "^2.0.0"
}
},
"@emotion/is-prop-valid": {
"version": "0.8.8",
"resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz",
"integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==",
"optional": true,
"requires": {
"@emotion/memoize": "0.7.4"
}
},
"@emotion/memoize": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz",
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
"optional": true
},
"@eslint/eslintrc": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz",
@ -4246,6 +4409,64 @@
"@jridgewell/sourcemap-codec": "1.4.14"
}
},
"@motionone/animation": {
"version": "10.14.0",
"resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.14.0.tgz",
"integrity": "sha512-h+1sdyBP8vbxEBW5gPFDnj+m2DCqdlAuf2g6Iafb1lcMnqjsRXWlPw1AXgvUMXmreyhqmPbJqoNfIKdytampRQ==",
"requires": {
"@motionone/easing": "^10.14.0",
"@motionone/types": "^10.14.0",
"@motionone/utils": "^10.14.0",
"tslib": "^2.3.1"
}
},
"@motionone/dom": {
"version": "10.13.1",
"resolved": "https://registry.npmjs.org/@motionone/dom/-/dom-10.13.1.tgz",
"integrity": "sha512-zjfX+AGMIt/fIqd/SL1Lj93S6AiJsEA3oc5M9VkUr+Gz+juRmYN1vfvZd6MvEkSqEjwPQgcjN7rGZHrDB9APfQ==",
"requires": {
"@motionone/animation": "^10.13.1",
"@motionone/generators": "^10.13.1",
"@motionone/types": "^10.13.0",
"@motionone/utils": "^10.13.1",
"hey-listen": "^1.0.8",
"tslib": "^2.3.1"
}
},
"@motionone/easing": {
"version": "10.14.0",
"resolved": "https://registry.npmjs.org/@motionone/easing/-/easing-10.14.0.tgz",
"integrity": "sha512-2vUBdH9uWTlRbuErhcsMmt1jvMTTqvGmn9fHq8FleFDXBlHFs5jZzHJT9iw+4kR1h6a4SZQuCf72b9ji92qNYA==",
"requires": {
"@motionone/utils": "^10.14.0",
"tslib": "^2.3.1"
}
},
"@motionone/generators": {
"version": "10.14.0",
"resolved": "https://registry.npmjs.org/@motionone/generators/-/generators-10.14.0.tgz",
"integrity": "sha512-6kRHezoFfIjFN7pPpaxmkdZXD36tQNcyJe3nwVqwJ+ZfC0e3rFmszR8kp9DEVFs9QL/akWjuGPSLBI1tvz+Vjg==",
"requires": {
"@motionone/types": "^10.14.0",
"@motionone/utils": "^10.14.0",
"tslib": "^2.3.1"
}
},
"@motionone/types": {
"version": "10.14.0",
"resolved": "https://registry.npmjs.org/@motionone/types/-/types-10.14.0.tgz",
"integrity": "sha512-3bNWyYBHtVd27KncnJLhksMFQ5o2MSdk1cA/IZqsHtA9DnRM1SYgN01CTcJ8Iw8pCXF5Ocp34tyAjY7WRpOJJQ=="
},
"@motionone/utils": {
"version": "10.14.0",
"resolved": "https://registry.npmjs.org/@motionone/utils/-/utils-10.14.0.tgz",
"integrity": "sha512-sLWBLPzRqkxmOTRzSaD3LFQXCPHvDzyHJ1a3VP9PRzBxyVd2pv51/gMOsdAcxQ9n+MIeGJnxzXBYplUHKj4jkw==",
"requires": {
"@motionone/types": "^10.14.0",
"hey-listen": "^1.0.8",
"tslib": "^2.3.1"
}
},
"@next/env": {
"version": "13.0.0",
"resolved": "https://registry.npmjs.org/@next/env/-/env-13.0.0.tgz",
@ -4742,6 +4963,11 @@
"shallow-clone": "^3.0.0"
}
},
"clsx": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
"integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg=="
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@ -5376,6 +5602,28 @@
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ=="
},
"framer-motion": {
"version": "7.6.4",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-7.6.4.tgz",
"integrity": "sha512-Ac3Bl9M45fS8A0ibOUnYMSCfjaCrFfWT0uh0/MZVm/DGWcr5IsRRinWRiVGABA9RGJgn4THehqcn235JVQkucQ==",
"requires": {
"@emotion/is-prop-valid": "^0.8.2",
"@motionone/dom": "10.13.1",
"framesync": "6.1.2",
"hey-listen": "^1.0.8",
"popmotion": "11.0.5",
"style-value-types": "5.1.2",
"tslib": "2.4.0"
}
},
"framesync": {
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/framesync/-/framesync-6.1.2.tgz",
"integrity": "sha512-jBTqhX6KaQVDyus8muwZbBeGGP0XgujBRbQ7gM7BRdS3CadCZIHiawyzYLnafYcvZIh5j8WE7cxZKFn7dXhu9g==",
"requires": {
"tslib": "2.4.0"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -5518,6 +5766,11 @@
"has-symbols": "^1.0.2"
}
},
"hey-listen": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/hey-listen/-/hey-listen-1.0.8.tgz",
"integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q=="
},
"highcharts": {
"version": "10.2.1",
"resolved": "https://registry.npmjs.org/highcharts/-/highcharts-10.2.1.tgz",
@ -6135,6 +6388,17 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
},
"popmotion": {
"version": "11.0.5",
"resolved": "https://registry.npmjs.org/popmotion/-/popmotion-11.0.5.tgz",
"integrity": "sha512-la8gPM1WYeFznb/JqF4GiTkRRPZsfaj2+kCxqQgr2MJylMmIKUwBfWW8Wa5fml/8gmtlD5yI01MP1QCZPWmppA==",
"requires": {
"framesync": "6.1.2",
"hey-listen": "^1.0.8",
"style-value-types": "5.1.2",
"tslib": "2.4.0"
}
},
"postcss": {
"version": "8.4.14",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
@ -6229,6 +6493,14 @@
"warning": "^4.0.2"
}
},
"react-toastify": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.0.tgz",
"integrity": "sha512-63i/5SROvfYz9yzdkmxIrpndtggTdif/5ZpswY3VH+s2/S1Hxo/hiv+oGXnPH6UO2pJBOgfcLNeyVh7okRmnhg==",
"requires": {
"clsx": "^1.1.1"
}
},
"react-transition-group": {
"version": "4.4.5",
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz",
@ -6449,6 +6721,15 @@
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="
},
"style-value-types": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/style-value-types/-/style-value-types-5.1.2.tgz",
"integrity": "sha512-Vs9fNreYF9j6W2VvuDTP7kepALi7sk0xtk2Tu8Yxi9UoajJdEVpNpCov0HsLTqXvNGKX+Uv09pkozVITi1jf3Q==",
"requires": {
"hey-listen": "^1.0.8",
"tslib": "2.4.0"
}
},
"styled-jsx": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.0.tgz",

@ -22,6 +22,7 @@
"clipboard": "^2.0.10",
"dotenv": "^8.6.0",
"eslint-config-next": "^13.0.0",
"framer-motion": "^7.6.4",
"highcharts-react-official": "^3.1.0",
"i18next": "^22.0.3",
"mailgun.js": "^3.3.2",
@ -32,6 +33,7 @@
"react-dom": "^18.2.0",
"react-flags-select": "^2.2.3",
"react-i18next": "^12.0.0",
"react-toastify": "^9.1.0",
"reactstrap": "^9.1.4",
"sass": "^1.32.13"
},

@ -3,20 +3,20 @@ import Head from "next/head";
import {useRouter} from "next/router";
import {useTranslation} from "next-i18next";
import {serverSideTranslations} from "next-i18next/serverSideTranslations";
// import {
// Collapse,
// Container,
// Row,
// Col,
// Input,
// Label,
// InputGroup,
// InputGroupAddon,
// Button,
// Card,
// CardBody,
// Modal, ModalHeader, ModalBody, ModalFooter, CustomInput
// } from "reactstrap";
import {
Collapse,
Container,
Row,
Col,
Input,
Label,
InputGroup,
InputGroupAddon,
Button,
Card,
CardBody,
Modal, ModalHeader, ModalBody, ModalFooter, CustomInput
} from "reactstrap";
// import {ReactMultiEmail, isEmail} from "react-multi-email";
// import "react-multi-email/style.css";
// import {toast, ToastContainer} from "react-toastify";
@ -43,439 +43,441 @@ import {serverSideTranslations} from "next-i18next/serverSideTranslations";
// Error messages
const AT_LEAST_2_CANDIDATES_ERROR = "Please add at least 2 candidates.";
const NO_TITLE_ERROR = "Please add a title.";
const isValidDate = (date) => date instanceof Date && !isNaN(date);
const getOnlyValidDate = (date) => (isValidDate(date) ? date : new Date());
// Convert a Date object into YYYY-MM-DD
const dateToISO = (date) =>
getOnlyValidDate(date).toISOString().substring(0, 10);
// Retrieve the current hour, minute, sec, ms, time into a timestamp
const hours = (date) => getOnlyValidDate(date).getHours() * 3600 * 1000;
const minutes = (date) => getOnlyValidDate(date).getMinutes() * 60 * 1000;
const seconds = (date) => getOnlyValidDate(date).getSeconds() * 1000;
const ms = (date) => getOnlyValidDate(date).getMilliseconds();
const time = (date) =>
hours(getOnlyValidDate(date)) +
minutes(getOnlyValidDate(date)) +
seconds(getOnlyValidDate(date)) +
ms(getOnlyValidDate(date));
// Retrieve the time part from a timestamp and remove the day. Return a int.
const timeMinusDate = (date) => time(getOnlyValidDate(date));
// Retrieve the day and remove the time. Return a Date
const dateMinusTime = (date) =>
new Date(getOnlyValidDate(date).getTime() - time(getOnlyValidDate(date)));
const displayClockOptions = () =>
Array(24)
.fill(1)
.map((x, i) => (
<option value={i} key={i}>
{i}h00
</option>
));
// const AT_LEAST_2_CANDIDATES_ERROR = "Please add at least 2 candidates.";
// const NO_TITLE_ERROR = "Please add a title.";
//
// const isValidDate = (date) => date instanceof Date && !isNaN(date);
// const getOnlyValidDate = (date) => (isValidDate(date) ? date : new Date());
//
// // Convert a Date object into YYYY-MM-DD
// const dateToISO = (date) =>
// getOnlyValidDate(date).toISOString().substring(0, 10);
//
// // Retrieve the current hour, minute, sec, ms, time into a timestamp
// const hours = (date) => getOnlyValidDate(date).getHours() * 3600 * 1000;
// const minutes = (date) => getOnlyValidDate(date).getMinutes() * 60 * 1000;
// const seconds = (date) => getOnlyValidDate(date).getSeconds() * 1000;
// const ms = (date) => getOnlyValidDate(date).getMilliseconds();
// const time = (date) =>
// hours(getOnlyValidDate(date)) +
// minutes(getOnlyValidDate(date)) +
// seconds(getOnlyValidDate(date)) +
// ms(getOnlyValidDate(date));
//
// // Retrieve the time part from a timestamp and remove the day. Return a int.
// const timeMinusDate = (date) => time(getOnlyValidDate(date));
//
// // Retrieve the day and remove the time. Return a Date
// const dateMinusTime = (date) =>
// new Date(getOnlyValidDate(date).getTime() - time(getOnlyValidDate(date)));
//
// const displayClockOptions = () =>
// Array(24)
// .fill(1)
// .map((x, i) => (
// <option value={i} key={i}>
// {i}h00
// </option>
// ));
export const getStaticProps = async ({locale}) => ({
props: {
...(await serverSideTranslations(locale, [])),
...(await serverSideTranslations(locale, ['resource'])),
},
});
const CreateElection = (props) => {
const {t} = useTranslation();
// default value : start at the last hour
const now = new Date();
const [title, setTitle] = useState("");
const [candidates, setCandidates] = useState([{label: ""}, {description: ""}]);
const [numGrades, setNumGrades] = useState(5);
const [waiting, setWaiting] = useState(false);
const [isAdvancedOptionsOpen, setAdvancedOptionsOpen] = useState(false);
const [isAddCandidateMOpen, setAddCandidateMOpen] = useState(false);
const [isTimeLimited, setTimeLimited] = useState(false);
const [restrictResult, setRestrictResult] = useState(false);
const [restrictVote, setRestrictVote] = useState(false);
const [start, setStart] = useState(
new Date(now.getTime() - minutes(now) - seconds(now) - ms(now))
);
const [finish, setFinish] = useState(
new Date(start.getTime() + 7 * 24 * 3600 * 1000)
);
const [emails, setEmails] = useState([]);
// set the title on loading
const router = useRouter();
useEffect(() => {
if (!router.isReady) return;
const {title: urlTitle} = router.query;
setTitle(urlTitle || "");
}, [router.isReady]);
const handleIsTimeLimited = (event) => {
setTimeLimited(event.target.value === "1");
};
const handleRestrictResultCheck = (event) => {
setRestrictResult(event.target.value === "1");
};
const handleRestrictVote = (event) => {
setRestrictVote(event.target.value === "1");
};
const toggleAdvancedOptions = () => {
setAdvancedOptionsOpen(!isAdvancedOptionsOpen);
};
const toggleAddCandidateM = () => {
setAddCandidateMOpen(!isAddCandidateMOpen);
};
const addCandidate = () => {
if (candidates.length < 1000) {
candidates.push({label: ""});
setCandidates(candidates);
}
};
const checkFields = () => {
if (!candidates) {
return {ok: false, msg: AT_LEAST_2_CANDIDATES_ERROR};
}
let numCandidates = 0;
candidates.forEach((c) => {
if (c.label !== "") numCandidates += 1;
});
if (numCandidates < 2) {
return {ok: false, msg: AT_LEAST_2_CANDIDATES_ERROR};
}
if (!title || title === "") {
return {ok: false, msg: NO_TITLE_ERROR};
}
return {ok: true, msg: "OK"};
};
const handleSubmit = () => {
const check = checkFields();
if (!check.ok) {
toast.error(t(check.msg), {
position: toast.POSITION.TOP_CENTER,
});
return;
}
setWaiting(true);
createElection(
title,
candidates.map((c) => c.label).filter((c) => c !== ""),
{
mails: emails,
numGrades,
start: start.getTime() / 1000,
finish: finish.getTime() / 1000,
restrictResult: restrictResult,
restrictVote: restrictVote,
locale: router.locale.substring(0, 2).toLowerCase(),
},
(result) => {
if (result.id) {
router.push(`/new/confirm/${result.id}`);
} else {
toast.error(t("Unknown error. Try again please."), {
position: toast.POSITION.TOP_CENTER,
});
setWaiting(false);
}
}
);
};
const [visibled, setVisibility] = useState(false);
const toggle = () => setVisibility(!visibled)
const handleSendNotReady = (msg) => {
toast.error(t(msg), {
position: toast.POSITION.TOP_CENTER,
});
};
const check = checkFields();
const grades = translateGrades(t);
// const {t} = useTranslation();
// // default value : start at the last hour
// const now = new Date();
// const [title, setTitle] = useState("");
// const [candidates, setCandidates] = useState([{label: ""}, {description: ""}]);
// const [numGrades, setNumGrades] = useState(5);
// const [waiting, setWaiting] = useState(false);
// const [isAdvancedOptionsOpen, setAdvancedOptionsOpen] = useState(false);
// const [isAddCandidateMOpen, setAddCandidateMOpen] = useState(false);
// const [isTimeLimited, setTimeLimited] = useState(false);
// const [restrictResult, setRestrictResult] = useState(false);
// const [restrictVote, setRestrictVote] = useState(false);
// const [start, setStart] = useState(
// new Date(now.getTime() - minutes(now) - seconds(now) - ms(now))
// );
// const [finish, setFinish] = useState(
// new Date(start.getTime() + 7 * 24 * 3600 * 1000)
// );
// const [emails, setEmails] = useState([]);
// // set the title on loading
// const router = useRouter();
// useEffect(() => {
// if (!router.isReady) return;
// const {title: urlTitle} = router.query;
// setTitle(urlTitle || "");
// }, [router.isReady]);
// const handleIsTimeLimited = (event) => {
// setTimeLimited(event.target.value === "1");
// };
// const handleRestrictResultCheck = (event) => {
// setRestrictResult(event.target.value === "1");
// };
// const handleRestrictVote = (event) => {
// setRestrictVote(event.target.value === "1");
// };
// const toggleAdvancedOptions = () => {
// setAdvancedOptionsOpen(!isAdvancedOptionsOpen);
// };
// const toggleAddCandidateM = () => {
// setAddCandidateMOpen(!isAddCandidateMOpen);
// };
// const addCandidate = () => {
// if (candidates.length < 1000) {
// candidates.push({label: ""});
// setCandidates(candidates);
// }
// };
// const checkFields = () => {
// if (!candidates) {
// return {ok: false, msg: AT_LEAST_2_CANDIDATES_ERROR};
// }
// let numCandidates = 0;
// candidates.forEach((c) => {
// if (c.label !== "") numCandidates += 1;
// });
// if (numCandidates < 2) {
// return {ok: false, msg: AT_LEAST_2_CANDIDATES_ERROR};
// }
// if (!title || title === "") {
// return {ok: false, msg: NO_TITLE_ERROR};
// }
// return {ok: true, msg: "OK"};
// };
// const handleSubmit = () => {
// const check = checkFields();
// if (!check.ok) {
// toast.error(t(check.msg), {
// position: toast.POSITION.TOP_CENTER,
// });
// return;
// }
// setWaiting(true);
// createElection(
// title,
// candidates.map((c) => c.label).filter((c) => c !== ""),
// {
// mails: emails,
// numGrades,
// start: start.getTime() / 1000,
// finish: finish.getTime() / 1000,
// restrictResult: restrictResult,
// restrictVote: restrictVote,
// locale: router.locale.substring(0, 2).toLowerCase(),
// },
// (result) => {
// if (result.id) {
// router.push(`/new/confirm/${result.id}`);
// } else {
// toast.error(t("Unknown error. Try again please."), {
// position: toast.POSITION.TOP_CENTER,
// });
// setWaiting(false);
// }
// }
// );
// };
// const [visibled, setVisibility] = useState(false);
// const toggle = () => setVisibility(!visibled)
// const handleSendNotReady = (msg) => {
// toast.error(t(msg), {
// position: toast.POSITION.TOP_CENTER,
// });
// };
// const check = checkFields();
// const grades = translateGrades(t);
const [showModal, setShowModal] = useState(false);
return (
<Container className="addCandidatePage">
<Head>
<meta
key="og:title"
property="og:title"
content={t("common.application")}
/>
<meta
property="og:description"
key="og:description"
content={t("resource.valueProp")}
/>
</Head>
<ToastContainer />
{waiting ? <Loader /> : ""}
<form onSubmit={handleSubmit} autoComplete="off">
<Row className="stepForm">
<Col className="stepFormCol">
<img src="/icone-one-white.svg" />
<h4>Les candidats</h4>
</Col>
<Col className="stepFormCol">
<img src="/icone-two-dark.svg" />
<h4>Paramètres du vote</h4>
</Col>
<Col className="stepFormCol">
<img src="/icone-three-dark.svg" />
<h4>Confirmation</h4>
</Col>
</Row>
<div className="settings-modal-body">
<Row>
<Col xs="10" lg="10">
<Label for="title">{t("Access to results")} {t("Immediately")}</Label>
<p>{t("No one will be able to see the result until the end date is reached or until all participants have voted.")}</p>
</Col>
<Col l xs="2" lg="2">
<CustomInput
type="switch"
id="restrict_result_false"
name={handleRestrictResultCheck}
/>
</Col>
</Row>
<hr className="mt-2 mb-2" />
<Row>
<Col md="10">
<Label for="title">{t("Voting time")}</Label>
</Col>
<Col l md="2">
<CustomInput
type="switch"
id="is_time_limited_true"
name={handleIsTimeLimited}
value={"1"}
/>
</Col>
</Row>
<div
className={
(isTimeLimited ? "d-block " : "d-none") + " bg-light p-3"
}
>
<Row>
<Col xs="12" md="3" lg="3">
<span className="label">- {t("Starting date")}</span>
</Col>
<Col xs="6" md="4" lg="3">
<input
className="form-control"
type="date"
value={dateToISO(start)}
onChange={(e) => {
setStart(
new Date(
timeMinusDate(start) +
new Date(e.target.valueAsNumber).getTime()
)
);
}}
/>
</Col>
<Col xs="6" md="5" lg="3">
<select
className="form-control"
value={getOnlyValidDate(start).getHours()}
onChange={(e) =>
setStart(
new Date(
dateMinusTime(start).getTime() +
e.target.value * 3600000
)
)
}
>
{displayClockOptions()}
</select>
</Col>
</Row>
<Row className="mt-2">
<Col xs="12" md="3" lg="3">
<span className="label">- {t("Ending date")}</span>
</Col>
<Col xs="6" md="4" lg="3">
<input
className="form-control"
type="date"
value={dateToISO(finish)}
min={dateToISO(start)}
onChange={(e) => {
setFinish(
new Date(
timeMinusDate(finish) +
new Date(e.target.valueAsNumber).getTime()
)
);
}}
/>
</Col>
<Col xs="6" md="5" lg="3">
<select
className="form-control"
value={getOnlyValidDate(finish).getHours()}
onChange={(e) =>
setFinish(
new Date(
dateMinusTime(finish).getTime() +
e.target.value * 3600000
)
)
}
>
{displayClockOptions()}
</select>
</Col>
</Row>
</div>
<hr className="mt-2 mb-2" />
<Row>
<Col xs="9">
<Label>{t("Grades")}</Label>
<p>{t("You can select here the number of grades for your election")}</p>
</Col>
<Col xs="3">
<div className="numGradesContainer justify-content-end" tabIndex={candidates.length + 3}
onChange={(e) => setNumGrades(e.target.value)}>
<Label className="numGrades">
<Input type="radio" name="radio" value="5" />
<div className="customCheckmarck numGradeFive"></div>
</Label>
<Label className="numGrades">
<Input type="radio" checked="checked" name="radio" value="6" />
<div className="customCheckmarck numGradeSix"></div>
</Label>
<Label className="numGrades">
<Input type="radio" name="radio" value="7" />
<div className="customCheckmarck numGradeSeven"></div>
</Label>
</div>
</Col>
<Col
xs="12"
md="9"
lg="9"
>
{grades.map((mention, i) => {
return (
<span
key={i}
className="badge badge-light mr-2 mt-2 "
style={{
backgroundColor: mention.color,
color: "#fff",
opacity: i < numGrades ? 1 : 0.3,
}}
>
{mention.label}
</span>
);
})}
</Col>
</Row>
<hr className="mt-2 mb-2" />
<Row>
<Col xs="10" lg="10">
<Label for="title">{t("Vote privée")}</Label>
<p>{t("Uniquement les personnes invités par mail pourront participé au vote")}</p>
</Col>
<Col l xs="2" lg="2">
<CustomInput
type="switch"
id="restrict_vote_false"
name={handleRestrictVote}
/>
</Col>
</Row>
<hr className="mt-2 mb-2" />
<Row>
<Col xs="12">
<Label>{t("Participants")}</Label>
<p>{t("If you list voters' emails, only them will be able to access the election")}</p>
<ReactMultiEmail
placeholder={t("Add here participants' emails")}
emails={emails}
onChange={setEmails}
validateEmail={(email) => {
return isEmail(email); // return boolean
}}
getLabel={(email, index, removeEmail) => {
return (
<div data-tag key={index}>
{email}
<span
data-tag-handle
onClick={() => removeEmail(index)}
>
×
</span>
</div>
);
}}
/>
<div className="mt-2 mailMutedText">
<small className="text-muted">
<FontAwesomeIcon icon={faExclamationCircle} className="mr-2" />
{t("Copier-coller les emails des participants depuis un fichier Excel")}
</small>
</div>
</Col>
</Row>
<hr className="mt-2 mb-2" />
<Col xs="12" md="3">
</Col>
</div>
<div className="justify-content-center">
{check.ok ? (
<ConfirmModal
title={title}
candidates={candidates}
isTimeLimited={isTimeLimited}
start={start}
finish={finish}
emails={emails}
restrictResult={restrictResult}
restrictVote={restrictVote}
grades={grades.slice(0, numGrades)}
className={"btn float-right btn-block"}
tabIndex={candidates.length + 1}
confirmCallback={handleSubmit}
/>
) : (
<Button onClick={toggle} className="cursorPointer btn-validation mb-5" >{t("Confirm")}<img src="/arrow-white.svg" /></Button>
)}
</div></form>
</Container >
);
};
<p>FOO</p>);
}
// <Container className="addCandidatePage">
// <Head>
// <meta
// key="og:title"
// property="og:title"
// content={t("common.application")}
// />
// <meta
// property="og:description"
// key="og:description"
// content={t("resource.valueProp")}
// />
// </Head>
// <ToastContainer />
// {waiting ? <Loader /> : ""}
// <form onSubmit={handleSubmit} autoComplete="off">
// <Row className="stepForm">
// <Col className="stepFormCol">
// <img src="/icone-one-white.svg" />
// <h4>Les candidats</h4>
// </Col>
// <Col className="stepFormCol">
// <img src="/icone-two-dark.svg" />
// <h4>Paramètres du vote</h4>
// </Col>
// <Col className="stepFormCol">
// <img src="/icone-three-dark.svg" />
// <h4>Confirmation</h4>
//
// </Col>
// </Row>
//
// <div className="settings-modal-body">
// <Row>
// <Col xs="10" lg="10">
// <Label for="title">{t("Access to results")} {t("Immediately")}</Label>
// <p>{t("No one will be able to see the result until the end date is reached or until all participants have voted.")}</p>
// </Col>
// <Col l xs="2" lg="2">
// <CustomInput
// type="switch"
// id="restrict_result_false"
// name={handleRestrictResultCheck}
// />
// </Col>
// </Row>
// <hr className="mt-2 mb-2" />
// <Row>
// <Col md="10">
// <Label for="title">{t("Voting time")}</Label>
// </Col>
// <Col l md="2">
// <CustomInput
// type="switch"
// id="is_time_limited_true"
// name={handleIsTimeLimited}
// value={"1"}
// />
// </Col>
// </Row>
// <div
// className={
// (isTimeLimited ? "d-block " : "d-none") + " bg-light p-3"
// }
// >
// <Row>
// <Col xs="12" md="3" lg="3">
// <span className="label">- {t("Starting date")}</span>
// </Col>
// <Col xs="6" md="4" lg="3">
// <input
// className="form-control"
// type="date"
// value={dateToISO(start)}
// onChange={(e) => {
// setStart(
// new Date(
// timeMinusDate(start) +
// new Date(e.target.valueAsNumber).getTime()
// )
// );
// }}
// />
// </Col>
// <Col xs="6" md="5" lg="3">
// <select
// className="form-control"
// value={getOnlyValidDate(start).getHours()}
// onChange={(e) =>
// setStart(
// new Date(
// dateMinusTime(start).getTime() +
// e.target.value * 3600000
// )
// )
// }
// >
// {displayClockOptions()}
// </select>
// </Col>
// </Row>
//
// <Row className="mt-2">
// <Col xs="12" md="3" lg="3">
// <span className="label">- {t("Ending date")}</span>
// </Col>
// <Col xs="6" md="4" lg="3">
// <input
// className="form-control"
// type="date"
// value={dateToISO(finish)}
// min={dateToISO(start)}
// onChange={(e) => {
// setFinish(
// new Date(
// timeMinusDate(finish) +
// new Date(e.target.valueAsNumber).getTime()
// )
// );
// }}
// />
// </Col>
// <Col xs="6" md="5" lg="3">
// <select
// className="form-control"
// value={getOnlyValidDate(finish).getHours()}
// onChange={(e) =>
// setFinish(
// new Date(
// dateMinusTime(finish).getTime() +
// e.target.value * 3600000
// )
// )
// }
// >
// {displayClockOptions()}
// </select>
// </Col>
// </Row>
// </div>
// <hr className="mt-2 mb-2" />
// <Row>
// <Col xs="9">
// <Label>{t("Grades")}</Label>
// <p>{t("You can select here the number of grades for your election")}</p>
// </Col>
// <Col xs="3">
// <div className="numGradesContainer justify-content-end" tabIndex={candidates.length + 3}
// onChange={(e) => setNumGrades(e.target.value)}>
// <Label className="numGrades">
// <Input type="radio" name="radio" value="5" />
// <div className="customCheckmarck numGradeFive"></div>
// </Label>
// <Label className="numGrades">
// <Input type="radio" checked="checked" name="radio" value="6" />
// <div className="customCheckmarck numGradeSix"></div>
// </Label>
// <Label className="numGrades">
// <Input type="radio" name="radio" value="7" />
// <div className="customCheckmarck numGradeSeven"></div>
// </Label>
// </div>
// </Col>
// <Col
// xs="12"
// md="9"
// lg="9"
// >
// {grades.map((mention, i) => {
// return (
// <span
// key={i}
// className="badge badge-light mr-2 mt-2 "
// style={{
// backgroundColor: mention.color,
// color: "#fff",
// opacity: i < numGrades ? 1 : 0.3,
// }}
// >
// {mention.label}
// </span>
// );
// })}
// </Col>
// </Row>
// <hr className="mt-2 mb-2" />
// <Row>
// <Col xs="10" lg="10">
// <Label for="title">{t("Vote privée")}</Label>
// <p>{t("Uniquement les personnes invités par mail pourront participé au vote")}</p>
// </Col>
// <Col l xs="2" lg="2">
// <CustomInput
// type="switch"
// id="restrict_vote_false"
// name={handleRestrictVote}
// />
// </Col>
// </Row>
// <hr className="mt-2 mb-2" />
// <Row>
// <Col xs="12">
// <Label>{t("Participants")}</Label>
// <p>{t("If you list voters' emails, only them will be able to access the election")}</p>
// <ReactMultiEmail
// placeholder={t("Add here participants' emails")}
// emails={emails}
// onChange={setEmails}
// validateEmail={(email) => {
// return isEmail(email); // return boolean
// }}
// getLabel={(email, index, removeEmail) => {
// return (
// <div data-tag key={index}>
// {email}
// <span
// data-tag-handle
// onClick={() => removeEmail(index)}
// >
// ×
// </span>
// </div>
// );
// }}
// />
// <div className="mt-2 mailMutedText">
// <small className="text-muted">
// <FontAwesomeIcon icon={faExclamationCircle} className="mr-2" />
// {t("Copier-coller les emails des participants depuis un fichier Excel")}
// </small>
// </div>
// </Col>
// </Row>
// <hr className="mt-2 mb-2" />
// <Col xs="12" md="3">
//
// </Col>
// </div>
// <div className="justify-content-center">
// {check.ok ? (
// <ConfirmModal
// title={title}
// candidates={candidates}
// isTimeLimited={isTimeLimited}
// start={start}
// finish={finish}
// emails={emails}
// restrictResult={restrictResult}
// restrictVote={restrictVote}
// grades={grades.slice(0, numGrades)}
// className={"btn float-right btn-block"}
// tabIndex={candidates.length + 1}
// confirmCallback={handleSubmit}
// />
// ) : (
//
// <Button onClick={toggle} className="cursorPointer btn-validation mb-5" >{t("Confirm")}<img src="/arrow-white.svg" /></Button>
//
// )}
// </div></form>
//
//
// </Container >
// );
// };
export default CreateElection;

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save