Merge branch 'master' into 'production'

1st Live deploy

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!48
This commit is contained in:
Aarni Halinen
2021-03-31 21:17:15 +00:00
78 changed files with 493 additions and 480 deletions
+1 -1
View File
@@ -130,7 +130,7 @@ deploy:prod:
- production
environment:
name: production
url: prod.sahkoinsinoorikilta.fi
url: sahkoinsinoorikilta.fi
when: manual
variables:
DOCKER_HOST: $CI_DOCKER_HOST
+41 -188
View File
@@ -23,6 +23,7 @@
"react-jsonschema-form": "1.8.1",
"react-markdown": "5.0.3",
"react-mde": "11.0.6",
"react-toastify": "^7.0.3",
"shortid": "2.2.16",
"styled-components": "5.2.1",
"swr": "0.4.2"
@@ -3012,9 +3013,6 @@
"dev": true,
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@hapi/accept": {
@@ -3086,10 +3084,6 @@
"source-map": "0.8.0-beta.0",
"stacktrace-parser": "0.1.10",
"strip-ansi": "6.0.0"
},
"peerDependencies": {
"react": "^16.9.0 || ^17",
"react-dom": "^16.9.0 || ^17"
}
},
"node_modules/@next/react-dev-overlay/node_modules/ansi-regex": {
@@ -3109,9 +3103,6 @@
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/@next/react-dev-overlay/node_modules/chalk": {
@@ -3124,9 +3115,6 @@
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/@next/react-dev-overlay/node_modules/color-convert": {
@@ -3189,16 +3177,7 @@
"node_modules/@next/react-refresh-utils": {
"version": "10.0.8",
"resolved": "https://registry.npmjs.org/@next/react-refresh-utils/-/react-refresh-utils-10.0.8.tgz",
"integrity": "sha512-ZMO77Xs2ioGV/nZB4GRDHgsNT2jhOp+cZIh6c7wf0xw9o/1KoTWN8nxWzwU/laAtkoSS+E6YdhuR4Mw3Ar3CSg==",
"peerDependencies": {
"react-refresh": "0.8.3",
"webpack": "^4 || ^5"
},
"peerDependenciesMeta": {
"webpack": {
"optional": true
}
}
"integrity": "sha512-ZMO77Xs2ioGV/nZB4GRDHgsNT2jhOp+cZIh6c7wf0xw9o/1KoTWN8nxWzwU/laAtkoSS+E6YdhuR4Mw3Ar3CSg=="
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.3",
@@ -3489,19 +3468,6 @@
},
"engines": {
"node": "^10.12.0 || >=12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"@typescript-eslint/parser": "^4.0.0",
"eslint": "^5.0.0 || ^6.0.0 || ^7.0.0"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/@typescript-eslint/experimental-utils": {
@@ -3519,13 +3485,6 @@
},
"engines": {
"node": "^10.12.0 || >=12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "*"
}
},
"node_modules/@typescript-eslint/parser": {
@@ -3541,18 +3500,6 @@
},
"engines": {
"node": "^10.12.0 || >=12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "^5.0.0 || ^6.0.0 || ^7.0.0"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/@typescript-eslint/scope-manager": {
@@ -3566,10 +3513,6 @@
},
"engines": {
"node": "^8.10.0 || ^10.13.0 || >=11.10.1"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/types": {
@@ -3579,10 +3522,6 @@
"dev": true,
"engines": {
"node": "^8.10.0 || ^10.13.0 || >=11.10.1"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/typescript-estree": {
@@ -3601,15 +3540,6 @@
},
"engines": {
"node": "^10.12.0 || >=12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/@nodelib/fs.stat": {
@@ -3686,9 +3616,6 @@
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/ignore": {
@@ -3745,10 +3672,6 @@
},
"engines": {
"node": "^8.10.0 || ^10.13.0 || >=11.10.1"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
@@ -3785,10 +3708,7 @@
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
"integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
"dev": true,
"peerDependencies": {
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
"dev": true
},
"node_modules/acorn-walk": {
"version": "8.0.1",
@@ -3820,10 +3740,6 @@
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/amdefine": {
@@ -4071,6 +3987,7 @@
"integrity": "sha512-d2Ovma+bfqNpvBzY/KU8oPY67ZworixTpkjSx0PCXnQi67c2cXmssaTxpFDUM0ttopXoGx/KRxNg/GDThYbXQA==",
"dev": true,
"dependencies": {
"@types/glob": "^7.1.1",
"chromium-pickle-js": "^0.2.0",
"commander": "^2.20.0",
"cuint": "^0.2.2",
@@ -4084,9 +4001,6 @@
},
"engines": {
"node": ">=8.0"
},
"optionalDependencies": {
"@types/glob": "^7.1.1"
}
},
"node_modules/asn1.js": {
@@ -4328,9 +4242,6 @@
"@babel/helper-module-imports": "^7.0.0",
"babel-plugin-syntax-jsx": "^6.18.0",
"lodash": "^4.17.11"
},
"peerDependencies": {
"styled-components": ">= 2"
}
},
"node_modules/babel-plugin-syntax-jsx": {
@@ -4747,9 +4658,6 @@
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/camelize": {
@@ -4974,6 +4882,14 @@
"node": ">=6"
}
},
"node_modules/clsx": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz",
"integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==",
"engines": {
"node": ">=6"
}
},
"node_modules/code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
@@ -5452,10 +5368,6 @@
"integrity": "sha512-NYyAg4wRmGVU4miKq5ivRACOODdZRY3q5WLmOJSq8djyzftYphU7dTHLcEtLqEvfqMKQ0jVv91P4BAwIjsXIcw==",
"engines": {
"node": ">=0.11"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/date-fns"
}
},
"node_modules/debug": {
@@ -6078,9 +5990,6 @@
},
"engines": {
"node": "^10.12.0 || >=12.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint-config-airbnb": {
@@ -7230,9 +7139,6 @@
},
"bin": {
"rimraf": "bin.js"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/flatted": {
@@ -7376,9 +7282,6 @@
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/glob-parent": {
@@ -7453,9 +7356,6 @@
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/globals/node_modules/type-fest": {
@@ -7864,16 +7764,6 @@
"resolved": "https://registry.npmjs.org/husky/-/husky-5.1.3.tgz",
"integrity": "sha512-fbNJ+Gz5wx2LIBtMweJNY1D7Uc8p1XERi5KNRMccwfQA+rXlxWNSdUxswo0gT8XqxywTIw7Ywm/F4v/O35RdMg==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/typicode"
},
{
"type": "opencollective",
"url": "https://opencollective.com/husky"
}
],
"bin": {
"husky": "lib/bin.js"
},
@@ -7917,9 +7807,6 @@
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/import-lazy": {
@@ -8965,9 +8852,6 @@
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/matcher/node_modules/escape-string-regexp": {
@@ -8977,9 +8861,6 @@
"dev": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/mathml-tag-names": {
@@ -9090,9 +8971,6 @@
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/meow/node_modules/hosted-git-info": {
@@ -9141,9 +9019,6 @@
"dev": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/merge-stream": {
@@ -9491,24 +9366,6 @@
},
"engines": {
"node": ">=10.13.0"
},
"peerDependencies": {
"fibers": ">= 3.1.0",
"node-sass": "^4.0.0 || ^5.0.0",
"react": "^16.6.0 || ^17",
"react-dom": "^16.6.0 || ^17",
"sass": "^1.3.0"
},
"peerDependenciesMeta": {
"fibers": {
"optional": true
},
"node-sass": {
"optional": true
},
"sass": {
"optional": true
}
}
},
"node_modules/next-sitemap": {
@@ -9523,9 +9380,6 @@
},
"bin": {
"next-sitemap": "bin/next-sitemap"
},
"peerDependencies": {
"next": "*"
}
},
"node_modules/next/node_modules/browserslist": {
@@ -10412,9 +10266,6 @@
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/pidtree": {
@@ -11260,11 +11111,7 @@
"node_modules/react-mde": {
"version": "11.0.6",
"resolved": "https://registry.npmjs.org/react-mde/-/react-mde-11.0.6.tgz",
"integrity": "sha512-yWiPSurQvjLVD070zycQR4x5zW3f/kxPlqOMmZoUtVQvUgcM+kwpDQAba5sqtqtAurgUx0Ae9p9Xzgqwt2+ZBA==",
"peerDependencies": {
"react": "^16.0.0",
"react-dom": "^16.0.0"
}
"integrity": "sha512-yWiPSurQvjLVD070zycQR4x5zW3f/kxPlqOMmZoUtVQvUgcM+kwpDQAba5sqtqtAurgUx0Ae9p9Xzgqwt2+ZBA=="
},
"node_modules/react-redux": {
"version": "7.2.2",
@@ -11320,6 +11167,18 @@
"node": ">=0.10.0"
}
},
"node_modules/react-toastify": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-7.0.3.tgz",
"integrity": "sha512-cxZ5rfurC8LzcZQMTYc8RHIkQTs+BFur18Pzk6Loz6uS8OXUWm6nXVlH/wqglz4Z7UAE8xxcF5mRjfE13487uQ==",
"dependencies": {
"clsx": "^1.1.1"
},
"peerDependencies": {
"react": ">=16",
"react-dom": ">=16"
}
},
"node_modules/read-file-relative": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/read-file-relative/-/read-file-relative-1.2.0.tgz",
@@ -11355,9 +11214,6 @@
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/read-pkg-up/node_modules/find-up": {
@@ -11395,9 +11251,6 @@
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/read-pkg-up/node_modules/p-locate": {
@@ -11434,9 +11287,6 @@
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/read-pkg-up/node_modules/path-exists": {
@@ -12957,10 +12807,6 @@
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/stylelint"
}
},
"node_modules/stylelint-config-recommended": {
@@ -13707,9 +13553,6 @@
"integrity": "sha512-SKGxcAfyijj/lE5ja5zVMDqJNudASH3WZPRUakDVOePTM18FnsXgugndjl9BSRwj+jokFCulMDe7F2pQL+VhEw==",
"dependencies": {
"dequal": "2.0.2"
},
"peerDependencies": {
"react": "^16.11.0 || ^17.0.0"
}
},
"node_modules/symbol-observable": {
@@ -18480,8 +18323,7 @@
"@next/react-refresh-utils": {
"version": "10.0.8",
"resolved": "https://registry.npmjs.org/@next/react-refresh-utils/-/react-refresh-utils-10.0.8.tgz",
"integrity": "sha512-ZMO77Xs2ioGV/nZB4GRDHgsNT2jhOp+cZIh6c7wf0xw9o/1KoTWN8nxWzwU/laAtkoSS+E6YdhuR4Mw3Ar3CSg==",
"requires": {}
"integrity": "sha512-ZMO77Xs2ioGV/nZB4GRDHgsNT2jhOp+cZIh6c7wf0xw9o/1KoTWN8nxWzwU/laAtkoSS+E6YdhuR4Mw3Ar3CSg=="
},
"@nodelib/fs.scandir": {
"version": "2.1.3",
@@ -18942,8 +18784,7 @@
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
"integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
"dev": true,
"requires": {}
"dev": true
},
"acorn-walk": {
"version": "8.0.1",
@@ -19934,6 +19775,11 @@
"is-regexp": "^2.0.0"
}
},
"clsx": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz",
"integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA=="
},
"code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
@@ -25128,8 +24974,7 @@
"react-mde": {
"version": "11.0.6",
"resolved": "https://registry.npmjs.org/react-mde/-/react-mde-11.0.6.tgz",
"integrity": "sha512-yWiPSurQvjLVD070zycQR4x5zW3f/kxPlqOMmZoUtVQvUgcM+kwpDQAba5sqtqtAurgUx0Ae9p9Xzgqwt2+ZBA==",
"requires": {}
"integrity": "sha512-yWiPSurQvjLVD070zycQR4x5zW3f/kxPlqOMmZoUtVQvUgcM+kwpDQAba5sqtqtAurgUx0Ae9p9Xzgqwt2+ZBA=="
},
"react-redux": {
"version": "7.2.2",
@@ -25181,6 +25026,14 @@
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
"integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg=="
},
"react-toastify": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-7.0.3.tgz",
"integrity": "sha512-cxZ5rfurC8LzcZQMTYc8RHIkQTs+BFur18Pzk6Loz6uS8OXUWm6nXVlH/wqglz4Z7UAE8xxcF5mRjfE13487uQ==",
"requires": {
"clsx": "^1.1.1"
}
},
"read-file-relative": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/read-file-relative/-/read-file-relative-1.2.0.tgz",
+1
View File
@@ -79,6 +79,7 @@
"react-jsonschema-form": "1.8.1",
"react-markdown": "5.0.3",
"react-mde": "11.0.6",
"react-toastify": "^7.0.3",
"shortid": "2.2.16",
"styled-components": "5.2.1",
"swr": "0.4.2"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 402 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 402 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 593 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 315 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 271 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 556 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 865 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 458 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 914 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 574 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 407 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 715 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 954 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 865 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

-7
View File
@@ -1,7 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3">
<g fill="#61DAFB">
<path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/>
<circle cx="420.9" cy="296.5" r="45.7"/>
<path d="M520.5 78.1z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 954 KiB

+14
View File
@@ -62,6 +62,20 @@ class FeedApi {
throw err;
}
}
static async deletePost(id: number) {
try {
const resp = await axios.delete(`${URL}${id}`, {
headers: {
Authorization: getAuthHeader(),
},
});
return resp.data;
} catch (err) {
console.error(err);
throw err;
}
}
}
export default FeedApi;
+14
View File
@@ -72,6 +72,20 @@ class JobAdApi {
throw err;
}
}
static async deleteJobAd(id: number) {
try {
const resp = await axios.delete(`${URL}${id}`, {
headers: {
Authorization: getAuthHeader(),
},
});
return resp.data;
} catch (err) {
console.error(err);
throw err;
}
}
}
export default JobAdApi;
-60
View File
@@ -1,60 +0,0 @@
import React from "react";
import styled from "styled-components";
import { Committee } from "@views/ContactsPage/ContactsPageView";
import { colors } from "@theme/colors";
import ContactCard from "./ContactCard";
const blank_profile = "/img/blank_profile.png";
interface CommitteeContainerProps {
committee: Committee;
}
const Container = styled.div`
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
color: ${colors.darkBlue};
& > p {
display: flex;
justify-content: center;
text-transform: uppercase;
letter-spacing: 3px;
line-height: 0.75;
font-weight: bold;
}
& > div {
display: flex;
flex-flow: row wrap;
justify-content: center;
}
`;
const CommitteeContainer: React.FC<CommitteeContainerProps> = ({ committee }) => (
<Container>
<p>
{committee.name_fi || committee.name_en}
</p>
<div>
{committee.roles.map((role) => (
role.representatives.map((representative) => (
<ContactCard
key={representative.name}
name={representative.name}
phone={representative.phone_number}
email={representative.email}
// conditional image for dev
image={!(committee.name_en === "Board") ? representative.image : blank_profile}
role_fi={role.name_fi}
role_en={role.name_en}
/>
))
))}
</div>
</Container>
);
export default CommitteeContainer;
+27 -24
View File
@@ -5,21 +5,22 @@ import { colors } from "@theme/colors";
const Card = styled.article`
display: flex;
align-items: flex-start;
flex-flow: row nowrap;
justify-content: space-between;
flex: 1 0 50%;
padding: 0.5rem;
color: ${colors.darkBlue};
width: 19rem;
`;
const Row = styled.div`
display: flex;
flex-flow: row nowrap;
`;
const ImageContainer = styled.div`
position: relative;
display: flex;
flex-shrink: 0;
justify-content: center;
align-items: center;
height: 5rem;
width: 5rem;
flex-shrink: 0;
img {
padding: 0.5rem !important;
@@ -39,7 +40,7 @@ const Info = styled.div`
margin: 0;
}
& > h1 {
& > h3 {
font-size: 0.9rem;
font-weight: 500;
}
@@ -58,22 +59,24 @@ const ContactCard: React.FC<ContactCardProps> = ({
name, phone, email, image, role_fi, role_en,
}) => (
<Card>
{image ? (
<ImageContainer>
<Image
src={image}
alt={name}
layout="fill"
objectFit="scale-down"
/>
</ImageContainer>
) : null}
<Info>
<h1>{name}</h1>
<p>{role_fi || role_en}</p>
{phone ? <p>{phone}</p> : null}
{email ? <p>{email}</p> : null}
</Info>
<Row>
{image ? (
<ImageContainer>
<Image
src={image}
alt={name}
layout="fill"
objectFit="scale-down"
/>
</ImageContainer>
) : null}
<Info>
<h3>{name}</h3>
<p>{role_fi || role_en}</p>
{phone ? <p>{phone}</p> : null}
{email ? <p>{email}</p> : null}
</Info>
</Row>
</Card>
);
+1 -1
View File
@@ -69,7 +69,7 @@ const CrossFadeImages: React.FC<CrossFadeImagesProps> = ({
$duration={len * SINGLE_IMAGE_TIME}
>
{ images.map((image, idx) => (
<div className={idx > 0 ? "not-first" : undefined}>
<div key={idx} className={idx > 0 ? "not-first" : undefined}>
<AnimatedImage
key={image}
src={image}
+3
View File
@@ -3,9 +3,11 @@ import React from "react";
import type { AppProps /* , AppContext' */ } from "next/app";
import Head from "next/head";
import styled, { createGlobalStyle } from "styled-components";
import { ToastContainer } from "react-toastify";
import { colors } from "@theme/colors";
import "react-mde/lib/styles/css/react-mde-all.css";
import "react-toastify/dist/ReactToastify.css";
const fontFamily = "'Montserrat', sans-serif";
const fontSize = 12; // 16px
@@ -141,6 +143,7 @@ const Web20App = ({ Component, pageProps }: AppProps) => (
<AppContainer>
<Component {...pageProps} />
</AppContainer>
<ToastContainer position="bottom-right" />
</>
);
+7 -6
View File
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react";
import { NextPage } from "next";
import { useRouter } from "next/router";
import { toast } from "react-toastify";
import AdminCreateCommon from "@views/admin/AdminCreateCommon";
import Tag from "@models/Tag";
import TagApi from "@api/tagApi";
@@ -66,6 +67,7 @@ const buildSchema = (formData: Event, signupForms: SignupForm[], tags: Tag[]) =>
enumNames: signupForms.map((form) => form.title_fi),
},
uniqueItems: true,
default: [],
},
image: {
type: ["string", "null"],
@@ -166,7 +168,6 @@ const EventCreatePage: NextPage = () => {
const [tags, setTags] = useState<Tag[]>([]);
const [signupForms, setSignupForms] = useState<SignupForm[]>([]);
const [error, setError] = useState<string>(null);
const [statusMessage, setStatusMessage] = useState<string>(null);
const router = useRouter();
@@ -212,7 +213,8 @@ const EventCreatePage: NextPage = () => {
// resp.signupForm = (resp.signupForm as any).map(inst => inst.id);
resp.tags = data.formData.tags;
resp.signupForm = data.formData.signupForm;
setStatusMessage("Event created successfully");
toast.success("Event created successfully 😎");
router.push("/admin/events");
setFormData(resp);
} else {
const resp = await EventApi.updateEvent(payload);
@@ -222,16 +224,17 @@ const EventCreatePage: NextPage = () => {
// resp.signupForm = (resp.signupForm as any).map(inst => inst.id);
resp.tags = data.formData.tags;
resp.signupForm = data.formData.signupForm;
setStatusMessage("Event updated successfully");
toast.success("Event updated successfully 😎");
router.push("/admin/events");
setFormData(resp);
}
} catch (err) {
toast.error("Uh oh! Something went wrong! Try again later. 😟");
setError(err);
}
};
const onChange = (data: any) => setFormData(data.formData);
const onFocus = () => setStatusMessage(null);
const title = formData?.id
? `Edit Event "${formData.title_fi}"`
: "Create Event";
@@ -243,9 +246,7 @@ const EventCreatePage: NextPage = () => {
schema={buildSchema(formData, signupForms, tags)}
UISchema={buildUISchema()}
onChange={onChange}
onFocus={onFocus}
onSubmit={onSubmit}
statusMessage={statusMessage}
error={error}
widgets={widgets}
/>
+30 -1
View File
@@ -1,14 +1,37 @@
import React from "react";
import { NextPage } from "next";
import { formatRelative } from "date-fns";
import { toast } from "react-toastify";
import styled from "styled-components";
import AdminListCommon from "@views/admin/AdminListCommon";
import { Link } from "@components/index";
import { Button, Link } from "@components/index";
import AddLink from "@components/AddLink";
import Event from "@models/Event";
import EventApi from "@api/eventApi";
import useFetchEvents from "@hooks/useFetchEvents";
const URL = "/admin/events";
const StyledButton = styled(Button) <{ $colorOverride: "red" }>`
background-color: ${(p) => p.$colorOverride};
border-radius: 8px;
color: white;
font-size: 13px;
font-weight: bold;
`;
const confirmDelete = async (event: Event) => {
if (window.confirm(`Delete: ${event.id}: ${event.title_fi}/${event.title_en}; Are you sure?`) === true) {
try {
await EventApi.deleteEvent(event.id);
toast.success("Event removed successfully 😎");
window.location.reload(); // TODO: Fetch/update event list, so user sees the signup in the list
} catch (err) {
toast.error("Uh oh! Something went wrong! Try again later. 😟");
}
}
};
const renderData = (events: Event[]) => {
if (!events || events.length === 0) {
return <div>No events.</div>;
@@ -29,12 +52,18 @@ const renderData = (events: Event[]) => {
<td><Link to={`${URL}/${event.id}`}>{event.title_fi}</Link></td>
<td>{formatRelative(new Date(event.start_time), new Date())}</td>
<td>{formatRelative(new Date(event.end_time), new Date())}</td>
<td>
<StyledButton $colorOverride="red" buttonStyle="filled" onClick={() => confirmDelete(event)}>
Delete
</StyledButton>
</td>
</tr>
))}
</tbody>
</table>
);
};
const AdminEventPage: NextPage = () => {
const { data } = useFetchEvents({ options: { auth: true } });
return (
+6 -6
View File
@@ -9,6 +9,7 @@ import FeedApi from "@api/feedApi";
import DatetimeWidget from "@components/Widgets/DatetimeWidget";
import SectionDividerWidget from "@components/Widgets/SectionDividerWidget";
import MarkdownEditorWidget from "@components/Widgets/MarkdownEditorWidget";
import { toast } from "react-toastify";
const widgets = {
datetime: DatetimeWidget,
@@ -133,7 +134,6 @@ const FeedCreatePage: NextPage = () => {
const [formData, setFormData] = useState<Post>(null);
const [tags, setTags] = useState<Tag[]>([]);
const [error, setError] = useState<string>(null);
const [statusMessage, setStatusMessage] = useState<string>(null);
const router = useRouter();
@@ -167,21 +167,23 @@ const FeedCreatePage: NextPage = () => {
if (payload.id === undefined) {
const resp = await FeedApi.createPost(payload);
// resp.tags = resp.tags;
setStatusMessage("Post created successfully");
toast.success("Post created successfully 😎");
router.push("/admin/feed");
setFormData(resp);
} else {
const resp = await FeedApi.updatePost(payload);
// resp.tags = resp.tag_id;
setStatusMessage("Post updated successfully");
toast.success("Post updated successfully 😎");
router.push("/admin/feed");
setFormData(resp);
}
} catch (err) {
toast.error("Uh oh! Something went wrong! Try again later. 😟");
setError(err);
}
};
const onChange = (data) => setFormData(data.formData);
const onFocus = () => setStatusMessage(null);
const title = formData?.id
? `Edit Post "${formData.title_fi}"`
@@ -194,9 +196,7 @@ const FeedCreatePage: NextPage = () => {
schema={buildSchema(formData, tags)}
UISchema={buildUISchema(formData)}
onChange={onChange}
onFocus={onFocus}
onSubmit={onSubmit}
statusMessage={statusMessage}
error={error}
widgets={widgets}
/>
+29 -1
View File
@@ -1,14 +1,37 @@
import React from "react";
import { NextPage } from "next";
import { formatRelative } from "date-fns";
import { toast } from "react-toastify";
import styled from "styled-components";
import AdminListCommon from "@views/admin/AdminListCommon";
import { Link } from "@components/index";
import { Button, Link } from "@components/index";
import AddLink from "@components/AddLink";
import Post from "@models/Feed";
import PostApi from "@api/feedApi";
import useFetchFeed from "@hooks/useFetchFeed";
const URL = "/admin/feed";
const StyledButton = styled(Button) <{ $colorOverride: "red" }>`
background-color: ${(p) => p.$colorOverride};
border-radius: 8px;
color: white;
font-size: 13px;
font-weight: bold;
`;
const confirmDelete = async (post: Post) => {
if (window.confirm(`Delete: ${post.id}: ${post.title_fi}/${post.title_en}; Are you sure?`) === true) {
try {
await PostApi.deletePost(post.id);
toast.success("Post removed successfully 😎");
window.location.reload(); // TODO: Fetch/update post list, so user sees the signup in the list
} catch (err) {
toast.error("Uh oh! Something went wrong! Try again later. 😟");
}
}
};
const renderData = (feed: Post[]) => {
if (!feed || feed.length === 0) {
return <div>No posts.</div>;
@@ -29,6 +52,11 @@ const renderData = (feed: Post[]) => {
<td><Link to={`${URL}/${post.id}`}>{post.title_fi}</Link></td>
<td>{post.description_fi}</td>
<td>{formatRelative(new Date(post.publish_time), new Date())}</td>
<td>
<StyledButton $colorOverride="red" buttonStyle="filled" onClick={() => confirmDelete(post)}>
Delete
</StyledButton>
</td>
</tr>
))}
</tbody>
+6 -6
View File
@@ -7,6 +7,7 @@ import JobAdApi from "@api/jobAdApi";
import DatetimeWidget from "@components/Widgets/DatetimeWidget";
import SectionDividerWidget from "@components/Widgets/SectionDividerWidget";
import MarkdownEditorWidget from "@components/Widgets/MarkdownEditorWidget";
import { toast } from "react-toastify";
const widgets = {
datetime: DatetimeWidget,
@@ -108,7 +109,6 @@ const buildUISchema = (formData: JobAd) => ({
const JobAdCreatePage: NextPage = () => {
const [formData, setFormData] = useState<JobAd>(null);
const [error, setError] = useState<string>(null);
const [statusMessage, setStatusMessage] = useState<string>(null);
const router = useRouter();
@@ -132,20 +132,22 @@ const JobAdCreatePage: NextPage = () => {
const payload = data.formData;
if (payload.id === undefined) {
const resp = await JobAdApi.createJobAd(payload);
setStatusMessage("Post created successfully");
toast.success("Job ad created successfully 😎");
router.push("/admin/jobads");
setFormData(resp);
} else {
const resp = await JobAdApi.updateJobAd(payload);
setStatusMessage("Post updated successfully");
toast.success("Job ad updated successfully 😎");
router.push("/admin/jobads");
setFormData(resp);
}
} catch (err) {
toast.error("Uh oh! Something went wrong! Try again later. 😟");
setError(err);
}
};
const onChange = (data) => setFormData(data.formData);
const onFocus = () => setStatusMessage(null);
const title = formData?.id
? `Edit Ad "${formData.title_fi}"`
@@ -158,9 +160,7 @@ const JobAdCreatePage: NextPage = () => {
schema={buildSchema(formData)}
UISchema={buildUISchema(formData)}
onChange={onChange}
onFocus={onFocus}
onSubmit={onSubmit}
statusMessage={statusMessage}
error={error}
widgets={widgets}
/>
+29 -1
View File
@@ -1,14 +1,37 @@
import React from "react";
import { NextPage } from "next";
import { formatRelative } from "date-fns";
import { toast } from "react-toastify";
import styled from "styled-components";
import AdminListCommon from "@views/admin/AdminListCommon";
import { Link } from "@components/index";
import { Button, Link } from "@components/index";
import AddLink from "@components/AddLink";
import JobAd from "@models/JobAd";
import useFetchJobAds from "@hooks/useFetchJobAds";
import JobAdApi from "@api/jobAdApi";
const URL = "/admin/jobads";
const StyledButton = styled(Button) <{ $colorOverride: "red" }>`
background-color: ${(p) => p.$colorOverride};
border-radius: 8px;
color: white;
font-size: 13px;
font-weight: bold;
`;
const confirmDelete = async (jobad: JobAd) => {
if (window.confirm(`Delete: ${jobad.id}: ${jobad.title_fi}/${jobad.title_en}; Are you sure?`) === true) {
try {
await JobAdApi.deleteJobAd(jobad.id);
toast.success("Job ad removed successfully 😎");
window.location.reload(); // TODO: Fetch/update event list, so user sees the signup in the list
} catch (err) {
toast.error("Uh oh! Something went wrong! Try again later. 😟");
}
}
};
const renderData = (jobAds: JobAd[]) => {
if (!jobAds || jobAds.length === 0) {
return <div>No advertisements.</div>;
@@ -33,6 +56,11 @@ const renderData = (jobAds: JobAd[]) => {
? formatRelative(new Date(ad.autohide_at), new Date())
: "Disabled"}
</td>
<td>
<StyledButton $colorOverride="red" buttonStyle="filled" onClick={() => confirmDelete(ad)}>
Delete
</StyledButton>
</td>
</tr>
))}
</tbody>
+6 -6
View File
@@ -8,6 +8,7 @@ import DatetimeWidget from "@components/Widgets/DatetimeWidget";
import SignupQuestionsWidget from "@components/Widgets/SignupQuestionsWidget/SignupQuestionsWidget";
import MarkdownEditorWidget from "@components/Widgets/MarkdownEditorWidget";
import { buildValidationSchema } from "@views/SignUpPage/FormUtils";
import { toast } from "react-toastify";
const DEFAULT_EMAIL = `Moikka,
@@ -98,7 +99,6 @@ const buildUISchema = () => {
const SignupCreatePage: NextPage = () => {
const [formData, setFormData] = useState<SignupForm>(null);
const [error, setError] = useState<string>(null);
const [statusMessage, setStatusMessage] = useState<string>(null);
const router = useRouter();
@@ -133,26 +133,28 @@ const SignupCreatePage: NextPage = () => {
if (payload.id === undefined) {
const resp = await SignupApi.createForm(payload);
setStatusMessage("Sign-up created successfully");
toast.success("Sign-up created successfully 😎");
router.push("/admin/signups");
setFormData({
...resp,
questions: JSON.stringify(resp.questions) as any,
});
} else {
const resp = await SignupApi.updateForm(payload);
setStatusMessage("Sign-up updated successfully");
toast.success("Sign-up updated successfully 😎");
router.push("/admin/signups");
setFormData({
...resp,
questions: JSON.stringify(resp.questions) as any,
});
}
} catch (err) {
toast.error("Uh oh! Something went wrong! Try again later. 😟");
setError(err);
}
};
const onChange = (data) => setFormData(data.formData);
const onFocus = () => setStatusMessage(null);
const title = formData?.id
? `Edit Sign-up Form "${formData.title_fi}"`
@@ -166,9 +168,7 @@ const SignupCreatePage: NextPage = () => {
schema={buildSchema(formData)}
UISchema={buildUISchema()}
onChange={onChange}
onFocus={onFocus}
onSubmit={onSubmit}
statusMessage={statusMessage}
error={error}
widgets={widgets}
/>
+3 -9
View File
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react";
import { NextPage } from "next";
import { useRouter } from "next/router";
import { toast } from "react-toastify";
import AdminCreateCommon from "@views/admin/AdminCreateCommon";
import MarkdownEditorWidget from "@components/Widgets/MarkdownEditorWidget";
import { SignupForm } from "@models/Signup";
@@ -63,33 +64,26 @@ const SignupEmailPage: NextPage = () => {
const signupForm = useInitializeData(id as string);
const [error, setError] = useState<string>(null);
const [statusMessage, setStatusMessage] = useState<string>(null);
const onSubmit = async (data) => {
try {
const payload = data.formData;
await SignupApi.signupFormSendEmail(payload, Number(id));
setStatusMessage("Email sent successfully");
toast.success("Email sent successfully 😎");
} catch (err) {
setError(err);
toast.error("Uh oh! Something went wrong! Try again later. 😟");
}
};
// const onChange = (data) => setFormData(data.formData);
const onFocus = () => setStatusMessage(null);
const title = signupForm ? signupForm.title_fi : "Loading...";
return (
<AdminCreateCommon
title={title}
// formData={formData}
schema={buildSchema(title)}
UISchema={buildUISchema()}
// onChange={onChange}
onFocus={onFocus}
onSubmit={onSubmit}
statusMessage={statusMessage}
error={error}
widgets={widgets}
/>
+7 -1
View File
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react";
import { NextPage } from "next";
import { useRouter } from "next/router";
import { toast } from "react-toastify";
import styled from "styled-components";
import { CSVLink } from "react-csv";
import AdminListCommon from "@views/admin/AdminListCommon";
@@ -11,6 +12,10 @@ import noop from "@utils/noop";
const StyledButton = styled(Button) <{ $colorOverride: "red" | "green" }>`
background-color: ${(p) => p.$colorOverride};
border-radius: 8px;
color: white;
font-size: 13px;
font-weight: bold;
`;
const SignupEmailPage: NextPage = () => {
@@ -33,8 +38,9 @@ const SignupEmailPage: NextPage = () => {
try {
await SignupApi.deleteSignup(signup.id);
setSignups(signups.filter((s) => s.id !== signup.id));
toast.success("Signup removed successfully 😎");
} catch (err) {
window.alert("Delete failed!");
toast.error("Uh oh! Something went wrong! Try again later. 😟");
}
}
};
+28 -1
View File
@@ -1,14 +1,36 @@
import React, { useEffect, useState } from "react";
import { NextPage } from "next";
import { formatRelative } from "date-fns";
import { toast } from "react-toastify";
import styled from "styled-components";
import AdminListCommon from "@views/admin/AdminListCommon";
import { Link } from "@components/index";
import { Button, Link } from "@components/index";
import AddLink from "@components/AddLink";
import { SignupForm } from "@models/Signup";
import SignupApi from "@api/signupApi";
const URL = "/admin/signups";
const StyledButton = styled(Button) <{ $colorOverride: "red" }>`
background-color: ${(p) => p.$colorOverride};
border-radius: 8px;
color: white;
font-size: 13px;
font-weight: bold;
`;
const confirmDelete = async (signup: SignupForm) => {
if (window.confirm(`Delete: ${signup.id}: ${signup.title_fi}/${signup.title_en}; Are you sure?`) === true) {
try {
await SignupApi.deleteForm(signup.id);
toast.success("Signup removed successfully 😎");
window.location.reload(); // TODO: Fetch/update event list, so user sees the signup in the list
} catch (err) {
toast.error("Uh oh! Something went wrong! Try again later. 😟");
}
}
};
const renderData = (signupForms: SignupForm[]) => {
if (!signupForms || signupForms.length === 0) {
return <div>No signup forms.</div>;
@@ -33,6 +55,11 @@ const renderData = (signupForms: SignupForm[]) => {
<td>{formatRelative(new Date(signupForm.end_time), new Date())}</td>
<td><Link to={`${URL}/${signupForm.id}/list`}>View</Link></td>
<td><Link to={`${URL}/${signupForm.id}/email`}>Send</Link></td>
<td>
<StyledButton $colorOverride="red" buttonStyle="filled" onClick={() => confirmDelete(signupForm)}>
Delete
</StyledButton>
</td>
</tr>
))}
</tbody>
+16 -2
View File
@@ -8,6 +8,7 @@ import useFetchEvents from "@hooks/useFetchEvents";
import EventPageView from "@views/EventPage/EventPageView";
import PageWrapper from "@views/common/PageWrapper";
import LoadingView from "@views/common/LoadingView";
import NotFoundPage from "@pages/404";
interface InitialProps {
initialEvent: Event;
@@ -20,7 +21,13 @@ const EventPage: NextPage<InitialProps> = ({ initialEvent }) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { data, error } = useFetchEvents({ initialData: initialEvent, id: id as string });
if (!data || router.isFallback) return <LoadingView />;
if (router.isFallback) return <LoadingView />;
if (!data) {
return (
<NotFoundPage />
);
}
return (
<>
@@ -50,12 +57,19 @@ export const getStaticPaths: GetStaticPaths = async () => {
export const getStaticProps: GetStaticProps<InitialProps> = async ({ params }) => {
const { id } = params;
const initialEvent = await EventApi.getEvent(Number(id));
let notFound = false;
let initialEvent: Event;
try {
initialEvent = await EventApi.getEvent(Number(id));
} catch (err) {
notFound = true;
}
return {
props: {
initialEvent,
},
revalidate: 10,
notFound,
};
};
+17 -2
View File
@@ -8,6 +8,7 @@ import useFetchFeed from "@hooks/useFetchFeed";
import FeedPageView from "@views/FeedPage/FeedPageView";
import PageWrapper from "@views/common/PageWrapper";
import LoadingView from "@views/common/LoadingView";
import NotFoundPage from "@pages/404";
interface InitialProps {
initialPost: Post;
@@ -20,7 +21,13 @@ const FeedPage: NextPage<InitialProps> = ({ initialPost }) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { data, error } = useFetchFeed({ initialData: initialPost, id: id as string });
if (!data || router.isFallback) return <LoadingView />;
if (router.isFallback) return <LoadingView />;
if (!data) {
return (
<NotFoundPage />
);
}
return (
<>
@@ -50,12 +57,20 @@ export const getStaticPaths: GetStaticPaths = async () => {
export const getStaticProps: GetStaticProps<InitialProps> = async ({ params }) => {
const { id } = params;
const initialPost = await FeedApi.getPost(Number(id));
let notFound = false;
let initialPost: Post;
try {
initialPost = await FeedApi.getPost(Number(id));
} catch (err) {
notFound = true;
}
return {
props: {
initialPost,
},
revalidate: 10,
notFound,
};
};
+20 -7
View File
@@ -1,13 +1,15 @@
import React, { useState } from "react";
import React from "react";
import { NextPage, GetStaticProps, GetStaticPaths } from "next";
import Head from "next/head";
import { useRouter } from "next/router";
import { toast } from "react-toastify";
import { Signup, SignupForm } from "@models/Signup";
import SignupApi from "@api/signupApi";
import SignUpPageView from "@views/SignUpPage/SignUpPageView";
import PageWrapper from "@views/common/PageWrapper";
import LoadingView from "@views/common/LoadingView";
import noop from "@utils/noop";
import NotFoundPage from "@pages/404";
type InitialProps = {
form: SignupForm;
@@ -15,12 +17,17 @@ type InitialProps = {
const SignUpPage: NextPage<InitialProps> = ({ form }) => {
const router = useRouter();
const [statusMessage, setStatus] = useState(null);
if (router.isFallback) {
return <LoadingView />;
}
if (!form) {
return (
<NotFoundPage />
);
}
const onSubmit = async (data) => {
const payload: Signup = {
signupForm_id: form.id,
@@ -29,11 +36,11 @@ const SignUpPage: NextPage<InitialProps> = ({ form }) => {
try {
await SignupApi.createSignup(payload);
// TODO: Fetch/update signup list, so user sees the signup in the list
setStatus("Sign-up submitted successfully");
toast.success("Sign-up submitted successfully 😎");
router.push(window.location.href); // TODO: Fetch/update signup list, so user sees the signup in the list
} catch (error) {
console.error(error);
setStatus("Bad request");
toast.error("Uh oh! Sign-up failed! 😟");
}
};
@@ -46,7 +53,6 @@ const SignUpPage: NextPage<InitialProps> = ({ form }) => {
<SignUpPageView
signUpForm={form}
formData={{}}
statusMessage={statusMessage}
onChange={noop}
onSubmit={onSubmit}
/>
@@ -71,12 +77,19 @@ export const getStaticPaths: GetStaticPaths = async () => {
export const getStaticProps: GetStaticProps<InitialProps> = async ({ params }) => {
const { id } = params;
const form = await SignupApi.getForm(Number(id));
let notFound = false;
let form: SignupForm;
try {
form = await SignupApi.getForm(Number(id));
} catch {
notFound = true;
}
return {
props: {
form,
},
revalidate: 10,
notFound,
};
};
+3 -4
View File
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react";
import { NextPage } from "next";
import { useRouter } from "next/router";
import { toast } from "react-toastify";
import { Signup, SignupForm } from "@models/Signup";
import SignupApi from "@api/signupApi";
import SignUpPageView from "@views/SignUpPage/SignUpPageView";
@@ -48,7 +49,6 @@ const useFetchSignup = (signupId: number, uuid: string) => {
const EditSignUpPage: NextPage = () => {
const router = useRouter();
const { signupId, uuid } = parseQueryParams(router.query);
const [statusMessage, setStatus] = useState(null);
const [form, formData] = useFetchSignup(signupId, uuid);
const onSubmit = async (data) => {
@@ -61,10 +61,10 @@ const EditSignUpPage: NextPage = () => {
try {
await SignupApi.updateSignup(payload, uuid);
// TODO: Update signup list, so user sees possible changes in the list
setStatus("Sign-up submission updated successfully");
toast.success("Sign-up updated successfully 😎");
} catch (error) {
console.error(error);
setStatus("Bad request");
toast.error("Uh oh! Updating sign-up failed! 😟");
}
};
@@ -73,7 +73,6 @@ const EditSignUpPage: NextPage = () => {
<SignUpPageView
signUpForm={form}
formData={formData}
statusMessage={statusMessage}
onChange={noop}
onSubmit={onSubmit}
/>
+2 -3
View File
@@ -49,7 +49,6 @@ const ActualPageHero: React.FC = () => (
linkText="Yritysyhteistyö&nbsp;"
/>
<HeroAsideItem
// TODO: Too long
header="Uusia suhteita ulkopaikkakuntalaisten kanssa"
link="#ulkosuhteet"
linkText="Ulkoiset suhteet&nbsp;"
@@ -61,12 +60,12 @@ const ActualPageHero: React.FC = () => (
>
<HeroSecondarySectionItem note="Ma">
<span>
Killan hallitus päivystää kiltahuoneella <strong>maanantaisin klo 12.1513.15.</strong> Tuolloin voit ostaa kiltatuotteita, kuten esim. haalarimerkkejä tai laulukirjoja.
Killan hallitus päivystää kiltahuoneella <strong>maanantaisin.</strong> Tuolloin voit ostaa kiltatuotteita, kuten esim. haalarimerkkejä tai laulukirjoja.
</span>
</HeroSecondarySectionItem>
<HeroSecondarySectionItem note="To">
<span>
Kiltapäiväkerho Kiltis kokoontuu <strong>torstaisin klo XX.XX kiltahuoneella.</strong> Lorem ipsum dolor sit amet. Lämpimästi tervetuloa kaikki SIKkiläiset ja SIK-mieliset!
Kiltapäiväkerho Kiltis kokoontuu <strong>torstaisin kiltahuoneella.</strong>. Lämpimästi tervetuloa kaikki SIKkiläiset ja SIK-mieliset!
</span>
</HeroSecondarySectionItem>
</HeroSecondarySection>
+12 -12
View File
@@ -55,10 +55,10 @@ const ActualPageView: React.FC<ActualPageViewProps> = ({ events, feed }) => (
presentationTime={5}
fadeTime={1}
images={[
"/img/carousel_images/elecyykka-jani-mannonen-6.jpg",
"/img/carousel_images/koydenveto-jani-mannonen-miika-koskela-17.jpg",
"/img/carousel_images/koydenveto-jani-mannonen-miika-koskela-28.jpg",
"/img/carousel_images/koydenveto-jani-mannonen-miika-koskela-78.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/elecyykka-jani-mannonen-6.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/koydenveto-jani-mannonen-miika-koskela-17.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/koydenveto-jani-mannonen-miika-koskela-28.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/koydenveto-jani-mannonen-miika-koskela-78.jpg",
]}
width={400}
height={400}
@@ -67,10 +67,10 @@ const ActualPageView: React.FC<ActualPageViewProps> = ({ events, feed }) => (
presentationTime={5}
fadeTime={1}
images={[
"/img/carousel_images/koydenveto-mikko-haapamaki-33.jpg",
"/img/carousel_images/Varaslahto2020-AinoSuomi-73.jpg",
"/img/carousel_images/varauksenpurku_2020_timitiira-80.jpg",
"/img/carousel_images/otatarhan-ajot-timi-tiira-172.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/koydenveto-mikko-haapamaki-33.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/Varaslahto2020-AinoSuomi-73.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/varauksenpurku_2020_timitiira-80.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/otatarhan-ajot-timi-tiira-172.jpg",
]}
width={400}
height={400}
@@ -79,10 +79,10 @@ const ActualPageView: React.FC<ActualPageViewProps> = ({ events, feed }) => (
presentationTime={5}
fadeTime={1}
images={[
"/img/carousel_images/kokkarit_kiia_einola-0631.jpg",
"/img/carousel_images/pota-jatkot-essi-jukkala-29.jpg",
"/img/carousel_images/pota99-paajuhla-oskari-lahti-171.jpg",
"/img/carousel_images/wappusitsit-jani-mannonen-29.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/kokkarit_kiia_einola-0631.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/pota-jatkot-essi-jukkala-29.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/pota99-paajuhla-oskari-lahti-171.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/wappusitsit-jani-mannonen-29.jpg",
]}
width={400}
height={400}
+58 -34
View File
@@ -1,8 +1,8 @@
import React from "react";
import styled from "styled-components";
import CommitteeContainer from "@components/CommitteeContainer";
import { Divider, TextSection, Link } from "@components/index";
import { colors } from "@theme/colors";
import ContactCard from "@components/ContactCard";
import BoardJson from "./board.json";
import HvtmkJson from "./hvtmk.json";
@@ -15,6 +15,8 @@ import TtmkJson from "./ttmk.json";
import UtmkJson from "./utmk.json";
import YtmkJson from "./ytmk.json";
const blank_profile = "/img/blank_profile.png";
const BlueLink = styled(Link)`
color: ${colors.blue1};
@@ -23,19 +25,59 @@ const BlueLink = styled(Link)`
}
`;
export interface Committee {
const Container = styled.div`
color: ${colors.darkBlue};
& > h2 {
text-transform: uppercase;
width: 100%;
}
& > div {
display: flex;
flex-flow: row wrap;
}
`;
const CommitteeContainer: React.FC<{
committee: Committee;
}> = ({ committee, children }) => (
<Container>
<h2>
{committee.name_fi || committee.name_en}
</h2>
<div>
{committee.roles.map((role) => (
role.representatives.map((representative) => (
<ContactCard
key={representative.name}
name={representative.name}
phone={representative.phone_number}
email={representative.email}
image={(committee.name_en === "Board") ? (representative.image || blank_profile) : null}
role_fi={role.name_fi}
role_en={role.name_en}
/>
))
))}
</div>
{children}
</Container>
);
interface Committee {
name_fi: string;
name_en: string;
roles: Array<Role>;
}
export interface Role {
interface Role {
name_fi: string;
name_en: string;
representatives: Array<Representative>
}
export interface Representative {
interface Representative {
name: string;
phone_number?: string;
email?: string;
@@ -45,6 +87,7 @@ export interface Representative {
const ContactsPageView: React.FC = () => (
<>
<TextSection>
<h1>Yhteystiedot</h1>
<p>
Asiaa olisi, mutta kehen ottaa yhteyttä?<br />
Tämä sivu yrittää valottaa sen oikean ihmisen puhelinnumeroa ja sähköpostiosoitetta.
@@ -52,87 +95,68 @@ const ContactsPageView: React.FC = () => (
</TextSection>
<TextSection>
<div>
<CommitteeContainer committee={BoardJson} />
<CommitteeContainer committee={BoardJson}>
<p>
{"Hallitukseen saa yhteyden lähettämällä sähköpostia "}
<BlueLink to="mailto:hallitus@sahkoinsinoorikilta.fi">
hallitus@sahkoinsinoorikilta.fi
</BlueLink>
</p>
</div>
</CommitteeContainer>
</TextSection>
<Divider />
<TextSection>
<div>
<CommitteeContainer committee={HvtmkJson} />
</div>
<CommitteeContainer committee={HvtmkJson} />
</TextSection>
<Divider />
<TextSection>
<div>
<CommitteeContainer committee={MtmkJson} />
</div>
<CommitteeContainer committee={MtmkJson} />
</TextSection>
<Divider />
<TextSection>
<div>
<CommitteeContainer committee={OptmkJson} />
</div>
<CommitteeContainer committee={OptmkJson} />
</TextSection>
<Divider />
<TextSection>
<div>
<CommitteeContainer committee={OtmkJson} />
</div>
<CommitteeContainer committee={OtmkJson} />
</TextSection>
<Divider />
<TextSection id="eptmk">
<div>
<CommitteeContainer committee={PtmkJson} />
</div>
<CommitteeContainer committee={PtmkJson} />
</TextSection>
<Divider />
<TextSection>
<div>
<CommitteeContainer committee={SstmkJson} />
</div>
<CommitteeContainer committee={SstmkJson} />
</TextSection>
<Divider />
<TextSection id="ttmk">
<div>
<CommitteeContainer committee={TtmkJson} />
</div>
<CommitteeContainer committee={TtmkJson} />
</TextSection>
<Divider />
<TextSection>
<div>
<CommitteeContainer committee={UtmkJson} />
</div>
<CommitteeContainer committee={UtmkJson} />
</TextSection>
<Divider />
<TextSection>
<div>
<CommitteeContainer committee={YtmkJson} />
</div>
<CommitteeContainer committee={YtmkJson} />
</TextSection>
<Divider />
+14 -13
View File
@@ -7,7 +7,8 @@
"name_en": "Chairman of the Board",
"representatives": [
{
"name": "Johannes Ora"
"name": "Johannes Ora",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/chairman.jpg"
}
]
},
@@ -19,7 +20,7 @@
"name": "Salla Lyytikäinen",
"phone_number": null,
"email": null,
"image": null
"image": "https://static.sahkoinsinoorikilta.fi/img/board/secretary.jpg"
}
]
},
@@ -31,7 +32,7 @@
"name": "Santeri Huhtala",
"phone_number": null,
"email": null,
"image": null
"image": "https://static.sahkoinsinoorikilta.fi/img/board/treasurer.jpg"
}
]
},
@@ -43,7 +44,7 @@
"name": "Toni Ojala",
"phone_number": null,
"email": null,
"image": null
"image": "https://static.sahkoinsinoorikilta.fi/img/board/captain1.jpg"
}
]
},
@@ -55,7 +56,7 @@
"name": "Toni Lyttinen",
"phone_number": null,
"email": null,
"image": null
"image": "https://static.sahkoinsinoorikilta.fi/img/board/captain2.jpg"
}
]
},
@@ -67,7 +68,7 @@
"name": "Eveliina Ahonen",
"phone_number": null,
"email": null,
"image": null
"image": "https://static.sahkoinsinoorikilta.fi/img/board/ceremonies.jpg"
}
]
},
@@ -79,7 +80,7 @@
"name": "Melisa Dönmez",
"phone_number": null,
"email": null,
"image": null
"image": "https://static.sahkoinsinoorikilta.fi/img/board/court_cancelor.jpg"
}
]
},
@@ -91,7 +92,7 @@
"name": "Heidi Mäkitalo",
"phone_number": null,
"email": null,
"image": null
"image": "https://static.sahkoinsinoorikilta.fi/img/board/isocoordinator.jpg"
}
]
},
@@ -103,7 +104,7 @@
"name": "Sauli Norja",
"phone_number": null,
"email": null,
"image": null
"image": "https://static.sahkoinsinoorikilta.fi/img/board/wellbeing.jpg"
}
]
},
@@ -115,7 +116,7 @@
"name": "Simo Hakanummi",
"phone_number": null,
"email": null,
"image": null
"image": "https://static.sahkoinsinoorikilta.fi/img/board/studies.jpg"
}
]
},
@@ -127,7 +128,7 @@
"name": "Oskari Ponkala",
"phone_number": null,
"email": null,
"image": null
"image": "https://static.sahkoinsinoorikilta.fi/img/board/technology.jpg"
}
]
},
@@ -139,7 +140,7 @@
"name": "Oliver Hiekkamies",
"phone_number": null,
"email": null,
"image": null
"image": "https://static.sahkoinsinoorikilta.fi/img/board/external.jpg"
}
]
},
@@ -151,7 +152,7 @@
"name": "Otto Julkunen",
"phone_number": null,
"email": null,
"image": null
"image": "https://static.sahkoinsinoorikilta.fi/img/board/corporate.jpg"
}
]
}
+25 -3
View File
@@ -15,7 +15,6 @@ interface EventPageViewProps {
}
const StyledTextSection = styled(TextSection)`
margin: auto;
align-items: center;
& > h1 {
@@ -24,6 +23,17 @@ const StyledTextSection = styled(TextSection)`
color: ${colors.orange1};
}
}
& > div {
margin: auto;
& > p {
font-size: 0.9rem;
font-weight: bold;
line-height: 0.4rem;
}
}
`;
const SignupButtons = styled.div`
@@ -38,6 +48,8 @@ const Content = styled(MarkdownStyles)`
const EventPageView: React.FC<EventPageViewProps> = ({ event }) => {
if (!event) return <LoadingView />;
const date_start = new Date(event.start_time).toLocaleString("fi-FI");
const date_end = new Date(event.end_time).toLocaleString("fi-FI");
return (
<StyledTextSection>
<h1>
@@ -48,13 +60,23 @@ const EventPageView: React.FC<EventPageViewProps> = ({ event }) => {
<Image
src={event.image || event.tags[0].icon}
alt={event.title_fi}
objectFit="scale-down"
layout="responsive"
width={0}
height={0}
width={16}
height={9}
/>
</h1>
<div>
<Content source={event.content_fi} escapeHtml={false} />
<p>
Paikka: {event.location_fi}
</p>
<p>
<time>Alkaa: {date_start}</time>
</p>
<p>
<time>Päättyy: {date_end}</time>
</p>
{/* We may have multiple signup forms. Generate own Button for each one */}
<SignupButtons>
{event.signupForm.map((sf) => (
+8 -8
View File
@@ -18,14 +18,14 @@ import noop from "@utils/noop";
import FrontPageHero from "./FrontPageHero";
// Corporate logos import
const ABB = "/img/corporate_logos/abb.png";
const Caruna = "/img/corporate_logos/caruna.jpg";
const Eaton = "/img/corporate_logos/eaton.png";
const Ensto = "/img/corporate_logos/ensto.jpg";
const eSett = "/img/corporate_logos/esett.png";
const Fingrid = "/img/corporate_logos/fingrid.jpg";
const NRCGroup = "/img/corporate_logos/nrcgroup.png";
const Okmetic = "/img/corporate_logos/okmetic.png";
const ABB = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/abb.jpg";
const Caruna = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/caruna.jpg";
const Eaton = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/eaton.jpg";
const Ensto = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/ensto.jpg";
const eSett = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/esett.jpg";
const Fingrid = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/fingrid.jpg";
const NRCGroup = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/nrcgroup.jpg";
const Okmetic = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/okmetic.jpg";
interface FrontPageViewProps {
events: Event[];
+18 -25
View File
@@ -80,13 +80,10 @@ const InEnglishPageView: React.FC<InEnglishPageViewProps> = ({ events, feed }) =
presentationTime={5}
fadeTime={1}
images={[
"/img/carousel_images/in_english/ulkoexcursio1-kiia-einola-3.jpg",
"/img/carousel_images/in_english/international-sitsit-jani-mannonen-8.jpg",
"/img/carousel_images/in_english/ulkoexcursio-kiia-einola-16.jpg",
"/img/carousel_images/in_english/haalarigaala-jani-mannonen-1.jpg",
"/img/carousel_images/in_english/Kaukkarit-2020-Elias-Hirvonen-44.jpg",
"/img/carousel_images/in_english/koydenveto-jani-mannonen-miika-koskela-4.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/elecyykka-jani-mannonen-6.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/koydenveto-jani-mannonen-miika-koskela-17.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/koydenveto-jani-mannonen-miika-koskela-28.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/koydenveto-jani-mannonen-miika-koskela-78.jpg",
]}
width={400}
height={400}
@@ -95,12 +92,10 @@ const InEnglishPageView: React.FC<InEnglishPageViewProps> = ({ events, feed }) =
presentationTime={5}
fadeTime={1}
images={[
"/img/carousel_images/in_english/international-sitsit-jani-mannonen-8.jpg",
"/img/carousel_images/in_english/Kaukkarit-2020-Elias-Hirvonen-44.jpg",
"/img/carousel_images/in_english/koydenveto-jani-mannonen-miika-koskela-4.jpg",
"/img/carousel_images/in_english/ulkoexcursio-kiia-einola-16.jpg",
"/img/carousel_images/in_english/haalarigaala-jani-mannonen-1.jpg",
"/img/carousel_images/in_english/ulkoexcursio1-kiia-einola-3.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/koydenveto-mikko-haapamaki-33.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/Varaslahto2020-AinoSuomi-73.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/varauksenpurku_2020_timitiira-80.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/otatarhan-ajot-timi-tiira-172.jpg",
]}
width={400}
height={400}
@@ -109,12 +104,10 @@ const InEnglishPageView: React.FC<InEnglishPageViewProps> = ({ events, feed }) =
presentationTime={5}
fadeTime={1}
images={[
"/img/carousel_images/in_english/haalarigaala-jani-mannonen-1.jpg",
"/img/carousel_images/in_english/ulkoexcursio1-kiia-einola-3.jpg",
"/img/carousel_images/in_english/international-sitsit-jani-mannonen-8.jpg",
"/img/carousel_images/in_english/Kaukkarit-2020-Elias-Hirvonen-44.jpg",
"/img/carousel_images/in_english/koydenveto-jani-mannonen-miika-koskela-4.jpg",
"/img/carousel_images/in_english/ulkoexcursio-kiia-einola-16.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/kokkarit_kiia_einola-0631.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/pota-jatkot-essi-jukkala-29.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/pota99-paajuhla-oskari-lahti-171.jpg",
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/wappusitsit-jani-mannonen-29.jpg",
]}
width={400}
height={400}
@@ -145,8 +138,8 @@ const InEnglishPageView: React.FC<InEnglishPageViewProps> = ({ events, feed }) =
presentationTime={5}
fadeTime={1}
images={[
"/img/carousel_images/in_english/tour/qtour1.jpg",
"/img/carousel_images/in_english/tour/qtour2.jpg",
"https://static.sahkoinsinoorikilta.fi/img/tour/qtour1.jpg",
"https://static.sahkoinsinoorikilta.fi/img/tour/qtour2.jpg",
]}
width={400}
height={400}
@@ -155,8 +148,8 @@ const InEnglishPageView: React.FC<InEnglishPageViewProps> = ({ events, feed }) =
presentationTime={5}
fadeTime={1}
images={[
"/img/carousel_images/in_english/tour/qtour3.jpg",
"/img/carousel_images/in_english/tour/qtour4.jpg",
"https://static.sahkoinsinoorikilta.fi/img/tour/qtour3.jpg",
"https://static.sahkoinsinoorikilta.fi/img/tour/qtour4.jpg",
]}
width={400}
height={400}
@@ -165,8 +158,8 @@ const InEnglishPageView: React.FC<InEnglishPageViewProps> = ({ events, feed }) =
presentationTime={5}
fadeTime={1}
images={[
"/img/carousel_images/in_english/tour/qtour5.jpg",
"/img/carousel_images/in_english/tour/qtour1.jpg",
"https://static.sahkoinsinoorikilta.fi/img/tour/qtour5.jpg",
"https://static.sahkoinsinoorikilta.fi/img/tour/qtour1.jpg",
]}
width={400}
height={400}
+40 -24
View File
@@ -18,22 +18,23 @@ const customWidgets = {
interface SignUpPageViewProps {
signUpForm: SignupForm;
formData: any;
statusMessage: string;
onChange: (e: IChangeEvent<unknown>, es?: ErrorSchema) => unknown;
onSubmit: (e: ISubmitEvent<unknown>) => unknown;
}
const renderList = (signUpForm: SignupForm) => (
<>
<h6>
Ilmoittautuneet{signUpForm.quota > 0 && (` (${signUpForm.signups.length}/${signUpForm.quota})`)}:
</h6>
<ol>
{signUpForm.signups.map((s, idx) => (
<li key={idx} className={signUpForm.quota && idx + 1 > signUpForm.quota ? "reserved" : ""}>{s}</li>
))}
</ol>
</>
<aside>
<div>
<h6>
Ilmoittautuneet{signUpForm.quota > 0 && (` (${signUpForm.signups.length}/${signUpForm.quota})`)}:
</h6>
<ol>
{signUpForm.signups.map((s, idx) => (
<li key={idx} className={signUpForm.quota && idx + 1 > signUpForm.quota ? "reserved" : ""}>{s}</li>
))}
</ol>
</div>
</aside>
);
const StyledSection = styled(TextSection)`
@@ -62,7 +63,6 @@ const StyledSection = styled(TextSection)`
const SignUpPageView: React.FC<SignUpPageViewProps> = ({
signUpForm,
formData,
statusMessage,
onChange,
onSubmit,
}) => {
@@ -83,11 +83,34 @@ const SignUpPageView: React.FC<SignUpPageViewProps> = ({
);
};
const form = signUpForm ? renderForm() : (
<Loader $color={colors.darkBlue} />
);
let form: JSX.Element;
let signups: JSX.Element = null;
const startTime = new Date(signUpForm?.start_time);
const endTime = new Date(signUpForm?.end_time);
if (!signUpForm) {
// Show loader if in edit mode and form has not yet loaded.
// For normal signup page, form is always defined on this level.
form = (
<Loader $color={colors.darkBlue} />
);
} else if (startTime > new Date()) {
form = (
<>
<p>Ilmoittauminen ei ole vielä auennut!</p>
<p>Se aukeaa {startTime.toLocaleString("fi-FI")}.</p>
</>
);
} else if (new Date() > endTime) {
form = (
<p>Ilmoittauminen on umpeutunut!</p>
);
signups = renderList(signUpForm);
} else {
form = renderForm();
signups = renderList(signUpForm);
}
const signups = signUpForm && signUpForm.signups ? renderList(signUpForm) : null;
return (
<StyledSection>
<h1>
@@ -97,16 +120,9 @@ const SignUpPageView: React.FC<SignUpPageViewProps> = ({
</h1>
<div>
<span className="sign-up-statusmessage">
{statusMessage}
</span>
{form}
</div>
<aside>
<div>
{signups}
</div>
</aside>
{signups}
</StyledSection>
);
};
+1 -14
View File
@@ -16,14 +16,6 @@ const Common = styled.div`
}
`;
const SuccessMsg = styled.p`
margin-bottom: 0.5rem;
border: 1px solid ${colors.green1};
padding: 8px 16px;
color: ${colors.green1};
display: inline-block;
`;
const ErrorMsg = styled.p`
margin-bottom: 0.5rem;
border: 1px solid ${colors.orange2};
@@ -44,9 +36,8 @@ type AdminCreateCommonProps = {
[name: string]: unknown;
};
onChange?: (e: IChangeEvent<FormTypes>, es?: ErrorSchema) => unknown;
onFocus: (id: string, value: string | number | boolean) => void;
onFocus?: (id: string, value: string | number | boolean) => void;
onSubmit: (e: ISubmitEvent<FormTypes>) => unknown;
statusMessage: string;
error: string;
widgets: {
[name: string]: any;
@@ -61,7 +52,6 @@ const AdminCreateCommon: React.FC<AdminCreateCommonProps> = ({
onChange,
onFocus,
onSubmit,
statusMessage,
error,
widgets,
}) => {
@@ -74,9 +64,6 @@ const AdminCreateCommon: React.FC<AdminCreateCommonProps> = ({
<AdminPageWrapper requiresAuthentication>
<Common>
<h1>{title}</h1>
{statusMessage && (
<SuccessMsg data-e2e="admin-form-status-message">{statusMessage}</SuccessMsg>
)}
<FormWrapper
schema={schema}
uiSchema={UISchema}
-2
View File
@@ -5,8 +5,6 @@ services:
image: registry.gitlab.com/sahkoinsinoorikilta/vtmk/web2.0-frontend:latest
deploy:
replicas: 1
restart_policy:
condition: on-failure
update_config:
order: start-first
ports:
-2
View File
@@ -5,8 +5,6 @@ services:
image: registry.gitlab.com/sahkoinsinoorikilta/vtmk/web2.0-frontend:prod
deploy:
replicas: 1
restart_policy:
condition: on-failure
update_config:
order: start-first
ports:
+2 -2
View File
@@ -81,10 +81,10 @@ test("Logged in user can create event", async (t) => {
// eslint-disable-next-line no-param-reassign
t.fixtureCtx.eventId = parsed.id;
const statusMessage = Selector("[data-e2e=\"admin-form-status-message\"]");
const statusMessage = Selector(".Toastify__toast-body");
await t
.hover(statusMessage)
.expect(
statusMessage.innerText,
).eql("Event created successfully");
).eql("Event created successfully 😎");
});
+2 -2
View File
@@ -86,10 +86,10 @@ test("Logged in user can create signup", async (t) => {
// eslint-disable-next-line no-param-reassign
t.fixtureCtx.formId = parsed.id;
const statusMessage = Selector("[data-e2e=\"admin-form-status-message\"]");
const statusMessage = Selector(".Toastify__toast-body");
await t
.hover(statusMessage)
.expect(
statusMessage.innerText,
).eql("Sign-up created successfully");
).eql("Sign-up created successfully 😎");
});
+2 -2
View File
@@ -52,10 +52,10 @@ test("User signups to event from front page", async (t) => {
await t.click(Selector("button").nth(-1));
const statusMessage = Selector(".sign-up-statusmessage");
const statusMessage = Selector(".Toastify__toast-body");
await t
.hover(statusMessage)
.expect(
statusMessage.innerText,
).eql("Sign-up submitted successfully");
).eql("Sign-up submitted successfully 😎");
});