Compare commits

..

11 Commits

Author SHA1 Message Date
jadera a3ab778a84 uskomaton säätö 2025-12-10 21:10:56 +02:00
jadera 4de56eef0b vitttttttuuuu 2025-12-10 20:51:29 +02:00
jadera b3eae06a5b vithu 2025-12-10 20:43:27 +02:00
jadera f8a711a869 vittu 2025-12-10 20:33:05 +02:00
jadera 19fbe71506 switch to testcafe image 2025-12-10 20:25:43 +02:00
jadera 469f4f4da6 chown test files to runner 2025-12-10 20:14:06 +02:00
jadera cd2a58a76d testcafe testing 2025-12-10 20:04:40 +02:00
jadera 84b2b450c6 drop testcafe node back to 16 2025-12-10 19:46:42 +02:00
jadera 7d3fd6857c fix crossfade from legacy 2025-12-10 19:38:18 +02:00
jadera 9f44bf57f6 node bump 16->20 2025-12-10 19:27:47 +02:00
jadera 9d9211fa9c testing version bumps
extras

kakka
2025-12-10 19:21:50 +02:00
45 changed files with 34131 additions and 28269 deletions
+1
View File
@@ -5,3 +5,4 @@ node_modules
# don't lint nyc coverage output
coverage
next-env.d.ts
tests
+17 -8
View File
@@ -8,7 +8,7 @@ stages:
- deploy
install:
image: node:16
image: node:20
stage: setup
script:
- npm ci
@@ -21,7 +21,7 @@ install:
expire_in: 1 week
audit:
image: node:16
image: node:20
needs: ["install"]
allow_failure: true
stage: audit
@@ -29,27 +29,27 @@ audit:
- npm audit --audit-level=critical
es:lint:
image: node:16
image: node:20
needs: ["install"]
stage: lint
script:
- npm run lint:es
css:lint:
image: node:16
image: node:20
needs: ["install"]
stage: lint
script:
- npm run lint:css
# test:unit:
# image: node:16
# image: node:20
# stage: test
# script:
# - npm run test:unit
build:
image: node:16
image: node:20
needs: ["install"]
stage: build
script:
@@ -67,11 +67,20 @@ build:
- .next/cache/
test:e2e:
image: circleci/node:16-browsers
# Use a Cypress image which has Node 20 + Chrome and runs as root (solves permission issues)
image: cypress/browsers:latest
needs: ["install", "build"]
stage: test
script:
- npm run testcafe
# 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
artifacts:
paths:
- e2e-screenshots
+2 -1
View File
@@ -1,5 +1,6 @@
/// <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/basic-features/typescript for more information.
// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information.
+46 -21
View File
@@ -1,29 +1,54 @@
// web2.0-frontend/next.config.js
const { withSentryConfig } = require("@sentry/nextjs");
const withBundleAnalyzer = require("@next/bundle-analyzer")({
enabled: process.env.ANALYZE === "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({
/** @type {import('next').NextConfig} */
const nextConfig = {
compiler: {
styledComponents: true,
},
images: {
domains: [
"api.sahkoinsinoorikilta.fi",
"static.sahkoinsinoorikilta.fi",
"api.dev.sahkoinsinoorikilta.fi",
remotePatterns: [
{
protocol: "https",
hostname: "api.sahkoinsinoorikilta.fi",
},
{
protocol: "https",
hostname: "static.sahkoinsinoorikilta.fi",
},
{
protocol: "https",
hostname: "api.dev.sahkoinsinoorikilta.fi",
},
],
},
sentry: {
hideSourceMaps: true, // Hide source maps, see: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#configure-source-maps
},
}, sentryWebpackPluginOptions));
// 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));
+33146 -27123
View File
File diff suppressed because it is too large Load Diff
+100 -99
View File
@@ -1,102 +1,103 @@
{
"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"
},
"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": "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"
}
}
}
}
+18
View File
@@ -0,0 +1,18 @@
// 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
});
+1 -1
View File
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/legacy/image";
import Image from "next/image";
const Icon = "/img/add-icon.png";
+3 -2
View File
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/legacy/image";
import Image from "next/image";
import styled from "styled-components";
import colors from "@theme/colors";
import Link from "@components/Link";
@@ -22,6 +22,7 @@ const StyledCard = styled.article`
display: flex;
flex-direction: column;
color: ${colors.black};
position: relative;
margin: 1rem;
text-align: center;
@@ -72,7 +73,7 @@ const WrappedCard: React.FC<WrappedCardProps> = ({
}) => (
<StyledCard {...props}>
{image && (
<Image src={image.src} alt={image.alt} layout="responsive" width={0} height={0} objectFit="scale-down" />
<Image src={image.src} alt={image.alt} fill sizes="(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw" style={{ objectFit: "scale-down" }} />
)}
<p>{startTime}</p>
<h3>{title}</h3>
+4 -3
View File
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/legacy/image";
import Image from "next/image";
import styled from "styled-components";
import colors from "@theme/colors";
@@ -73,8 +73,9 @@ const ContactCard: React.FC<ContactCardProps> = ({
<Image
src={image}
alt={name}
layout="fill"
objectFit="cover"
fill
sizes="128px"
style={{ objectFit: "cover" }}
/>
</ImageContainer>
) : null}
+8 -7
View File
@@ -1,16 +1,16 @@
import React from "react";
import Image, { ImageProps } from "next/legacy/image";
import Image from "next/image";
import styled, { keyframes, Keyframes } from "styled-components";
interface CrossFadeImagesProps {
width: ImageProps["width"];
height: ImageProps["height"];
width: number | string;
height: number | string;
images: string[];
presentationTime: number;
fadeTime: number;
}
const AnimatedImage = styled(Image)<{ layout: string; $delay: number }>`
const AnimatedImage = styled(Image) <{ $delay: number }>`
animation-delay: ${(p) => p.$delay}s;
`;
@@ -69,14 +69,15 @@ 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"
width={width}
height={height}
alt=""
width={width as any}
height={height as any}
layout="responsive"
$delay={delays[idx]}
/>
+4 -3
View File
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/legacy/image";
import Image from "next/image";
import styled from "styled-components";
import { Link } from "@components/index";
@@ -18,8 +18,9 @@ const HeaderLogo: React.FC = () => (
<Image
src={TitleImage}
alt="logo"
layout="fill"
objectFit="scale-down"
fill
sizes="200px"
style={{ objectFit: "scale-down" }}
/>
</Logo>
);
+20 -10
View File
@@ -1,5 +1,5 @@
import React, {
createContext, useContext, useMemo, useReducer,
createContext, useContext, useMemo, useReducer, useEffect,
} from "react";
import fi from "./locales/fi/common.json";
import en from "./locales/en/common.json";
@@ -36,16 +36,10 @@ interface Store {
changeLanguage: React.Dispatch<Lang>,
}
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.)
}
// Always default to 'fi' for the initial state to ensure Server/Client match.
// We will hydrate the user's preference in useEffect below.
const initialState: Store = {
language: initialLanguage,
language: "fi",
changeLanguage: null,
};
@@ -69,6 +63,22 @@ 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 {
@@ -1,7 +1,4 @@
// 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/
/* eslint-disable import/prefer-default-export */
import * as Sentry from "@sentry/nextjs";
const SENTRY_DSN = process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN;
@@ -14,3 +11,6 @@ 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;
+13
View File
@@ -0,0 +1,13 @@
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;
-27
View File
@@ -23,9 +23,6 @@ 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}/`;
@@ -47,13 +44,6 @@ const SignUpPage: NextPage<InitialProps> = ({ initialForm }) => {
}
const onSubmit = async ({ formData }: ISubmitEvent<string>) => {
if (honeypot !== "") {
console.log("bot cought in honeypot cought lacking");
toast.success("Sign-up submitted successfully 😎");
return;
}
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,
@@ -76,23 +66,6 @@ const SignUpPage: NextPage<InitialProps> = ({ initialForm }) => {
<link rel="canonical" href={`${process.env.NEXT_PUBLIC_SITE_URL}/signup/${signupForm.id}`} />
</Head>
<PageWrapper>
{/* 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>
<SignUpPageView
signUpForm={signupForm}
formData={{}}
+39 -39
View File
@@ -8,10 +8,10 @@
"name_en": "Chairman of the Board",
"representatives": [
{
"name": "Sauli Hakala",
"name": "Emma Uusküla",
"phone_number": null,
"email": "sauli.hakala@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/sauli.jpg"
"email": "emma.uuskula@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Emma.jpg"
}
]
},
@@ -20,10 +20,10 @@
"name_en": "Vice Chair",
"representatives": [
{
"name": "Eemeli Hintsanen",
"name": "Johannes Viirimäki",
"phone_number": null,
"email": "eemeli.hintsanen@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/eemeli.jpg"
"email": "johannes.viirimaki@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Johannes.jpg"
}
]
},
@@ -32,10 +32,10 @@
"name_en": "Treasurer",
"representatives": [
{
"name": "Nea Kanerva",
"name": "Nelli Liljasto",
"phone_number": null,
"email": "nea.kanerva@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/nea.jpg"
"email": "nelli.liljasto@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Nelli.jpg"
}
]
},
@@ -44,10 +44,10 @@
"name_en": "",
"representatives": [
{
"name": "Aura Friman",
"name": "Teemu Heikkinen",
"phone_number": null,
"email": "aura.friman@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/aura.jpg"
"email": "teemu.heikkinen@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Teemu.jpg"
}
]
},
@@ -56,10 +56,10 @@
"name_en": "",
"representatives": [
{
"name": "Antti Salpakari",
"name": "Henri Aito",
"phone_number": null,
"email": "antti.salpakari@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/antti.jpg"
"email": "henri.aito@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Henri.jpg"
}
]
},
@@ -68,10 +68,10 @@
"name_en": "",
"representatives": [
{
"name": "Aino Saarela",
"name": "Tuomas Rantamäki",
"phone_number": null,
"email": "aino.saarela@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/aino_sa.jpg"
"email": "tuomas.rantamaki@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/TuomasR.jpg"
}
]
},
@@ -80,10 +80,10 @@
"name_en": "",
"representatives": [
{
"name": "Rosanna Reims",
"name": "Matilda Ahonen",
"phone_number": null,
"email": "rosanna.reims@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/rosanna.jpg"
"email": "matilda.ahonen@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Matilda.jpg"
}
]
},
@@ -92,10 +92,10 @@
"name_en": "",
"representatives": [
{
"name": "Valentin Juhela",
"name": "Niklas Ritalahti",
"phone_number": null,
"email": "valentin.juhela@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/valentin.jpg"
"email": "niklas.ritalahti@sahkoinsinoorikilta.fi",
"image": ""
}
]
},
@@ -104,10 +104,10 @@
"name_en": "",
"representatives": [
{
"name": "Elida Widgren",
"name": "Mikael Vatiainen",
"phone_number": null,
"email": "elida.widgren@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/elida.jpg"
"email": "mikael.vatiainen@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Mikael.jpg"
}
]
},
@@ -116,10 +116,10 @@
"name_en": "",
"representatives": [
{
"name": "Joona Maaranen",
"name": "Simeon Pursiainen",
"phone_number": null,
"email": "joona.maaranen@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/joona.jpg"
"email": "simeon.pursiainen@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Simeon.jpg"
}
]
},
@@ -128,10 +128,10 @@
"name_en": "",
"representatives": [
{
"name": "Jere Oinonen",
"name": "Markus Aaltio",
"phone_number": null,
"email": "jere.oinonen@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/jere.jpg"
"email": "markus.aaltio@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Markus.jpg"
}
]
},
@@ -140,10 +140,10 @@
"name_en": "",
"representatives": [
{
"name": "Into Saarinen",
"name": "Tuomas Hintikka",
"phone_number": null,
"email": "into.saarinen@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/into.jpg"
"email": "tuomas.hintikka@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/TuomasH.jpg"
}
]
},
@@ -152,10 +152,10 @@
"name_en": "",
"representatives": [
{
"name": "Aino Svahn",
"name": "Yassine Ramid",
"phone_number": null,
"email": "aino.svahn@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/2026/aino_sv.jpg"
"email": "yassine.ramid@sahkoinsinoorikilta.fi",
"image": "https://static.sahkoinsinoorikilta.fi/img/board/Yassine.jpg"
}
]
}
@@ -16,9 +16,6 @@ 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 = [
@@ -34,9 +31,6 @@ const orderedCommittees = [
VtmkJson,
SwtmkJson,
NtmkJson,
SiccJson,
SptmkJson,
PotatmkJson,
Others,
];
+7 -7
View File
@@ -9,7 +9,7 @@
"name_en": "",
"representatives": [
{
"name": "Aura Friman"
"name": "Teemu Heikkinen"
}
]
},
@@ -18,7 +18,7 @@
"name_en": "",
"representatives": [
{
"name": "Antti Salpakari"
"name": "Henri Aito"
}
]
},
@@ -27,10 +27,10 @@
"name_en": "International Fuksi Captain",
"representatives": [
{
"name": "Jere Oinonen"
"name": "Markus Aaltio"
},
{
"name": "Hocine Montenez"
"name": "Apollo Ailus"
}
]
},
@@ -39,7 +39,7 @@
"name_en": "Tutor Coordinator",
"representatives": [
{
"name": "Veera Lindroos"
"name": "Axel Aurola"
}
]
},
@@ -48,9 +48,9 @@
"name_en": "International Tutor Coordinator",
"representatives": [
{
"name": "Janne Yrjölä"
"name": "Igor Oinonen"
}
]
}
]
}
}
+52 -55
View File
@@ -1,59 +1,56 @@
{
"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": [
"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": [
{
"name_fi": "Hovimestari",
"name_en": "Master of Ceremonies",
"representatives": [
{
"name": "Aino Saarela"
}
]
},
{
"name_fi": "Hovineuvos",
"name_en": "Court Counsellor",
"representatives": [
{
"name": "Rosanna Reims"
}
]
},
{
"name_fi": "Emäntä",
"name_en": "Hostess",
"representatives": [
{
"name": "Elina Pyylampi"
},
{
"name": "Elle Leivo"
},
{
"name": "Emma Salmenaho"
}
]
},
{
"name_fi": "Isäntä",
"name_en": "Host",
"representatives": [
{
"name": "Aleksi Nuutinen"
},
{
"name": "Juho Rosnell"
},
{
"name": "Julius Härkönen"
},
{
"name": "Joonas Hilvo"
}
]
"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": "Aino Saarela"
},
{
"name": "Nea Kanerva"
},
{
"name": "Rosanna Reims"
}
]
},
{
"name_fi": "Isäntä",
"name_en": "Host",
"representatives": [
{
"name": "Eemeli Hintsanen"
},
{
"name": "André Palosaari"
}
]
}
]
}
+94 -96
View File
@@ -1,101 +1,99 @@
{
"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": [
"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": [
{
"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": "Niklas Ritalahti"
}
]
},
{
"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"
}
]
}
]
}
+55 -58
View File
@@ -1,65 +1,62 @@
{
"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": [
"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": [
{
"name_fi": "Lukkarimestari",
"name_en": "",
"representatives": [
{
"name": "Aino Salmi"
}
]
"name": "Aino Salmi"
},
{
"name_fi": "Lukkari",
"name_en": "",
"representatives": [
{
"name": "Alex Hyytinen"
},
{
"name": "Ilmari Reponen"
},
{
"name": "Iiris Kuulusa"
},
{
"name": "Samuel Södervall"
},
{
"name": "Tapio Immonen"
}
]
"name": "Ilmari Reponen"
},
{
"name_fi": "Lukkarikisälli",
"name_en": "",
"representatives": [
{
"name": "Aapo Palojärvi"
},
{
"name": "André Paloari"
},
{
"name": "Kaisa Lehtimäki"
},
{
"name": "Olav Hamel"
},
{
"name": "Otto Tuominen"
},
{
"name": "Panu Leinonen"
},
{
"name": "Terhi Lukkari"
}
]
"name": "Jenni Marttinen"
},
{
"name": "Peter Lindahl"
},
{
"name": "Patrik Varteva"
},
{
"name": "Tapio Immonen"
}
]
}
]
},
{
"name_fi": "Lukkarikisälli",
"name_en": "",
"representatives": [
{
"name": "Alex Hyytinen"
},
{
"name": "Antti Salpakari"
},
{
"name": "Iiris Kuulusa"
},
{
"name": "Roman Shalamov"
},
{
"name": "Samuel Södervall"
}
]
}
]
}
+100 -106
View File
@@ -1,110 +1,104 @@
{
"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": [
"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": [
{
"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 Nikkinen"
}
]
},
{
"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ähkönen"
}
]
},
{
"name_fi": "Heevistriimaaja",
"name_en": "Heevistreamer",
"representatives": [
{
"name": "Aaro Rasilainen"
}
]
"name": "Topi Manskinen",
"phone_number": null,
"email": null,
"image": null
}
]
]
},
{
"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"
}
]
}
]
}
+76 -68
View File
@@ -5,85 +5,93 @@
"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 puheenjohtaja",
"name_fi": "N-toimikunnan nestori",
"name_en": "",
"representatives": [
{
"name": "Elina Huttunen"
}
{
"name": "Karoliina Talvikangas"
}
]
},
{
"name_fi": "N-toimikunnan Varapuheenjohtaja",
"name_en": "",
"representatives": [
{
"name": "Ville Lairila"
}
]
"name_fi": "N-toimikunnan varanestori, Kiltapatruuna",
"name_en": "",
"representatives": [
{
"name": "Aaron Löfgren"
}
]
},
{
"name_fi": "Kiltapatruuna",
"name_en": "",
"representatives": [
{
"name": "Aaron Löfgren"
},
{
"name": "Axel Aurola"
},
{
"name": "Emma Uusküla"
},
{
"name": "Johannes Viirimäki"
},
{
"name": "Tuomas Rantamäki"
},
{
"name": "Yassine Ramid"
}
]
"name_fi": "Sklubi-yhdyshenkilö",
"name_en": "",
"representatives": [
{
"name": "Melisa Dönmez"
},
{
"name": "Eveliina Ahonen"
}
]
},
{
"name_fi": "N-vastaava",
"name_fi": "Kiltapatruuna",
"name_en": "",
"representatives": [
{
"name": "Ville Lairila"
},
{
"name": "Visa Kurvi"
}
]
},
{
"name_fi":
"Kiltapatruuna, Nipsu",
"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"
}
{
"name": "Mikko Sandström"
},
{
"name": "Liisa Haltia"
},
{
"name": "Elina Huttunen"
}
]
},
{
"name_fi": "Nipsu",
"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"
}
]
}
]
}
}
+35 -48
View File
@@ -1,54 +1,41 @@
{
"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": [
"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": [
{
"name_fi": "Opintomestari",
"name_en": "Master of Studies",
"representatives": [
{
"name": "Elida Widgren"
}
]
"name": "Mikael Vatiainen"
}
]
},
{
"name_fi": "Opintovastaava",
"name_en": "Study Coordinator",
"representatives": [
{
"name": "Atu Vahla"
},
{
"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": "Antti Lehtonen"
},
{
"name": "Aleksi Liukkonen"
},
{
"name": "Ilmari Reponen"
},
{
"name": "Milla Heino"
},
{
"name": "Samuel Södervall"
}
]
]
}
]
}
+28 -48
View File
@@ -1,52 +1,32 @@
{
"slug": "others",
"name_fi": "Muut",
"name_en": "Other officials",
"info": "",
"roles": [
"slug": "others",
"name_fi": "Muut",
"name_en": "Other officials",
"info": "",
"roles": [
{
"name_fi": "Merikapteeni",
"name_en": "Sea captain",
"representatives": [
{
"name_fi": "Arkistovastaava",
"name_en": "",
"representatives": [
{
"name": "Aaron Löfgren",
"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
}
]
"name": "Ville Lairila",
"phone_number": null,
"email": null
}
]
]
},
{
"name_fi": "Meripojankloppi",
"name_en": "ship's boy",
"representatives": [
{
"name": "Peter Lindahl",
"phone_number": null,
"email": null
}
]
}
]
}
-83
View File
@@ -1,83 +0,0 @@
{
"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"
}
]
}
]
}
+49 -52
View File
@@ -1,56 +1,53 @@
{
"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": [
"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": [
{
"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 Tram"
}
]
"name": "Jere Oinonen"
}
]
]
},
{
"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
@@ -1,44 +0,0 @@
{
"slug": "sicc",
"name_fi": "SIK International Comittee Counsil",
"name_en": "SIK International Comittee Counsil",
"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
@@ -1,45 +0,0 @@
{
"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"
}
]
}
]
}
+35 -44
View File
@@ -1,47 +1,38 @@
{
"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": [
"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": [
{
"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": "Tiitus Koski"
}
]
}
]
},
{
"name_fi": "Myyjä",
"name_en": "Clerk",
"representatives": [
{
"name": "Arvi Virkkunen"
},
{
"name": "Valentin Juhela"
},
{
"name": "Otto Rinne"
},
{
"name": "Auli Purolinna"
},
{
"name": "Patrik Varteva"
}
]
}
]
}
+32 -29
View File
@@ -1,35 +1,38 @@
{
"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": [
"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": [
{
"name_fi": "Teknologiamestari",
"name_en": "Master of technology",
"representatives": [
{
"name": "Joona Maaranen"
}
]
"name": "Simeon Pursiainen"
}
]
},
{
"name_fi": "Teknologiavastaava",
"name_en": "",
"representatives": [
{
"name": "Joona Maaranen"
},
{
"name_fi": "Teknologiavastaava",
"name_en": "",
"representatives": [
{
"name": "Alekdsandr Lemin"
},
{
"name": "Atte Elo"
},
{
"name": "Dat Tram"
},
{
"name": "Oiva Haapaniemi"
}
]
"name": "Aleksi Liukkonen"
},
{
"name": "Elmo Kankkunen"
},
{
"name": "Justus Ojala"
},
{
"name": "Tommi Sytelä"
}
]
]
}
]
}
+27 -41
View File
@@ -9,7 +9,7 @@
"name_en": "Head of communcations",
"representatives": [
{
"name": "Aino Svahn"
"name": "Yassine Ramid"
}
]
},
@@ -18,22 +18,25 @@
"name_en": "",
"representatives": [
{
"name": "Aada Tättilä"
"name": "Aaron Löfgren"
},
{
"name": "Ada Minkkinen"
"name": "Elina Huttunen"
},
{
"name": "Aino Tasapuro"
"name": "Aura Friman"
}
]
},
{
"name_fi": "Somevastaava, Brändivastaava",
"name_en": "",
"representatives": [
{
"name": "Aapo Saranpää"
},
{
"name": "Ira Kosunen"
},
{
"name": "Lukas Iles"
},
{
"name": "Tytti Solonen"
"name": "Aino Svahn"
}
]
},
@@ -42,15 +45,23 @@
"name_en": "",
"representatives": [
{
"name": "Aapo Saranpää"
"name": "Aleksandr Lemin"
},
{
"name": "Roope Jaskari"
},
{
"name": "Sauli Hakala"
},
{
"name": "Ville Lairila"
},
{
"name": "Aapo Nyyssönen"
},
{
"name": "Kehrä Halme"
"name": "Mikko Sandström"
}
]
},
{
@@ -58,37 +69,12 @@
"name_en": "",
"representatives": [
{
"name": "Apollo Ailus"
"name": "Veera Melvasalo"
},
{
"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ähkönen"
},
{
"name": "Veikko Räty"
}
]
}
]
}
}
+82 -52
View File
@@ -1,56 +1,86 @@
{
"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": [
"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": [
{
"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": "Tuomas Hintikka"
}
]
]
},
{
"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"
}
]
}
]
}
+2 -3
View File
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/legacy/image";
import Image from "next/image";
import styled from "styled-components";
import rehypeRaw from "rehype-raw";
import rehypeSanitize from "rehype-sanitize";
@@ -81,10 +81,9 @@ 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>
+2 -3
View File
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/legacy/image";
import Image from "next/image";
import styled from "styled-components";
import rehypeRaw from "rehype-raw";
import rehypeSanitize from "rehype-sanitize";
@@ -65,10 +65,9 @@ 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/legacy/image";
import Image from "next/image";
import styled from "styled-components";
import {
CTASection, TextSection, InfoBox, PageLink, Link,
@@ -61,10 +61,9 @@ const ForFreshmenPageView: React.FC = () => (
<Image
src="https://static.sahkoinsinoorikilta.fi/FTMK/IMG_6539.JPG"
alt="Kipparit"
layout="responsive"
width={100}
height={80}
objectFit="contain"
style={{ objectFit: "contain" }}
/>
</ImageContainer>
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/legacy/image";
import Image from "next/image";
import styled from "styled-components";
import {
CTASection, TextSection, InfoBox, PageLink, Link,
@@ -78,10 +78,9 @@ const ForIntlPageView: React.FC = () => (
<Image
src="https://static.sahkoinsinoorikilta.fi/FTMK/Captains2025.jpg"
alt="Kipparit"
layout="responsive"
width={100}
height={80}
objectFit="contain"
style={{ objectFit: "contain" }}
/>
</ImageContainer>
+2 -3
View File
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/legacy/image";
import Image from "next/image";
import styled from "styled-components";
import {
CTASection, TextSection, InfoBox, PageLink, Link,
@@ -60,10 +60,9 @@ const FreshmenPageView: React.FC = () => (
<Image
src="https://static.sahkoinsinoorikilta.fi/FTMK/IMG_6539.JPG"
alt="Kipparit"
layout="responsive"
width={100}
height={80}
objectFit="contain"
style={{ objectFit: "contain" }}
/>
</ImageContainer>
+14 -14
View File
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/legacy/image";
import Image from "next/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" layout="responsive" width={200} height={100} objectFit="contain" />
<Image src={ABB} alt="ABB" width={200} height={100} style={{ objectFit: "contain" }} />
</Link>
<Link to="https://caruna.fi/">
<Image src={Caruna} alt="Caruna" layout="responsive" width={200} height={100} objectFit="contain" />
<Image src={Caruna} alt="Caruna" width={200} height={100} style={{ objectFit: "contain" }} />
</Link>
<Link to="https://www.nokia.com/">
<Image src={Nokia} alt="Nokia" layout="responsive" width={200} height={100} objectFit="contain" />
<Image src={Nokia} alt="Nokia" width={200} height={100} style={{ objectFit: "contain" }} />
</Link>
<Link to="https://www.ensto.com/fi/">
<Image src={Ensto} alt="Ensto" layout="responsive" width={200} height={100} objectFit="contain" />
<Image src={Ensto} alt="Ensto" width={200} height={100} style={{ objectFit: "contain" }} />
</Link>
<Link to="https://www.esett.com/">
<Image src={eSett} alt="eSett" layout="responsive" width={200} height={100} objectFit="contain" />
<Image src={eSett} alt="eSett" width={200} height={100} style={{ objectFit: "contain" }} />
</Link>
<Link to="https://www.fingrid.fi/">
<Image src={Fingrid} alt="Fingrid" layout="responsive" width={200} height={100} objectFit="contain" />
<Image src={Fingrid} alt="Fingrid" width={200} height={100} style={{ objectFit: "contain" }} />
</Link>
<Link to="https://www.okmetic.com/fi/">
<Image src={Okmetic} alt="Okmetic" layout="responsive" width={200} height={100} objectFit="contain" />
<Image src={Okmetic} alt="Okmetic" width={200} height={100} style={{ objectFit: "contain" }} />
</Link>
<Link to="https://www.granlund.fi/">
<Image src={Granlund} alt="Granlund" layout="responsive" width={200} height={100} objectFit="contain" />
<Image src={Granlund} alt="Granlund" width={200} height={100} style={{ objectFit: "contain" }} />
</Link>
<Link to="https://www.eaton.com/fi/fi-fi.html">
<Image src={Eaton} alt="Eaton" layout="responsive" width={200} height={100} objectFit="contain" />
<Image src={Eaton} alt="Eaton" width={200} height={100} style={{ objectFit: "contain" }} />
</Link>
<Link to="https://www.ericsson.com/en">
<Image src={Ericsson} alt="Ericsson" layout="responsive" width={200} height={100} objectFit="contain" />
<Image src={Ericsson} alt="Ericsson" width={200} height={100} style={{ objectFit: "contain" }} />
</Link>
<Link to="https://www.saab.com/fi/markets/finland">
<Image src={Saab} alt="Saab" layout="responsive" width={200} height={100} objectFit="contain" />
<Image src={Saab} alt="Saab" width={200} height={100} style={{ objectFit: "contain" }} />
</Link>
<Link to="https://www.stul.fi/">
<Image src={STUL} alt="STUL" layout="responsive" width={200} height={100} objectFit="contain" />
<Image src={STUL} alt="STUL" width={200} height={100} style={{ objectFit: "contain" }} />
</Link>
<Link to="https://www.metso.com/fi/">
<Image src={Metso} alt="Metso" layout="responsive" width={200} height={100} objectFit="contain" />
<Image src={Metso} alt="Metso" width={200} height={100} style={{ objectFit: "contain" }} />
</Link>
</div>
<Link to="/yritysyhteistyo">Haluatko kuulla lisää yhteistyöstä kanssamme?</Link>
+2 -3
View File
@@ -1,5 +1,5 @@
import React from "react";
import Image from "next/legacy/image";
import Image from "next/image";
import {
CTASection, TextSection, PageLink, Link,
} from "@components/index";
@@ -81,8 +81,7 @@ const StudiesPageView: React.FC = () => (
alt="Ville Viikari"
width={300}
height={150}
layout="responsive"
objectFit="contain"
style={{ objectFit: "contain" }}
/>
<h6>Ville Viikari</h6>
<p>
+1 -1
View File
@@ -8,5 +8,5 @@
},
"skipJsErrors": true,
"appCommand": "npm run serve",
"appInitDelay": 2000
"appInitDelay": 10000
}
+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++) {
for (let i = 0; i < 50; i += 1) {
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": "preserve",
"jsx": "react-jsx",
"lib": [
"dom",
"esnext"