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 - production
environment: environment:
name: production name: production
url: prod.sahkoinsinoorikilta.fi url: sahkoinsinoorikilta.fi
when: manual when: manual
variables: variables:
DOCKER_HOST: $CI_DOCKER_HOST DOCKER_HOST: $CI_DOCKER_HOST
+41 -188
View File
@@ -23,6 +23,7 @@
"react-jsonschema-form": "1.8.1", "react-jsonschema-form": "1.8.1",
"react-markdown": "5.0.3", "react-markdown": "5.0.3",
"react-mde": "11.0.6", "react-mde": "11.0.6",
"react-toastify": "^7.0.3",
"shortid": "2.2.16", "shortid": "2.2.16",
"styled-components": "5.2.1", "styled-components": "5.2.1",
"swr": "0.4.2" "swr": "0.4.2"
@@ -3012,9 +3013,6 @@
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=8" "node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/@hapi/accept": { "node_modules/@hapi/accept": {
@@ -3086,10 +3084,6 @@
"source-map": "0.8.0-beta.0", "source-map": "0.8.0-beta.0",
"stacktrace-parser": "0.1.10", "stacktrace-parser": "0.1.10",
"strip-ansi": "6.0.0" "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": { "node_modules/@next/react-dev-overlay/node_modules/ansi-regex": {
@@ -3109,9 +3103,6 @@
}, },
"engines": { "engines": {
"node": ">=8" "node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
} }
}, },
"node_modules/@next/react-dev-overlay/node_modules/chalk": { "node_modules/@next/react-dev-overlay/node_modules/chalk": {
@@ -3124,9 +3115,6 @@
}, },
"engines": { "engines": {
"node": ">=10" "node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
} }
}, },
"node_modules/@next/react-dev-overlay/node_modules/color-convert": { "node_modules/@next/react-dev-overlay/node_modules/color-convert": {
@@ -3189,16 +3177,7 @@
"node_modules/@next/react-refresh-utils": { "node_modules/@next/react-refresh-utils": {
"version": "10.0.8", "version": "10.0.8",
"resolved": "https://registry.npmjs.org/@next/react-refresh-utils/-/react-refresh-utils-10.0.8.tgz", "resolved": "https://registry.npmjs.org/@next/react-refresh-utils/-/react-refresh-utils-10.0.8.tgz",
"integrity": "sha512-ZMO77Xs2ioGV/nZB4GRDHgsNT2jhOp+cZIh6c7wf0xw9o/1KoTWN8nxWzwU/laAtkoSS+E6YdhuR4Mw3Ar3CSg==", "integrity": "sha512-ZMO77Xs2ioGV/nZB4GRDHgsNT2jhOp+cZIh6c7wf0xw9o/1KoTWN8nxWzwU/laAtkoSS+E6YdhuR4Mw3Ar3CSg=="
"peerDependencies": {
"react-refresh": "0.8.3",
"webpack": "^4 || ^5"
},
"peerDependenciesMeta": {
"webpack": {
"optional": true
}
}
}, },
"node_modules/@nodelib/fs.scandir": { "node_modules/@nodelib/fs.scandir": {
"version": "2.1.3", "version": "2.1.3",
@@ -3489,19 +3468,6 @@
}, },
"engines": { "engines": {
"node": "^10.12.0 || >=12.0.0" "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": { "node_modules/@typescript-eslint/experimental-utils": {
@@ -3519,13 +3485,6 @@
}, },
"engines": { "engines": {
"node": "^10.12.0 || >=12.0.0" "node": "^10.12.0 || >=12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "*"
} }
}, },
"node_modules/@typescript-eslint/parser": { "node_modules/@typescript-eslint/parser": {
@@ -3541,18 +3500,6 @@
}, },
"engines": { "engines": {
"node": "^10.12.0 || >=12.0.0" "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": { "node_modules/@typescript-eslint/scope-manager": {
@@ -3566,10 +3513,6 @@
}, },
"engines": { "engines": {
"node": "^8.10.0 || ^10.13.0 || >=11.10.1" "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
} }
}, },
"node_modules/@typescript-eslint/types": { "node_modules/@typescript-eslint/types": {
@@ -3579,10 +3522,6 @@
"dev": true, "dev": true,
"engines": { "engines": {
"node": "^8.10.0 || ^10.13.0 || >=11.10.1" "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": { "node_modules/@typescript-eslint/typescript-estree": {
@@ -3601,15 +3540,6 @@
}, },
"engines": { "engines": {
"node": "^10.12.0 || >=12.0.0" "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": { "node_modules/@typescript-eslint/typescript-estree/node_modules/@nodelib/fs.stat": {
@@ -3686,9 +3616,6 @@
}, },
"engines": { "engines": {
"node": ">=10" "node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/@typescript-eslint/typescript-estree/node_modules/ignore": { "node_modules/@typescript-eslint/typescript-estree/node_modules/ignore": {
@@ -3745,10 +3672,6 @@
}, },
"engines": { "engines": {
"node": "^8.10.0 || ^10.13.0 || >=11.10.1" "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": { "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
@@ -3785,10 +3708,7 @@
"version": "5.3.1", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
"integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
"dev": true, "dev": true
"peerDependencies": {
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
}
}, },
"node_modules/acorn-walk": { "node_modules/acorn-walk": {
"version": "8.0.1", "version": "8.0.1",
@@ -3820,10 +3740,6 @@
"fast-json-stable-stringify": "^2.0.0", "fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1", "json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2" "uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
} }
}, },
"node_modules/amdefine": { "node_modules/amdefine": {
@@ -4071,6 +3987,7 @@
"integrity": "sha512-d2Ovma+bfqNpvBzY/KU8oPY67ZworixTpkjSx0PCXnQi67c2cXmssaTxpFDUM0ttopXoGx/KRxNg/GDThYbXQA==", "integrity": "sha512-d2Ovma+bfqNpvBzY/KU8oPY67ZworixTpkjSx0PCXnQi67c2cXmssaTxpFDUM0ttopXoGx/KRxNg/GDThYbXQA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@types/glob": "^7.1.1",
"chromium-pickle-js": "^0.2.0", "chromium-pickle-js": "^0.2.0",
"commander": "^2.20.0", "commander": "^2.20.0",
"cuint": "^0.2.2", "cuint": "^0.2.2",
@@ -4084,9 +4001,6 @@
}, },
"engines": { "engines": {
"node": ">=8.0" "node": ">=8.0"
},
"optionalDependencies": {
"@types/glob": "^7.1.1"
} }
}, },
"node_modules/asn1.js": { "node_modules/asn1.js": {
@@ -4328,9 +4242,6 @@
"@babel/helper-module-imports": "^7.0.0", "@babel/helper-module-imports": "^7.0.0",
"babel-plugin-syntax-jsx": "^6.18.0", "babel-plugin-syntax-jsx": "^6.18.0",
"lodash": "^4.17.11" "lodash": "^4.17.11"
},
"peerDependencies": {
"styled-components": ">= 2"
} }
}, },
"node_modules/babel-plugin-syntax-jsx": { "node_modules/babel-plugin-syntax-jsx": {
@@ -4747,9 +4658,6 @@
}, },
"engines": { "engines": {
"node": ">=8" "node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/camelize": { "node_modules/camelize": {
@@ -4974,6 +4882,14 @@
"node": ">=6" "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": { "node_modules/code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
@@ -5452,10 +5368,6 @@
"integrity": "sha512-NYyAg4wRmGVU4miKq5ivRACOODdZRY3q5WLmOJSq8djyzftYphU7dTHLcEtLqEvfqMKQ0jVv91P4BAwIjsXIcw==", "integrity": "sha512-NYyAg4wRmGVU4miKq5ivRACOODdZRY3q5WLmOJSq8djyzftYphU7dTHLcEtLqEvfqMKQ0jVv91P4BAwIjsXIcw==",
"engines": { "engines": {
"node": ">=0.11" "node": ">=0.11"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/date-fns"
} }
}, },
"node_modules/debug": { "node_modules/debug": {
@@ -6078,9 +5990,6 @@
}, },
"engines": { "engines": {
"node": "^10.12.0 || >=12.0.0" "node": "^10.12.0 || >=12.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
} }
}, },
"node_modules/eslint-config-airbnb": { "node_modules/eslint-config-airbnb": {
@@ -7230,9 +7139,6 @@
}, },
"bin": { "bin": {
"rimraf": "bin.js" "rimraf": "bin.js"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/flatted": { "node_modules/flatted": {
@@ -7376,9 +7282,6 @@
}, },
"engines": { "engines": {
"node": "*" "node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/glob-parent": { "node_modules/glob-parent": {
@@ -7453,9 +7356,6 @@
}, },
"engines": { "engines": {
"node": ">=8" "node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/globals/node_modules/type-fest": { "node_modules/globals/node_modules/type-fest": {
@@ -7864,16 +7764,6 @@
"resolved": "https://registry.npmjs.org/husky/-/husky-5.1.3.tgz", "resolved": "https://registry.npmjs.org/husky/-/husky-5.1.3.tgz",
"integrity": "sha512-fbNJ+Gz5wx2LIBtMweJNY1D7Uc8p1XERi5KNRMccwfQA+rXlxWNSdUxswo0gT8XqxywTIw7Ywm/F4v/O35RdMg==", "integrity": "sha512-fbNJ+Gz5wx2LIBtMweJNY1D7Uc8p1XERi5KNRMccwfQA+rXlxWNSdUxswo0gT8XqxywTIw7Ywm/F4v/O35RdMg==",
"dev": true, "dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/typicode"
},
{
"type": "opencollective",
"url": "https://opencollective.com/husky"
}
],
"bin": { "bin": {
"husky": "lib/bin.js" "husky": "lib/bin.js"
}, },
@@ -7917,9 +7807,6 @@
}, },
"engines": { "engines": {
"node": ">=6" "node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/import-lazy": { "node_modules/import-lazy": {
@@ -8965,9 +8852,6 @@
}, },
"engines": { "engines": {
"node": ">=10" "node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/matcher/node_modules/escape-string-regexp": { "node_modules/matcher/node_modules/escape-string-regexp": {
@@ -8977,9 +8861,6 @@
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=10" "node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/mathml-tag-names": { "node_modules/mathml-tag-names": {
@@ -9090,9 +8971,6 @@
}, },
"engines": { "engines": {
"node": ">=10" "node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/meow/node_modules/hosted-git-info": { "node_modules/meow/node_modules/hosted-git-info": {
@@ -9141,9 +9019,6 @@
"dev": true, "dev": true,
"engines": { "engines": {
"node": ">=10" "node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/merge-stream": { "node_modules/merge-stream": {
@@ -9491,24 +9366,6 @@
}, },
"engines": { "engines": {
"node": ">=10.13.0" "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": { "node_modules/next-sitemap": {
@@ -9523,9 +9380,6 @@
}, },
"bin": { "bin": {
"next-sitemap": "bin/next-sitemap" "next-sitemap": "bin/next-sitemap"
},
"peerDependencies": {
"next": "*"
} }
}, },
"node_modules/next/node_modules/browserslist": { "node_modules/next/node_modules/browserslist": {
@@ -10412,9 +10266,6 @@
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
"engines": { "engines": {
"node": ">=8.6" "node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
} }
}, },
"node_modules/pidtree": { "node_modules/pidtree": {
@@ -11260,11 +11111,7 @@
"node_modules/react-mde": { "node_modules/react-mde": {
"version": "11.0.6", "version": "11.0.6",
"resolved": "https://registry.npmjs.org/react-mde/-/react-mde-11.0.6.tgz", "resolved": "https://registry.npmjs.org/react-mde/-/react-mde-11.0.6.tgz",
"integrity": "sha512-yWiPSurQvjLVD070zycQR4x5zW3f/kxPlqOMmZoUtVQvUgcM+kwpDQAba5sqtqtAurgUx0Ae9p9Xzgqwt2+ZBA==", "integrity": "sha512-yWiPSurQvjLVD070zycQR4x5zW3f/kxPlqOMmZoUtVQvUgcM+kwpDQAba5sqtqtAurgUx0Ae9p9Xzgqwt2+ZBA=="
"peerDependencies": {
"react": "^16.0.0",
"react-dom": "^16.0.0"
}
}, },
"node_modules/react-redux": { "node_modules/react-redux": {
"version": "7.2.2", "version": "7.2.2",
@@ -11320,6 +11167,18 @@
"node": ">=0.10.0" "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": { "node_modules/read-file-relative": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/read-file-relative/-/read-file-relative-1.2.0.tgz", "resolved": "https://registry.npmjs.org/read-file-relative/-/read-file-relative-1.2.0.tgz",
@@ -11355,9 +11214,6 @@
}, },
"engines": { "engines": {
"node": ">=8" "node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/read-pkg-up/node_modules/find-up": { "node_modules/read-pkg-up/node_modules/find-up": {
@@ -11395,9 +11251,6 @@
}, },
"engines": { "engines": {
"node": ">=6" "node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/read-pkg-up/node_modules/p-locate": { "node_modules/read-pkg-up/node_modules/p-locate": {
@@ -11434,9 +11287,6 @@
}, },
"engines": { "engines": {
"node": ">=8" "node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/read-pkg-up/node_modules/path-exists": { "node_modules/read-pkg-up/node_modules/path-exists": {
@@ -12957,10 +12807,6 @@
}, },
"engines": { "engines": {
"node": ">=10.13.0" "node": ">=10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/stylelint"
} }
}, },
"node_modules/stylelint-config-recommended": { "node_modules/stylelint-config-recommended": {
@@ -13707,9 +13553,6 @@
"integrity": "sha512-SKGxcAfyijj/lE5ja5zVMDqJNudASH3WZPRUakDVOePTM18FnsXgugndjl9BSRwj+jokFCulMDe7F2pQL+VhEw==", "integrity": "sha512-SKGxcAfyijj/lE5ja5zVMDqJNudASH3WZPRUakDVOePTM18FnsXgugndjl9BSRwj+jokFCulMDe7F2pQL+VhEw==",
"dependencies": { "dependencies": {
"dequal": "2.0.2" "dequal": "2.0.2"
},
"peerDependencies": {
"react": "^16.11.0 || ^17.0.0"
} }
}, },
"node_modules/symbol-observable": { "node_modules/symbol-observable": {
@@ -18480,8 +18323,7 @@
"@next/react-refresh-utils": { "@next/react-refresh-utils": {
"version": "10.0.8", "version": "10.0.8",
"resolved": "https://registry.npmjs.org/@next/react-refresh-utils/-/react-refresh-utils-10.0.8.tgz", "resolved": "https://registry.npmjs.org/@next/react-refresh-utils/-/react-refresh-utils-10.0.8.tgz",
"integrity": "sha512-ZMO77Xs2ioGV/nZB4GRDHgsNT2jhOp+cZIh6c7wf0xw9o/1KoTWN8nxWzwU/laAtkoSS+E6YdhuR4Mw3Ar3CSg==", "integrity": "sha512-ZMO77Xs2ioGV/nZB4GRDHgsNT2jhOp+cZIh6c7wf0xw9o/1KoTWN8nxWzwU/laAtkoSS+E6YdhuR4Mw3Ar3CSg=="
"requires": {}
}, },
"@nodelib/fs.scandir": { "@nodelib/fs.scandir": {
"version": "2.1.3", "version": "2.1.3",
@@ -18942,8 +18784,7 @@
"version": "5.3.1", "version": "5.3.1",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz",
"integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
"dev": true, "dev": true
"requires": {}
}, },
"acorn-walk": { "acorn-walk": {
"version": "8.0.1", "version": "8.0.1",
@@ -19934,6 +19775,11 @@
"is-regexp": "^2.0.0" "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": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
@@ -25128,8 +24974,7 @@
"react-mde": { "react-mde": {
"version": "11.0.6", "version": "11.0.6",
"resolved": "https://registry.npmjs.org/react-mde/-/react-mde-11.0.6.tgz", "resolved": "https://registry.npmjs.org/react-mde/-/react-mde-11.0.6.tgz",
"integrity": "sha512-yWiPSurQvjLVD070zycQR4x5zW3f/kxPlqOMmZoUtVQvUgcM+kwpDQAba5sqtqtAurgUx0Ae9p9Xzgqwt2+ZBA==", "integrity": "sha512-yWiPSurQvjLVD070zycQR4x5zW3f/kxPlqOMmZoUtVQvUgcM+kwpDQAba5sqtqtAurgUx0Ae9p9Xzgqwt2+ZBA=="
"requires": {}
}, },
"react-redux": { "react-redux": {
"version": "7.2.2", "version": "7.2.2",
@@ -25181,6 +25026,14 @@
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
"integrity": "sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg==" "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": { "read-file-relative": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/read-file-relative/-/read-file-relative-1.2.0.tgz", "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-jsonschema-form": "1.8.1",
"react-markdown": "5.0.3", "react-markdown": "5.0.3",
"react-mde": "11.0.6", "react-mde": "11.0.6",
"react-toastify": "^7.0.3",
"shortid": "2.2.16", "shortid": "2.2.16",
"styled-components": "5.2.1", "styled-components": "5.2.1",
"swr": "0.4.2" "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; 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; export default FeedApi;
+14
View File
@@ -72,6 +72,20 @@ class JobAdApi {
throw err; 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; 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` const Card = styled.article`
display: flex; display: flex;
align-items: flex-start; justify-content: space-between;
flex-flow: row nowrap; flex: 1 0 50%;
padding: 0.5rem; padding: 0.5rem;
color: ${colors.darkBlue}; color: ${colors.darkBlue};
width: 19rem; `;
const Row = styled.div`
display: flex;
flex-flow: row nowrap;
`; `;
const ImageContainer = styled.div` const ImageContainer = styled.div`
position: relative; position: relative;
display: flex;
flex-shrink: 0;
justify-content: center;
align-items: center;
height: 5rem; height: 5rem;
width: 5rem; width: 5rem;
flex-shrink: 0;
img { img {
padding: 0.5rem !important; padding: 0.5rem !important;
@@ -39,7 +40,7 @@ const Info = styled.div`
margin: 0; margin: 0;
} }
& > h1 { & > h3 {
font-size: 0.9rem; font-size: 0.9rem;
font-weight: 500; font-weight: 500;
} }
@@ -58,22 +59,24 @@ const ContactCard: React.FC<ContactCardProps> = ({
name, phone, email, image, role_fi, role_en, name, phone, email, image, role_fi, role_en,
}) => ( }) => (
<Card> <Card>
{image ? ( <Row>
<ImageContainer> {image ? (
<Image <ImageContainer>
src={image} <Image
alt={name} src={image}
layout="fill" alt={name}
objectFit="scale-down" layout="fill"
/> objectFit="scale-down"
</ImageContainer> />
) : null} </ImageContainer>
<Info> ) : null}
<h1>{name}</h1> <Info>
<p>{role_fi || role_en}</p> <h3>{name}</h3>
{phone ? <p>{phone}</p> : null} <p>{role_fi || role_en}</p>
{email ? <p>{email}</p> : null} {phone ? <p>{phone}</p> : null}
</Info> {email ? <p>{email}</p> : null}
</Info>
</Row>
</Card> </Card>
); );
+1 -1
View File
@@ -69,7 +69,7 @@ const CrossFadeImages: React.FC<CrossFadeImagesProps> = ({
$duration={len * SINGLE_IMAGE_TIME} $duration={len * SINGLE_IMAGE_TIME}
> >
{ images.map((image, idx) => ( { images.map((image, idx) => (
<div className={idx > 0 ? "not-first" : undefined}> <div key={idx} className={idx > 0 ? "not-first" : undefined}>
<AnimatedImage <AnimatedImage
key={image} key={image}
src={image} src={image}
+3
View File
@@ -3,9 +3,11 @@ import React from "react";
import type { AppProps /* , AppContext' */ } from "next/app"; import type { AppProps /* , AppContext' */ } from "next/app";
import Head from "next/head"; import Head from "next/head";
import styled, { createGlobalStyle } from "styled-components"; import styled, { createGlobalStyle } from "styled-components";
import { ToastContainer } from "react-toastify";
import { colors } from "@theme/colors"; import { colors } from "@theme/colors";
import "react-mde/lib/styles/css/react-mde-all.css"; import "react-mde/lib/styles/css/react-mde-all.css";
import "react-toastify/dist/ReactToastify.css";
const fontFamily = "'Montserrat', sans-serif"; const fontFamily = "'Montserrat', sans-serif";
const fontSize = 12; // 16px const fontSize = 12; // 16px
@@ -141,6 +143,7 @@ const Web20App = ({ Component, pageProps }: AppProps) => (
<AppContainer> <AppContainer>
<Component {...pageProps} /> <Component {...pageProps} />
</AppContainer> </AppContainer>
<ToastContainer position="bottom-right" />
</> </>
); );
+7 -6
View File
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { NextPage } from "next"; import { NextPage } from "next";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { toast } from "react-toastify";
import AdminCreateCommon from "@views/admin/AdminCreateCommon"; import AdminCreateCommon from "@views/admin/AdminCreateCommon";
import Tag from "@models/Tag"; import Tag from "@models/Tag";
import TagApi from "@api/tagApi"; import TagApi from "@api/tagApi";
@@ -66,6 +67,7 @@ const buildSchema = (formData: Event, signupForms: SignupForm[], tags: Tag[]) =>
enumNames: signupForms.map((form) => form.title_fi), enumNames: signupForms.map((form) => form.title_fi),
}, },
uniqueItems: true, uniqueItems: true,
default: [],
}, },
image: { image: {
type: ["string", "null"], type: ["string", "null"],
@@ -166,7 +168,6 @@ const EventCreatePage: NextPage = () => {
const [tags, setTags] = useState<Tag[]>([]); const [tags, setTags] = useState<Tag[]>([]);
const [signupForms, setSignupForms] = useState<SignupForm[]>([]); const [signupForms, setSignupForms] = useState<SignupForm[]>([]);
const [error, setError] = useState<string>(null); const [error, setError] = useState<string>(null);
const [statusMessage, setStatusMessage] = useState<string>(null);
const router = useRouter(); const router = useRouter();
@@ -212,7 +213,8 @@ const EventCreatePage: NextPage = () => {
// resp.signupForm = (resp.signupForm as any).map(inst => inst.id); // resp.signupForm = (resp.signupForm as any).map(inst => inst.id);
resp.tags = data.formData.tags; resp.tags = data.formData.tags;
resp.signupForm = data.formData.signupForm; resp.signupForm = data.formData.signupForm;
setStatusMessage("Event created successfully"); toast.success("Event created successfully 😎");
router.push("/admin/events");
setFormData(resp); setFormData(resp);
} else { } else {
const resp = await EventApi.updateEvent(payload); const resp = await EventApi.updateEvent(payload);
@@ -222,16 +224,17 @@ const EventCreatePage: NextPage = () => {
// resp.signupForm = (resp.signupForm as any).map(inst => inst.id); // resp.signupForm = (resp.signupForm as any).map(inst => inst.id);
resp.tags = data.formData.tags; resp.tags = data.formData.tags;
resp.signupForm = data.formData.signupForm; resp.signupForm = data.formData.signupForm;
setStatusMessage("Event updated successfully"); toast.success("Event updated successfully 😎");
router.push("/admin/events");
setFormData(resp); setFormData(resp);
} }
} catch (err) { } catch (err) {
toast.error("Uh oh! Something went wrong! Try again later. 😟");
setError(err); setError(err);
} }
}; };
const onChange = (data: any) => setFormData(data.formData); const onChange = (data: any) => setFormData(data.formData);
const onFocus = () => setStatusMessage(null);
const title = formData?.id const title = formData?.id
? `Edit Event "${formData.title_fi}"` ? `Edit Event "${formData.title_fi}"`
: "Create Event"; : "Create Event";
@@ -243,9 +246,7 @@ const EventCreatePage: NextPage = () => {
schema={buildSchema(formData, signupForms, tags)} schema={buildSchema(formData, signupForms, tags)}
UISchema={buildUISchema()} UISchema={buildUISchema()}
onChange={onChange} onChange={onChange}
onFocus={onFocus}
onSubmit={onSubmit} onSubmit={onSubmit}
statusMessage={statusMessage}
error={error} error={error}
widgets={widgets} widgets={widgets}
/> />
+30 -1
View File
@@ -1,14 +1,37 @@
import React from "react"; import React from "react";
import { NextPage } from "next"; import { NextPage } from "next";
import { formatRelative } from "date-fns"; import { formatRelative } from "date-fns";
import { toast } from "react-toastify";
import styled from "styled-components";
import AdminListCommon from "@views/admin/AdminListCommon"; import AdminListCommon from "@views/admin/AdminListCommon";
import { Link } from "@components/index"; import { Button, Link } from "@components/index";
import AddLink from "@components/AddLink"; import AddLink from "@components/AddLink";
import Event from "@models/Event"; import Event from "@models/Event";
import EventApi from "@api/eventApi";
import useFetchEvents from "@hooks/useFetchEvents"; import useFetchEvents from "@hooks/useFetchEvents";
const URL = "/admin/events"; 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[]) => { const renderData = (events: Event[]) => {
if (!events || events.length === 0) { if (!events || events.length === 0) {
return <div>No events.</div>; 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><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.start_time), new Date())}</td>
<td>{formatRelative(new Date(event.end_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> </tr>
))} ))}
</tbody> </tbody>
</table> </table>
); );
}; };
const AdminEventPage: NextPage = () => { const AdminEventPage: NextPage = () => {
const { data } = useFetchEvents({ options: { auth: true } }); const { data } = useFetchEvents({ options: { auth: true } });
return ( return (
+6 -6
View File
@@ -9,6 +9,7 @@ import FeedApi from "@api/feedApi";
import DatetimeWidget from "@components/Widgets/DatetimeWidget"; import DatetimeWidget from "@components/Widgets/DatetimeWidget";
import SectionDividerWidget from "@components/Widgets/SectionDividerWidget"; import SectionDividerWidget from "@components/Widgets/SectionDividerWidget";
import MarkdownEditorWidget from "@components/Widgets/MarkdownEditorWidget"; import MarkdownEditorWidget from "@components/Widgets/MarkdownEditorWidget";
import { toast } from "react-toastify";
const widgets = { const widgets = {
datetime: DatetimeWidget, datetime: DatetimeWidget,
@@ -133,7 +134,6 @@ const FeedCreatePage: NextPage = () => {
const [formData, setFormData] = useState<Post>(null); const [formData, setFormData] = useState<Post>(null);
const [tags, setTags] = useState<Tag[]>([]); const [tags, setTags] = useState<Tag[]>([]);
const [error, setError] = useState<string>(null); const [error, setError] = useState<string>(null);
const [statusMessage, setStatusMessage] = useState<string>(null);
const router = useRouter(); const router = useRouter();
@@ -167,21 +167,23 @@ const FeedCreatePage: NextPage = () => {
if (payload.id === undefined) { if (payload.id === undefined) {
const resp = await FeedApi.createPost(payload); const resp = await FeedApi.createPost(payload);
// resp.tags = resp.tags; // resp.tags = resp.tags;
setStatusMessage("Post created successfully"); toast.success("Post created successfully 😎");
router.push("/admin/feed");
setFormData(resp); setFormData(resp);
} else { } else {
const resp = await FeedApi.updatePost(payload); const resp = await FeedApi.updatePost(payload);
// resp.tags = resp.tag_id; // resp.tags = resp.tag_id;
setStatusMessage("Post updated successfully"); toast.success("Post updated successfully 😎");
router.push("/admin/feed");
setFormData(resp); setFormData(resp);
} }
} catch (err) { } catch (err) {
toast.error("Uh oh! Something went wrong! Try again later. 😟");
setError(err); setError(err);
} }
}; };
const onChange = (data) => setFormData(data.formData); const onChange = (data) => setFormData(data.formData);
const onFocus = () => setStatusMessage(null);
const title = formData?.id const title = formData?.id
? `Edit Post "${formData.title_fi}"` ? `Edit Post "${formData.title_fi}"`
@@ -194,9 +196,7 @@ const FeedCreatePage: NextPage = () => {
schema={buildSchema(formData, tags)} schema={buildSchema(formData, tags)}
UISchema={buildUISchema(formData)} UISchema={buildUISchema(formData)}
onChange={onChange} onChange={onChange}
onFocus={onFocus}
onSubmit={onSubmit} onSubmit={onSubmit}
statusMessage={statusMessage}
error={error} error={error}
widgets={widgets} widgets={widgets}
/> />
+29 -1
View File
@@ -1,14 +1,37 @@
import React from "react"; import React from "react";
import { NextPage } from "next"; import { NextPage } from "next";
import { formatRelative } from "date-fns"; import { formatRelative } from "date-fns";
import { toast } from "react-toastify";
import styled from "styled-components";
import AdminListCommon from "@views/admin/AdminListCommon"; import AdminListCommon from "@views/admin/AdminListCommon";
import { Link } from "@components/index"; import { Button, Link } from "@components/index";
import AddLink from "@components/AddLink"; import AddLink from "@components/AddLink";
import Post from "@models/Feed"; import Post from "@models/Feed";
import PostApi from "@api/feedApi";
import useFetchFeed from "@hooks/useFetchFeed"; import useFetchFeed from "@hooks/useFetchFeed";
const URL = "/admin/feed"; 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[]) => { const renderData = (feed: Post[]) => {
if (!feed || feed.length === 0) { if (!feed || feed.length === 0) {
return <div>No posts.</div>; 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><Link to={`${URL}/${post.id}`}>{post.title_fi}</Link></td>
<td>{post.description_fi}</td> <td>{post.description_fi}</td>
<td>{formatRelative(new Date(post.publish_time), new Date())}</td> <td>{formatRelative(new Date(post.publish_time), new Date())}</td>
<td>
<StyledButton $colorOverride="red" buttonStyle="filled" onClick={() => confirmDelete(post)}>
Delete
</StyledButton>
</td>
</tr> </tr>
))} ))}
</tbody> </tbody>
+6 -6
View File
@@ -7,6 +7,7 @@ import JobAdApi from "@api/jobAdApi";
import DatetimeWidget from "@components/Widgets/DatetimeWidget"; import DatetimeWidget from "@components/Widgets/DatetimeWidget";
import SectionDividerWidget from "@components/Widgets/SectionDividerWidget"; import SectionDividerWidget from "@components/Widgets/SectionDividerWidget";
import MarkdownEditorWidget from "@components/Widgets/MarkdownEditorWidget"; import MarkdownEditorWidget from "@components/Widgets/MarkdownEditorWidget";
import { toast } from "react-toastify";
const widgets = { const widgets = {
datetime: DatetimeWidget, datetime: DatetimeWidget,
@@ -108,7 +109,6 @@ const buildUISchema = (formData: JobAd) => ({
const JobAdCreatePage: NextPage = () => { const JobAdCreatePage: NextPage = () => {
const [formData, setFormData] = useState<JobAd>(null); const [formData, setFormData] = useState<JobAd>(null);
const [error, setError] = useState<string>(null); const [error, setError] = useState<string>(null);
const [statusMessage, setStatusMessage] = useState<string>(null);
const router = useRouter(); const router = useRouter();
@@ -132,20 +132,22 @@ const JobAdCreatePage: NextPage = () => {
const payload = data.formData; const payload = data.formData;
if (payload.id === undefined) { if (payload.id === undefined) {
const resp = await JobAdApi.createJobAd(payload); const resp = await JobAdApi.createJobAd(payload);
setStatusMessage("Post created successfully"); toast.success("Job ad created successfully 😎");
router.push("/admin/jobads");
setFormData(resp); setFormData(resp);
} else { } else {
const resp = await JobAdApi.updateJobAd(payload); const resp = await JobAdApi.updateJobAd(payload);
setStatusMessage("Post updated successfully"); toast.success("Job ad updated successfully 😎");
router.push("/admin/jobads");
setFormData(resp); setFormData(resp);
} }
} catch (err) { } catch (err) {
toast.error("Uh oh! Something went wrong! Try again later. 😟");
setError(err); setError(err);
} }
}; };
const onChange = (data) => setFormData(data.formData); const onChange = (data) => setFormData(data.formData);
const onFocus = () => setStatusMessage(null);
const title = formData?.id const title = formData?.id
? `Edit Ad "${formData.title_fi}"` ? `Edit Ad "${formData.title_fi}"`
@@ -158,9 +160,7 @@ const JobAdCreatePage: NextPage = () => {
schema={buildSchema(formData)} schema={buildSchema(formData)}
UISchema={buildUISchema(formData)} UISchema={buildUISchema(formData)}
onChange={onChange} onChange={onChange}
onFocus={onFocus}
onSubmit={onSubmit} onSubmit={onSubmit}
statusMessage={statusMessage}
error={error} error={error}
widgets={widgets} widgets={widgets}
/> />
+29 -1
View File
@@ -1,14 +1,37 @@
import React from "react"; import React from "react";
import { NextPage } from "next"; import { NextPage } from "next";
import { formatRelative } from "date-fns"; import { formatRelative } from "date-fns";
import { toast } from "react-toastify";
import styled from "styled-components";
import AdminListCommon from "@views/admin/AdminListCommon"; import AdminListCommon from "@views/admin/AdminListCommon";
import { Link } from "@components/index"; import { Button, Link } from "@components/index";
import AddLink from "@components/AddLink"; import AddLink from "@components/AddLink";
import JobAd from "@models/JobAd"; import JobAd from "@models/JobAd";
import useFetchJobAds from "@hooks/useFetchJobAds"; import useFetchJobAds from "@hooks/useFetchJobAds";
import JobAdApi from "@api/jobAdApi";
const URL = "/admin/jobads"; 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[]) => { const renderData = (jobAds: JobAd[]) => {
if (!jobAds || jobAds.length === 0) { if (!jobAds || jobAds.length === 0) {
return <div>No advertisements.</div>; return <div>No advertisements.</div>;
@@ -33,6 +56,11 @@ const renderData = (jobAds: JobAd[]) => {
? formatRelative(new Date(ad.autohide_at), new Date()) ? formatRelative(new Date(ad.autohide_at), new Date())
: "Disabled"} : "Disabled"}
</td> </td>
<td>
<StyledButton $colorOverride="red" buttonStyle="filled" onClick={() => confirmDelete(ad)}>
Delete
</StyledButton>
</td>
</tr> </tr>
))} ))}
</tbody> </tbody>
+6 -6
View File
@@ -8,6 +8,7 @@ import DatetimeWidget from "@components/Widgets/DatetimeWidget";
import SignupQuestionsWidget from "@components/Widgets/SignupQuestionsWidget/SignupQuestionsWidget"; import SignupQuestionsWidget from "@components/Widgets/SignupQuestionsWidget/SignupQuestionsWidget";
import MarkdownEditorWidget from "@components/Widgets/MarkdownEditorWidget"; import MarkdownEditorWidget from "@components/Widgets/MarkdownEditorWidget";
import { buildValidationSchema } from "@views/SignUpPage/FormUtils"; import { buildValidationSchema } from "@views/SignUpPage/FormUtils";
import { toast } from "react-toastify";
const DEFAULT_EMAIL = `Moikka, const DEFAULT_EMAIL = `Moikka,
@@ -98,7 +99,6 @@ const buildUISchema = () => {
const SignupCreatePage: NextPage = () => { const SignupCreatePage: NextPage = () => {
const [formData, setFormData] = useState<SignupForm>(null); const [formData, setFormData] = useState<SignupForm>(null);
const [error, setError] = useState<string>(null); const [error, setError] = useState<string>(null);
const [statusMessage, setStatusMessage] = useState<string>(null);
const router = useRouter(); const router = useRouter();
@@ -133,26 +133,28 @@ const SignupCreatePage: NextPage = () => {
if (payload.id === undefined) { if (payload.id === undefined) {
const resp = await SignupApi.createForm(payload); const resp = await SignupApi.createForm(payload);
setStatusMessage("Sign-up created successfully"); toast.success("Sign-up created successfully 😎");
router.push("/admin/signups");
setFormData({ setFormData({
...resp, ...resp,
questions: JSON.stringify(resp.questions) as any, questions: JSON.stringify(resp.questions) as any,
}); });
} else { } else {
const resp = await SignupApi.updateForm(payload); const resp = await SignupApi.updateForm(payload);
setStatusMessage("Sign-up updated successfully"); toast.success("Sign-up updated successfully 😎");
router.push("/admin/signups");
setFormData({ setFormData({
...resp, ...resp,
questions: JSON.stringify(resp.questions) as any, questions: JSON.stringify(resp.questions) as any,
}); });
} }
} catch (err) { } catch (err) {
toast.error("Uh oh! Something went wrong! Try again later. 😟");
setError(err); setError(err);
} }
}; };
const onChange = (data) => setFormData(data.formData); const onChange = (data) => setFormData(data.formData);
const onFocus = () => setStatusMessage(null);
const title = formData?.id const title = formData?.id
? `Edit Sign-up Form "${formData.title_fi}"` ? `Edit Sign-up Form "${formData.title_fi}"`
@@ -166,9 +168,7 @@ const SignupCreatePage: NextPage = () => {
schema={buildSchema(formData)} schema={buildSchema(formData)}
UISchema={buildUISchema()} UISchema={buildUISchema()}
onChange={onChange} onChange={onChange}
onFocus={onFocus}
onSubmit={onSubmit} onSubmit={onSubmit}
statusMessage={statusMessage}
error={error} error={error}
widgets={widgets} widgets={widgets}
/> />
+3 -9
View File
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { NextPage } from "next"; import { NextPage } from "next";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { toast } from "react-toastify";
import AdminCreateCommon from "@views/admin/AdminCreateCommon"; import AdminCreateCommon from "@views/admin/AdminCreateCommon";
import MarkdownEditorWidget from "@components/Widgets/MarkdownEditorWidget"; import MarkdownEditorWidget from "@components/Widgets/MarkdownEditorWidget";
import { SignupForm } from "@models/Signup"; import { SignupForm } from "@models/Signup";
@@ -63,33 +64,26 @@ const SignupEmailPage: NextPage = () => {
const signupForm = useInitializeData(id as string); const signupForm = useInitializeData(id as string);
const [error, setError] = useState<string>(null); const [error, setError] = useState<string>(null);
const [statusMessage, setStatusMessage] = useState<string>(null);
const onSubmit = async (data) => { const onSubmit = async (data) => {
try { try {
const payload = data.formData; const payload = data.formData;
await SignupApi.signupFormSendEmail(payload, Number(id)); await SignupApi.signupFormSendEmail(payload, Number(id));
setStatusMessage("Email sent successfully"); toast.success("Email sent successfully 😎");
} catch (err) { } catch (err) {
setError(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..."; const title = signupForm ? signupForm.title_fi : "Loading...";
return ( return (
<AdminCreateCommon <AdminCreateCommon
title={title} title={title}
// formData={formData}
schema={buildSchema(title)} schema={buildSchema(title)}
UISchema={buildUISchema()} UISchema={buildUISchema()}
// onChange={onChange}
onFocus={onFocus}
onSubmit={onSubmit} onSubmit={onSubmit}
statusMessage={statusMessage}
error={error} error={error}
widgets={widgets} widgets={widgets}
/> />
+7 -1
View File
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { NextPage } from "next"; import { NextPage } from "next";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { toast } from "react-toastify";
import styled from "styled-components"; import styled from "styled-components";
import { CSVLink } from "react-csv"; import { CSVLink } from "react-csv";
import AdminListCommon from "@views/admin/AdminListCommon"; import AdminListCommon from "@views/admin/AdminListCommon";
@@ -11,6 +12,10 @@ import noop from "@utils/noop";
const StyledButton = styled(Button) <{ $colorOverride: "red" | "green" }>` const StyledButton = styled(Button) <{ $colorOverride: "red" | "green" }>`
background-color: ${(p) => p.$colorOverride}; background-color: ${(p) => p.$colorOverride};
border-radius: 8px;
color: white;
font-size: 13px;
font-weight: bold;
`; `;
const SignupEmailPage: NextPage = () => { const SignupEmailPage: NextPage = () => {
@@ -33,8 +38,9 @@ const SignupEmailPage: NextPage = () => {
try { try {
await SignupApi.deleteSignup(signup.id); await SignupApi.deleteSignup(signup.id);
setSignups(signups.filter((s) => s.id !== signup.id)); setSignups(signups.filter((s) => s.id !== signup.id));
toast.success("Signup removed successfully 😎");
} catch (err) { } 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 React, { useEffect, useState } from "react";
import { NextPage } from "next"; import { NextPage } from "next";
import { formatRelative } from "date-fns"; import { formatRelative } from "date-fns";
import { toast } from "react-toastify";
import styled from "styled-components";
import AdminListCommon from "@views/admin/AdminListCommon"; import AdminListCommon from "@views/admin/AdminListCommon";
import { Link } from "@components/index"; import { Button, Link } from "@components/index";
import AddLink from "@components/AddLink"; import AddLink from "@components/AddLink";
import { SignupForm } from "@models/Signup"; import { SignupForm } from "@models/Signup";
import SignupApi from "@api/signupApi"; import SignupApi from "@api/signupApi";
const URL = "/admin/signups"; 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[]) => { const renderData = (signupForms: SignupForm[]) => {
if (!signupForms || signupForms.length === 0) { if (!signupForms || signupForms.length === 0) {
return <div>No signup forms.</div>; 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>{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}/list`}>View</Link></td>
<td><Link to={`${URL}/${signupForm.id}/email`}>Send</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> </tr>
))} ))}
</tbody> </tbody>
+16 -2
View File
@@ -8,6 +8,7 @@ import useFetchEvents from "@hooks/useFetchEvents";
import EventPageView from "@views/EventPage/EventPageView"; import EventPageView from "@views/EventPage/EventPageView";
import PageWrapper from "@views/common/PageWrapper"; import PageWrapper from "@views/common/PageWrapper";
import LoadingView from "@views/common/LoadingView"; import LoadingView from "@views/common/LoadingView";
import NotFoundPage from "@pages/404";
interface InitialProps { interface InitialProps {
initialEvent: Event; initialEvent: Event;
@@ -20,7 +21,13 @@ const EventPage: NextPage<InitialProps> = ({ initialEvent }) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const { data, error } = useFetchEvents({ initialData: initialEvent, id: id as string }); 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 ( return (
<> <>
@@ -50,12 +57,19 @@ export const getStaticPaths: GetStaticPaths = async () => {
export const getStaticProps: GetStaticProps<InitialProps> = async ({ params }) => { export const getStaticProps: GetStaticProps<InitialProps> = async ({ params }) => {
const { id } = 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 { return {
props: { props: {
initialEvent, initialEvent,
}, },
revalidate: 10, revalidate: 10,
notFound,
}; };
}; };
+17 -2
View File
@@ -8,6 +8,7 @@ import useFetchFeed from "@hooks/useFetchFeed";
import FeedPageView from "@views/FeedPage/FeedPageView"; import FeedPageView from "@views/FeedPage/FeedPageView";
import PageWrapper from "@views/common/PageWrapper"; import PageWrapper from "@views/common/PageWrapper";
import LoadingView from "@views/common/LoadingView"; import LoadingView from "@views/common/LoadingView";
import NotFoundPage from "@pages/404";
interface InitialProps { interface InitialProps {
initialPost: Post; initialPost: Post;
@@ -20,7 +21,13 @@ const FeedPage: NextPage<InitialProps> = ({ initialPost }) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
const { data, error } = useFetchFeed({ initialData: initialPost, id: id as string }); 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 ( return (
<> <>
@@ -50,12 +57,20 @@ export const getStaticPaths: GetStaticPaths = async () => {
export const getStaticProps: GetStaticProps<InitialProps> = async ({ params }) => { export const getStaticProps: GetStaticProps<InitialProps> = async ({ params }) => {
const { id } = 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 { return {
props: { props: {
initialPost, initialPost,
}, },
revalidate: 10, 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 { NextPage, GetStaticProps, GetStaticPaths } from "next";
import Head from "next/head"; import Head from "next/head";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { toast } from "react-toastify";
import { Signup, SignupForm } from "@models/Signup"; import { Signup, SignupForm } from "@models/Signup";
import SignupApi from "@api/signupApi"; import SignupApi from "@api/signupApi";
import SignUpPageView from "@views/SignUpPage/SignUpPageView"; import SignUpPageView from "@views/SignUpPage/SignUpPageView";
import PageWrapper from "@views/common/PageWrapper"; import PageWrapper from "@views/common/PageWrapper";
import LoadingView from "@views/common/LoadingView"; import LoadingView from "@views/common/LoadingView";
import noop from "@utils/noop"; import noop from "@utils/noop";
import NotFoundPage from "@pages/404";
type InitialProps = { type InitialProps = {
form: SignupForm; form: SignupForm;
@@ -15,12 +17,17 @@ type InitialProps = {
const SignUpPage: NextPage<InitialProps> = ({ form }) => { const SignUpPage: NextPage<InitialProps> = ({ form }) => {
const router = useRouter(); const router = useRouter();
const [statusMessage, setStatus] = useState(null);
if (router.isFallback) { if (router.isFallback) {
return <LoadingView />; return <LoadingView />;
} }
if (!form) {
return (
<NotFoundPage />
);
}
const onSubmit = async (data) => { const onSubmit = async (data) => {
const payload: Signup = { const payload: Signup = {
signupForm_id: form.id, signupForm_id: form.id,
@@ -29,11 +36,11 @@ const SignUpPage: NextPage<InitialProps> = ({ form }) => {
try { try {
await SignupApi.createSignup(payload); await SignupApi.createSignup(payload);
// TODO: Fetch/update signup list, so user sees the signup in the list toast.success("Sign-up submitted successfully 😎");
setStatus("Sign-up submitted successfully"); router.push(window.location.href); // TODO: Fetch/update signup list, so user sees the signup in the list
} catch (error) { } catch (error) {
console.error(error); console.error(error);
setStatus("Bad request"); toast.error("Uh oh! Sign-up failed! 😟");
} }
}; };
@@ -46,7 +53,6 @@ const SignUpPage: NextPage<InitialProps> = ({ form }) => {
<SignUpPageView <SignUpPageView
signUpForm={form} signUpForm={form}
formData={{}} formData={{}}
statusMessage={statusMessage}
onChange={noop} onChange={noop}
onSubmit={onSubmit} onSubmit={onSubmit}
/> />
@@ -71,12 +77,19 @@ export const getStaticPaths: GetStaticPaths = async () => {
export const getStaticProps: GetStaticProps<InitialProps> = async ({ params }) => { export const getStaticProps: GetStaticProps<InitialProps> = async ({ params }) => {
const { id } = 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 { return {
props: { props: {
form, form,
}, },
revalidate: 10, revalidate: 10,
notFound,
}; };
}; };
+3 -4
View File
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { NextPage } from "next"; import { NextPage } from "next";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { toast } from "react-toastify";
import { Signup, SignupForm } from "@models/Signup"; import { Signup, SignupForm } from "@models/Signup";
import SignupApi from "@api/signupApi"; import SignupApi from "@api/signupApi";
import SignUpPageView from "@views/SignUpPage/SignUpPageView"; import SignUpPageView from "@views/SignUpPage/SignUpPageView";
@@ -48,7 +49,6 @@ const useFetchSignup = (signupId: number, uuid: string) => {
const EditSignUpPage: NextPage = () => { const EditSignUpPage: NextPage = () => {
const router = useRouter(); const router = useRouter();
const { signupId, uuid } = parseQueryParams(router.query); const { signupId, uuid } = parseQueryParams(router.query);
const [statusMessage, setStatus] = useState(null);
const [form, formData] = useFetchSignup(signupId, uuid); const [form, formData] = useFetchSignup(signupId, uuid);
const onSubmit = async (data) => { const onSubmit = async (data) => {
@@ -61,10 +61,10 @@ const EditSignUpPage: NextPage = () => {
try { try {
await SignupApi.updateSignup(payload, uuid); await SignupApi.updateSignup(payload, uuid);
// TODO: Update signup list, so user sees possible changes in the list // 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) { } catch (error) {
console.error(error); console.error(error);
setStatus("Bad request"); toast.error("Uh oh! Updating sign-up failed! 😟");
} }
}; };
@@ -73,7 +73,6 @@ const EditSignUpPage: NextPage = () => {
<SignUpPageView <SignUpPageView
signUpForm={form} signUpForm={form}
formData={formData} formData={formData}
statusMessage={statusMessage}
onChange={noop} onChange={noop}
onSubmit={onSubmit} onSubmit={onSubmit}
/> />
+2 -3
View File
@@ -49,7 +49,6 @@ const ActualPageHero: React.FC = () => (
linkText="Yritysyhteistyö&nbsp;" linkText="Yritysyhteistyö&nbsp;"
/> />
<HeroAsideItem <HeroAsideItem
// TODO: Too long
header="Uusia suhteita ulkopaikkakuntalaisten kanssa" header="Uusia suhteita ulkopaikkakuntalaisten kanssa"
link="#ulkosuhteet" link="#ulkosuhteet"
linkText="Ulkoiset suhteet&nbsp;" linkText="Ulkoiset suhteet&nbsp;"
@@ -61,12 +60,12 @@ const ActualPageHero: React.FC = () => (
> >
<HeroSecondarySectionItem note="Ma"> <HeroSecondarySectionItem note="Ma">
<span> <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> </span>
</HeroSecondarySectionItem> </HeroSecondarySectionItem>
<HeroSecondarySectionItem note="To"> <HeroSecondarySectionItem note="To">
<span> <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> </span>
</HeroSecondarySectionItem> </HeroSecondarySectionItem>
</HeroSecondarySection> </HeroSecondarySection>
+12 -12
View File
@@ -55,10 +55,10 @@ const ActualPageView: React.FC<ActualPageViewProps> = ({ events, feed }) => (
presentationTime={5} presentationTime={5}
fadeTime={1} fadeTime={1}
images={[ images={[
"/img/carousel_images/elecyykka-jani-mannonen-6.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/elecyykka-jani-mannonen-6.jpg",
"/img/carousel_images/koydenveto-jani-mannonen-miika-koskela-17.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/koydenveto-jani-mannonen-miika-koskela-17.jpg",
"/img/carousel_images/koydenveto-jani-mannonen-miika-koskela-28.jpg", "https://static.sahkoinsinoorikilta.fi/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/koydenveto-jani-mannonen-miika-koskela-78.jpg",
]} ]}
width={400} width={400}
height={400} height={400}
@@ -67,10 +67,10 @@ const ActualPageView: React.FC<ActualPageViewProps> = ({ events, feed }) => (
presentationTime={5} presentationTime={5}
fadeTime={1} fadeTime={1}
images={[ images={[
"/img/carousel_images/koydenveto-mikko-haapamaki-33.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/koydenveto-mikko-haapamaki-33.jpg",
"/img/carousel_images/Varaslahto2020-AinoSuomi-73.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/Varaslahto2020-AinoSuomi-73.jpg",
"/img/carousel_images/varauksenpurku_2020_timitiira-80.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/varauksenpurku_2020_timitiira-80.jpg",
"/img/carousel_images/otatarhan-ajot-timi-tiira-172.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/otatarhan-ajot-timi-tiira-172.jpg",
]} ]}
width={400} width={400}
height={400} height={400}
@@ -79,10 +79,10 @@ const ActualPageView: React.FC<ActualPageViewProps> = ({ events, feed }) => (
presentationTime={5} presentationTime={5}
fadeTime={1} fadeTime={1}
images={[ images={[
"/img/carousel_images/kokkarit_kiia_einola-0631.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/kokkarit_kiia_einola-0631.jpg",
"/img/carousel_images/pota-jatkot-essi-jukkala-29.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/pota-jatkot-essi-jukkala-29.jpg",
"/img/carousel_images/pota99-paajuhla-oskari-lahti-171.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/pota99-paajuhla-oskari-lahti-171.jpg",
"/img/carousel_images/wappusitsit-jani-mannonen-29.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/wappusitsit-jani-mannonen-29.jpg",
]} ]}
width={400} width={400}
height={400} height={400}
+58 -34
View File
@@ -1,8 +1,8 @@
import React from "react"; import React from "react";
import styled from "styled-components"; import styled from "styled-components";
import CommitteeContainer from "@components/CommitteeContainer";
import { Divider, TextSection, Link } from "@components/index"; import { Divider, TextSection, Link } from "@components/index";
import { colors } from "@theme/colors"; import { colors } from "@theme/colors";
import ContactCard from "@components/ContactCard";
import BoardJson from "./board.json"; import BoardJson from "./board.json";
import HvtmkJson from "./hvtmk.json"; import HvtmkJson from "./hvtmk.json";
@@ -15,6 +15,8 @@ import TtmkJson from "./ttmk.json";
import UtmkJson from "./utmk.json"; import UtmkJson from "./utmk.json";
import YtmkJson from "./ytmk.json"; import YtmkJson from "./ytmk.json";
const blank_profile = "/img/blank_profile.png";
const BlueLink = styled(Link)` const BlueLink = styled(Link)`
color: ${colors.blue1}; 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_fi: string;
name_en: string; name_en: string;
roles: Array<Role>; roles: Array<Role>;
} }
export interface Role { interface Role {
name_fi: string; name_fi: string;
name_en: string; name_en: string;
representatives: Array<Representative> representatives: Array<Representative>
} }
export interface Representative { interface Representative {
name: string; name: string;
phone_number?: string; phone_number?: string;
email?: string; email?: string;
@@ -45,6 +87,7 @@ export interface Representative {
const ContactsPageView: React.FC = () => ( const ContactsPageView: React.FC = () => (
<> <>
<TextSection> <TextSection>
<h1>Yhteystiedot</h1>
<p> <p>
Asiaa olisi, mutta kehen ottaa yhteyttä?<br /> Asiaa olisi, mutta kehen ottaa yhteyttä?<br />
Tämä sivu yrittää valottaa sen oikean ihmisen puhelinnumeroa ja sähköpostiosoitetta. Tämä sivu yrittää valottaa sen oikean ihmisen puhelinnumeroa ja sähköpostiosoitetta.
@@ -52,87 +95,68 @@ const ContactsPageView: React.FC = () => (
</TextSection> </TextSection>
<TextSection> <TextSection>
<div> <CommitteeContainer committee={BoardJson}>
<CommitteeContainer committee={BoardJson} />
<p> <p>
{"Hallitukseen saa yhteyden lähettämällä sähköpostia "} {"Hallitukseen saa yhteyden lähettämällä sähköpostia "}
<BlueLink to="mailto:hallitus@sahkoinsinoorikilta.fi"> <BlueLink to="mailto:hallitus@sahkoinsinoorikilta.fi">
hallitus@sahkoinsinoorikilta.fi hallitus@sahkoinsinoorikilta.fi
</BlueLink> </BlueLink>
</p> </p>
</div> </CommitteeContainer>
</TextSection> </TextSection>
<Divider /> <Divider />
<TextSection> <TextSection>
<div> <CommitteeContainer committee={HvtmkJson} />
<CommitteeContainer committee={HvtmkJson} />
</div>
</TextSection> </TextSection>
<Divider /> <Divider />
<TextSection> <TextSection>
<div> <CommitteeContainer committee={MtmkJson} />
<CommitteeContainer committee={MtmkJson} />
</div>
</TextSection> </TextSection>
<Divider /> <Divider />
<TextSection> <TextSection>
<div> <CommitteeContainer committee={OptmkJson} />
<CommitteeContainer committee={OptmkJson} />
</div>
</TextSection> </TextSection>
<Divider /> <Divider />
<TextSection> <TextSection>
<div> <CommitteeContainer committee={OtmkJson} />
<CommitteeContainer committee={OtmkJson} />
</div>
</TextSection> </TextSection>
<Divider /> <Divider />
<TextSection id="eptmk"> <TextSection id="eptmk">
<div> <CommitteeContainer committee={PtmkJson} />
<CommitteeContainer committee={PtmkJson} />
</div>
</TextSection> </TextSection>
<Divider /> <Divider />
<TextSection> <TextSection>
<div> <CommitteeContainer committee={SstmkJson} />
<CommitteeContainer committee={SstmkJson} />
</div>
</TextSection> </TextSection>
<Divider /> <Divider />
<TextSection id="ttmk"> <TextSection id="ttmk">
<div> <CommitteeContainer committee={TtmkJson} />
<CommitteeContainer committee={TtmkJson} />
</div>
</TextSection> </TextSection>
<Divider /> <Divider />
<TextSection> <TextSection>
<div> <CommitteeContainer committee={UtmkJson} />
<CommitteeContainer committee={UtmkJson} />
</div>
</TextSection> </TextSection>
<Divider /> <Divider />
<TextSection> <TextSection>
<div> <CommitteeContainer committee={YtmkJson} />
<CommitteeContainer committee={YtmkJson} />
</div>
</TextSection> </TextSection>
<Divider /> <Divider />
+14 -13
View File
@@ -7,7 +7,8 @@
"name_en": "Chairman of the Board", "name_en": "Chairman of the Board",
"representatives": [ "representatives": [
{ {
"name": "Johannes Ora" "name": "Johannes Ora",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/chairman.jpg"
} }
] ]
}, },
@@ -19,7 +20,7 @@
"name": "Salla Lyytikäinen", "name": "Salla Lyytikäinen",
"phone_number": null, "phone_number": null,
"email": null, "email": null,
"image": null "image": "https://static.sahkoinsinoorikilta.fi/img/board/secretary.jpg"
} }
] ]
}, },
@@ -31,7 +32,7 @@
"name": "Santeri Huhtala", "name": "Santeri Huhtala",
"phone_number": null, "phone_number": null,
"email": null, "email": null,
"image": null "image": "https://static.sahkoinsinoorikilta.fi/img/board/treasurer.jpg"
} }
] ]
}, },
@@ -43,7 +44,7 @@
"name": "Toni Ojala", "name": "Toni Ojala",
"phone_number": null, "phone_number": null,
"email": null, "email": null,
"image": null "image": "https://static.sahkoinsinoorikilta.fi/img/board/captain1.jpg"
} }
] ]
}, },
@@ -55,7 +56,7 @@
"name": "Toni Lyttinen", "name": "Toni Lyttinen",
"phone_number": null, "phone_number": null,
"email": null, "email": null,
"image": null "image": "https://static.sahkoinsinoorikilta.fi/img/board/captain2.jpg"
} }
] ]
}, },
@@ -67,7 +68,7 @@
"name": "Eveliina Ahonen", "name": "Eveliina Ahonen",
"phone_number": null, "phone_number": null,
"email": null, "email": null,
"image": null "image": "https://static.sahkoinsinoorikilta.fi/img/board/ceremonies.jpg"
} }
] ]
}, },
@@ -79,7 +80,7 @@
"name": "Melisa Dönmez", "name": "Melisa Dönmez",
"phone_number": null, "phone_number": null,
"email": null, "email": null,
"image": null "image": "https://static.sahkoinsinoorikilta.fi/img/board/court_cancelor.jpg"
} }
] ]
}, },
@@ -91,7 +92,7 @@
"name": "Heidi Mäkitalo", "name": "Heidi Mäkitalo",
"phone_number": null, "phone_number": null,
"email": null, "email": null,
"image": null "image": "https://static.sahkoinsinoorikilta.fi/img/board/isocoordinator.jpg"
} }
] ]
}, },
@@ -103,7 +104,7 @@
"name": "Sauli Norja", "name": "Sauli Norja",
"phone_number": null, "phone_number": null,
"email": null, "email": null,
"image": null "image": "https://static.sahkoinsinoorikilta.fi/img/board/wellbeing.jpg"
} }
] ]
}, },
@@ -115,7 +116,7 @@
"name": "Simo Hakanummi", "name": "Simo Hakanummi",
"phone_number": null, "phone_number": null,
"email": null, "email": null,
"image": null "image": "https://static.sahkoinsinoorikilta.fi/img/board/studies.jpg"
} }
] ]
}, },
@@ -127,7 +128,7 @@
"name": "Oskari Ponkala", "name": "Oskari Ponkala",
"phone_number": null, "phone_number": null,
"email": null, "email": null,
"image": null "image": "https://static.sahkoinsinoorikilta.fi/img/board/technology.jpg"
} }
] ]
}, },
@@ -139,7 +140,7 @@
"name": "Oliver Hiekkamies", "name": "Oliver Hiekkamies",
"phone_number": null, "phone_number": null,
"email": null, "email": null,
"image": null "image": "https://static.sahkoinsinoorikilta.fi/img/board/external.jpg"
} }
] ]
}, },
@@ -151,7 +152,7 @@
"name": "Otto Julkunen", "name": "Otto Julkunen",
"phone_number": null, "phone_number": null,
"email": 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)` const StyledTextSection = styled(TextSection)`
margin: auto;
align-items: center; align-items: center;
& > h1 { & > h1 {
@@ -24,6 +23,17 @@ const StyledTextSection = styled(TextSection)`
color: ${colors.orange1}; color: ${colors.orange1};
} }
} }
& > div {
margin: auto;
& > p {
font-size: 0.9rem;
font-weight: bold;
line-height: 0.4rem;
}
}
`; `;
const SignupButtons = styled.div` const SignupButtons = styled.div`
@@ -38,6 +48,8 @@ const Content = styled(MarkdownStyles)`
const EventPageView: React.FC<EventPageViewProps> = ({ event }) => { const EventPageView: React.FC<EventPageViewProps> = ({ event }) => {
if (!event) return <LoadingView />; 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 ( return (
<StyledTextSection> <StyledTextSection>
<h1> <h1>
@@ -48,13 +60,23 @@ const EventPageView: React.FC<EventPageViewProps> = ({ event }) => {
<Image <Image
src={event.image || event.tags[0].icon} src={event.image || event.tags[0].icon}
alt={event.title_fi} alt={event.title_fi}
objectFit="scale-down"
layout="responsive" layout="responsive"
width={0} width={16}
height={0} height={9}
/> />
</h1> </h1>
<div> <div>
<Content source={event.content_fi} escapeHtml={false} /> <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 */} {/* We may have multiple signup forms. Generate own Button for each one */}
<SignupButtons> <SignupButtons>
{event.signupForm.map((sf) => ( {event.signupForm.map((sf) => (
+8 -8
View File
@@ -18,14 +18,14 @@ import noop from "@utils/noop";
import FrontPageHero from "./FrontPageHero"; import FrontPageHero from "./FrontPageHero";
// Corporate logos import // Corporate logos import
const ABB = "/img/corporate_logos/abb.png"; const ABB = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/abb.jpg";
const Caruna = "/img/corporate_logos/caruna.jpg"; const Caruna = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/caruna.jpg";
const Eaton = "/img/corporate_logos/eaton.png"; const Eaton = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/eaton.jpg";
const Ensto = "/img/corporate_logos/ensto.jpg"; const Ensto = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/ensto.jpg";
const eSett = "/img/corporate_logos/esett.png"; const eSett = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/esett.jpg";
const Fingrid = "/img/corporate_logos/fingrid.jpg"; const Fingrid = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/fingrid.jpg";
const NRCGroup = "/img/corporate_logos/nrcgroup.png"; const NRCGroup = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/nrcgroup.jpg";
const Okmetic = "/img/corporate_logos/okmetic.png"; const Okmetic = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/okmetic.jpg";
interface FrontPageViewProps { interface FrontPageViewProps {
events: Event[]; events: Event[];
+18 -25
View File
@@ -80,13 +80,10 @@ const InEnglishPageView: React.FC<InEnglishPageViewProps> = ({ events, feed }) =
presentationTime={5} presentationTime={5}
fadeTime={1} fadeTime={1}
images={[ images={[
"https://static.sahkoinsinoorikilta.fi/img/carousel_images/elecyykka-jani-mannonen-6.jpg",
"/img/carousel_images/in_english/ulkoexcursio1-kiia-einola-3.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/koydenveto-jani-mannonen-miika-koskela-17.jpg",
"/img/carousel_images/in_english/international-sitsit-jani-mannonen-8.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/koydenveto-jani-mannonen-miika-koskela-28.jpg",
"/img/carousel_images/in_english/ulkoexcursio-kiia-einola-16.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/koydenveto-jani-mannonen-miika-koskela-78.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",
]} ]}
width={400} width={400}
height={400} height={400}
@@ -95,12 +92,10 @@ const InEnglishPageView: React.FC<InEnglishPageViewProps> = ({ events, feed }) =
presentationTime={5} presentationTime={5}
fadeTime={1} fadeTime={1}
images={[ images={[
"/img/carousel_images/in_english/international-sitsit-jani-mannonen-8.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/koydenveto-mikko-haapamaki-33.jpg",
"/img/carousel_images/in_english/Kaukkarit-2020-Elias-Hirvonen-44.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/Varaslahto2020-AinoSuomi-73.jpg",
"/img/carousel_images/in_english/koydenveto-jani-mannonen-miika-koskela-4.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/varauksenpurku_2020_timitiira-80.jpg",
"/img/carousel_images/in_english/ulkoexcursio-kiia-einola-16.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/otatarhan-ajot-timi-tiira-172.jpg",
"/img/carousel_images/in_english/haalarigaala-jani-mannonen-1.jpg",
"/img/carousel_images/in_english/ulkoexcursio1-kiia-einola-3.jpg",
]} ]}
width={400} width={400}
height={400} height={400}
@@ -109,12 +104,10 @@ const InEnglishPageView: React.FC<InEnglishPageViewProps> = ({ events, feed }) =
presentationTime={5} presentationTime={5}
fadeTime={1} fadeTime={1}
images={[ images={[
"/img/carousel_images/in_english/haalarigaala-jani-mannonen-1.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/kokkarit_kiia_einola-0631.jpg",
"/img/carousel_images/in_english/ulkoexcursio1-kiia-einola-3.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/pota-jatkot-essi-jukkala-29.jpg",
"/img/carousel_images/in_english/international-sitsit-jani-mannonen-8.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/pota99-paajuhla-oskari-lahti-171.jpg",
"/img/carousel_images/in_english/Kaukkarit-2020-Elias-Hirvonen-44.jpg", "https://static.sahkoinsinoorikilta.fi/img/carousel_images/wappusitsit-jani-mannonen-29.jpg",
"/img/carousel_images/in_english/koydenveto-jani-mannonen-miika-koskela-4.jpg",
"/img/carousel_images/in_english/ulkoexcursio-kiia-einola-16.jpg",
]} ]}
width={400} width={400}
height={400} height={400}
@@ -145,8 +138,8 @@ const InEnglishPageView: React.FC<InEnglishPageViewProps> = ({ events, feed }) =
presentationTime={5} presentationTime={5}
fadeTime={1} fadeTime={1}
images={[ images={[
"/img/carousel_images/in_english/tour/qtour1.jpg", "https://static.sahkoinsinoorikilta.fi/img/tour/qtour1.jpg",
"/img/carousel_images/in_english/tour/qtour2.jpg", "https://static.sahkoinsinoorikilta.fi/img/tour/qtour2.jpg",
]} ]}
width={400} width={400}
height={400} height={400}
@@ -155,8 +148,8 @@ const InEnglishPageView: React.FC<InEnglishPageViewProps> = ({ events, feed }) =
presentationTime={5} presentationTime={5}
fadeTime={1} fadeTime={1}
images={[ images={[
"/img/carousel_images/in_english/tour/qtour3.jpg", "https://static.sahkoinsinoorikilta.fi/img/tour/qtour3.jpg",
"/img/carousel_images/in_english/tour/qtour4.jpg", "https://static.sahkoinsinoorikilta.fi/img/tour/qtour4.jpg",
]} ]}
width={400} width={400}
height={400} height={400}
@@ -165,8 +158,8 @@ const InEnglishPageView: React.FC<InEnglishPageViewProps> = ({ events, feed }) =
presentationTime={5} presentationTime={5}
fadeTime={1} fadeTime={1}
images={[ images={[
"/img/carousel_images/in_english/tour/qtour5.jpg", "https://static.sahkoinsinoorikilta.fi/img/tour/qtour5.jpg",
"/img/carousel_images/in_english/tour/qtour1.jpg", "https://static.sahkoinsinoorikilta.fi/img/tour/qtour1.jpg",
]} ]}
width={400} width={400}
height={400} height={400}
+40 -24
View File
@@ -18,22 +18,23 @@ const customWidgets = {
interface SignUpPageViewProps { interface SignUpPageViewProps {
signUpForm: SignupForm; signUpForm: SignupForm;
formData: any; formData: any;
statusMessage: string;
onChange: (e: IChangeEvent<unknown>, es?: ErrorSchema) => unknown; onChange: (e: IChangeEvent<unknown>, es?: ErrorSchema) => unknown;
onSubmit: (e: ISubmitEvent<unknown>) => unknown; onSubmit: (e: ISubmitEvent<unknown>) => unknown;
} }
const renderList = (signUpForm: SignupForm) => ( const renderList = (signUpForm: SignupForm) => (
<> <aside>
<h6> <div>
Ilmoittautuneet{signUpForm.quota > 0 && (` (${signUpForm.signups.length}/${signUpForm.quota})`)}: <h6>
</h6> Ilmoittautuneet{signUpForm.quota > 0 && (` (${signUpForm.signups.length}/${signUpForm.quota})`)}:
<ol> </h6>
{signUpForm.signups.map((s, idx) => ( <ol>
<li key={idx} className={signUpForm.quota && idx + 1 > signUpForm.quota ? "reserved" : ""}>{s}</li> {signUpForm.signups.map((s, idx) => (
))} <li key={idx} className={signUpForm.quota && idx + 1 > signUpForm.quota ? "reserved" : ""}>{s}</li>
</ol> ))}
</> </ol>
</div>
</aside>
); );
const StyledSection = styled(TextSection)` const StyledSection = styled(TextSection)`
@@ -62,7 +63,6 @@ const StyledSection = styled(TextSection)`
const SignUpPageView: React.FC<SignUpPageViewProps> = ({ const SignUpPageView: React.FC<SignUpPageViewProps> = ({
signUpForm, signUpForm,
formData, formData,
statusMessage,
onChange, onChange,
onSubmit, onSubmit,
}) => { }) => {
@@ -83,11 +83,34 @@ const SignUpPageView: React.FC<SignUpPageViewProps> = ({
); );
}; };
const form = signUpForm ? renderForm() : ( let form: JSX.Element;
<Loader $color={colors.darkBlue} /> 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 ( return (
<StyledSection> <StyledSection>
<h1> <h1>
@@ -97,16 +120,9 @@ const SignUpPageView: React.FC<SignUpPageViewProps> = ({
</h1> </h1>
<div> <div>
<span className="sign-up-statusmessage">
{statusMessage}
</span>
{form} {form}
</div> </div>
<aside> {signups}
<div>
{signups}
</div>
</aside>
</StyledSection> </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` const ErrorMsg = styled.p`
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
border: 1px solid ${colors.orange2}; border: 1px solid ${colors.orange2};
@@ -44,9 +36,8 @@ type AdminCreateCommonProps = {
[name: string]: unknown; [name: string]: unknown;
}; };
onChange?: (e: IChangeEvent<FormTypes>, es?: ErrorSchema) => 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; onSubmit: (e: ISubmitEvent<FormTypes>) => unknown;
statusMessage: string;
error: string; error: string;
widgets: { widgets: {
[name: string]: any; [name: string]: any;
@@ -61,7 +52,6 @@ const AdminCreateCommon: React.FC<AdminCreateCommonProps> = ({
onChange, onChange,
onFocus, onFocus,
onSubmit, onSubmit,
statusMessage,
error, error,
widgets, widgets,
}) => { }) => {
@@ -74,9 +64,6 @@ const AdminCreateCommon: React.FC<AdminCreateCommonProps> = ({
<AdminPageWrapper requiresAuthentication> <AdminPageWrapper requiresAuthentication>
<Common> <Common>
<h1>{title}</h1> <h1>{title}</h1>
{statusMessage && (
<SuccessMsg data-e2e="admin-form-status-message">{statusMessage}</SuccessMsg>
)}
<FormWrapper <FormWrapper
schema={schema} schema={schema}
uiSchema={UISchema} uiSchema={UISchema}
-2
View File
@@ -5,8 +5,6 @@ services:
image: registry.gitlab.com/sahkoinsinoorikilta/vtmk/web2.0-frontend:latest image: registry.gitlab.com/sahkoinsinoorikilta/vtmk/web2.0-frontend:latest
deploy: deploy:
replicas: 1 replicas: 1
restart_policy:
condition: on-failure
update_config: update_config:
order: start-first order: start-first
ports: ports:
-2
View File
@@ -5,8 +5,6 @@ services:
image: registry.gitlab.com/sahkoinsinoorikilta/vtmk/web2.0-frontend:prod image: registry.gitlab.com/sahkoinsinoorikilta/vtmk/web2.0-frontend:prod
deploy: deploy:
replicas: 1 replicas: 1
restart_policy:
condition: on-failure
update_config: update_config:
order: start-first order: start-first
ports: 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 // eslint-disable-next-line no-param-reassign
t.fixtureCtx.eventId = parsed.id; t.fixtureCtx.eventId = parsed.id;
const statusMessage = Selector("[data-e2e=\"admin-form-status-message\"]"); const statusMessage = Selector(".Toastify__toast-body");
await t await t
.hover(statusMessage) .hover(statusMessage)
.expect( .expect(
statusMessage.innerText, 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 // eslint-disable-next-line no-param-reassign
t.fixtureCtx.formId = parsed.id; t.fixtureCtx.formId = parsed.id;
const statusMessage = Selector("[data-e2e=\"admin-form-status-message\"]"); const statusMessage = Selector(".Toastify__toast-body");
await t await t
.hover(statusMessage) .hover(statusMessage)
.expect( .expect(
statusMessage.innerText, 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)); await t.click(Selector("button").nth(-1));
const statusMessage = Selector(".sign-up-statusmessage"); const statusMessage = Selector(".Toastify__toast-body");
await t await t
.hover(statusMessage) .hover(statusMessage)
.expect( .expect(
statusMessage.innerText, statusMessage.innerText,
).eql("Sign-up submitted successfully"); ).eql("Sign-up submitted successfully 😎");
}); });