Compare commits

..

40 Commits

Author SHA1 Message Date
einstein 6af5d7fa1f Fix CI build SSG timeouts
- Add backend request timeout to prevent hanging builds

- Make getStaticProps resilient to API failures

- Avoid build-time crawling for dynamic routes (blocking fallback)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-26 18:47:04 +03:00
Your Name 1df9b22fa3 lint fixes 2026-05-25 18:57:55 +03:00
Your Name 17713d4f9d picutre updates for 2026 fuksis 2026-05-25 18:56:26 +03:00
toimistokone d0a930794e fix poop overflow 2026-03-23 14:13:09 +02:00
toimistokone 170e7b3c31 hallitusbigpick 2026-03-18 14:56:02 +02:00
jadera 20f39b545d allow ... operator 2026-03-11 12:04:30 +02:00
jadera 22454369fd xd 2026-03-11 11:56:44 +02:00
jadera 7a9805ebe9 kappaa 2026-03-11 11:52:18 +02:00
jadera 4c69a4620d to detect source 2026-03-11 11:44:37 +02:00
jadera ae28ec183e 2026 prosik,oltermanni,ansiomerkit 2026-03-10 22:35:16 +02:00
Aarni Halinen b49e9e70b2 add hyphens to cards if text needs breaks 2026-03-10 21:10:43 +02:00
toimistokone 4510bb08d8 eslint xD 2026-03-10 21:10:43 +02:00
toimistokone 0825d87d0f antibot 2026-03-10 17:27:16 +02:00
J4DER4 bcad873b97 Merge branch 'atte-temp-2' into 'production'
Fixed typos in committees (again)

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!201
2026-02-27 20:48:29 +00:00
Atte Elo f6a5080769 Update 5 files
- /src/views/CommitteePage/ltmk.json
- /src/views/CommitteePage/mtmk.json
- /src/views/CommitteePage/ptmk.json
- /src/views/CommitteePage/sicc.json
- /src/views/CommitteePage/vtmk.json
2026-02-27 19:50:24 +00:00
J4DER4 e3d3b736f1 Merge branch 'boardimg26' into 'production'
change board images howth his work

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!199
2026-02-16 18:38:02 +00:00
jadera 56c509b4c1 change board images howth his work 2026-02-16 20:27:12 +02:00
J4DER4 771b9eb391 Merge branch 'comiteeentries' into 'production'
Comitee entries

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!198
2026-02-13 16:52:53 +00:00
J4DER4 75cf2e2ce1 Comitee entries 2026-02-13 16:52:53 +00:00
J4DER4 4fe78fd96d Merge branch 'master' into 'production'
Change board members for 2026

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!196
2026-01-06 18:26:03 +00:00
J4DER4 50fd27d193 Change board members for 2026 2026-01-06 18:26:02 +00:00
J4DER4 6cb18c4a13 Merge branch 'master' into 'production'
Master

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!194
2025-11-21 19:23:29 +00:00
SimeonPursiainen 2009a65f55 Added silver honoraries for 2025 2025-10-28 14:13:21 +02:00
Simeon Pursiainen 3c72152704 Merge branch 'textFix' into 'production'
Textfix

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!191
2025-09-24 13:00:08 +03:00
SimeonPursiainen 2ad2907f5f Fixup 2025-09-23 21:27:48 +03:00
SimeonPursiainen f61fc155a8 Updated membership fee payment info 2025-09-23 21:18:20 +03:00
Simeon Pursiainen 802b308826 Merge branch 'master' into 'production'
Master

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!188
2025-09-11 21:21:13 +03:00
Simeon Pursiainen e4784e1932 Master 2025-09-11 21:21:13 +03:00
Simeon Pursiainen c015f0a275 Merge branch 'master' into 'production'
touch d'andre

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!185
2025-09-09 19:18:11 +03:00
Simeon Pursiainen 6a9cb63cff touch d'andre 2025-09-09 19:18:11 +03:00
Simeon Pursiainen 5007d443e7 Merge branch 'master' into 'production'
Fixup

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!184
2025-09-09 14:42:39 +03:00
Simeon Pursiainen 648c49582e Merge branch 'master' into 'production'
Changed instructions for job ads

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!183
2025-09-05 12:30:03 +03:00
Simeon Pursiainen c50a09c691 Merge branch 'master' into 'production'
added new media card for sosso

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!182
2025-09-02 16:55:36 +03:00
Simeon Pursiainen 2b75f5a567 Merge branch 'master' into 'production'
Added Metso to sponsors

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!181
2025-09-01 20:04:25 +03:00
Simeon Pursiainen 4e27d892d5 Merge branch 'master' into 'production'
fix stack compose

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!180
2025-09-01 19:29:30 +03:00
Simeon Pursiainen 0a36c1c233 Merge branch 'master' into 'production'
removing replicas

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!179
2025-09-01 18:57:43 +03:00
Simeon Pursiainen 9459930291 Merge branch 'master' into 'production'
Separate eng and international fuksi pages

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!177
2025-08-16 14:51:57 +03:00
Justus Ojala cea106b134 Separate eng and international fuksi pages 2025-08-16 14:51:57 +03:00
Simeon Pursiainen af9b115205 Merge branch 'master' into 'production'
Master

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!173
2025-08-13 21:16:40 +03:00
Simeon Pursiainen 7ed7849c43 Merge branch 'master' into 'production'
FIx fopas links

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!171
2025-07-15 21:41:51 +03:00
58 changed files with 28623 additions and 34342 deletions
-1
View File
@@ -5,4 +5,3 @@ node_modules
# don't lint nyc coverage output
coverage
next-env.d.ts
tests
+6
View File
@@ -47,5 +47,11 @@ module.exports = {
"jsx-a11y/no-noninteractive-element-interactions": "off",
"jsx-a11y/no-static-element-interactions": "off",
"@typescript-eslint/default-param-last": "warn",
"object-curly-newline": "warn",
"no-mixed-spaces-and-tabs": "warn",
"no-tabs": "warn",
"react/jsx-indent": "warn",
"padded-blocks": "warn",
"spaced-comment": "warn",
},
};
@@ -0,0 +1,78 @@
---
description: "Use this agent when the user asks to set up or fix ESLint in a project, especially legacy or older projects.\n\nTrigger phrases include:\n- 'get ESLint working'\n- 'fix ESLint'\n- 'setup ESLint for this project'\n- 'enable linting locally'\n- 'ESLint not working'\n- 'get linting working on this old project'\n\nExamples:\n- User says 'get this old projects eslint working so i can lint locally' → invoke this agent to diagnose and repair ESLint setup\n- User asks 'why isn't ESLint running?' → invoke this agent to troubleshoot configuration and dependencies\n- User says 'I need to lint locally but ESLint is broken' → invoke this agent to fix the setup end-to-end"
name: eslint-setup-fixer
---
# eslint-setup-fixer instructions
You are an expert build and tooling engineer specializing in getting ESLint working in legacy and older projects. Your mission is to diagnose ESLint issues and establish a working local linting setup that the user can reliably use.
Your core responsibilities:
- Diagnose why ESLint is not working in the project
- Identify and fix configuration issues
- Ensure all dependencies are properly installed and compatible
- Verify Node.js version compatibility
- Establish a working local linting workflow
- Document any fixes applied
Methodology:
1. First, examine the current project state:
- Check if .eslintrc file exists (any format: .js, .json, .yml, .yaml)
- Look for eslintConfig in package.json
- Review package.json to see if eslint is listed as a dependency
- Check the Node.js version being used
2. Diagnose the root cause:
- Run eslint to see what error messages appear
- Check if eslint is installed (node_modules)
- Identify dependency version conflicts
- Look for missing parser or plugin dependencies
- Check for Node version incompatibilities
3. Fix the issues systematically:
- Install or update eslint if needed
- Install any missing parser or plugin dependencies
- Create or repair .eslintrc configuration if missing
- Update package.json scripts with lint commands if needed
- Handle any Node version issues (upgrade, use nvm, etc.)
4. Validate the setup:
- Successfully run eslint on the codebase
- Verify linting rules are being applied
- Test that local linting works reliably
- Confirm users can run lint commands
Common pitfalls to avoid:
- Old ESLint versions (< v6) may not work with modern Node versions
- Missing @babel/eslint-parser for projects using older Babel
- Incompatible parser versions (e.g., wrong TypeScript parser)
- Node version too old or too new for the project's dependencies
- Configuration files with syntax errors preventing parsing
- Circular dependency issues in plugin configurations
Edge cases to handle:
- Project using TypeScript: ensure typescript parser is installed
- Project with React: ensure react plugin is installed
- Project with old Node version requirements: provide upgrade guidance
- Multiple conflicting .eslintrc files: consolidate to single source of truth
- Projects with monorepo structure: handle root and package-level configs
Output format:
- Clear summary of what was broken and why
- Step-by-step list of all fixes applied
- Verification results showing linting now works
- Any warnings about compatibility or recommendations for modernization
- Command to run linting locally (e.g., `npm run lint` or `npm run eslint`)
Quality checks:
- Verify eslint command runs without errors
- Confirm linting actually processes files (not just succeeding with no output)
- Test that rules are being enforced
- Ensure the fix is reproducible for other developers
- Document any version constraints or platform-specific requirements
When to ask for clarification:
- If you're unsure whether the project uses TypeScript, React, or other special configs
- If multiple conflicting approaches exist and you need user preference
- If Node version constraints prevent a standard fix
- If the project has unusual structure that prevents standard ESLint discovery
+8 -17
View File
@@ -8,7 +8,7 @@ stages:
- deploy
install:
image: node:20
image: node:16
stage: setup
script:
- npm ci
@@ -21,7 +21,7 @@ install:
expire_in: 1 week
audit:
image: node:20
image: node:16
needs: ["install"]
allow_failure: true
stage: audit
@@ -29,27 +29,27 @@ audit:
- npm audit --audit-level=critical
es:lint:
image: node:20
image: node:16
needs: ["install"]
stage: lint
script:
- npm run lint:es
css:lint:
image: node:20
image: node:16
needs: ["install"]
stage: lint
script:
- npm run lint:css
# test:unit:
# image: node:20
# image: node:16
# stage: test
# script:
# - npm run test:unit
build:
image: node:20
image: node:16
needs: ["install"]
stage: build
script:
@@ -67,20 +67,11 @@ build:
- .next/cache/
test:e2e:
# Use a Cypress image which has Node 20 + Chrome and runs as root (solves permission issues)
image: cypress/browsers:latest
image: circleci/node:16-browsers
needs: ["install", "build"]
stage: test
script:
# No sudo needed if running as root.
# If permissions are still wrong, we CAN fix them because we are root.
# But usually, being root means we can overwrite/rm the files anyway.
# 1. Clean install to ensure native modules match this container's environment
- npm ci
# 2. Run TestCafe (using the CI script for headless mode)
- npm run testcafe:ci
- npm run testcafe
artifacts:
paths:
- e2e-screenshots
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run lint
npm run lint:es
+1 -2
View File
@@ -1,6 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
import "./.next/types/routes.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information.
// see https://nextjs.org/docs/basic-features/typescript for more information.
+21 -46
View File
@@ -1,54 +1,29 @@
// web2.0-frontend/next.config.js
const { withSentryConfig } = require("@sentry/nextjs");
const withBundleAnalyzer = require("@next/bundle-analyzer")({
enabled: process.env.ANALYZE === "true",
});
/** @type {import('next').NextConfig} */
const nextConfig = {
compiler: {
styledComponents: true,
},
const sentryWebpackPluginOptions = {
// Additional config options for the Sentry Webpack plugin. Keep in mind that
// the following options are set automatically, and overriding them is not
// recommended:
// release, url, org, project, authToken, configFile, stripPrefix,
// urlPrefix, include, ignore
silent: true, // Suppresses all logs
// For all available options, see:
// https://github.com/getsentry/sentry-webpack-plugin#options.
};
module.exports = withBundleAnalyzer(withSentryConfig({
images: {
remotePatterns: [
{
protocol: "https",
hostname: "api.sahkoinsinoorikilta.fi",
},
{
protocol: "https",
hostname: "static.sahkoinsinoorikilta.fi",
},
{
protocol: "https",
hostname: "api.dev.sahkoinsinoorikilta.fi",
},
domains: [
"api.sahkoinsinoorikilta.fi",
"static.sahkoinsinoorikilta.fi",
"api.dev.sahkoinsinoorikilta.fi",
],
},
// Note: The 'sentry' key is removed from here as it is no longer supported in v8
};
// Sentry options are now passed as a single object in the second argument
const sentryOptions = {
// For all available options, see:
// https://github.com/getsentry/sentry-webpack-plugin#options
// Suppresses all logs
silent: true,
// Hides source maps from generated client bundles
hideSourceMaps: true,
// Automatically tree-shake Sentry logger statements to reduce bundle size
disableLogger: true,
// Upload a larger set of source maps for prettier stack traces (increases build time)
widenClientFileUpload: true,
// (Optional) You can add org and project if not set in environment variables
// org: "your-org-slug",
// project: "your-project-slug",
};
// Wrap the config with Sentry first, then Bundle Analyzer
module.exports = withBundleAnalyzer(withSentryConfig(nextConfig, sentryOptions));
sentry: {
hideSourceMaps: true, // Hide source maps, see: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#configure-source-maps
},
}, sentryWebpackPluginOptions));
+27214 -33237
View File
File diff suppressed because it is too large Load Diff
+102 -100
View File
@@ -1,103 +1,105 @@
{
"name": "web2.0-frontend",
"version": "0.1.0",
"description": "Web 2.0 Frontend. React, Typescript.",
"repository": {
"type": "git",
"url": "https://gitlab.com/sahkoinsinoorikilta/vtmk/web2.0-frontend.git"
},
"keywords": [
"react",
"next.js",
"typescript",
"styled-components"
],
"author": "Aarni Halinen",
"license": "MIT",
"homepage": "https://sahkoinsinoorikilta.fi",
"scripts": {
"build": "next build",
"postbuild": "next-sitemap",
"export": "next export",
"lint": "npm run lint:es && npm run lint:css",
"lint:es": "eslint . --ext .js,.jsx,.ts,.tsx",
"lint:es:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
"lint:css": "stylelint \"./src/**/*.{ts,tsx}\"",
"dev": "next dev --webpack",
"start": "next dev --webpack",
"start-prod": "next start --port ${SERVER_PORT:=80}",
"serve": "next start --port 3000",
"test:unit": "jest --coverage",
"test": "npm run testcafe",
"testcafe": "testcafe --config-file testcafe.json",
"testcafe:ci": "testcafe 'chrome:headless --no-sandbox --disable-dev-shm-usage' --config-file testcafe.json",
"build-analyze": "ANALYZE=true npm run build",
"prepare": "husky install"
},
"devDependencies": {
"@types/jest": "^30.0.0",
"@types/js-cookie": "^3.0.1",
"@types/node": "^16.11.36",
"@types/react": "^18.0.15",
"@types/react-csv": "^1.1.3",
"@types/react-dom": "^18.0.6",
"@types/shortid": "^0.0.29",
"@types/styled-components": "^5.1.25",
"@typescript-eslint/eslint-plugin": "^5.18.0",
"@typescript-eslint/parser": "^5.18.0",
"babel-plugin-styled-components": "^2.0.7",
"eslint": "^8.57.1",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^17.0.0",
"eslint-config-next": "^13.5.11",
"eslint-plugin-import": "^2.26.0",
"husky": "^7.0.4",
"jest": "^30.2.0",
"next-sitemap": "^3.1.11",
"npm-run-all": "^4.1.5",
"postcss-jsx": "^0.36.4",
"postcss-syntax": "^0.36.2",
"stylelint": "^14.2.0",
"stylelint-config-recommended": "^6.0.0",
"stylelint-config-styled-components": "^0.1.1",
"testcafe": "^3.7.2",
"ts-jest": "^29.4.6",
"typescript": "^5.9.3"
},
"dependencies": {
"@next/bundle-analyzer": "^12.2.3",
"@rjsf/core": "^4.2.0",
"@sentry/nextjs": "^10.29.0",
"axios": "^1.13.2",
"date-fns": "^2.28.0",
"fast-deep-equal": "^3.1.3",
"js-cookie": "^3.0.1",
"lodash": "^4.17.21",
"mqtt": "^5.14.1",
"next": "^16.0.8",
"normalize.css": "^8.0.1",
"react": "^18.2.0",
"react-csv": "^2.2.2",
"react-dnd": "15.0.2",
"react-dnd-html5-backend": "15.0.2",
"react-dnd-touch-backend": "15.0.2",
"react-dom": "^18.2.0",
"react-is": "^18.2.0",
"react-markdown": "^8.0.3",
"react-mde": "^11.5.0",
"react-toastify": "^9.0.7",
"rehype-raw": "^6.1.1",
"rehype-sanitize": "^5.0.1",
"sharp": "^0.34.5",
"shortid": "^2.2.16",
"styled-components": "^5.3.5",
"swr": "^1.2.2",
"uuid": "^13.0.0"
},
"overrides": {
"react-mde": {
"react": "$react",
"react-dom": "$react-dom"
}
"name": "web2.0-frontend",
"version": "0.1.0",
"description": "Web 2.0 Frontend. React, Typescript.",
"repository": {
"type": "git",
"url": "https://gitlab.com/sahkoinsinoorikilta/vtmk/web2.0-frontend.git"
},
"keywords": [
"react",
"next.js",
"typescript",
"styled-components"
],
"author": "Aarni Halinen",
"license": "MIT",
"homepage": "https://sahkoinsinoorikilta.fi",
"scripts": {
"build": "next build",
"postbuild": "next-sitemap",
"export": "next export",
"lint": "npm run lint:es && npm run lint:css",
"lint:es": "next lint",
"lint:es:fix": "next lint --fix",
"lint:css": "stylelint \"./src/**/*.{ts,tsx}\"",
"dev": "next dev",
"start": "next dev",
"start-prod": "next start --port ${SERVER_PORT:=80}",
"serve": "next start --port 3000",
"test:unit": "jest --coverage",
"test": "npm run testcafe",
"testcafe": "testcafe --config-file testcafe.json",
"build-analyze": "ANALYZE=true npm run build",
"prepare": "husky install"
},
"devDependencies": {
"@types/jest": "^27.4.1",
"@types/js-cookie": "^3.0.1",
"@types/node": "^16.11.36",
"@types/react": "^18.0.15",
"@types/react-csv": "^1.1.3",
"@types/react-dom": "^18.0.6",
"@types/shortid": "^0.0.29",
"@types/styled-components": "^5.1.25",
"@typescript-eslint/eslint-plugin": "^5.18.0",
"@typescript-eslint/parser": "^5.18.0",
"babel-plugin-styled-components": "^2.0.7",
"eslint": "^8.13.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^17.0.0",
"eslint-config-next": "^13.1.6",
"eslint-plugin-import": "^2.26.0",
"husky": "^7.0.4",
"jest": "^27.5.1",
"next-sitemap": "^3.1.11",
"npm-run-all": "^4.1.5",
"postcss-jsx": "^0.36.4",
"postcss-syntax": "^0.36.2",
"stylelint": "^14.2.0",
"stylelint-config-recommended": "^6.0.0",
"stylelint-config-styled-components": "^0.1.1",
"testcafe": "^1.18.5",
"ts-jest": "^27.1.4",
"typescript": "^4.6.3"
},
"dependencies": {
"@next/bundle-analyzer": "^12.2.3",
"@rjsf/core": "^4.2.0",
"@sentry/nextjs": "^7.34.0",
"axios": "^0.26.1",
"date-fns": "^2.28.0",
"fast-deep-equal": "^3.1.3",
"js-cookie": "^3.0.1",
"lodash": "^4.17.21",
"mqtt": "^5.14.1",
"next": "^13.1.6",
"normalize.css": "^8.0.1",
"react": "^18.2.0",
"react-csv": "^2.2.2",
"react-dnd": "15.0.2",
"react-dnd-html5-backend": "15.0.2",
"react-dnd-touch-backend": "15.0.2",
"react-dom": "^18.2.0",
"react-is": "^18.2.0",
"react-markdown": "^8.0.3",
"react-mde": "^11.5.0",
"react-toastify": "^9.0.7",
"rehype-raw": "^6.1.1",
"rehype-sanitize": "^5.0.1",
"sharp": "^0.30.3",
"shortid": "^2.2.16",
"styled-components": "^5.3.5",
"swr": "^1.2.2",
"uuid": "^13.0.0"
},
"engines": {
"node": "16"
},
"overrides": {
"react-mde": {
"react": "$react",
"react-dom": "$react-dom"
}
}
}
@@ -1,4 +1,7 @@
/* eslint-disable import/prefer-default-export */
// This file configures the initialization of Sentry on the browser.
// The config you add here will be used whenever a page is visited.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
import * as Sentry from "@sentry/nextjs";
const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
@@ -11,6 +14,3 @@ Sentry.init({
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
// that it will also get attached to your source maps
});
// This is required by Sentry v8 to instrument navigation (tracing)
export const onRouterTransitionStart = Sentry.captureRouterTransitionStart;
-18
View File
@@ -1,18 +0,0 @@
// This file configures the initialization of Sentry for edge features (middleware, edge routes, and so on).
// The config you add here will be used whenever one of the edge features is loaded.
// Note that this config is unrelated to the Vercel Edge Runtime and is also required when running locally.
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
import * as Sentry from "@sentry/nextjs";
const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
const ENV = process.env.NEXT_PUBLIC_DEPLOY_ENV;
Sentry.init({
dsn: SENTRY_DSN,
environment: ENV,
// Adjust this value in production, or use tracesSampler for greater control
// tracesSampleRate: 1.0, // Commented out as client/server configs don't have it
// Setting this option to true will print useful information to the console while you're setting up Sentry.
// debug: false, // Commented out as client/server configs don't have it
});
+3
View File
@@ -1,8 +1,11 @@
import axios, { AxiosInstance, AxiosRequestConfig } from "axios";
import { getAccessTokenCookie } from "@utils/auth";
const API_TIMEOUT_MS = 10000;
const axiosInstance: AxiosInstance = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL,
timeout: API_TIMEOUT_MS,
});
export enum APIPath {
+1 -1
View File
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/image";
import Image from "next/legacy/image";
const Icon = "/img/add-icon.png";
+3 -3
View File
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/image";
import Image from "next/legacy/image";
import styled from "styled-components";
import colors from "@theme/colors";
import Link from "@components/Link";
@@ -22,7 +22,6 @@ const StyledCard = styled.article`
display: flex;
flex-direction: column;
color: ${colors.black};
position: relative;
margin: 1rem;
text-align: center;
@@ -44,6 +43,7 @@ const StyledCard = styled.article`
}
h3 {
hyphens: auto;
padding: 0.5rem;
font-size: 1.5rem;
font-weight: 300;
@@ -73,7 +73,7 @@ const WrappedCard: React.FC<WrappedCardProps> = ({
}) => (
<StyledCard {...props}>
{image && (
<Image src={image.src} alt={image.alt} fill sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw" style={{ objectFit: "scale-down" }} />
<Image src={image.src} alt={image.alt} layout="responsive" width={0} height={0} objectFit="scale-down" />
)}
<p>{startTime}</p>
<h3>{title}</h3>
+3 -4
View File
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/image";
import Image from "next/legacy/image";
import styled from "styled-components";
import colors from "@theme/colors";
@@ -73,9 +73,8 @@ const ContactCard: React.FC<ContactCardProps> = ({
<Image
src={image}
alt={name}
fill
sizes="128px"
style={{ objectFit: "cover" }}
layout="fill"
objectFit="cover"
/>
</ImageContainer>
) : null}
+7 -8
View File
@@ -1,16 +1,16 @@
import React from "react";
import Image from "next/image";
import Image, { ImageProps } from "next/legacy/image";
import styled, { keyframes, Keyframes } from "styled-components";
interface CrossFadeImagesProps {
width: number | string;
height: number | string;
width: ImageProps["width"];
height: ImageProps["height"];
images: string[];
presentationTime: number;
fadeTime: number;
}
const AnimatedImage = styled(Image) <{ $delay: number }>`
const AnimatedImage = styled(Image)<{ layout: string; $delay: number }>`
animation-delay: ${(p) => p.$delay}s;
`;
@@ -69,15 +69,14 @@ const CrossFadeImages: React.FC<CrossFadeImagesProps> = ({
$animation={animation}
$duration={len * SINGLE_IMAGE_TIME}
>
{images.map((image, idx) => (
{ images.map((image, idx) => (
// eslint-disable-next-line react/no-array-index-key
<div key={idx} className={idx > 0 ? "not-first" : undefined}>
<AnimatedImage
src={image}
objectFit="cover"
alt=""
width={width as any}
height={height as any}
width={width}
height={height}
layout="responsive"
$delay={delays[idx]}
/>
+3 -4
View File
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/image";
import Image from "next/legacy/image";
import styled from "styled-components";
import { Link } from "@components/index";
@@ -18,9 +18,8 @@ const HeaderLogo: React.FC = () => (
<Image
src={TitleImage}
alt="logo"
fill
sizes="200px"
style={{ objectFit: "scale-down" }}
layout="fill"
objectFit="scale-down"
/>
</Logo>
);
+10 -20
View File
@@ -1,5 +1,5 @@
import React, {
createContext, useContext, useMemo, useReducer, useEffect,
createContext, useContext, useMemo, useReducer,
} from "react";
import fi from "./locales/fi/common.json";
import en from "./locales/en/common.json";
@@ -36,10 +36,16 @@ interface Store {
changeLanguage: React.Dispatch<Lang>,
}
// Always default to 'fi' for the initial state to ensure Server/Client match.
// We will hydrate the user's preference in useEffect below.
let initialLanguage: Lang = "fi";
try {
const storedLang = localStorage.getItem(LOCAL_STORAGE_KEY) as Lang;
initialLanguage = storedLang;
} catch (err) {
// Just ignore if fails to get value from browser (server etc.)
}
const initialState: Store = {
language: "fi",
language: initialLanguage,
changeLanguage: null,
};
@@ -63,22 +69,6 @@ const Reducer = (state: Store, action: Lang) => {
const LocaleContext = createContext(initialState);
const LocaleStore: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
const [state, dispatch] = useReducer(Reducer, initialState);
// Sync with localStorage only after the component has mounted (client-side)
useEffect(() => {
try {
const storedLang = localStorage.getItem(LOCAL_STORAGE_KEY) as Lang;
if (storedLang && (storedLang === "fi" || storedLang === "en")) {
// Only dispatch if different to prevent unnecessary re-renders
if (storedLang !== state.language) {
dispatch(storedLang);
}
}
} catch (err) {
// Just ignore if fails to get value from browser
}
}, []); // Empty dependency array ensures this runs once on mount
const changeLanguage = (action: Lang) => {
dispatch(action);
try {
-13
View File
@@ -1,13 +0,0 @@
import * as Sentry from "@sentry/nextjs";
export async function register() {
if (process.env.NEXT_RUNTIME === "nodejs") {
await import("../sentry.server.config");
}
if (process.env.NEXT_RUNTIME === "edge") {
await import("../sentry.edge.config");
}
}
export const onRequestError = Sentry.captureRequestError;
+26 -29
View File
@@ -14,14 +14,13 @@ interface InitialProps {
const EventPage: NextPage<InitialProps> = ({ event }) => {
const router = useRouter();
const { id } = router.query;
if (router.isFallback) return <LoadingView />;
return (
<>
<Head>
<link rel="canonical" href={`${process.env.NEXT_PUBLIC_SITE_URL}/events/${id}`} />
<link rel="canonical" href={`${process.env.NEXT_PUBLIC_SITE_URL}/events/${event.id}`} />
</Head>
<PageWrapper>
<EventPageView event={event} />
@@ -30,36 +29,34 @@ const EventPage: NextPage<InitialProps> = ({ event }) => {
);
};
export const getStaticPaths: GetStaticPaths = async () => {
const allEvents = await EventApi.getEvents();
const paths = allEvents.map((e: Event) => ({
params: {
id: String(e.id),
},
}
));
return {
paths,
fallback: true,
};
};
export const getStaticPaths: GetStaticPaths = async () => ({
paths: [],
fallback: "blocking",
});
export const getStaticProps: GetStaticProps<InitialProps> = async ({ params }) => {
const { id } = params;
let notFound = false;
let event: Event;
try {
event = await EventApi.getEvent(Number(id));
} catch (err) {
notFound = true;
const id = Number(params?.id);
if (!id) {
return {
notFound: true,
revalidate: 10,
};
}
try {
const event = await EventApi.getEvent(id);
return {
props: {
event,
},
revalidate: 10, // Required for deleting hidden pages
};
} catch {
return {
notFound: true,
revalidate: 10,
};
}
return {
props: {
event,
},
revalidate: 10, // Required for deleting hidden pages
notFound,
};
};
export default EventPage;
+25 -29
View File
@@ -14,14 +14,13 @@ interface InitialProps {
const FeedPage: NextPage<InitialProps> = ({ post }) => {
const router = useRouter();
const { id } = router.query;
if (router.isFallback) return <LoadingView />;
return (
<>
<Head>
<link rel="canonical" href={`${process.env.NEXT_PUBLIC_SITE_URL}/feed/${id}`} />
<link rel="canonical" href={`${process.env.NEXT_PUBLIC_SITE_URL}/feed/${post.id}`} />
</Head>
<PageWrapper>
<FeedPageView post={post} />
@@ -30,37 +29,34 @@ const FeedPage: NextPage<InitialProps> = ({ post }) => {
);
};
export const getStaticPaths: GetStaticPaths = async () => {
const feed = await FeedApi.getFeed();
const paths = feed.map((post: Post) => ({
params: {
id: String(post.id),
},
}
));
return {
paths,
fallback: true,
};
};
export const getStaticPaths: GetStaticPaths = async () => ({
paths: [],
fallback: "blocking",
});
export const getStaticProps: GetStaticProps<InitialProps> = async ({ params }) => {
const { id } = params;
let notFound = false;
let post: Post;
try {
post = await FeedApi.getPost(Number(id));
} catch (err) {
notFound = true;
const id = Number(params?.id);
if (!id) {
return {
notFound: true,
revalidate: 10,
};
}
return {
props: {
post,
},
revalidate: 10, // Required for deleting hidden pages
notFound,
};
try {
const post = await FeedApi.getPost(id);
return {
props: {
post,
},
revalidate: 10, // Required for deleting hidden pages
};
} catch {
return {
notFound: true,
revalidate: 10,
};
}
};
export default FeedPage;
+7 -4
View File
@@ -44,12 +44,15 @@ const InEnglishPage: NextPage<InitialProps> = ({ initialEvents, initialFeed }) =
};
export const getStaticProps: GetStaticProps<InitialProps> = async () => {
const initialEvents = await fetcher<Event[]>(eventApi);
const initialFeed = await fetcher<Post[]>(feedApi);
const [eventsResult, feedResult] = await Promise.allSettled([
fetcher<Event[]>(eventApi),
fetcher<Post[]>(feedApi),
]);
return {
props: {
initialEvents,
initialFeed,
initialEvents: eventsResult.status === "fulfilled" ? eventsResult.value : [],
initialFeed: feedResult.status === "fulfilled" ? feedResult.value : [],
},
revalidate: 10,
};
+7 -4
View File
@@ -43,12 +43,15 @@ const FrontPage: NextPage<InitialProps> = ({ initialEvents, initialFeed }) => {
};
export const getStaticProps: GetStaticProps<InitialProps> = async () => {
const initialEvents = fetcher<Event[]>(eventApi);
const initialFeed = fetcher<Post[]>(feedApi);
const [eventsResult, feedResult] = await Promise.allSettled([
fetcher<Event[]>(eventApi),
fetcher<Post[]>(feedApi),
]);
return {
props: {
initialEvents: await initialEvents,
initialFeed: await initialFeed,
initialEvents: eventsResult.status === "fulfilled" ? eventsResult.value : [],
initialFeed: feedResult.status === "fulfilled" ? feedResult.value : [],
},
revalidate: 10,
};
+7 -6
View File
@@ -3,9 +3,7 @@ import { NextPage, GetStaticProps } from "next";
import Head from "next/head";
import useSWR from "swr";
import Event from "@models/Event";
import EventApi from "@api/eventApi";
import Post from "@models/Feed";
import FeedApi from "@api/feedApi";
import ActualPageView from "@views/ActualPage/ActualPageView";
import PageWrapper from "@views/common/PageWrapper";
import { fetcher, APIPath, API } from "@api/backend";
@@ -40,12 +38,15 @@ const ActualPage: NextPage<InitialProps> = ({ initialEvents, initialFeed }) => {
};
export const getStaticProps: GetStaticProps<InitialProps> = async () => {
const initialEvents = await EventApi.getEvents();
const initialFeed = await FeedApi.getFeed();
const [eventsResult, feedResult] = await Promise.allSettled([
fetcher<Event[]>(eventApi),
fetcher<Post[]>(feedApi),
]);
return {
props: {
initialEvents,
initialFeed,
initialEvents: eventsResult.status === "fulfilled" ? eventsResult.value : [],
initialFeed: feedResult.status === "fulfilled" ? feedResult.value : [],
},
revalidate: 10,
};
+62 -29
View File
@@ -23,6 +23,9 @@ const FORM_URL = `${process.env.NEXT_PUBLIC_API_URL}/signupForm/`;
const SignUpPage: NextPage<InitialProps> = ({ initialForm }) => {
const router = useRouter();
const [honeypot, setHoneypot] = useState("");
const id = String(initialForm?.id ?? "");
const SUBMIT_ID = uuid(); // Submission key, generated on page refresh
const URL = `${FORM_URL}${id}/`;
@@ -43,11 +46,23 @@ const SignUpPage: NextPage<InitialProps> = ({ initialForm }) => {
);
}
const onSubmit = async ({ formData }: ISubmitEvent<string>) => {
const onSubmit = async ({ formData }: ISubmitEvent<any>) => {
// for bot detection
if (honeypot !== "") {
console.log("bot cought in honeypot cought lacking");
toast.success("Sign-up submitted successfully 😎");
return;
}
const trackedForm = {
...formData,
_source: "from the webs submit",
};
const payload: Signup = {
submit_id: SUBMIT_ID, // This is for preventing duplicate requests; NOT RELATED TO THE SIGNUP ID IN DATABASE
signupForm_id: signupForm.id,
answer: formData,
answer: trackedForm,
};
try {
@@ -72,41 +87,59 @@ const SignUpPage: NextPage<InitialProps> = ({ initialForm }) => {
onChange={noop}
onSubmit={onSubmit}
/>
{/* 3. HONEYPOT INPUT FIELD */}
<div
style={
{
position: "absolute", top: "-9999px", left: "-9999px", opacity: 0,
}
}
aria-hidden="true"
>
<label htmlFor="website_url">Do not fill this out if you are human</label>
<input
id="website_url"
type="text"
name="website_url"
value={honeypot}
onChange={(e) => setHoneypot(e.target.value)}
tabIndex={-1} // Removes it from the "tab" cycle so keyboard users don't hit it
autoComplete="off"
/>
</div>
</PageWrapper>
</>
);
};
export const getStaticPaths: GetStaticPaths = async () => {
const allForms = await SignupApi.getForms();
const paths = allForms.map((e: SignupForm) => ({
params: {
id: String(e.id),
},
}
));
return {
paths,
fallback: true,
};
};
export const getStaticPaths: GetStaticPaths = async () => ({
paths: [],
fallback: "blocking",
});
export const getStaticProps: GetStaticProps<InitialProps> = async ({ params }) => {
const { id } = params;
let notFound = false;
let initialForm: SignupForm;
try {
initialForm = await SignupApi.getForm(Number(id));
} catch {
notFound = true;
const id = Number(params?.id);
if (!id) {
return {
notFound: true,
revalidate: 10,
};
}
try {
const initialForm = await SignupApi.getForm(id);
return {
props: {
initialForm,
},
revalidate: 10, // Required for deleting hidden pages
};
} catch {
return {
notFound: true,
revalidate: 10,
};
}
return {
props: {
initialForm,
},
revalidate: 10, // Required for deleting hidden pages
notFound,
};
};
export default SignUpPage;
+5 -2
View File
@@ -30,10 +30,13 @@ const CorporatePage: NextPage<InitialProps> = ({ initialJobAds }) => {
};
export const getStaticProps: GetStaticProps<InitialProps> = async () => {
const initialJobAds = await fetcher<JobAd[]>(jobAdApi);
const jobAdsResult = await Promise.allSettled([
fetcher<JobAd[]>(jobAdApi),
]);
return {
props: {
initialJobAds,
initialJobAds: jobAdsResult[0].status === "fulfilled" ? jobAdsResult[0].value : [],
},
revalidate: 10,
};
+15 -1
View File
@@ -38,10 +38,17 @@ const Container = styled.div`
}
@media (max-width: 950px) {
width: 100vw;
width: 80vw;
}
`;
const BoardImage = styled.img`
width: 100%;
height: auto;
margin-bottom: 2rem;
border-radius: 8px;
`;
const ContactContainer = styled.div`
overflow-x: hidden;
@media (max-width: 950px) {
@@ -54,6 +61,12 @@ const CommitteeContainer: React.FC<{
children: React.ReactNode;
}> = ({ committee, children }) => (
<Container>
{committee.slug === "board" && (
<BoardImage
src="https://static.sahkoinsinoorikilta.fi/img/board/2026/Pota105_sikh26_webiin.jpg"
alt="Hallitus 2026"
/>
)}
<div>
{committee.roles.map((role) => (
role.representatives.map((representative) => (
@@ -74,6 +87,7 @@ const CommitteeContainer: React.FC<{
);
interface Committee {
slug: string;
name_fi: string;
name_en: string;
roles: Array<Role>;
+40 -40
View File
@@ -1,6 +1,6 @@
{
"slug": "board",
"name_fi": "Hallitus 2024",
"name_fi": "Hallitus 2026",
"name_en": "Board",
"roles": [
{
@@ -8,10 +8,10 @@
"name_en": "Chairman of the Board",
"representatives": [
{
"name": "Emma Uusküla",
"name": "Sauli Hakala",
"phone_number": null,
"email": "emma.uuskula@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Emma.jpg"
"email": "sauli.hakala@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/sauli.jpg"
}
]
},
@@ -20,10 +20,10 @@
"name_en": "Vice Chair",
"representatives": [
{
"name": "Johannes Viirimäki",
"name": "Eemeli Hintsanen",
"phone_number": null,
"email": "johannes.viirimaki@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Johannes.jpg"
"email": "eemeli.hintsanen@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/eemeli.jpg"
}
]
},
@@ -32,10 +32,10 @@
"name_en": "Treasurer",
"representatives": [
{
"name": "Nelli Liljasto",
"name": "Nea Kanerva",
"phone_number": null,
"email": "nelli.liljasto@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Nelli.jpg"
"email": "nea.kanerva@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/nea.jpg"
}
]
},
@@ -44,10 +44,10 @@
"name_en": "",
"representatives": [
{
"name": "Teemu Heikkinen",
"name": "Aura Friman",
"phone_number": null,
"email": "teemu.heikkinen@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Teemu.jpg"
"email": "aura.friman@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/aura.jpg"
}
]
},
@@ -56,10 +56,10 @@
"name_en": "",
"representatives": [
{
"name": "Henri Aito",
"name": "Antti Salpakari",
"phone_number": null,
"email": "henri.aito@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Henri.jpg"
"email": "antti.salpakari@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/antti.jpg"
}
]
},
@@ -68,10 +68,10 @@
"name_en": "",
"representatives": [
{
"name": "Tuomas Rantamäki",
"name": "Aino Saarela",
"phone_number": null,
"email": "tuomas.rantamaki@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/TuomasR.jpg"
"email": "aino.saarela@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/aino_sa.jpg"
}
]
},
@@ -80,10 +80,10 @@
"name_en": "",
"representatives": [
{
"name": "Matilda Ahonen",
"name": "Rosanna Reims",
"phone_number": null,
"email": "matilda.ahonen@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Matilda.jpg"
"email": "rosanna.reims@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/rosanna.jpg"
}
]
},
@@ -92,10 +92,10 @@
"name_en": "",
"representatives": [
{
"name": "Niklas Ritalahti",
"name": "Valentin Juhela",
"phone_number": null,
"email": "niklas.ritalahti@sahkoinsinoorikilta.fi",
"image": ""
"email": "valentin.juhela@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/valentin.jpg"
}
]
},
@@ -104,10 +104,10 @@
"name_en": "",
"representatives": [
{
"name": "Mikael Vatiainen",
"name": "Elida Widgren",
"phone_number": null,
"email": "mikael.vatiainen@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Mikael.jpg"
"email": "elida.widgren@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/elida.jpg"
}
]
},
@@ -116,10 +116,10 @@
"name_en": "",
"representatives": [
{
"name": "Simeon Pursiainen",
"name": "Joona Maaranen",
"phone_number": null,
"email": "simeon.pursiainen@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Simeon.jpg"
"email": "joona.maaranen@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/joona.jpg"
}
]
},
@@ -128,10 +128,10 @@
"name_en": "",
"representatives": [
{
"name": "Markus Aaltio",
"name": "Jere Oinonen",
"phone_number": null,
"email": "markus.aaltio@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Markus.jpg"
"email": "jere.oinonen@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/jere.jpg"
}
]
},
@@ -140,10 +140,10 @@
"name_en": "",
"representatives": [
{
"name": "Tuomas Hintikka",
"name": "Into Saarinen",
"phone_number": null,
"email": "tuomas.hintikka@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/TuomasH.jpg"
"email": "into.saarinen@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/into.jpg"
}
]
},
@@ -152,10 +152,10 @@
"name_en": "",
"representatives": [
{
"name": "Yassine Ramid",
"name": "Aino Svahn",
"phone_number": null,
"email": "yassine.ramid@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Yassine.jpg"
"email": "aino.svahn@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/aino_sv.jpg"
}
]
}
@@ -16,6 +16,9 @@ import YtmkJson from "./ytmk.json";
import SwtmkJson from "./swtmk.json";
import VtmkJson from "./vtmk.json";
import LtmkJson from "./ltmk.json";
import SiccJson from "./sicc.json";
import SptmkJson from "./sptmk.json";
import PotatmkJson from "./potatmk.json";
import Others from "./others.json";
const orderedCommittees = [
@@ -31,6 +34,9 @@ const orderedCommittees = [
VtmkJson,
SwtmkJson,
NtmkJson,
SiccJson,
SptmkJson,
PotatmkJson,
Others,
];
+7 -7
View File
@@ -9,7 +9,7 @@
"name_en": "",
"representatives": [
{
"name": "Teemu Heikkinen"
"name": "Aura Friman"
}
]
},
@@ -18,7 +18,7 @@
"name_en": "",
"representatives": [
{
"name": "Henri Aito"
"name": "Antti Salpakari"
}
]
},
@@ -27,10 +27,10 @@
"name_en": "International Fuksi Captain",
"representatives": [
{
"name": "Markus Aaltio"
"name": "Jere Oinonen"
},
{
"name": "Apollo Ailus"
"name": "Hocine Montenez"
}
]
},
@@ -39,7 +39,7 @@
"name_en": "Tutor Coordinator",
"representatives": [
{
"name": "Axel Aurola"
"name": "Veera Lindroos"
}
]
},
@@ -48,9 +48,9 @@
"name_en": "International Tutor Coordinator",
"representatives": [
{
"name": "Igor Oinonen"
"name": "Janne Yrjölä"
}
]
}
]
}
}
+49 -46
View File
@@ -1,56 +1,59 @@
{
"slug": "htmk",
"name_fi": "Hupitoimikunta",
"name_en": "Entertainment Committee",
"info": "Hupitoimikunta järjestää päätoimenaan kaikenkirjavia tapahtumia, kuten sitsejä, saunailtoja sekä muita juhlia. Hupitoimikuntaa johtaa Hovimestari ja Hovineuvos. Toimikunnassa toimii Hovin lisäksi emäntiä ja isäntiä, jotka hoitavat juhlien käytännön järjestelyjä, esimerkiksi ruoanlaiton, kattauksen ja tarjoilun Hovin johdolla.",
"roles": [
{
"name_fi": "Hovimestari",
"name_en": "Master of Ceremonies",
"representatives": [
"slug": "htmk",
"name_fi": "Hupitoimikunta",
"name_en": "Entertainment Committee",
"info": "Hupitoimikunta järjestää päätoimenaan kaikenkirjavia tapahtumia, kuten sitsejä, saunailtoja sekä muita juhlia. Hupitoimikuntaa johtaa Hovimestari ja Hovineuvos. Toimikunnassa toimii Hovin lisäksi emäntiä ja isäntiä, jotka hoitavat juhlien käytännön järjestelyjä, esimerkiksi ruoanlaiton, kattauksen ja tarjoilun Hovin johdolla.",
"roles": [
{
"name": "Tuomas Rantamäki"
}
]
},
{
"name_fi": "Hovineuvos",
"name_en": "Court Counsellor",
"representatives": [
{
"name": "Matilda Ahonen"
}
]
},
{
"name_fi": "Emäntä",
"name_en": "Hostess",
"representatives": [
{
"name": "Veera Lindroos"
"name_fi": "Hovimestari",
"name_en": "Master of Ceremonies",
"representatives": [
{
"name": "Aino Saarela"
}
]
},
{
"name": "Aino Saarela"
"name_fi": "Hovineuvos",
"name_en": "Court Counsellor",
"representatives": [
{
"name": "Rosanna Reims"
}
]
},
{
"name": "Nea Kanerva"
"name_fi": "Emäntä",
"name_en": "Hostess",
"representatives": [
{
"name": "Elina Pyylampi"
},
{
"name": "Elle Leivo"
},
{
"name": "Emma Salmenaho"
}
]
},
{
"name": "Rosanna Reims"
"name_fi": "Isäntä",
"name_en": "Host",
"representatives": [
{
"name": "Aleksi Nuutinen"
},
{
"name": "Juho Rosnell"
},
{
"name": "Julius Härkönen"
},
{
"name": "Joonas Hilvo"
}
]
}
]
},
{
"name_fi": "Isäntä",
"name_en": "Host",
"representatives": [
{
"name": "Eemeli Hintsanen"
},
{
"name": "André Palosaari"
}
]
}
]
]
}
+96 -94
View File
@@ -1,99 +1,101 @@
{
"slug": "hvtmk",
"name_fi": "Hyvinvointitoimikunta",
"name_en": "Committee of Wellbeing",
"info": "Hyvinvointitoimikunta järjestää monipuolisesti kiltalaisten hyvinvointia edistävää hyvän mielen toimintaa. Toimikunta koostuu liikunta-, retkeily-, kulttuuri- ja kiltahuonevastaavista, ja toimikuntaa johtaa hyvinvointimestari.",
"roles": [
{
"name_fi": "Hyvinvointimestari",
"name_en": "Master of Wellbeing",
"representatives": [
"slug": "hvtmk",
"name_fi": "Hyvinvointitoimikunta",
"name_en": "Committee of Wellbeing",
"info": "Hyvinvointitoimikunta järjestää monipuolisesti kiltalaisten hyvinvointia edistävää hyvän mielen toimintaa. Toimikunta koostuu liikunta-, retkeily-, kulttuuri- ja kiltahuonevastaavista, ja toimikuntaa johtaa hyvinvointimestari.",
"roles": [
{
"name": "Niklas Ritalahti"
"name_fi": "Hyvinvointimestari",
"name_en": "Master of Wellbeing",
"representatives": [
{
"name": "Valentin Juhela"
}
]
},
{
"name_fi": "Kulttuurivastaava",
"name_en": "Culture Representative",
"representatives": [
{
"name": "Johannes Viirimäki"
},
{
"name": "Linnea Viitasalo"
},
{
"name": "Matilda Ahonen"
}
]
},
{
"name_fi": "Liikuntavastaava",
"name_en": "Sports Representative",
"representatives": [
{
"name": "Aino Salmi"
},
{
"name": "Eeda Alasaari"
},
{
"name": "Iiris Kuulusa"
}
]
},
{
"name_fi": "Kiltahuonevastaava",
"name_en": "Guild Room Representative",
"representatives": [
{
"name": "Milja Kuusela"
},
{
"name": "Tuomas Rantamäki"
}
]
},
{
"name_fi": "Retkeilyvastaava",
"name_en": "",
"representatives": [
{
"name": "Arvi Virkkunen"
},
{
"name": "Auli Purolinna"
},
{
"name": "Ville Lairila"
},
{
"name": "Tiitus Koski"
}
]
},
{
"name_fi": "Yhdenvertaisuusvastaava",
"name_en": "",
"representatives": [
{
"name": "Teemu Heikkinen"
},
{
"name": "Aaron Löfgren"
},
{
"name": "Matilda Ahonen"
}
]
},
{
"name_fi": "Kiltamuori",
"name_en": "",
"representatives": [
{
"name": "Markus Aaltio"
}
]
}
]
},
{
"name_fi": "Kulttuurivastaava",
"name_en": "Culture Representative",
"representatives": [
{
"name": "Peter Lindahl"
},
{
"name": "Kuura Janhunen"
},
{
"name": "Valentin Juhela"
},
{
"name": "Leevi Leinonen"
},
{
"name": "Milla Heino"
},
{
"name": "Hocine Montenez"
}
]
},
{
"name_fi": "Liikuntavastaava",
"name_en": "Sports Representative",
"representatives": [
{
"name": "Matias Hendolin"
},
{
"name": "Sauli Hakala"
}
]
},
{
"name_fi": "Kiltahuonevastaava",
"name_en": "Guild Room Representative",
"representatives": [
{
"name": "Milja Kuusela"
},
{
"name": "Aaro Rasilainen"
}
]
},
{
"name_fi": "Retkeilyvastaava",
"name_en": "",
"representatives": [
{
"name": "Tommi Sytelä"
},
{
"name": "Konsta Hakala"
},
{
"name": "Ville Lairila"
}
]
},
{
"name_fi": "Yhdenvertaisuusvastaava",
"name_en": "",
"representatives": [
{
"name": "Saara Rossi"
},
{
"name": "Aaron Löfgren"
},
{
"name": "Milla Heino"
},
{
"name": "Sauli Hakala"
}
]
}
]
}
+58 -55
View File
@@ -1,62 +1,65 @@
{
"slug": "ltmk",
"name_fi": "Lukkaritoimikunta",
"name_en": "",
"info": "Lukkaritoimikunta on vastuussa killan laulukulttuurin kehittämisestä sekä ylläpitämisestä. Toimikunnan muodostaa lukkarimestari, lukkarit sekä lukkarikisällit. Meidät tapaat sitseillä sekä muissa tapahtumissa muistuttamassa, että teekkari laulaa mieluummin kuin hyvin.",
"roles": [
{
"name_fi": "Lukkarimestari",
"name_en": "",
"representatives": [
{
"name": "Leevi Oikarinen"
}
]
},
{
"name_fi": "Lukkari",
"name_en": "",
"representatives": [
"slug": "ltmk",
"name_fi": "Lukkaritoimikunta",
"name_en": "",
"info": "Lukkaritoimikunta on vastuussa killan laulukulttuurin kehittämisestä sekä ylläpitämisestä. Toimikunnan muodostaa lukkarimestari, lukkarit sekä lukkarikisällit. Meidät tapaat sitseillä sekä muissa tapahtumissa muistuttamassa, että teekkari laulaa mieluummin kuin hyvin.",
"roles": [
{
"name": "Aino Salmi"
"name_fi": "Lukkarimestari",
"name_en": "",
"representatives": [
{
"name": "Aino Salmi"
}
]
},
{
"name": "Ilmari Reponen"
"name_fi": "Lukkari",
"name_en": "",
"representatives": [
{
"name": "Alex Hyytinen"
},
{
"name": "Ilmari Reponen"
},
{
"name": "Iiris Kuulusa"
},
{
"name": "Samuel Södervall"
},
{
"name": "Tapio Immonen"
}
]
},
{
"name": "Jenni Marttinen"
},
{
"name": "Peter Lindahl"
},
{
"name": "Patrik Varteva"
},
{
"name": "Tapio Immonen"
"name_fi": "Lukkarikisälli",
"name_en": "",
"representatives": [
{
"name": "Aapo Palojärvi"
},
{
"name": "André Palosaari"
},
{
"name": "Kaisa Lehtimäki"
},
{
"name": "Olav Hamel"
},
{
"name": "Otto Tuominen"
},
{
"name": "Panu Leinonen"
},
{
"name": "Terhi Lukkari"
}
]
}
]
},
{
"name_fi": "Lukkarikisälli",
"name_en": "",
"representatives": [
{
"name": "Alex Hyytinen"
},
{
"name": "Antti Salpakari"
},
{
"name": "Iiris Kuulusa"
},
{
"name": "Roman Shalamov"
},
{
"name": "Samuel Södervall"
}
]
}
]
}
]
}
+106 -100
View File
@@ -1,104 +1,110 @@
{
"slug": "mtmk",
"name_fi": "Sössö-toimikunta",
"name_en": "Media Committee",
"info": "Sössö-toimikunta toimittaa Sössöä, Sähköinsinöörikillan ikiomaa lehteä, joka on ikänsä ja laatunsa puolesta Otaniemen eliittiä. Toimikunta julkaisee vuodessa kaksi painettua lehteä sekä lukuisia nettiartikkeleita ynnä muuta. Toimikunta hoitaa lisäksi myös valokuvat ja live-striimit.",
"roles": [
{
"name_fi": "Päätoimittaja",
"name_en": "Editor in Chief",
"representatives": [
"slug": "mtmk",
"name_fi": "Sössö-toimikunta",
"name_en": "Media Committee",
"info": "Sössö-toimikunta toimittaa Sössöä, Sähköinsinöörikillan ikiomaa lehteä, joka on ikänsä ja laatunsa puolesta Otaniemen eliittiä. Toimikunta julkaisee vuodessa kaksi painettua lehteä sekä lukuisia nettiartikkeleita ynnä muuta. Toimikunta hoitaa lisäksi myös valokuvat ja live-striimit.",
"roles": [
{
"name": "Topi Manskinen",
"phone_number": null,
"email": null,
"image": null
"name_fi": "Päätoimittaja",
"name_en": "Editor in Chief",
"representatives": [
{
"name": "Joona Komonen",
"phone_number": null,
"email": null,
"image": null
}
]
},
{
"name_fi": "Tyhjäntoimittaja",
"name_en": "",
"representatives": [
{
"name": "Topi Manskinen",
"phone_number": null,
"email": null,
"image": null
}
]
},
{
"name_fi": "Toimittaja",
"name_en": "Journalist",
"representatives": [
{
"name": "Aake Laukkanen"
},
{
"name": "Alex Hyytinen"
},
{
"name": "Apollo Ailus"
},
{
"name": "Eetu Tossavainen"
},
{
"name": "Jenni Marttinen"
},
{
"name": "Juho Laukka"
},
{
"name": "Lauri Anttila"
},
{
"name": "Otto kievimaa"
},
{
"name": "Sampo Haarala"
},
{
"name": "Venla Nikkanen"
}
]
},
{
"name_fi": "Taittaja",
"name_en": "",
"representatives": [
{
"name": "Atte Vitie"
},
{
"name": "Lauri Anttila"
},
{
"name": "Otto Kievimaa"
},
{
"name": "Partrik Varteva"
}
]
},
{
"name_fi": "Graafikko",
"name_en": "Photographer & Graphic Artist",
"representatives": [
{
"name": "Annika Tattari"
},
{
"name": "Elian Salmimaa"
},
{
"name": "Lotta Kähönen"
}
]
},
{
"name_fi": "Heevistriimaaja",
"name_en": "Heevistreamer",
"representatives": [
{
"name": "Aaro Rasilainen"
}
]
}
]
},
{
"name_fi": "Tyhjäntoimittaja",
"name_en": "",
"representatives": [
{
"name": "Visa Kurvi",
"phone_number": null,
"email": null,
"image": null
}
]
},
{
"name_fi": "Toimittaja",
"name_en": "Journalist",
"representatives": [
{
"name": "Joona Komonen"
},
{
"name": "Olli Vaismaa"
},
{
"name": "Jenni Marttinen"
},
{
"name": "Ilmari Reponen"
},
{
"name": "Igor Oinonen"
},
{
"name": "Otto Kievimaa"
}
]
},
{
"name_fi": "Toimittaja, Taittaja",
"name_en": "",
"representatives": [
{
"name": "Atte Vitie"
}
]
},
{
"name_fi": "Taittaja",
"name_en": "",
"representatives": [
{
"name": "Otto Kievimaa"
}
]
},
{
"name_fi": "Graafikko",
"name_en": "Photographer & Graphic Artist",
"representatives": [
{
"name": "Elian Salmimaa"
}
]
},
{
"name_fi": "Valokuvaaja",
"name_en": "Photographer",
"representatives": [
{
"name": "Veikko Räty"
},
{
"name": "Into Saarinen"
},
{
"name": "Aaro Rasilainen"
},
{
"name": "Anton Niemi"
},
{
"name": "Veera Melvasalo"
}
]
}
]
]
}
+67 -75
View File
@@ -5,93 +5,85 @@
"info": "N-toimikunta järjestää erinäisiä tapahtumia vanhemmille ja vanhemmanmielisille kiltalaisille, kuten sitsejä, aftereita, ulkoilutapahtumia ja mitä ikinä keksitäänkään. N-toimikunta toimii myös matalan kynnyksen välinä Sklubiin, eli alumniyhdistykseemme. N-toimikuntaan kuuluu myös killan kiltapatruunat, jotka pitävät huolta killan jatkuvuudesta.",
"roles": [
{
"name_fi": "N-toimikunnan nestori",
"name_fi": "N-toimikunnan puheenjohtaja",
"name_en": "",
"representatives": [
{
"name": "Karoliina Talvikangas"
}
{
"name": "Elina Huttunen"
}
]
},
{
"name_fi": "N-toimikunnan varanestori, Kiltapatruuna",
"name_en": "",
"representatives": [
{
"name": "Aaron Löfgren"
}
]
},
{
"name_fi": "Sklubi-yhdyshenkilö",
"name_en": "",
"representatives": [
{
"name": "Melisa Dönmez"
},
{
"name": "Eveliina Ahonen"
}
]
},
{
"name_fi": "Kiltapatruuna",
"name_en": "",
"representatives": [
{
"name": "Ville Lairila"
},
{
"name": "Visa Kurvi"
}
]
},
{
"name_fi":
"Kiltapatruuna, Nipsu",
"name_fi": "N-toimikunnan Varapuheenjohtaja",
"name_en": "",
"representatives": [
{
"name": "Mikko Sandström"
},
{
"name": "Liisa Haltia"
},
{
"name": "Elina Huttunen"
}
{
"name": "Ville Lairila"
}
]
},
{
"name_fi": "Nipsu",
"name_fi": "Kiltapatruuna",
"name_en": "",
"representatives": [
{
"name": "Mikael Siikonen"
},
{
"name": "Axel Aurola"
},
{
"name": "Elian Salmimaa"
},
{
"name": "Elias Damski"
},
{
"name": "Elias Lindberg"
},
{
"name": "Eero Ketonen"
},
{
"name": "Verneri Turkki"
},
{
"name": "Akseli Heikkinen"
}
{
"name": "Aaron Löfgren"
},
{
"name": "Axel Aurola"
},
{
"name": "Emma Uusküla"
},
{
"name": "Johannes Viirimäki"
},
{
"name": "Tuomas Rantamäki"
},
{
"name": "Yassine Ramid"
}
]
},
{
"name_fi": "N-vastaava",
"name_en": "",
"representatives": [
{
"name": "Aaron Löfgren"
},
{
"name": "Aleksi Saajakari"
},
{
"name": "Elian Salmimaa"
},
{
"name": "Johannes Viirimäki"
},
{
"name": "Karoliina Talvikangas"
},
{
"name": "Markus Aaltio"
},
{
"name": "Miika Helminen"
},
{
"name": "Mikael Siikonen"
},
{
"name": "Peter Lindahl"
},
{
"name": "Veikko Räty"
},
{
"name": "Verneri Turkki"
}
]
}
]
}
}
+50 -37
View File
@@ -1,41 +1,54 @@
{
"slug": "optmk",
"name_fi": "Opintotoimikunta",
"name_en": "Study Committee",
"info": "Opintotoimikunta vastaa edunvalvonnasta, killan tekemästä abimarkkinoinnista, sekä pitää yhteyttä korkeakoulun henkilökuntaan. Toimikunta järjestää opintoihin liittyviä tapahtumia, kuten opintosaunoja. Tomikunta koostuu opintomestarista ja opintovastaavista.",
"roles": [
{
"name_fi": "Opintomestari",
"name_en": "Master of Studies",
"representatives": [
"slug": "optmk",
"name_fi": "Opintotoimikunta",
"name_en": "Study Committee",
"info": "Opintotoimikunta vastaa edunvalvonnasta, killan tekemästä abimarkkinoinnista, sekä pitää yhteyttä korkeakoulun henkilökuntaan. Toimikunta järjestää opintoihin liittyviä tapahtumia, kuten opintosaunoja. Tomikunta koostuu opintomestarista ja opintovastaavista.",
"roles": [
{
"name": "Mikael Vatiainen"
"name_fi": "Opintomestari",
"name_en": "Master of Studies",
"representatives": [
{
"name": "Elida Widgren"
}
]
},
{
"name_fi": "Opintovastaava",
"name_en": "Study Coordinator",
"representatives": [
{
"name": "Aapo Tynninen"
},
{
"name": "Aleksi Liukkonen"
},
{
"name": "Antti Lehtonen"
},
{
"name": "Atu Vahla"
},
{
"name": "Iiris Kuulusa"
},
{
"name": "Ilmari Reponen"
},
{
"name": "Jesper Seppäläinen"
},
{
"name": "Mikael Vatiainen"
},
{
"name": "Vi Tam"
},
{
"name": "Yassine Ramid"
}
]
}
]
},
{
"name_fi": "Opintovastaava",
"name_en": "Study Coordinator",
"representatives": [
{
"name": "Atu Vahla"
},
{
"name": "Antti Lehtonen"
},
{
"name": "Aleksi Liukkonen"
},
{
"name": "Ilmari Reponen"
},
{
"name": "Milla Heino"
},
{
"name": "Samuel Södervall"
}
]
}
]
]
}
+47 -27
View File
@@ -1,32 +1,52 @@
{
"slug": "others",
"name_fi": "Muut",
"name_en": "Other officials",
"info": "",
"roles": [
{
"name_fi": "Merikapteeni",
"name_en": "Sea captain",
"representatives": [
"slug": "others",
"name_fi": "Muut",
"name_en": "Other officials",
"info": "",
"roles": [
{
"name": "Ville Lairila",
"phone_number": null,
"email": null
}
]
},
{
"name_fi": "Meripojankloppi",
"name_en": "ship's boy",
"representatives": [
"name_fi": "Arkistovastaava",
"name_en": "",
"representatives": [
{
"name": "Aaron Löfgren",
"phone_number": null,
"email": null
}
]
},
{
"name": "Peter Lindahl",
"phone_number": null,
"email": null
"name_fi": "Sklubi-yhdyshenkilö",
"name_en": "",
"representatives": [
{
"name": "Ville Kurko",
"phone_number": null,
"email": null
}
]
},
{
"name_fi": "Teekkarikokousen kiltaedustaja",
"name_en": "",
"representatives": [
{
"name": "Aaron Löfgren",
"phone_number": null,
"email": null
}
]
},
{
"name_fi": "TEK-yhdyshenkilö",
"name_en": "",
"representatives": [
{
"name": "Visa Kurvi",
"phone_number": null,
"email": null
}
]
}
]
}
]
]
}
+83
View File
@@ -0,0 +1,83 @@
{
"slug": "potatmk",
"name_fi": "Potentiaalin Tasaus 105-toimikunta",
"name_en": "",
"info": "Killan vuosijuhlat",
"roles": [
{
"name_fi": "PoTa-tirehtööri",
"name_en": "",
"representatives": [
{
"name": "Axel Aurola"
},
{
"name": "Karoliina Talvikangas"
}
]
},
{
"name_fi": "Kukkohäntävastaava",
"name_en": "",
"representatives": [
{
"name": "Antti Salpakari"
},
{
"name": "Tuomas Rantamäki"
}
]
},
{
"name_fi": "Seremoniamestari",
"name_en": "",
"representatives": [
{
"name": "Henri Aito"
}
]
},
{
"name_fi": "Jatkovastaava",
"name_en": "",
"representatives": [
{
"name": "Aino Tasapuro"
},
{
"name": "Eemeli Hintsanen"
}
]
},
{
"name_fi": "Koristeluvastaava",
"name_en": "",
"representatives": [
{
"name": "Elina Huttunen"
}
]
},
{
"name_fi": "Sillisvastaava",
"name_en": "",
"representatives": [
{
"name": "Leevi Oikarinen"
},
{
"name": "Valentin Juhela"
}
]
},
{
"name_fi": "Graafikko",
"name_en": "",
"representatives": [
{
"name": "Elian Salmimaa"
}
]
}
]
}
+52 -49
View File
@@ -1,53 +1,56 @@
{
"slug": "ptmk",
"name_fi": "Pajatoimikunta",
"name_en": "",
"info": "Pajatoimikunta vastaa killan oman elektroniikkapajan eli SIK-pajan ylläpidosta ja kehityksestä. Toimikuntaa johtaa pajamestari ja toimikunta koostuu pajavastaavista ja pajakisälleistä.",
"roles": [
{
"name_fi": "Pajamestari",
"name_en": "",
"representatives": [
"slug": "ptmk",
"name_fi": "Pajatoimikunta",
"name_en": "",
"info": "Pajatoimikunta vastaa killan oman elektroniikkapajan eli SIK-pajan ylläpidosta ja kehityksestä. Toimikuntaa johtaa pajamestari ja toimikunta koostuu pajavastaavista ja pajakisälleistä.",
"roles": [
{
"name": "Jere Oinonen"
"name_fi": "Pajamestari",
"name_en": "",
"representatives": [
{
"name": "Simeon Pursiainen"
}
]
},
{
"name_fi": "Pajavastaava",
"name_en": "",
"representatives": [
{
"name": "Axel Söderberg"
},
{
"name": "Đình Minh Trần"
}
]
},
{
"name_fi": "Pajakisälli",
"name_en": "",
"representatives": [
{
"name": "Aapo Tynninen"
},
{
"name": "Aarni Kämppi"
},
{
"name": "Atte Elo"
},
{
"name": "Emma Uusküla"
},
{
"name": "Jusi Seppälä"
},
{
"name": "Tuomas Rantamäki"
},
{
"name": "Vi Tam"
}
]
}
]
},
{
"name_fi": "Pajakisälli",
"name_en": "",
"representatives": [
{
"name": "Otto Kievimaa"
},
{
"name": "Đình Minh Trần"
},
{
"name": "Valentin Juhela"
},
{
"name": "Axel Söderberg"
},
{
"name": "Auli Purolinna"
},
{
"name": "Karl Lipping"
},
{
"name": "Petrus Asikainen"
},
{
"name": "Elmo Kankkunen"
},
{
"name": "Samu Nyman"
},
{
"name": "Hilkka Gröhn"
}
]
}
]
]
}
+44
View File
@@ -0,0 +1,44 @@
{
"slug": "sicc",
"name_fi": "SIK International Committee Council",
"name_en": "SIK International Committee Council",
"info": "*coming soon*",
"roles": [
{
"name_fi": "International Ambassador",
"name_en": "International Ambassador",
"representatives": [
{
"name": "Igor Oinonen"
}
]
},
{
"name_fi": "International Attaché",
"name_en": "International Attaché",
"representatives": [
{
"name": "Kuura Janhunen"
}
]
},
{
"name_fi": "International Envoy",
"name_en": "International Envoy",
"representatives": [
{
"name": "Aleksanteri Vesala"
},
{
"name": "Apollo Ailus"
},
{
"name": "Juho Aikio"
},
{
"name": "Léo Di Poi"
}
]
}
]
}
+45
View File
@@ -0,0 +1,45 @@
{
"slug": "sptmk",
"name_fi": "Sähköpäivätoimikunta",
"name_en": "",
"info": "",
"roles": [
{
"name_fi": "Sähköpäivätirehtööri",
"name_en": "",
"representatives": [
{
"name": "Aino Tasapuro"
},
{
"name": "Matilda Ahonen"
}
]
},
{
"name_fi": "Sähköpäivävastaava",
"name_en": "",
"representatives": [
{
"name": "Aapo Nyyssönen"
},
{
"name": "Aapo Saranpää"
},
{
"name": "André Palosaari"
},
{
"name": "Ilmari Reponen"
},
{
"name": "Oliver Hannula"
},
{
"name": "Teemu Heikkinen"
}
]
}
]
}
+44 -35
View File
@@ -1,38 +1,47 @@
{
"slug": "swtmk",
"name_fi": "SIKin Wapaa-aika -toimikunta",
"name_en": "",
"info": "Sikin Wapaa-aika -toimikunta eli tuttavallisemmin SiWa on killan uusin toimikunta. Toimikunnan tavoitteena on järjestää monipuolisesti erilaisia hassunhauskoja matalan kynnyksen tapahtumia kiltalaisille laidasta laitaan. Esimerkkejä SiWan tapahtumista ovat mm. wappulautta, pitsapäivä ja pokeriturnaus.",
"roles": [
{
"name_fi": "Myymäläpäällikkö",
"name_en": "Head of sales",
"representatives": [
"slug": "swtmk",
"name_fi": "SIKin Wapaa-aika -toimikunta",
"name_en": "",
"info": "Sikin Wapaa-aika -toimikunta eli tuttavallisemmin SiWa on killan uusin toimikunta. Toimikunnan tavoitteena on järjestää monipuolisesti erilaisia hassunhauskoja matalan kynnyksen tapahtumia kiltalaisille laidasta laitaan. Esimerkkejä SiWan tapahtumista ovat mm. wappulautta, pitsapäivä ja pokeriturnaus.",
"roles": [
{
"name": "Tiitus Koski"
"name_fi": "Myymäläpäällikkö",
"name_en": "Head of sales",
"representatives": [
{
"name": "Leevi Oikarinen"
}
]
},
{
"name_fi": "Myyjä",
"name_en": "Clerk",
"representatives": [
{
"name": "Alexandr Lemin"
},
{
"name": "Henri Aito"
},
{
"name": "Ossi Jalkanen"
},
{
"name": "Tiitus Koski"
},
{
"name": "Veikko Räty"
}
]
},
{
"name_fi": "Kiltapäiväkerhovastaava",
"name_en": "",
"representatives": [
{
"name": "Matilda Ahonen"
}
]
}
]
},
{
"name_fi": "Myyjä",
"name_en": "Clerk",
"representatives": [
{
"name": "Arvi Virkkunen"
},
{
"name": "Valentin Juhela"
},
{
"name": "Otto Rinne"
},
{
"name": "Auli Purolinna"
},
{
"name": "Patrik Varteva"
}
]
}
]
}
]
}
+31 -34
View File
@@ -1,38 +1,35 @@
{
"slug": "ttmk",
"name_fi": "Teknologiatoimikunta",
"name_en": "Technology Committee",
"info": "Teknologiatoimikunta huolehtii killan tekniikan toiminnasta. Toimikunnan vastuulle kuuluu killan tietojärjestelmien ylläpito ja kehitys sekä viestintäkanavien toimivuudesta huolehtiminen. Toimikunta koostuu teknologiamestarista ja teknologiavastaavista.",
"roles": [
{
"name_fi": "Teknologiamestari",
"name_en": "Master of technology",
"representatives": [
"slug": "ttmk",
"name_fi": "Teknologiatoimikunta",
"name_en": "Technology Committee",
"info": "Teknologiatoimikunta huolehtii killan tekniikan toiminnasta. Toimikunnan vastuulle kuuluu killan tietojärjestelmien ylläpito ja kehitys sekä viestintäkanavien toimivuudesta huolehtiminen. Toimikunta koostuu teknologiamestarista ja teknologiavastaavista.",
"roles": [
{
"name": "Simeon Pursiainen"
"name_fi": "Teknologiamestari",
"name_en": "Master of technology",
"representatives": [
{
"name": "Joona Maaranen"
}
]
},
{
"name_fi": "Teknologiavastaava",
"name_en": "",
"representatives": [
{
"name": "Alekdsandr Lemin"
},
{
"name": "Atte Elo"
},
{
"name": "Dat Tram"
},
{
"name": "Oiva Haapaniemi"
}
]
}
]
},
{
"name_fi": "Teknologiavastaava",
"name_en": "",
"representatives": [
{
"name": "Joona Maaranen"
},
{
"name": "Aleksi Liukkonen"
},
{
"name": "Elmo Kankkunen"
},
{
"name": "Justus Ojala"
},
{
"name": "Tommi Sytelä"
}
]
}
]
]
}
+41 -27
View File
@@ -9,7 +9,7 @@
"name_en": "Head of communcations",
"representatives": [
{
"name": "Yassine Ramid"
"name": "Aino Svahn"
}
]
},
@@ -18,25 +18,22 @@
"name_en": "",
"representatives": [
{
"name": "Aaron Löfgren"
"name": "Aada Tättilä"
},
{
"name": "Elina Huttunen"
"name": "Ada Minkkinen"
},
{
"name": "Aura Friman"
}
]
},
{
"name_fi": "Somevastaava, Brändivastaava",
"name_en": "",
"representatives": [
{
"name": "Aapo Saranpää"
"name": "Aino Tasapuro"
},
{
"name": "Aino Svahn"
"name": "Ira Kosunen"
},
{
"name": "Lukas Iles"
},
{
"name": "Tytti Solonen"
}
]
},
@@ -45,23 +42,15 @@
"name_en": "",
"representatives": [
{
"name": "Aleksandr Lemin"
},
{
"name": "Roope Jaskari"
},
{
"name": "Sauli Hakala"
},
{
"name": "Ville Lairila"
"name": "Aapo Saranpää"
},
{
"name": "Aapo Nyyssönen"
},
{
"name": "Mikko Sandström"
"name": "Kehrä Halme"
}
]
},
{
@@ -69,12 +58,37 @@
"name_en": "",
"representatives": [
{
"name": "Veera Melvasalo"
"name": "Apollo Ailus"
},
{
"name": "Julius Männistö"
}
]
},
{
"name_fi": "Valokuvaaja",
"name_en": "",
"representatives": [
{
"name": "Aaro Rasilainen"
},
{
"name": "Apollo Ailus"
},
{
"name": "Arvi Virkkunen"
},
{
"name": "Julius Männistö"
},
{
"name": "Lotta Kähönen"
},
{
"name": "Veikko Räty"
}
]
}
]
}
}
+52 -82
View File
@@ -1,86 +1,56 @@
{
"slug": "ytmk",
"name_fi": "Yrityssuhdetoimikunta",
"name_en": "Corporate Relations Committee",
"info": "Yrityssuhdetoimikunta toimii linkkinä yritysmaailman ja Sähköinsinöörikillan välillä. Toimikunnan tehtäviin kuuluu esimerkiksi excursioiden eli yritysvierailujen järjestäminen, yrityssaunailtojen ja muiden yhteistyösopimuksilla rahoitettujen tapahtumien järjestäminen, sekä sponsoreiden hankinta Sähköinsinöörikillan puhtaanvalkoisiin haalareihin. Lisäksi yrityssuhdetoimikunnan vastuulla on ulkosuhteiden ylläpito ystävyysainejärjestöihin kotimaassa ja ulkomailla.",
"roles": [
{
"name_fi": "Yrityssuhdemestari",
"name_en": "Head of Corporate Relations",
"representatives": [
"slug": "ytmk",
"name_fi": "Yrityssuhdetoimikunta",
"name_en": "Corporate Relations Committee",
"info": "Yrityssuhdetoimikunta toimii linkkinä yritysmaailman ja Sähköinsinöörikillan välillä. Toimikunnan tehtäviin kuuluu esimerkiksi excursioiden eli yritysvierailujen järjestäminen, yrityssaunailtojen ja muiden yhteistyösopimuksilla rahoitettujen tapahtumien järjestäminen, sekä sponsoreiden hankinta Sähköinsinöörikillan puhtaanvalkoisiin haalareihin. Lisäksi yrityssuhdetoimikunnan vastuulla on ulkosuhteiden ylläpito ystävyysainejärjestöihin kotimaassa ja ulkomailla.",
"roles": [
{
"name": "Tuomas Hintikka"
"name_fi": "Yrityssuhdemestari",
"name_en": "Head of Corporate Relations",
"representatives": [
{
"name": "Into Saarinen"
}
]
},
{
"name_fi": "Yrityssuhdeguru",
"name_en": "Guru of yritysuhde",
"representatives": [
{
"name": "Tuomas Hintikka"
}
]
},
{
"name_fi": "Excursiomestari",
"name_en": "Head of Excursions",
"representatives": [
{
"name": "Roope Palo"
}
]
},
{
"name_fi": "Yrityssuhde- ja excursiovastaava",
"name_en": "Apprentice of Corporate Relations",
"representatives": [
{
"name": "Axel Aurola"
},
{
"name": "Mikael Sundell"
},
{
"name": "Kaisa Lehtimäki"
},
{
"name": "Timo Kaleva"
},
{
"name": "Väinö Saarinen"
}
]
}
]
},
{
"name_fi": "Excursiomestari",
"name_en": "Head of Excursions",
"representatives": [
{
"name": "Aino Tasapuro"
}
]
},
{
"name_fi": "Yrityssuhdevastaava",
"name_en": "Apprentice of Corporate Relations",
"representatives": [
{
"name": "Mikael Sundell"
},
{
"name": "Henrik Ervasti"
},
{
"name": "Samuel Södervall"
},
{
"name": "Markus Määttänen"
},
{
"name": "Aura Friman"
},
{
"name": "Anton Niemi"
},
{
"name": "Iida Toivanen"
},
{
"name": "Joona Kivioja"
},
{
"name": "Jussi Seppälä"
},
{
"name": "Roope Palo"
},
{
"name": "Väinö Saarinen"
},
{
"name": "Junias Vasama"
},
{
"name": "Anton Saari"
},
{
"name": "Väinö Silvenius"
}
]
},
{
"name_fi": "Excursiovastaava",
"name_en": "",
"representatives": [
{
"name": "Into Saarinen"
},
{
"name": "Otto Rinne"
}
]
}
]
]
}
+3 -2
View File
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/image";
import Image from "next/legacy/image";
import styled from "styled-components";
import rehypeRaw from "rehype-raw";
import rehypeSanitize from "rehype-sanitize";
@@ -81,9 +81,10 @@ const EventPageView: React.FC<EventPageViewProps> = ({ event }) => {
<Image
src={event.image || event.tags[0].icon}
alt={title}
objectFit="scale-down"
layout="responsive"
width={16}
height={9}
style={{ objectFit: "scale-down" }}
/>
</h1>
<div>
+3 -2
View File
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/image";
import Image from "next/legacy/image";
import styled from "styled-components";
import rehypeRaw from "rehype-raw";
import rehypeSanitize from "rehype-sanitize";
@@ -65,9 +65,10 @@ const FeedPageView: React.FC<FeedPageViewProps> = ({ post }) => {
<Image
src={post.image}
alt={title}
objectFit="scale-down"
layout="responsive"
width={16}
height={9}
style={{ objectFit: "scale-down" }}
/>
)}
</h1>
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/image";
import Image from "next/legacy/image";
import styled from "styled-components";
import {
CTASection, TextSection, InfoBox, PageLink, Link,
@@ -11,6 +11,8 @@ const TG_GROUP_CHAT_LINK = "https://t.me/+ctpg4H0-Y3hlZTY0";
const TG_NOTIFICATIONS_LINK = "https://t.me/+v30Nts-MrIMyMjNk";
const EMAIL_LINK = "ftmk@sahkoinsinoorikilta.fi";
const EMAIL_LINK_MAILTO = `mailto:${EMAIL_LINK}`;
const SIK_QR = "https://static.sahkoinsinoorikilta.fi/FTMK/SIK-Fuksit-2026-telegram.jpg";
const SIK_QR_TIEDOTUS = "https://static.sahkoinsinoorikilta.fi/FTMK/SIK-Fuksit-2026-telegram-tiedotus.jpg";
const ImageContainer = styled.div`
width: 100%;
@@ -59,11 +61,12 @@ const ForFreshmenPageView: React.FC = () => (
<ImageContainer>
<Image
src="https://static.sahkoinsinoorikilta.fi/FTMK/IMG_6539.JPG"
src="https://static.sahkoinsinoorikilta.fi/FTMK/kipparit-26.jpg"
alt="Kipparit"
layout="responsive"
width={100}
height={80}
style={{ objectFit: "contain" }}
objectFit="contain"
/>
</ImageContainer>
@@ -81,8 +84,8 @@ const ForFreshmenPageView: React.FC = () => (
Over time, the pieces of the puzzle will come together to form an image that reflects you, and you&apos;ll have the opportunity to shape what the final result looks like.
</p>
<p>
Orientation week is held from August 25th to 29th, 2025, but even before then, you&apos;ll have the chance to meet us, other freshmen, and the ISOs at a relaxed Pre-Start event.
The Pre-Start for the freshman year is organized on Saturday, August 16th, 2025. Find more details in the Telegram groups!
Orientation week is held from August 25th to 29th, 2026, but even before then, you&apos;ll have the chance to meet us, other freshmen, and the ISOs at a relaxed Pre-Start event.
The Pre-Start for the freshman year is organized on Saturday, August 16th, 2026. Find more details in the Telegram groups!
</p>
<h6>Teemu Heikkinen</h6>
@@ -127,12 +130,12 @@ const ForFreshmenPageView: React.FC = () => (
SIK fuksis have a group chat, which you can join by scanning the QR code below:
</p>
<QRImages
src="https://static.sahkoinsinoorikilta.fi/FTMK/SIK-Fuksit-2025.jpg"
src={SIK_QR}
/>
<p>or <Link to={TG_GROUP_CHAT_LINK} target="_blank">press me!</Link></p>
<p>Also join the notifications channel for SIK fuksis, to stay in the loop!:</p>
<QRImages
src="https://static.sahkoinsinoorikilta.fi/FTMK/SIK-Fuksit-tiedotus-2025.jpg"
src="https://static.sahkoinsinoorikilta.fi/FTMK/SIK-Fuksit-tiedotus-2026.jpg"
/>
<p>or <Link to={TG_NOTIFICATIONS_LINK} target="_blank">press me!</Link></p>
</InfoBox>
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/image";
import Image from "next/legacy/image";
import styled from "styled-components";
import {
CTASection, TextSection, InfoBox, PageLink, Link,
@@ -11,6 +11,8 @@ const TG_GROUP_CHAT_LINK = "https://t.me/+oNrBDLI5cXZhNDEx";
const TG_NOTIFICATIONS_LINK = "https://t.me/sikhotline2526";
const EMAIL_LINK = "ftmk@sahkoinsinoorikilta.fi";
const EMAIL_LINK_MAILTO = `mailto:${EMAIL_LINK}`;
const SIK_QR = "https://static.sahkoinsinoorikilta.fi/FTMK/SIK-Fuksit-2026-telegram.jpg";
const SIK_QR_TIEDOTUS = "https://static.sahkoinsinoorikilta.fi/FTMK/SIK-Fuksit-2026-telegram-tiedotus.jpg";
const ImageContainer = styled.div`
width: 100%;
@@ -76,11 +78,12 @@ const ForIntlPageView: React.FC = () => (
<ImageContainer>
<Image
src="https://static.sahkoinsinoorikilta.fi/FTMK/Captains2025.jpg"
src="https://static.sahkoinsinoorikilta.fi/FTMK/Captains2026.jpg"
alt="Kipparit"
layout="responsive"
width={100}
height={80}
style={{ objectFit: "contain" }}
objectFit="contain"
/>
</ImageContainer>
@@ -101,9 +104,9 @@ const ForIntlPageView: React.FC = () => (
having just as much fun as we are. Always remember that as a teekkari in Otaniemi, you&apos;re never alone.
</p>
<p>
Orientation week will be held from 25 to 29 August 2025, but even before that you have the
Orientation week will be held from 25 to 29 August 2026, but even before that you have the
opportunity to come and get to know us, other freshmen and ISOs at a relaxed Headstart event.
This will be held on Saturday 16 August 2025. More about that in the Telegram groups!
This will be held on Saturday 16 August 2026. More about that in the Telegram groups!
</p>
<h6>Apollo Ailus</h6>
@@ -148,12 +151,12 @@ const ForIntlPageView: React.FC = () => (
SIK fuksis have a group chat, which you can join by scanning the QR code below:
</p>
<QRImages
src="https://static.sahkoinsinoorikilta.fi/FTMK/SIK-Fuksit-2025.jpg"
src={SIK_QR}
/>
<p>or <Link to={TG_GROUP_CHAT_LINK} target="_blank">press me!</Link></p>
<p>Also join the notifications channel for SIK fuksis, to stay in the loop!:</p>
<QRImages
src="https://static.sahkoinsinoorikilta.fi/FTMK/SIK-Fuksit-tiedotus-2025.jpg"
src={SIK_QR_TIEDOTUS}
/>
<p>or <Link to={TG_NOTIFICATIONS_LINK} target="_blank">press me!</Link></p>
</InfoBox>
+10 -7
View File
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/image";
import Image from "next/legacy/image";
import styled from "styled-components";
import {
CTASection, TextSection, InfoBox, PageLink, Link,
@@ -11,6 +11,8 @@ const TG_GROUP_CHAT_LINK = "https://t.me/+ctpg4H0-Y3hlZTY0";
const TG_NOTIFICATIONS_LINK = "https://t.me/+v30Nts-MrIMyMjNk";
const EMAIL_LINK = "ftmk@sahkoinsinoorikilta.fi";
const EMAIL_LINK_MAILTO = `mailto:${EMAIL_LINK}`;
const SIK_QR = "https://static.sahkoinsinoorikilta.fi/FTMK/SIK-Fuksit-2026-telegram.jpg";
const SIK_QR_TIEDOTUS = "https://static.sahkoinsinoorikilta.fi/FTMK/SIK-Fuksit-2026-telegram-tiedotus.jpg";
const ImageContainer = styled.div`
width: 100%;
@@ -58,11 +60,12 @@ const FreshmenPageView: React.FC = () => (
<ImageContainer>
<Image
src="https://static.sahkoinsinoorikilta.fi/FTMK/IMG_6539.JPG"
src="https://static.sahkoinsinoorikilta.fi/FTMK/kipparit-26.jpg"
alt="Kipparit"
layout="responsive"
width={100}
height={80}
style={{ objectFit: "contain" }}
objectFit="contain"
/>
</ImageContainer>
@@ -79,8 +82,8 @@ const FreshmenPageView: React.FC = () => (
Ajan myötä palapelin palat muodostavat sinun näköisesi kuvan ja pääset itse vaikuttamaan siihen, miltä lopputulos näyttää.
</p>
<p>
Orientaatioviikko järjestetään 25.-29.8.2025, mutta jo ennen sitä sinulla on mahdollisuus tulla tutustumaan meihin, muihin fukseihin ja ISOihin rentoon Varaslähtöön.
Varaslähtö fuksivuoteen järjestetään lauantaina 16.8.2025. Siitä lisää Telegram-ryhmissä!
Orientaatioviikko järjestetään 25.-29.8.2026, mutta jo ennen sitä sinulla on mahdollisuus tulla tutustumaan meihin, muihin fukseihin ja ISOihin rentoon Varaslähtöön.
Varaslähtö fuksivuoteen järjestetään lauantaina 16.8.2026. Siitä lisää Telegram-ryhmissä!
</p>
<h6>Teemu Heikkinen</h6>
@@ -125,12 +128,12 @@ const FreshmenPageView: React.FC = () => (
SIK:n fukseilla on oma Telegram-ryhmä, jonne pääset liitymään tästä:
</p>
<QRImages
src="https://static.sahkoinsinoorikilta.fi/FTMK/SIK-Fuksit-2025.jpg"
src={SIK_QR}
/>
<p>tai <Link to={TG_GROUP_CHAT_LINK} target="_blank">tästä</Link></p>
<p>Liity myös samalla SIK-fuksien tiedotuskanavalle tästä:</p>
<QRImages
src="https://static.sahkoinsinoorikilta.fi/FTMK/SIK-Fuksit-tiedotus-2025.jpg"
src={SIK_QR_TIEDOTUS}
/>
<p>tai <Link to={TG_NOTIFICATIONS_LINK} target="_blank">tästä</Link></p>
</InfoBox>
+14 -14
View File
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/image";
import Image from "next/legacy/image";
import styled from "styled-components";
import {
Divider,
@@ -93,43 +93,43 @@ const FrontPageView: React.FC<FrontPageViewProps> = ({ events, feed }) => (
<SponsorReel>
<div>
<Link to="https://new.abb.com/fi/">
<Image src={ABB} alt="ABB" width={200} height={100} style={{ objectFit: "contain" }} />
<Image src={ABB} alt="ABB" layout="responsive" width={200} height={100} objectFit="contain" />
</Link>
<Link to="https://caruna.fi/">
<Image src={Caruna} alt="Caruna" width={200} height={100} style={{ objectFit: "contain" }} />
<Image src={Caruna} alt="Caruna" layout="responsive" width={200} height={100} objectFit="contain" />
</Link>
<Link to="https://www.nokia.com/">
<Image src={Nokia} alt="Nokia" width={200} height={100} style={{ objectFit: "contain" }} />
<Image src={Nokia} alt="Nokia" layout="responsive" width={200} height={100} objectFit="contain" />
</Link>
<Link to="https://www.ensto.com/fi/">
<Image src={Ensto} alt="Ensto" width={200} height={100} style={{ objectFit: "contain" }} />
<Image src={Ensto} alt="Ensto" layout="responsive" width={200} height={100} objectFit="contain" />
</Link>
<Link to="https://www.esett.com/">
<Image src={eSett} alt="eSett" width={200} height={100} style={{ objectFit: "contain" }} />
<Image src={eSett} alt="eSett" layout="responsive" width={200} height={100} objectFit="contain" />
</Link>
<Link to="https://www.fingrid.fi/">
<Image src={Fingrid} alt="Fingrid" width={200} height={100} style={{ objectFit: "contain" }} />
<Image src={Fingrid} alt="Fingrid" layout="responsive" width={200} height={100} objectFit="contain" />
</Link>
<Link to="https://www.okmetic.com/fi/">
<Image src={Okmetic} alt="Okmetic" width={200} height={100} style={{ objectFit: "contain" }} />
<Image src={Okmetic} alt="Okmetic" layout="responsive" width={200} height={100} objectFit="contain" />
</Link>
<Link to="https://www.granlund.fi/">
<Image src={Granlund} alt="Granlund" width={200} height={100} style={{ objectFit: "contain" }} />
<Image src={Granlund} alt="Granlund" layout="responsive" width={200} height={100} objectFit="contain" />
</Link>
<Link to="https://www.eaton.com/fi/fi-fi.html">
<Image src={Eaton} alt="Eaton" width={200} height={100} style={{ objectFit: "contain" }} />
<Image src={Eaton} alt="Eaton" layout="responsive" width={200} height={100} objectFit="contain" />
</Link>
<Link to="https://www.ericsson.com/en">
<Image src={Ericsson} alt="Ericsson" width={200} height={100} style={{ objectFit: "contain" }} />
<Image src={Ericsson} alt="Ericsson" layout="responsive" width={200} height={100} objectFit="contain" />
</Link>
<Link to="https://www.saab.com/fi/markets/finland">
<Image src={Saab} alt="Saab" width={200} height={100} style={{ objectFit: "contain" }} />
<Image src={Saab} alt="Saab" layout="responsive" width={200} height={100} objectFit="contain" />
</Link>
<Link to="https://www.stul.fi/">
<Image src={STUL} alt="STUL" width={200} height={100} style={{ objectFit: "contain" }} />
<Image src={STUL} alt="STUL" layout="responsive" width={200} height={100} objectFit="contain" />
</Link>
<Link to="https://www.metso.com/fi/">
<Image src={Metso} alt="Metso" width={200} height={100} style={{ objectFit: "contain" }} />
<Image src={Metso} alt="Metso" layout="responsive" width={200} height={100} objectFit="contain" />
</Link>
</div>
<Link to="/yritysyhteistyo">Haluatko kuulla lisää yhteistyöstä kanssamme?</Link>
+24 -1
View File
@@ -40,7 +40,8 @@ const HonoraryPageView: React.FC = () => (
<li>Keijo Nikoskinen 20112014</li>
<li>Jussi Ryynänen 20142017</li>
<li>Ville Viikari 20172020</li>
<li>Anu Lehtovuori 2020</li>
<li>Anu Lehtovuori 20202026</li>
<li>Marko Hinkkanen 2026-</li>
</ul>
<h2>Pro SIK</h2>
<p>
@@ -91,6 +92,8 @@ const HonoraryPageView: React.FC = () => (
<li>2023 Emmaleena Ahonen</li>
<li>2024 Jonna Tammikivi</li>
<li>2025 Eveliina Ahonen</li>
<li>2026 Otto Julkunen</li>
<li>2026 Melisa Dönmez</li>
</ul>
<h2>Standaari</h2>
<p>Standaari voidaan hallituksen päätöksellä lahjoittaa killan toimintaan myönteisesti vaikuttaneille tahoille. Standaarit on numeroitu lahjoittamisjärjestyksessä.</p>
@@ -233,6 +236,12 @@ const HonoraryPageView: React.FC = () => (
<li>2025 Iikka Huttu</li>
<li>2025 Heidi Mäkitalo</li>
</ul>
<ul>
<li>2026 Aaron Löfgren</li>
<li>2025 Elina Huttunen</li>
<li>2026 Karoliina Talvikangas</li>
<li>2026 Tommi Sytelä</li>
</ul>
<h2>Hopeiset ansiomerkit</h2>
<p>Killan hallitus voi myöntää hopeisen ansiomerkin killan jäsenelle tai perustellusta syystä myös muulle henkilölle tunnustuksena erityisestä kiinnostuksesta kiltaa kohtaan sekä ansioituneesta toiminnasta killan hyväksi.</p>
<ul>
@@ -630,6 +639,20 @@ const HonoraryPageView: React.FC = () => (
<li>2024 Veikko Räty</li>
<li>2024 Visa Kurvi</li>
</ul>
<ul>
<li>2025 Alisa Ahonen</li>
<li>2025 Axel Aurola</li>
<li>2025 Axel Söderberg</li>
<li>2025 Leevi Oikarinen</li>
<li>2025 Liisa Haltia</li>
<li>2025 Mikael Siikonen</li>
<li>2025 Mikko Sandström</li>
<li>2025 Peter Lindahl</li>
<li>2025 Roope Jaskari</li>
<li>2025 Sauli Hakala</li>
<li>2025 Valentin Juhela</li>
<li>2025 Ville Lairila</li>
</ul>
</div>
</TextSection>
</>
@@ -15,8 +15,8 @@ const MembershipPageView: React.FC = () => (
sekä pääsyn killan tiloihin kuten kiltahuoneelle ja SIK-pajalle.
</p>
<p>
Killan varsinaiseksi jäseneksi voidaan hyväksyä kaikki killan toiminnasta kiinnotuneet AYY:n jäsenet.
Killan ulkojäseneksi voidaan hyväksyä jäsenmaksun maksanut henkilö, joita ei voida hyväksyä varsinaiseksi jäseneksi.
Killan varsinaiseksi jäseneksi voidaan hyväksyä kaikki killan toiminnasta kiinnostuneet AYY:n jäsenet.
Killan ulkojäseneksi voidaan hyväksyä jäsenmaksun maksanut henkilö, jota ei voida hyväksyä varsinaiseksi jäseneksi.
Killan kannatusjäseneksi voidaan hyväksyä henkilö tai yhteisö, joka haluaa tukea killan toimintaa.
</p>
<p>
+3 -2
View File
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/image";
import Image from "next/legacy/image";
import {
CTASection, TextSection, PageLink, Link,
} from "@components/index";
@@ -81,7 +81,8 @@ const StudiesPageView: React.FC = () => (
alt="Ville Viikari"
width={300}
height={150}
style={{ objectFit: "contain" }}
layout="responsive"
objectFit="contain"
/>
<h6>Ville Viikari</h6>
<p>
+1 -1
View File
@@ -8,5 +8,5 @@
},
"skipJsErrors": true,
"appCommand": "npm run serve",
"appInitDelay": 10000
"appInitDelay": 2000
}
+1 -1
View File
@@ -1,6 +1,6 @@
import { Selector } from "testcafe";
import {
getSiteRoot, getPageUrl, deleteForm, doLogin, generateAccessToken, getPostRequestLogger, waitForLogger,
getSiteRoot, getPageUrl, deleteForm, doLogin, generateAccessToken, getPostRequestLogger, waitForLogger
} from "../utils";
const LOGGER = getPostRequestLogger("signupForm/");
+4 -4
View File
@@ -159,10 +159,10 @@ export const generateTestEvent = async (formIds = [], jwt_access: string) => (
export const sleep = async (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
export const waitForLogger = async (logger: RequestLogger) => {
for (let i = 0; i < 50; i += 1) {
for (let i = 0; i < 50; i++) {
await sleep(100);
if (logger.requests.length > 0) {
return;
if (logger.requests.length > 0 ) {
return;
}
}
};
}
+1 -1
View File
@@ -5,7 +5,7 @@
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"jsx": "react-jsx",
"jsx": "preserve",
"lib": [
"dom",
"esnext"