Merge branch 'i18n' into 'master'

i18n support for event, post and job ads

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!51

(cherry picked from commit 9e7fe73c04)

39104f70 install localisation library
7ce9f384 translate event page contents
9bec3f1e translate calendars
feaaa981 translate feed page
1f7d842b fix news button translation
ac0d33ef fix e2e tests
4eeb798d add getStaticProps to use static optimization
This commit is contained in:
Aarni Halinen
2021-04-01 15:54:01 +00:00
parent 7e0b0d2ae8
commit 0e98ea0b32
32 changed files with 721 additions and 111 deletions
+3
View File
@@ -4,6 +4,9 @@ const withBundleAnalyzer = require("@next/bundle-analyzer")({
module.exports = withBundleAnalyzer({ module.exports = withBundleAnalyzer({
target: "server", target: "server",
publicRuntimeConfig: {
localeSubpaths: {},
},
images: { images: {
domains: [ domains: [
"sahkoinsinoorikilta.fi", "sahkoinsinoorikilta.fi",
+389
View File
@@ -15,6 +15,7 @@
"js-cookie": "2.2.1", "js-cookie": "2.2.1",
"lodash": "4.17.21", "lodash": "4.17.21",
"next": "10.1.2", "next": "10.1.2",
"next-i18next": "7.0.1",
"normalize.css": "8.0.1", "normalize.css": "8.0.1",
"react": "17.0.1", "react": "17.0.1",
"react-beautiful-dnd": "13.1.0", "react-beautiful-dnd": "13.1.0",
@@ -1887,6 +1888,23 @@
"postcss-syntax": ">=0.36.2" "postcss-syntax": ">=0.36.2"
} }
}, },
"node_modules/@types/body-parser": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
"integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==",
"dependencies": {
"@types/connect": "*",
"@types/node": "*"
}
},
"node_modules/@types/connect": {
"version": "3.4.34",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz",
"integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/error-stack-parser": { "node_modules/@types/error-stack-parser": {
"version": "1.3.18", "version": "1.3.18",
"resolved": "https://registry.npmjs.org/@types/error-stack-parser/-/error-stack-parser-1.3.18.tgz", "resolved": "https://registry.npmjs.org/@types/error-stack-parser/-/error-stack-parser-1.3.18.tgz",
@@ -1899,6 +1917,27 @@
"integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
"dev": true "dev": true
}, },
"node_modules/@types/express": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.11.tgz",
"integrity": "sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg==",
"dependencies": {
"@types/body-parser": "*",
"@types/express-serve-static-core": "^4.17.18",
"@types/qs": "*",
"@types/serve-static": "*"
}
},
"node_modules/@types/express-serve-static-core": {
"version": "4.17.19",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.19.tgz",
"integrity": "sha512-DJOSHzX7pCiSElWaGR8kCprwibCB/3yW6vcT8VG3P0SJjnv19gnWG/AZMfM60Xj/YJIp/YCaDHyvzsFVeniARA==",
"dependencies": {
"@types/node": "*",
"@types/qs": "*",
"@types/range-parser": "*"
}
},
"node_modules/@types/glob": { "node_modules/@types/glob": {
"version": "7.1.3", "version": "7.1.3",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz",
@@ -1950,6 +1989,11 @@
"@types/unist": "*" "@types/unist": "*"
} }
}, },
"node_modules/@types/mime": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw=="
},
"node_modules/@types/minimatch": { "node_modules/@types/minimatch": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz",
@@ -1984,6 +2028,16 @@
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
"integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
}, },
"node_modules/@types/qs": {
"version": "6.9.6",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz",
"integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA=="
},
"node_modules/@types/range-parser": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
"integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA=="
},
"node_modules/@types/react": { "node_modules/@types/react": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.2.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.2.tgz",
@@ -2041,6 +2095,15 @@
"redux": "^4.0.0" "redux": "^4.0.0"
} }
}, },
"node_modules/@types/serve-static": {
"version": "1.13.9",
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz",
"integrity": "sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==",
"dependencies": {
"@types/mime": "^1",
"@types/node": "*"
}
},
"node_modules/@types/shortid": { "node_modules/@types/shortid": {
"version": "0.0.29", "version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/shortid/-/shortid-0.0.29.tgz", "resolved": "https://registry.npmjs.org/@types/shortid/-/shortid-0.0.29.tgz",
@@ -6343,6 +6406,14 @@
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
"dev": true "dev": true
}, },
"node_modules/html-parse-stringify2": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/html-parse-stringify2/-/html-parse-stringify2-2.0.1.tgz",
"integrity": "sha1-3FZwtyksoVi3vJFsmmc1rIhyg0o=",
"dependencies": {
"void-elements": "^2.0.1"
}
},
"node_modules/html-tags": { "node_modules/html-tags": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz", "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz",
@@ -6443,6 +6514,40 @@
"node": ">= 10" "node": ">= 10"
} }
}, },
"node_modules/i18next": {
"version": "19.9.2",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-19.9.2.tgz",
"integrity": "sha512-0i6cuo6ER6usEOtKajUUDj92zlG+KArFia0857xxiEHAQcUwh/RtOQocui1LPJwunSYT574Pk64aNva1kwtxZg==",
"dependencies": {
"@babel/runtime": "^7.12.0"
}
},
"node_modules/i18next-browser-languagedetector": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-5.0.1.tgz",
"integrity": "sha512-7K4A6DJ2rNz3Yd835Y493UgkzUxgpGsCeIMKLGkt6Ps0cbgSaJ+LdATFNFA+ujp2brmsUM9BeDThXKhabXUbUw==",
"dependencies": {
"@babel/runtime": "^7.5.5"
}
},
"node_modules/i18next-fs-backend": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-1.1.1.tgz",
"integrity": "sha512-RFkfy10hNxJqc7MVAp5iAZq0Tum6msBCNebEe3OelOBvrROvzHUPaR8Qe10RQrOGokTm0W4vJGEJzruFkEt+hQ=="
},
"node_modules/i18next-http-backend": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-1.2.1.tgz",
"integrity": "sha512-9L2sa+wybqi57/+VsrJPo5DCI7WLoudaK12xz0okYSmsi3Izyj7sCgrYL52WHy/O3BFY9HGORBwSwlD1WYuH6Q==",
"dependencies": {
"node-fetch": "2.6.1"
}
},
"node_modules/i18next-http-middleware": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/i18next-http-middleware/-/i18next-http-middleware-3.1.0.tgz",
"integrity": "sha512-65rP8bi5b7znBzfgIUy0KE00SWg1X6mL5XEkassgTrjAeLSfSb4vQ2bs9cN3qwHCynKIpmHjmNDu5c8NylTVmw=="
},
"node_modules/iconv-lite": { "node_modules/iconv-lite": {
"version": "0.6.2", "version": "0.6.2",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
@@ -8162,6 +8267,46 @@
} }
} }
}, },
"node_modules/next-i18next": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/next-i18next/-/next-i18next-7.0.1.tgz",
"integrity": "sha512-x97lSfB11q/5Flf1Ocz02WoXeIRuVi7oJQ+8p9kNSfoIJExz1nTLPpJmWr2SF8wDxaljzL/kjlETUOyptGhSjQ==",
"dependencies": {
"@types/express": "^4.16.1",
"core-js": "^3",
"hoist-non-react-statics": "^3.2.0",
"i18next": "^19.6.3",
"i18next-browser-languagedetector": "^5.0.0",
"i18next-fs-backend": "^1.0.7",
"i18next-http-backend": "^1.0.17",
"i18next-http-middleware": "^3.0.2",
"path-match": "^1.2.4",
"prop-types": "^15.6.2",
"react-i18next": "^11.7.3",
"url": "^0.11.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/isaachinman"
},
"peerDependencies": {
"next": ">= 9.5.0",
"react": ">= 16.8.0"
}
},
"node_modules/next-i18next/node_modules/core-js": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.10.0.tgz",
"integrity": "sha512-MQx/7TLgmmDVamSyfE+O+5BHvG1aUGj/gHhLn1wVtm2B5u1eVIPvh7vkfjwWKNCjrTJB8+He99IntSQ1qP+vYQ==",
"hasInstallScript": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/core-js"
}
},
"node_modules/next-sitemap": { "node_modules/next-sitemap": {
"version": "1.6.18", "version": "1.6.18",
"resolved": "https://registry.npmjs.org/next-sitemap/-/next-sitemap-1.6.18.tgz", "resolved": "https://registry.npmjs.org/next-sitemap/-/next-sitemap-1.6.18.tgz",
@@ -9173,12 +9318,51 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/path-match": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/path-match/-/path-match-1.2.4.tgz",
"integrity": "sha1-pidH88fgwlFHYml/JEQ1hbCRAOo=",
"dependencies": {
"http-errors": "~1.4.0",
"path-to-regexp": "^1.0.0"
}
},
"node_modules/path-match/node_modules/http-errors": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.4.0.tgz",
"integrity": "sha1-bAJC3qaz33r9oVPHEImzHG6Cqr8=",
"dependencies": {
"inherits": "2.0.1",
"statuses": ">= 1.2.1 < 2"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/path-match/node_modules/inherits": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
"integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
},
"node_modules/path-parse": { "node_modules/path-parse": {
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
"dev": true "dev": true
}, },
"node_modules/path-to-regexp": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
"integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
"dependencies": {
"isarray": "0.0.1"
}
},
"node_modules/path-to-regexp/node_modules/isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
},
"node_modules/path-type": { "node_modules/path-type": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
@@ -10268,6 +10452,19 @@
"react": "17.0.1" "react": "17.0.1"
} }
}, },
"node_modules/react-i18next": {
"version": "11.8.12",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.8.12.tgz",
"integrity": "sha512-M2PSVP9MzT/7yofXfCOF5gAVotinrM4BXWiguk8uFSznJsfFzTjrp3K9CBWcXitpoCBVZGZJ2AnbaWGSNkJqfw==",
"dependencies": {
"@babel/runtime": "^7.13.6",
"html-parse-stringify2": "^2.0.1"
},
"peerDependencies": {
"i18next": ">= 19.0.0",
"react": ">= 16.8.0"
}
},
"node_modules/react-is": { "node_modules/react-is": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@@ -14074,6 +14271,14 @@
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ=="
}, },
"node_modules/void-elements": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
"integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/watchpack": { "node_modules/watchpack": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.1.tgz", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.1.tgz",
@@ -15944,6 +16149,23 @@
"unist-util-find-all-after": "^3.0.2" "unist-util-find-all-after": "^3.0.2"
} }
}, },
"@types/body-parser": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
"integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==",
"requires": {
"@types/connect": "*",
"@types/node": "*"
}
},
"@types/connect": {
"version": "3.4.34",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz",
"integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==",
"requires": {
"@types/node": "*"
}
},
"@types/error-stack-parser": { "@types/error-stack-parser": {
"version": "1.3.18", "version": "1.3.18",
"resolved": "https://registry.npmjs.org/@types/error-stack-parser/-/error-stack-parser-1.3.18.tgz", "resolved": "https://registry.npmjs.org/@types/error-stack-parser/-/error-stack-parser-1.3.18.tgz",
@@ -15956,6 +16178,27 @@
"integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
"dev": true "dev": true
}, },
"@types/express": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.11.tgz",
"integrity": "sha512-no+R6rW60JEc59977wIxreQVsIEOAYwgCqldrA/vkpCnbD7MqTefO97lmoBe4WE0F156bC4uLSP1XHDOySnChg==",
"requires": {
"@types/body-parser": "*",
"@types/express-serve-static-core": "^4.17.18",
"@types/qs": "*",
"@types/serve-static": "*"
}
},
"@types/express-serve-static-core": {
"version": "4.17.19",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.19.tgz",
"integrity": "sha512-DJOSHzX7pCiSElWaGR8kCprwibCB/3yW6vcT8VG3P0SJjnv19gnWG/AZMfM60Xj/YJIp/YCaDHyvzsFVeniARA==",
"requires": {
"@types/node": "*",
"@types/qs": "*",
"@types/range-parser": "*"
}
},
"@types/glob": { "@types/glob": {
"version": "7.1.3", "version": "7.1.3",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz",
@@ -16007,6 +16250,11 @@
"@types/unist": "*" "@types/unist": "*"
} }
}, },
"@types/mime": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw=="
},
"@types/minimatch": { "@types/minimatch": {
"version": "3.0.4", "version": "3.0.4",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz",
@@ -16041,6 +16289,16 @@
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz",
"integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw=="
}, },
"@types/qs": {
"version": "6.9.6",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz",
"integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA=="
},
"@types/range-parser": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
"integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA=="
},
"@types/react": { "@types/react": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.2.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.2.tgz",
@@ -16098,6 +16356,15 @@
"redux": "^4.0.0" "redux": "^4.0.0"
} }
}, },
"@types/serve-static": {
"version": "1.13.9",
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz",
"integrity": "sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==",
"requires": {
"@types/mime": "^1",
"@types/node": "*"
}
},
"@types/shortid": { "@types/shortid": {
"version": "0.0.29", "version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/shortid/-/shortid-0.0.29.tgz", "resolved": "https://registry.npmjs.org/@types/shortid/-/shortid-0.0.29.tgz",
@@ -19446,6 +19713,14 @@
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
"dev": true "dev": true
}, },
"html-parse-stringify2": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/html-parse-stringify2/-/html-parse-stringify2-2.0.1.tgz",
"integrity": "sha1-3FZwtyksoVi3vJFsmmc1rIhyg0o=",
"requires": {
"void-elements": "^2.0.1"
}
},
"html-tags": { "html-tags": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz", "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz",
@@ -19515,6 +19790,40 @@
"integrity": "sha512-fbNJ+Gz5wx2LIBtMweJNY1D7Uc8p1XERi5KNRMccwfQA+rXlxWNSdUxswo0gT8XqxywTIw7Ywm/F4v/O35RdMg==", "integrity": "sha512-fbNJ+Gz5wx2LIBtMweJNY1D7Uc8p1XERi5KNRMccwfQA+rXlxWNSdUxswo0gT8XqxywTIw7Ywm/F4v/O35RdMg==",
"dev": true "dev": true
}, },
"i18next": {
"version": "19.9.2",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-19.9.2.tgz",
"integrity": "sha512-0i6cuo6ER6usEOtKajUUDj92zlG+KArFia0857xxiEHAQcUwh/RtOQocui1LPJwunSYT574Pk64aNva1kwtxZg==",
"requires": {
"@babel/runtime": "^7.12.0"
}
},
"i18next-browser-languagedetector": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-5.0.1.tgz",
"integrity": "sha512-7K4A6DJ2rNz3Yd835Y493UgkzUxgpGsCeIMKLGkt6Ps0cbgSaJ+LdATFNFA+ujp2brmsUM9BeDThXKhabXUbUw==",
"requires": {
"@babel/runtime": "^7.5.5"
}
},
"i18next-fs-backend": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/i18next-fs-backend/-/i18next-fs-backend-1.1.1.tgz",
"integrity": "sha512-RFkfy10hNxJqc7MVAp5iAZq0Tum6msBCNebEe3OelOBvrROvzHUPaR8Qe10RQrOGokTm0W4vJGEJzruFkEt+hQ=="
},
"i18next-http-backend": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-1.2.1.tgz",
"integrity": "sha512-9L2sa+wybqi57/+VsrJPo5DCI7WLoudaK12xz0okYSmsi3Izyj7sCgrYL52WHy/O3BFY9HGORBwSwlD1WYuH6Q==",
"requires": {
"node-fetch": "2.6.1"
}
},
"i18next-http-middleware": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/i18next-http-middleware/-/i18next-http-middleware-3.1.0.tgz",
"integrity": "sha512-65rP8bi5b7znBzfgIUy0KE00SWg1X6mL5XEkassgTrjAeLSfSb4vQ2bs9cN3qwHCynKIpmHjmNDu5c8NylTVmw=="
},
"iconv-lite": { "iconv-lite": {
"version": "0.6.2", "version": "0.6.2",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
@@ -20831,6 +21140,32 @@
} }
} }
}, },
"next-i18next": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/next-i18next/-/next-i18next-7.0.1.tgz",
"integrity": "sha512-x97lSfB11q/5Flf1Ocz02WoXeIRuVi7oJQ+8p9kNSfoIJExz1nTLPpJmWr2SF8wDxaljzL/kjlETUOyptGhSjQ==",
"requires": {
"@types/express": "^4.16.1",
"core-js": "^3",
"hoist-non-react-statics": "^3.2.0",
"i18next": "^19.6.3",
"i18next-browser-languagedetector": "^5.0.0",
"i18next-fs-backend": "^1.0.7",
"i18next-http-backend": "^1.0.17",
"i18next-http-middleware": "^3.0.2",
"path-match": "^1.2.4",
"prop-types": "^15.6.2",
"react-i18next": "^11.7.3",
"url": "^0.11.0"
},
"dependencies": {
"core-js": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.10.0.tgz",
"integrity": "sha512-MQx/7TLgmmDVamSyfE+O+5BHvG1aUGj/gHhLn1wVtm2B5u1eVIPvh7vkfjwWKNCjrTJB8+He99IntSQ1qP+vYQ=="
}
}
},
"next-sitemap": { "next-sitemap": {
"version": "1.6.18", "version": "1.6.18",
"resolved": "https://registry.npmjs.org/next-sitemap/-/next-sitemap-1.6.18.tgz", "resolved": "https://registry.npmjs.org/next-sitemap/-/next-sitemap-1.6.18.tgz",
@@ -21581,12 +21916,52 @@
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true "dev": true
}, },
"path-match": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/path-match/-/path-match-1.2.4.tgz",
"integrity": "sha1-pidH88fgwlFHYml/JEQ1hbCRAOo=",
"requires": {
"http-errors": "~1.4.0",
"path-to-regexp": "^1.0.0"
},
"dependencies": {
"http-errors": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.4.0.tgz",
"integrity": "sha1-bAJC3qaz33r9oVPHEImzHG6Cqr8=",
"requires": {
"inherits": "2.0.1",
"statuses": ">= 1.2.1 < 2"
}
},
"inherits": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
"integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
}
}
},
"path-parse": { "path-parse": {
"version": "1.0.6", "version": "1.0.6",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
"integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
"dev": true "dev": true
}, },
"path-to-regexp": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
"integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
"requires": {
"isarray": "0.0.1"
},
"dependencies": {
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
}
}
},
"path-type": { "path-type": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
@@ -22443,6 +22818,15 @@
"scheduler": "^0.20.1" "scheduler": "^0.20.1"
} }
}, },
"react-i18next": {
"version": "11.8.12",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.8.12.tgz",
"integrity": "sha512-M2PSVP9MzT/7yofXfCOF5gAVotinrM4BXWiguk8uFSznJsfFzTjrp3K9CBWcXitpoCBVZGZJ2AnbaWGSNkJqfw==",
"requires": {
"@babel/runtime": "^7.13.6",
"html-parse-stringify2": "^2.0.1"
}
},
"react-is": { "react-is": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
@@ -25515,6 +25899,11 @@
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ=="
}, },
"void-elements": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
"integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w="
},
"watchpack": { "watchpack": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.1.tgz", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.1.1.tgz",
+1
View File
@@ -71,6 +71,7 @@
"js-cookie": "2.2.1", "js-cookie": "2.2.1",
"lodash": "4.17.21", "lodash": "4.17.21",
"next": "10.1.2", "next": "10.1.2",
"next-i18next": "7.0.1",
"normalize.css": "8.0.1", "normalize.css": "8.0.1",
"react": "17.0.1", "react": "17.0.1",
"react-beautiful-dnd": "13.1.0", "react-beautiful-dnd": "13.1.0",
+51
View File
@@ -0,0 +1,51 @@
{
"Lue lisää": "Read more",
"lngButton": "Suomeksi",
"Paikka": "Location",
"Alkaa": "Starts at",
"Päättyy": "Ends at",
"Lataa lisää": "Load more",
"Tapahtumat": "Events",
"Uutiset": "News",
"Hakemaasi sivua":
"Page",
"ei löydy":
"does not exist",
"Hups, tapahtui virhe": "Oops, an error occured",
"Lue lisää täältä": "More information here",
"Tärkeä tiedote!": "Important notice!",
"Katso kaikki tapahtumat":
"All events",
"Ilmoittaudu":
"Sign-up",
"Ilmoittautuminen":
"Sign-up",
"Peruuta":
"Cancel",
"Kokonaishinta":
"Total price",
"Ilmoittautuminen ei ole vielä auki!":
"Signup is not open yet!",
"Se aukeaa":
"Signup opens at",
"Ilmoittautumalla hyväksyn":
"By signing up I accept the",
"tietosuojaselosteen":
"privacy policy",
"ja tietojeni tallentamisen.":
"and storing of my data."
}
+3
View File
@@ -0,0 +1,3 @@
{
"lngButton": "In English"
}
+14 -28
View File
@@ -7,7 +7,7 @@ import breakpoints from "@theme/breakpoints";
interface WrappedCardProps { interface WrappedCardProps {
title: string; title: string;
start_time: string; startTime: string;
text: string; text: string;
link: string; link: string;
image?: { image?: {
@@ -15,6 +15,7 @@ interface WrappedCardProps {
alt: string; alt: string;
}; };
buttonOnClick?: () => void; buttonOnClick?: () => void;
buttonText?: string;
} }
const StyledCard = styled.article` const StyledCard = styled.article`
@@ -69,36 +70,21 @@ const StyledCard = styled.article`
`; `;
const WrappedCard: React.FC<WrappedCardProps> = ({ const WrappedCard: React.FC<WrappedCardProps> = ({
title, text, link, image, start_time, buttonOnClick, ...props title, text, link, image, startTime, buttonOnClick, buttonText, ...props
}) => { }) => (
const options: Intl.DateTimeFormatOptions = { <StyledCard {...props}>
day: "numeric", {image && (
month: "numeric", <Image src={image.src} alt={image.alt} layout="responsive" width={0} height={0} objectFit="scale-down" />
year: "numeric", )}
hour: "numeric", <p>{startTime}</p>
minute: "2-digit", <h3>{title}</h3>
}; <p>{text}</p>
const datetime = new Date(start_time).toLocaleString("fi-FI", options);
const button = (
<Link to={link}> <Link to={link}>
<button type="button" onClick={buttonOnClick}> <button type="button" onClick={buttonOnClick}>
Lue lisää&nbsp; {buttonText}
</button> </button>
</Link> </Link>
); </StyledCard>
);
return (
<StyledCard {...props}>
{image && (
<Image src={image.src} alt={image.alt} layout="responsive" width={0} height={0} objectFit="scale-down" />
)}
<p>{datetime}</p>
<h3>{title}</h3>
<p>{text}</p>
{button}
</StyledCard>
);
};
export default WrappedCard; export default WrappedCard;
+26
View File
@@ -0,0 +1,26 @@
import React from "react";
import styled from "styled-components";
import i18nNext from "../i18n";
import Icon, { IconType } from "./Icon";
const ChangeLanguageButton: React.FC = (props) => {
const { language, changeLanguage } = i18nNext.i18n;
return (
<button
{...props}
type="button"
onClick={() => {
changeLanguage(language === "fi" ? "en" : "fi");
}}
>
<Icon name={language === "fi" ? IconType.GBFlag : IconType.FinlandFlag} />
</button>
);
};
export default styled(ChangeLanguageButton)`
font-size: 4rem;
background: none;
border: none;
width: fit-content;
`;
+10 -2
View File
@@ -69,10 +69,18 @@ const nameToIcon = (name: IconType): JSX.Element | string => {
); );
} }
if (name === IconType.FinlandFlag) { if (name === IconType.FinlandFlag) {
return "🇫🇮"; return (
<span role="img">
🇫🇮
</span>
);
} }
if (name === IconType.GBFlag) { if (name === IconType.GBFlag) {
return "🇬🇧"; return (
<span role="img">
🇬🇧
</span>
);
} }
return null; return null;
}; };
+1
View File
@@ -10,3 +10,4 @@ export { default as InfoBox } from "./InfoBox";
export { default as Accordion } from "./Accordion/Accordion"; export { default as Accordion } from "./Accordion/Accordion";
export { default as Link } from "./Link"; export { default as Link } from "./Link";
export { default as CrossFadeImages } from "./CrossFadeImages"; export { default as CrossFadeImages } from "./CrossFadeImages";
export { default as ChangeLanguageButton } from "./ChangeLanguageButton";
+16
View File
@@ -0,0 +1,16 @@
import NextI18Next from "next-i18next";
import Config from "next/config";
import path from "path";
const NextI18NextInstance = new NextI18Next({
defaultLanguage: "fi",
defaultNS: "common",
localeSubpaths: Config().publicRuntimeConfig.localeSubpaths,
localePath: path.resolve("./public/locales"),
otherLanguages: ["en"],
});
export const { appWithTranslation, useTranslation } = NextI18NextInstance;
export default NextI18NextInstance;
+3 -1
View File
@@ -1,5 +1,5 @@
import React from "react"; import React from "react";
import { NextPage } from "next"; import { NextPage, GetStaticProps } from "next";
import Head from "next/head"; import Head from "next/head";
import styled from "styled-components"; import styled from "styled-components";
@@ -25,4 +25,6 @@ const NotFoundPage: NextPage = () => (
</> </>
); );
export const getStaticProps: GetStaticProps = async () => ({ props: {} });
export default NotFoundPage; export default NotFoundPage;
+2 -1
View File
@@ -5,6 +5,7 @@ import Head from "next/head";
import styled, { createGlobalStyle } from "styled-components"; import styled, { createGlobalStyle } from "styled-components";
import { ToastContainer } from "react-toastify"; import { ToastContainer } from "react-toastify";
import { colors } from "@theme/colors"; import { colors } from "@theme/colors";
import { appWithTranslation } from "../i18n";
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"; import "react-toastify/dist/ReactToastify.css";
@@ -158,4 +159,4 @@ const Web20App = ({ Component, pageProps }: AppProps) => (
// return { ...appProps } // return { ...appProps }
// } // }
export default Web20App; export default appWithTranslation(Web20App);
+3 -1
View File
@@ -1,5 +1,5 @@
import React from "react"; import React from "react";
import { NextPage } from "next"; import { NextPage, GetStaticProps } from "next";
import { formatRelative } from "date-fns"; import { formatRelative } from "date-fns";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import styled from "styled-components"; import styled from "styled-components";
@@ -75,4 +75,6 @@ const AdminEventPage: NextPage = () => {
); );
}; };
export const getStaticProps: GetStaticProps = async () => ({ props: {} });
export default AdminEventPage; export default AdminEventPage;
+3 -1
View File
@@ -1,5 +1,5 @@
import React from "react"; import React from "react";
import { NextPage } from "next"; import { NextPage, GetStaticProps } from "next";
import { formatRelative } from "date-fns"; import { formatRelative } from "date-fns";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import styled from "styled-components"; import styled from "styled-components";
@@ -75,4 +75,6 @@ const AdminFeedPage: NextPage = () => {
); );
}; };
export const getStaticProps: GetStaticProps = async () => ({ props: {} });
export default AdminFeedPage; export default AdminFeedPage;
+3 -1
View File
@@ -1,5 +1,5 @@
import React from "react"; import React from "react";
import { NextPage } from "next"; import { NextPage, GetStaticProps } from "next";
import Head from "next/head"; import Head from "next/head";
import AdminPageWrapper from "@views/common/AdminPageWrapper"; import AdminPageWrapper from "@views/common/AdminPageWrapper";
@@ -16,4 +16,6 @@ const AdminFrontPage: NextPage = () => (
</> </>
); );
export const getStaticProps: GetStaticProps = async () => ({ props: {} });
export default AdminFrontPage; export default AdminFrontPage;
+3 -1
View File
@@ -1,5 +1,5 @@
import React from "react"; import React from "react";
import { NextPage } from "next"; import { NextPage, GetStaticProps } from "next";
import { formatRelative } from "date-fns"; import { formatRelative } from "date-fns";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import styled from "styled-components"; import styled from "styled-components";
@@ -79,4 +79,6 @@ const AdminJobAdPage: NextPage = () => {
); );
}; };
export const getStaticProps: GetStaticProps = async () => ({ props: {} });
export default AdminJobAdPage; export default AdminJobAdPage;
+3 -1
View File
@@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { NextPage } from "next"; import { NextPage, GetStaticProps } from "next";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import styled from "styled-components"; import styled from "styled-components";
import { generateToken, setTokenCookie, isAuthenticated } from "@utils/auth"; import { generateToken, setTokenCookie, isAuthenticated } from "@utils/auth";
@@ -80,4 +80,6 @@ const AdminLoginPage: NextPage = () => {
); );
}; };
export const getStaticProps: GetStaticProps = async () => ({ props: {} });
export default AdminLoginPage; export default AdminLoginPage;
+3 -1
View File
@@ -1,4 +1,4 @@
import { NextPage } from "next"; import { NextPage, GetStaticProps } from "next";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { deleteTokenCookie } from "@utils/auth"; import { deleteTokenCookie } from "@utils/auth";
@@ -12,4 +12,6 @@ const AdminLogoutPage: NextPage = () => {
return null; return null;
}; };
export const getStaticProps: GetStaticProps = async () => ({ props: {} });
export default AdminLogoutPage; export default AdminLogoutPage;
+3 -1
View File
@@ -1,5 +1,5 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { NextPage } from "next"; import { NextPage, GetStaticProps } from "next";
import { formatRelative } from "date-fns"; import { formatRelative } from "date-fns";
import { toast } from "react-toastify"; import { toast } from "react-toastify";
import styled from "styled-components"; import styled from "styled-components";
@@ -84,4 +84,6 @@ const AdminSignupPage: NextPage = () => {
); );
}; };
export const getStaticProps: GetStaticProps = async () => ({ props: {} });
export default AdminSignupPage; export default AdminSignupPage;
+3 -1
View File
@@ -1,5 +1,5 @@
import React from "react"; import React from "react";
import { NextPage } from "next"; import { NextPage, GetStaticProps } from "next";
import Head from "next/head"; import Head from "next/head";
import FreshmenPageView from "@views/FreshmenPage/FreshmenPageView"; import FreshmenPageView from "@views/FreshmenPage/FreshmenPageView";
import PageWrapper from "@views/common/PageWrapper"; import PageWrapper from "@views/common/PageWrapper";
@@ -15,4 +15,6 @@ const FreshmenPage: NextPage = () => (
</> </>
); );
export const getStaticProps: GetStaticProps = async () => ({ props: {} });
export default FreshmenPage; export default FreshmenPage;
+3 -1
View File
@@ -1,5 +1,5 @@
import React from "react"; import React from "react";
import { NextPage } from "next"; import { NextPage, GetStaticProps } from "next";
import Head from "next/head"; import Head from "next/head";
import GuildPageView from "@views/GuildPage/GuildPageView"; import GuildPageView from "@views/GuildPage/GuildPageView";
import PageWrapper from "@views/common/PageWrapper"; import PageWrapper from "@views/common/PageWrapper";
@@ -15,4 +15,6 @@ const GuildPage: NextPage = () => (
</> </>
); );
export const getStaticProps: GetStaticProps = async () => ({ props: {} });
export default GuildPage; export default GuildPage;
+3 -1
View File
@@ -1,5 +1,5 @@
import React from "react"; import React from "react";
import { NextPage } from "next"; import { NextPage, GetStaticProps } from "next";
import Head from "next/head"; import Head from "next/head";
import HonoraryPageView from "@views/HonoraryPage/HonoraryPageView"; import HonoraryPageView from "@views/HonoraryPage/HonoraryPageView";
import PageWrapper from "@views/common/PageWrapper"; import PageWrapper from "@views/common/PageWrapper";
@@ -15,4 +15,6 @@ const HonoraryPage: NextPage = () => (
</> </>
); );
export const getStaticProps: GetStaticProps = async () => ({ props: {} });
export default HonoraryPage; export default HonoraryPage;
+3 -1
View File
@@ -1,5 +1,5 @@
import React from "react"; import React from "react";
import { NextPage } from "next"; import { NextPage, GetStaticProps } from "next";
import Head from "next/head"; import Head from "next/head";
import StudiesPageView from "@views/StudiesPage/StudiesPageView"; import StudiesPageView from "@views/StudiesPage/StudiesPageView";
import PageWrapper from "@views/common/PageWrapper"; import PageWrapper from "@views/common/PageWrapper";
@@ -15,4 +15,6 @@ const StudiesPage: NextPage = () => (
</> </>
); );
export const getStaticProps: GetStaticProps = async () => ({ props: {} });
export default StudiesPage; export default StudiesPage;
+3 -1
View File
@@ -1,5 +1,5 @@
import React from "react"; import React from "react";
import { NextPage } from "next"; import { NextPage, GetStaticProps } from "next";
import Head from "next/head"; import Head from "next/head";
import ContactsPageView from "@views/ContactsPage/ContactsPageView"; import ContactsPageView from "@views/ContactsPage/ContactsPageView";
import PageWrapper from "@views/common/PageWrapper"; import PageWrapper from "@views/common/PageWrapper";
@@ -15,4 +15,6 @@ const ContactsPage: NextPage = () => (
</> </>
); );
export const getStaticProps: GetStaticProps = async () => ({ props: {} });
export default ContactsPage; export default ContactsPage;
+7 -3
View File
@@ -5,7 +5,7 @@ import Event from "@models/Event";
import Post from "@models/Feed"; import Post from "@models/Feed";
import { import {
Divider, CTASection, TextSection, Link, CrossFadeImages, Divider, CTASection, TextSection, Link, CrossFadeImages, ChangeLanguageButton,
} from "@components/index"; } from "@components/index";
import ActualPageHero from "./ActualPageHero"; import ActualPageHero from "./ActualPageHero";
import EventCalendar from "./EventCalendar"; import EventCalendar from "./EventCalendar";
@@ -32,14 +32,18 @@ const Gallery = styled.div`
} }
`; `;
const LngButton = styled(ChangeLanguageButton)`
align-self: flex-end;
margin-right: 1rem;
`;
const ActualPageView: React.FC<ActualPageViewProps> = ({ events, feed }) => ( const ActualPageView: React.FC<ActualPageViewProps> = ({ events, feed }) => (
<> <>
<ActualPageHero /> <ActualPageHero />
<LngButton />
<EventCalendar events={events} /> <EventCalendar events={events} />
<Divider /> <Divider />
<News feed={feed} /> <News feed={feed} />
<CTASection <CTASection
+30 -6
View File
@@ -5,6 +5,7 @@ import Button from "@components/Button";
import { CardSection, Card, FullWidthSection } from "@components/index"; import { CardSection, Card, FullWidthSection } from "@components/index";
import noop from "@utils/noop"; import noop from "@utils/noop";
import FilterContainer from "./FilterContainer"; import FilterContainer from "./FilterContainer";
import i18nNext, { useTranslation } from "../../i18n";
interface EventCalendarProps { interface EventCalendarProps {
events: Event[]; events: Event[];
@@ -13,11 +14,33 @@ interface EventCalendarProps {
const EventCalendar: React.FC<EventCalendarProps> = ({ events }) => { const EventCalendar: React.FC<EventCalendarProps> = ({ events }) => {
// const [filterSelected, setFilter] = useState(0); // const [filterSelected, setFilter] = useState(0);
const [numberShown, setNumberShown] = useState(8); const [numberShown, setNumberShown] = useState(8);
const filteredEvents = events.slice(0, numberShown);
const { t } = useTranslation();
const { language } = i18nNext.i18n;
const isFi = language === "fi";
const options: Intl.DateTimeFormatOptions = {
day: "numeric",
month: "numeric",
year: "numeric",
hour: "numeric",
minute: "2-digit",
};
const filteredEvents = events.slice(0, numberShown).map((e) => ({
...e,
title: isFi ? e.title_fi : e.title_en,
description: isFi ? e.description_fi : e.description_en,
content: isFi ? e.content_fi : e.content_en,
location: isFi ? e.location_fi : e.location_en,
startDate: new Date(e.start_time).toLocaleString(isFi ? "fi-FI" : "en-GB", options),
endDate: new Date(e.end_time).toLocaleString(isFi ? "fi-FI" : "en-GB", options),
}));
return ( return (
<FullWidthSection> <FullWidthSection>
<h1 id="tapahtumat"> <h1 id="tapahtumat">
Tapahtumat {t("Tapahtumat")}
{/* <FilterContainer> {/* <FilterContainer>
<Button buttonStyle="filter" onClick={() => { setFilter(0); }} selected={filterSelected === 0}> <Button buttonStyle="filter" onClick={() => { setFilter(0); }} selected={filterSelected === 0}>
Näytä kaikki Näytä kaikki
@@ -35,18 +58,19 @@ const EventCalendar: React.FC<EventCalendarProps> = ({ events }) => {
{filteredEvents.map((e) => ( {filteredEvents.map((e) => (
<Card <Card
key={e.id} key={e.id}
title={e.title_fi} title={e.title}
start_time={e.start_time} startTime={e.startDate}
text={e.description_fi} text={e.description}
link={`/events/${e.id}`} link={`/events/${e.id}`}
buttonOnClick={noop} buttonOnClick={noop}
buttonText={`${t("Lue lisää")} `}
/> />
))} ))}
</CardSection> </CardSection>
{ numberShown < events.length && ( { numberShown < events.length && (
<FilterContainer> <FilterContainer>
<Button buttonStyle="bordered" onClick={() => { setNumberShown(numberShown + 8); }}> <Button buttonStyle="bordered" onClick={() => { setNumberShown(numberShown + 8); }}>
Lataa lisää {t("Lataa lisää")}
</Button> </Button>
</FilterContainer> </FilterContainer>
)} )}
+27 -6
View File
@@ -5,6 +5,7 @@ import Button from "@components/Button";
import { CardSection, Card, FullWidthSection } from "@components/index"; import { CardSection, Card, FullWidthSection } from "@components/index";
import noop from "@utils/noop"; import noop from "@utils/noop";
import FilterContainer from "./FilterContainer"; import FilterContainer from "./FilterContainer";
import i18nNext, { useTranslation } from "../../i18n";
interface NewsProps { interface NewsProps {
feed: Post[]; feed: Post[];
@@ -13,11 +14,30 @@ interface NewsProps {
const News: React.FC<NewsProps> = ({ feed }) => { const News: React.FC<NewsProps> = ({ feed }) => {
// const [filterSelected, setFilter] = useState(0); // const [filterSelected, setFilter] = useState(0);
const [numberShown, setNumberShown] = useState(8); const [numberShown, setNumberShown] = useState(8);
const filteredFeed = feed.slice(0, numberShown);
const { t } = useTranslation();
const { language } = i18nNext.i18n;
const isFi = language === "fi";
const options: Intl.DateTimeFormatOptions = {
day: "numeric",
month: "numeric",
year: "numeric",
hour: "numeric",
minute: "2-digit",
};
const filteredFeed = feed.slice(0, numberShown).map((p) => ({
...p,
title: isFi ? p.title_fi : p.title_en,
description: isFi ? p.description_fi : p.description_en,
content: isFi ? p.content_fi : p.content_en,
publishTime: new Date(p.publish_time).toLocaleString(isFi ? "fi-FI" : "en-GB", options),
}));
return ( return (
<FullWidthSection> <FullWidthSection>
<h1 id="uutiset"> <h1 id="uutiset">
Uutiset {t("Uutiset")}
{/* <FilterContainer> {/* <FilterContainer>
<Button buttonStyle="filter" onClick={() => { setFilter(0); }} selected={filterSelected === 0}> <Button buttonStyle="filter" onClick={() => { setFilter(0); }} selected={filterSelected === 0}>
Näytä kaikki Näytä kaikki
@@ -34,18 +54,19 @@ const News: React.FC<NewsProps> = ({ feed }) => {
{filteredFeed.map((post) => ( {filteredFeed.map((post) => (
<Card <Card
key={post.id} key={post.id}
title={post.title_fi} title={post.title}
start_time={post.publish_time} startTime={post.publishTime}
text={post.description_fi} text={post.description}
link={`/feed/${post.id}`} link={`/feed/${post.id}`}
buttonOnClick={noop} buttonOnClick={noop}
buttonText={`${t("Lue lisää")} `}
/> />
))} ))}
</CardSection> </CardSection>
{ numberShown < feed.length && ( { numberShown < feed.length && (
<FilterContainer> <FilterContainer>
<Button buttonStyle="bordered" onClick={() => { setNumberShown(numberShown + 8); }}> <Button buttonStyle="bordered" onClick={() => { setNumberShown(numberShown + 8); }}>
Lataa lisää {t("Lataa lisää")}
</Button> </Button>
</FilterContainer> </FilterContainer>
)} )}
+62 -43
View File
@@ -4,11 +4,11 @@ import styled from "styled-components";
import colors from "@theme/colors"; import colors from "@theme/colors";
import Event from "@models/Event"; import Event from "@models/Event";
import Button from "@components/Button"; import Button from "@components/Button";
import { Link, TextSection } from "@components/index"; import { Link, TextSection, ChangeLanguageButton } from "@components/index";
import noop from "@utils/noop"; import noop from "@utils/noop";
import MarkdownStyles from "@views/common/MarkdownStyles"; import MarkdownStyles from "@views/common/MarkdownStyles";
import LoadingView from "@views/common/LoadingView"; import LoadingView from "@views/common/LoadingView";
import i18nNext, { useTranslation } from "../../i18n";
interface EventPageViewProps { interface EventPageViewProps {
event?: Event; event?: Event;
@@ -33,7 +33,6 @@ const StyledTextSection = styled(TextSection)`
line-height: 0.4rem; line-height: 0.4rem;
} }
} }
`; `;
const SignupButtons = styled.div` const SignupButtons = styled.div`
@@ -46,49 +45,69 @@ const Content = styled(MarkdownStyles)`
margin-top: 1.5rem; margin-top: 1.5rem;
`; `;
const LngButton = styled(ChangeLanguageButton)`
align-self: flex-end;
margin-right: 1rem;
`;
const EventPageView: React.FC<EventPageViewProps> = ({ event }) => { const EventPageView: React.FC<EventPageViewProps> = ({ event }) => {
const { t } = useTranslation();
if (!event) return <LoadingView />; if (!event) return <LoadingView />;
const date_start = new Date(event.start_time).toLocaleString("fi-FI"); const { language } = i18nNext.i18n;
const date_end = new Date(event.end_time).toLocaleString("fi-FI"); const isFi = language === "fi";
const {
title, description, content, location, startDate, endDate,
} = {
title: isFi ? event.title_fi : event.title_en,
description: isFi ? event.description_fi : event.description_en,
content: isFi ? event.content_fi : event.content_en,
location: isFi ? event.location_fi : event.location_en,
startDate: new Date(event.start_time).toLocaleString(isFi ? "fi-FI" : "en-GB"),
endDate: new Date(event.end_time).toLocaleString(isFi ? "fi-FI" : "en-GB"),
};
return ( return (
<StyledTextSection> <>
<h1> <LngButton />
{event.title_fi} <StyledTextSection>
<p> <h1>
{event.description_fi} {title}
</p> <p>
<Image {description}
src={event.image || event.tags[0].icon} </p>
alt={event.title_fi} <Image
objectFit="scale-down" src={event.image || event.tags[0].icon}
layout="responsive" alt={title}
width={16} objectFit="scale-down"
height={9} layout="responsive"
/> width={16}
</h1> height={9}
<div> />
<Content source={event.content_fi} escapeHtml={false} /> </h1>
<p> <div>
Paikka: {event.location_fi} <Content source={content} escapeHtml={false} />
</p> <p>
<p> {`${t("Paikka")}: ${location}`}
<time>Alkaa: {date_start}</time> </p>
</p> <p>
<p> <time>{`${t("Alkaa")}: ${startDate}`}</time>
<time>Päättyy: {date_end}</time> </p>
</p> <p>
{/* We may have multiple signup forms. Generate own Button for each one */} <time>{`${t("Päättyy")}: ${endDate}`}</time>
<SignupButtons> </p>
{event.signupForm.map((sf) => ( {/* We may have multiple signup forms. Generate own Button for each one */}
<Link key={sf.id} to={`/signup/${sf.id}`}> <SignupButtons>
<Button buttonStyle="filled" onClick={noop}> {event.signupForm.map((sf) => (
{sf.title_fi} <Link key={sf.id} to={`/signup/${sf.id}`}>
</Button> <Button data-e2e="signup-button" buttonStyle="filled" onClick={noop}>
</Link> {isFi ? sf.title_fi : sf.title_en}
))} </Button>
</SignupButtons> </Link>
</div> ))}
</StyledTextSection> </SignupButtons>
</div>
</StyledTextSection>
</>
); );
}; };
export default EventPageView; export default EventPageView;
+15 -4
View File
@@ -6,6 +6,7 @@ import Post from "@models/Feed";
import { TextSection } from "@components/index"; import { TextSection } from "@components/index";
import MarkdownStyles from "@views/common/MarkdownStyles"; import MarkdownStyles from "@views/common/MarkdownStyles";
import LoadingView from "@views/common/LoadingView"; import LoadingView from "@views/common/LoadingView";
import i18nNext from "../../i18n";
interface FeedPageViewProps { interface FeedPageViewProps {
post?: Post; post?: Post;
@@ -32,17 +33,27 @@ const Content = styled(MarkdownStyles)`
const FeedPageView: React.FC<FeedPageViewProps> = ({ post }) => { const FeedPageView: React.FC<FeedPageViewProps> = ({ post }) => {
if (!post) return <LoadingView />; if (!post) return <LoadingView />;
const { language } = i18nNext.i18n;
const isFi = language === "fi";
const {
title, description, content,
} = {
title: isFi ? post.title_fi : post.title_en,
description: isFi ? post.description_fi : post.description_en,
content: isFi ? post.content_fi : post.content_en,
};
return ( return (
<StyledTextSection> <StyledTextSection>
<h1> <h1>
{post.title_fi} {title}
<p> <p>
{post.description_fi} {description}
</p> </p>
{post.image && ( {post.image && (
<Image <Image
src={post.image} src={post.image}
alt={post.title_fi} alt={title}
objectFit="scale-down" objectFit="scale-down"
layout="responsive" layout="responsive"
width={16} width={16}
@@ -51,7 +62,7 @@ const FeedPageView: React.FC<FeedPageViewProps> = ({ post }) => {
)} )}
</h1> </h1>
<div> <div>
<Content source={post.content_fi} escapeHtml={false} /> <Content source={content} escapeHtml={false} />
</div> </div>
</StyledTextSection> </StyledTextSection>
); );
+12 -2
View File
@@ -32,6 +32,14 @@ interface FrontPageViewProps {
feed: Post[]; feed: Post[];
} }
const cardTimeOpts: Intl.DateTimeFormatOptions = {
day: "numeric",
month: "numeric",
year: "numeric",
hour: "numeric",
minute: "2-digit",
};
const SponsorReel = styled.div` const SponsorReel = styled.div`
text-align: center; text-align: center;
& > div { & > div {
@@ -72,7 +80,7 @@ const FrontPageView: React.FC<FrontPageViewProps> = ({ events, feed }) => (
<Card <Card
key={event.id} key={event.id}
title={event.title_fi} title={event.title_fi}
start_time={event.start_time} startTime={new Date(event.start_time).toLocaleString("fi-FI", cardTimeOpts)}
text={event.description_fi} text={event.description_fi}
link={`/events/${event.id}`} link={`/events/${event.id}`}
image={{ image={{
@@ -80,6 +88,7 @@ const FrontPageView: React.FC<FrontPageViewProps> = ({ events, feed }) => (
alt: event.title_fi, alt: event.title_fi,
}} }}
buttonOnClick={noop} buttonOnClick={noop}
buttonText="Lue lisää&nbsp;"
data-e2e="event-card" data-e2e="event-card"
/> />
))} ))}
@@ -104,10 +113,11 @@ const FrontPageView: React.FC<FrontPageViewProps> = ({ events, feed }) => (
<Card <Card
key={inst.id} key={inst.id}
title={inst.title_fi} title={inst.title_fi}
start_time={inst.publish_time} startTime={new Date(inst.publish_time).toLocaleString("fi-FI", cardTimeOpts)}
text={inst.description_fi} text={inst.description_fi}
link={`/feed/${inst.id}`} link={`/feed/${inst.id}`}
buttonOnClick={noop} buttonOnClick={noop}
buttonText="Lue lisää&nbsp;"
/> />
))} ))}
<aside> <aside>
+12 -2
View File
@@ -37,6 +37,14 @@ interface InEnglishPageViewProps {
feed: Post[]; feed: Post[];
} }
const cardTimeOpts: Intl.DateTimeFormatOptions = {
day: "numeric",
month: "numeric",
year: "numeric",
hour: "numeric",
minute: "2-digit",
};
const InEnglishPageView: React.FC<InEnglishPageViewProps> = ({ events, feed }) => ( const InEnglishPageView: React.FC<InEnglishPageViewProps> = ({ events, feed }) => (
<> <>
<InEnglishPageHero /> <InEnglishPageHero />
@@ -198,7 +206,7 @@ const InEnglishPageView: React.FC<InEnglishPageViewProps> = ({ events, feed }) =
<Card <Card
key={event.id} key={event.id}
title={event.title_en} title={event.title_en}
start_time={event.start_time} startTime={new Date(event.start_time).toLocaleString("en-GB", cardTimeOpts)}
text={event.description_en} text={event.description_en}
link={`/events/${event.id}`} link={`/events/${event.id}`}
image={{ image={{
@@ -206,6 +214,7 @@ const InEnglishPageView: React.FC<InEnglishPageViewProps> = ({ events, feed }) =
alt: event.title_en, alt: event.title_en,
}} }}
buttonOnClick={noop} buttonOnClick={noop}
buttonText="Read more&nbsp;"
data-e2e="event-card" data-e2e="event-card"
/> />
))} ))}
@@ -227,10 +236,11 @@ const InEnglishPageView: React.FC<InEnglishPageViewProps> = ({ events, feed }) =
<Card <Card
key={inst.id} key={inst.id}
title={inst.title_en} title={inst.title_en}
start_time={inst.publish_time} startTime={new Date(inst.publish_time).toLocaleString("en-GB", cardTimeOpts)}
text={inst.description_en} text={inst.description_en}
link={`/feed/${inst.id}`} link={`/feed/${inst.id}`}
buttonOnClick={noop} buttonOnClick={noop}
buttonText="Read more&nbsp;"
/> />
))} ))}
<aside> <aside>
+1 -1
View File
@@ -32,7 +32,7 @@ test("User signups to event from front page", async (t) => {
await t.wait(3000); await t.wait(3000);
await t.expect(await getPageUrl()).match(/\/events\/\d{1,4}/, "URL isn't /events/<id>"); await t.expect(await getPageUrl()).match(/\/events\/\d{1,4}/, "URL isn't /events/<id>");
const SignupButton = Selector("button"); const SignupButton = Selector("[data-e2e=\"signup-button\"]");
await t await t
.click(SignupButton); .click(SignupButton);