Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6af5d7fa1f | |||
| 1df9b22fa3 | |||
| 17713d4f9d | |||
| d0a930794e | |||
| 170e7b3c31 | |||
| 20f39b545d | |||
| 22454369fd | |||
| 7a9805ebe9 | |||
| 4c69a4620d | |||
| ae28ec183e | |||
| b49e9e70b2 | |||
| 4510bb08d8 | |||
| 0825d87d0f | |||
| bcad873b97 | |||
| f6a5080769 | |||
| e3d3b736f1 | |||
| 56c509b4c1 | |||
| 771b9eb391 | |||
| 75cf2e2ce1 | |||
| 4fe78fd96d | |||
| 50fd27d193 | |||
| 6cb18c4a13 | |||
| 2009a65f55 | |||
| 3c72152704 | |||
| 2ad2907f5f | |||
| f61fc155a8 | |||
| 802b308826 | |||
| e4784e1932 | |||
| c015f0a275 | |||
| 6a9cb63cff | |||
| 5007d443e7 | |||
| 648c49582e | |||
| c50a09c691 | |||
| 2b75f5a567 | |||
| 4e27d892d5 | |||
| 0a36c1c233 | |||
| 9459930291 | |||
| cea106b134 | |||
| af9b115205 | |||
| 7ed7849c43 |
@@ -5,4 +5,3 @@ node_modules
|
||||
# don't lint nyc coverage output
|
||||
coverage
|
||||
next-env.d.ts
|
||||
tests
|
||||
|
||||
@@ -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
@@ -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
@@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
npm run lint
|
||||
npm run lint:es
|
||||
|
||||
Vendored
+1
-2
@@ -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
@@ -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));
|
||||
|
||||
Generated
+8479
-14502
File diff suppressed because it is too large
Load Diff
+18
-16
@@ -20,22 +20,21 @@
|
||||
"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:es": "next lint",
|
||||
"lint:es:fix": "next lint --fix",
|
||||
"lint:css": "stylelint \"./src/**/*.{ts,tsx}\"",
|
||||
"dev": "next dev --webpack",
|
||||
"start": "next dev --webpack",
|
||||
"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",
|
||||
"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/jest": "^27.4.1",
|
||||
"@types/js-cookie": "^3.0.1",
|
||||
"@types/node": "^16.11.36",
|
||||
"@types/react": "^18.0.15",
|
||||
@@ -46,13 +45,13 @@
|
||||
"@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": "^8.13.0",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
"eslint-config-airbnb-typescript": "^17.0.0",
|
||||
"eslint-config-next": "^13.5.11",
|
||||
"eslint-config-next": "^13.1.6",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"husky": "^7.0.4",
|
||||
"jest": "^30.2.0",
|
||||
"jest": "^27.5.1",
|
||||
"next-sitemap": "^3.1.11",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss-jsx": "^0.36.4",
|
||||
@@ -60,21 +59,21 @@
|
||||
"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"
|
||||
"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": "^10.29.0",
|
||||
"axios": "^1.13.2",
|
||||
"@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": "^16.0.8",
|
||||
"next": "^13.1.6",
|
||||
"normalize.css": "^8.0.1",
|
||||
"react": "^18.2.0",
|
||||
"react-csv": "^2.2.2",
|
||||
@@ -88,12 +87,15 @@
|
||||
"react-toastify": "^9.0.7",
|
||||
"rehype-raw": "^6.1.1",
|
||||
"rehype-sanitize": "^5.0.1",
|
||||
"sharp": "^0.34.5",
|
||||
"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",
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
});
|
||||
@@ -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,5 +1,5 @@
|
||||
import React from "react";
|
||||
import Image from "next/image";
|
||||
import Image from "next/legacy/image";
|
||||
|
||||
const Icon = "/img/add-icon.png";
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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]}
|
||||
/>
|
||||
|
||||
@@ -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
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
+20
-23
@@ -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
|
||||
notFound,
|
||||
};
|
||||
} catch {
|
||||
return {
|
||||
notFound: true,
|
||||
revalidate: 10,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default EventPage;
|
||||
|
||||
+19
-23
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const post = await FeedApi.getPost(id);
|
||||
return {
|
||||
props: {
|
||||
post,
|
||||
},
|
||||
revalidate: 10, // Required for deleting hidden pages
|
||||
notFound,
|
||||
};
|
||||
} catch {
|
||||
return {
|
||||
notFound: true,
|
||||
revalidate: 10,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default FeedPage;
|
||||
|
||||
@@ -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
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
+56
-23
@@ -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
|
||||
notFound,
|
||||
};
|
||||
} catch {
|
||||
return {
|
||||
notFound: true,
|
||||
revalidate: 10,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export default SignUpPage;
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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,
|
||||
];
|
||||
|
||||
|
||||
@@ -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,7 +48,7 @@
|
||||
"name_en": "International Tutor Coordinator",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Igor Oinonen"
|
||||
"name": "Janne Yrjölä"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"name_en": "Master of Ceremonies",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Tuomas Rantamäki"
|
||||
"name": "Aino Saarela"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -18,7 +18,7 @@
|
||||
"name_en": "Court Counsellor",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Matilda Ahonen"
|
||||
"name": "Rosanna Reims"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -27,16 +27,13 @@
|
||||
"name_en": "Hostess",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Veera Lindroos"
|
||||
"name": "Elina Pyylampi"
|
||||
},
|
||||
{
|
||||
"name": "Aino Saarela"
|
||||
"name": "Elle Leivo"
|
||||
},
|
||||
{
|
||||
"name": "Nea Kanerva"
|
||||
},
|
||||
{
|
||||
"name": "Rosanna Reims"
|
||||
"name": "Emma Salmenaho"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -45,10 +42,16 @@
|
||||
"name_en": "Host",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Eemeli Hintsanen"
|
||||
"name": "Aleksi Nuutinen"
|
||||
},
|
||||
{
|
||||
"name": "André Palosaari"
|
||||
"name": "Juho Rosnell"
|
||||
},
|
||||
{
|
||||
"name": "Julius Härkönen"
|
||||
},
|
||||
{
|
||||
"name": "Joonas Hilvo"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"name_en": "Master of Wellbeing",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Niklas Ritalahti"
|
||||
"name": "Valentin Juhela"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -18,22 +18,13 @@
|
||||
"name_en": "Culture Representative",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Peter Lindahl"
|
||||
"name": "Johannes Viirimäki"
|
||||
},
|
||||
{
|
||||
"name": "Kuura Janhunen"
|
||||
"name": "Linnea Viitasalo"
|
||||
},
|
||||
{
|
||||
"name": "Valentin Juhela"
|
||||
},
|
||||
{
|
||||
"name": "Leevi Leinonen"
|
||||
},
|
||||
{
|
||||
"name": "Milla Heino"
|
||||
},
|
||||
{
|
||||
"name": "Hocine Montenez"
|
||||
"name": "Matilda Ahonen"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -42,10 +33,13 @@
|
||||
"name_en": "Sports Representative",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Matias Hendolin"
|
||||
"name": "Aino Salmi"
|
||||
},
|
||||
{
|
||||
"name": "Sauli Hakala"
|
||||
"name": "Eeda Alasaari"
|
||||
},
|
||||
{
|
||||
"name": "Iiris Kuulusa"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -57,7 +51,7 @@
|
||||
"name": "Milja Kuusela"
|
||||
},
|
||||
{
|
||||
"name": "Aaro Rasilainen"
|
||||
"name": "Tuomas Rantamäki"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -66,15 +60,17 @@
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Tommi Sytelä"
|
||||
"name": "Arvi Virkkunen"
|
||||
},
|
||||
{
|
||||
"name": "Konsta Hakala"
|
||||
"name": "Auli Purolinna"
|
||||
},
|
||||
{
|
||||
"name": "Ville Lairila"
|
||||
},
|
||||
{
|
||||
"name": "Tiitus Koski"
|
||||
}
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -82,16 +78,22 @@
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Saara Rossi"
|
||||
"name": "Teemu Heikkinen"
|
||||
},
|
||||
{
|
||||
"name": "Aaron Löfgren"
|
||||
},
|
||||
{
|
||||
"name": "Milla Heino"
|
||||
"name": "Matilda Ahonen"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Sauli Hakala"
|
||||
"name_fi": "Kiltamuori",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Markus Aaltio"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Leevi Oikarinen"
|
||||
"name": "Aino Salmi"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -18,19 +18,16 @@
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Aino Salmi"
|
||||
"name": "Alex Hyytinen"
|
||||
},
|
||||
{
|
||||
"name": "Ilmari Reponen"
|
||||
},
|
||||
{
|
||||
"name": "Jenni Marttinen"
|
||||
"name": "Iiris Kuulusa"
|
||||
},
|
||||
{
|
||||
"name": "Peter Lindahl"
|
||||
},
|
||||
{
|
||||
"name": "Patrik Varteva"
|
||||
"name": "Samuel Södervall"
|
||||
},
|
||||
{
|
||||
"name": "Tapio Immonen"
|
||||
@@ -42,19 +39,25 @@
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Alex Hyytinen"
|
||||
"name": "Aapo Palojärvi"
|
||||
},
|
||||
{
|
||||
"name": "Antti Salpakari"
|
||||
"name": "André Palosaari"
|
||||
},
|
||||
{
|
||||
"name": "Iiris Kuulusa"
|
||||
"name": "Kaisa Lehtimäki"
|
||||
},
|
||||
{
|
||||
"name": "Roman Shalamov"
|
||||
"name": "Olav Hamel"
|
||||
},
|
||||
{
|
||||
"name": "Samuel Södervall"
|
||||
"name": "Otto Tuominen"
|
||||
},
|
||||
{
|
||||
"name": "Panu Leinonen"
|
||||
},
|
||||
{
|
||||
"name": "Terhi Lukkari"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"name_en": "Editor in Chief",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Topi Manskinen",
|
||||
"name": "Joona Komonen",
|
||||
"phone_number": null,
|
||||
"email": null,
|
||||
"image": null
|
||||
@@ -21,7 +21,7 @@
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Visa Kurvi",
|
||||
"name": "Topi Manskinen",
|
||||
"phone_number": null,
|
||||
"email": null,
|
||||
"image": null
|
||||
@@ -33,31 +33,34 @@
|
||||
"name_en": "Journalist",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Joona Komonen"
|
||||
"name": "Aake Laukkanen"
|
||||
},
|
||||
{
|
||||
"name": "Olli Vaismaa"
|
||||
"name": "Alex Hyytinen"
|
||||
},
|
||||
{
|
||||
"name": "Apollo Ailus"
|
||||
},
|
||||
{
|
||||
"name": "Eetu Tossavainen"
|
||||
},
|
||||
{
|
||||
"name": "Jenni Marttinen"
|
||||
},
|
||||
{
|
||||
"name": "Ilmari Reponen"
|
||||
"name": "Juho Laukka"
|
||||
},
|
||||
{
|
||||
"name": "Igor Oinonen"
|
||||
"name": "Lauri Anttila"
|
||||
},
|
||||
{
|
||||
"name": "Otto Kievimaa"
|
||||
}
|
||||
]
|
||||
"name": "Otto kievimaa"
|
||||
},
|
||||
{
|
||||
"name_fi": "Toimittaja, Taittaja",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
"name": "Sampo Haarala"
|
||||
},
|
||||
{
|
||||
"name": "Atte Vitie"
|
||||
"name": "Venla Nikkanen"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -65,8 +68,17 @@
|
||||
"name_fi": "Taittaja",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Atte Vitie"
|
||||
},
|
||||
{
|
||||
"name": "Lauri Anttila"
|
||||
},
|
||||
{
|
||||
"name": "Otto Kievimaa"
|
||||
},
|
||||
{
|
||||
"name": "Partrik Varteva"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -74,29 +86,23 @@
|
||||
"name_fi": "Graafikko",
|
||||
"name_en": "Photographer & Graphic Artist",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Annika Tattari"
|
||||
},
|
||||
{
|
||||
"name": "Elian Salmimaa"
|
||||
},
|
||||
{
|
||||
"name": "Lotta Kähönen"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi": "Valokuvaaja",
|
||||
"name_en": "Photographer",
|
||||
"name_fi": "Heevistriimaaja",
|
||||
"name_en": "Heevistreamer",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Veikko Räty"
|
||||
},
|
||||
{
|
||||
"name": "Into Saarinen"
|
||||
},
|
||||
{
|
||||
"name": "Aaro Rasilainen"
|
||||
},
|
||||
{
|
||||
"name": "Anton Niemi"
|
||||
},
|
||||
{
|
||||
"name": "Veera Melvasalo"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -5,32 +5,20 @@
|
||||
"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_fi": "N-toimikunnan Varapuheenjohtaja",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Aaron Löfgren"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi": "Sklubi-yhdyshenkilö",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Melisa Dönmez"
|
||||
},
|
||||
{
|
||||
"name": "Eveliina Ahonen"
|
||||
"name": "Ville Lairila"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -39,57 +27,61 @@
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Ville Lairila"
|
||||
},
|
||||
{
|
||||
"name": "Visa Kurvi"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi":
|
||||
"Kiltapatruuna, Nipsu",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Mikko Sandström"
|
||||
},
|
||||
{
|
||||
"name": "Liisa Haltia"
|
||||
},
|
||||
{
|
||||
"name": "Elina Huttunen"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"name_fi": "Nipsu",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Mikael Siikonen"
|
||||
"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": "Elias Damski"
|
||||
"name": "Johannes Viirimäki"
|
||||
},
|
||||
{
|
||||
"name": "Elias Lindberg"
|
||||
"name": "Karoliina Talvikangas"
|
||||
},
|
||||
{
|
||||
"name": "Eero Ketonen"
|
||||
"name": "Markus Aaltio"
|
||||
},
|
||||
{
|
||||
"name": "Miika Helminen"
|
||||
},
|
||||
{
|
||||
"name": "Mikael Siikonen"
|
||||
},
|
||||
{
|
||||
"name": "Peter Lindahl"
|
||||
},
|
||||
{
|
||||
"name": "Veikko Räty"
|
||||
},
|
||||
{
|
||||
"name": "Verneri Turkki"
|
||||
},
|
||||
{
|
||||
"name": "Akseli Heikkinen"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"name_en": "Master of Studies",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Mikael Vatiainen"
|
||||
"name": "Elida Widgren"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -18,23 +18,36 @@
|
||||
"name_en": "Study Coordinator",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Atu Vahla"
|
||||
},
|
||||
{
|
||||
"name": "Antti Lehtonen"
|
||||
"name": "Aapo Tynninen"
|
||||
},
|
||||
{
|
||||
"name": "Aleksi Liukkonen"
|
||||
},
|
||||
{
|
||||
"name": "Antti Lehtonen"
|
||||
},
|
||||
{
|
||||
"name": "Atu Vahla"
|
||||
},
|
||||
{
|
||||
"name": "Iiris Kuulusa"
|
||||
},
|
||||
{
|
||||
"name": "Ilmari Reponen"
|
||||
},
|
||||
{
|
||||
"name": "Milla Heino"
|
||||
"name": "Jesper Seppäläinen"
|
||||
},
|
||||
{
|
||||
"name": "Samuel Södervall"
|
||||
"name": "Mikael Vatiainen"
|
||||
},
|
||||
{
|
||||
"name": "Vi Tam"
|
||||
},
|
||||
{
|
||||
"name": "Yassine Ramid"
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -5,27 +5,47 @@
|
||||
"info": "",
|
||||
"roles": [
|
||||
{
|
||||
"name_fi": "Merikapteeni",
|
||||
"name_en": "Sea captain",
|
||||
"name_fi": "Arkistovastaava",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Ville Lairila",
|
||||
"name": "Aaron Löfgren",
|
||||
"phone_number": null,
|
||||
"email": null
|
||||
}
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi": "Meripojankloppi",
|
||||
"name_en": "ship's boy",
|
||||
"name_fi": "Sklubi-yhdyshenkilö",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Peter Lindahl",
|
||||
"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
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -9,7 +9,19 @@
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Jere Oinonen"
|
||||
"name": "Simeon Pursiainen"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi": "Pajavastaava",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Axel Söderberg"
|
||||
},
|
||||
{
|
||||
"name": "Đình Minh Trần"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -18,34 +30,25 @@
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Otto Kievimaa"
|
||||
"name": "Aapo Tynninen"
|
||||
},
|
||||
{
|
||||
"name": "Đình Minh Trần"
|
||||
"name": "Aarni Kämppi"
|
||||
},
|
||||
{
|
||||
"name": "Valentin Juhela"
|
||||
"name": "Atte Elo"
|
||||
},
|
||||
{
|
||||
"name": "Axel Söderberg"
|
||||
"name": "Emma Uusküla"
|
||||
},
|
||||
{
|
||||
"name": "Auli Purolinna"
|
||||
"name": "Jusi Seppälä"
|
||||
},
|
||||
{
|
||||
"name": "Karl Lipping"
|
||||
"name": "Tuomas Rantamäki"
|
||||
},
|
||||
{
|
||||
"name": "Petrus Asikainen"
|
||||
},
|
||||
{
|
||||
"name": "Elmo Kankkunen"
|
||||
},
|
||||
{
|
||||
"name": "Samu Nyman"
|
||||
},
|
||||
{
|
||||
"name": "Hilkka Gröhn"
|
||||
"name": "Vi Tam"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
"name_en": "Head of sales",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Tiitus Koski"
|
||||
"name": "Leevi Oikarinen"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -18,19 +18,28 @@
|
||||
"name_en": "Clerk",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Arvi Virkkunen"
|
||||
"name": "Alexandr Lemin"
|
||||
},
|
||||
{
|
||||
"name": "Valentin Juhela"
|
||||
"name": "Henri Aito"
|
||||
},
|
||||
{
|
||||
"name": "Otto Rinne"
|
||||
"name": "Ossi Jalkanen"
|
||||
},
|
||||
{
|
||||
"name": "Auli Purolinna"
|
||||
"name": "Tiitus Koski"
|
||||
},
|
||||
{
|
||||
"name": "Patrik Varteva"
|
||||
"name": "Veikko Räty"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi": "Kiltapäiväkerhovastaava",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Matilda Ahonen"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"name_en": "Master of technology",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Simeon Pursiainen"
|
||||
"name": "Joona Maaranen"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -18,19 +18,16 @@
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Joona Maaranen"
|
||||
"name": "Alekdsandr Lemin"
|
||||
},
|
||||
{
|
||||
"name": "Aleksi Liukkonen"
|
||||
"name": "Atte Elo"
|
||||
},
|
||||
{
|
||||
"name": "Elmo Kankkunen"
|
||||
"name": "Dat Tram"
|
||||
},
|
||||
{
|
||||
"name": "Justus Ojala"
|
||||
},
|
||||
{
|
||||
"name": "Tommi Sytelä"
|
||||
"name": "Oiva Haapaniemi"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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": "Aino Tasapuro"
|
||||
},
|
||||
{
|
||||
"name_fi": "Somevastaava, Brändivastaava",
|
||||
"name_en": "",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Aapo Saranpää"
|
||||
"name": "Ira Kosunen"
|
||||
},
|
||||
{
|
||||
"name": "Aino Svahn"
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
@@ -7,6 +7,15 @@
|
||||
{
|
||||
"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"
|
||||
@@ -18,67 +27,28 @@
|
||||
"name_en": "Head of Excursions",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Aino Tasapuro"
|
||||
"name": "Roope Palo"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name_fi": "Yrityssuhdevastaava",
|
||||
"name_fi": "Yrityssuhde- ja excursiovastaava",
|
||||
"name_en": "Apprentice of Corporate Relations",
|
||||
"representatives": [
|
||||
{
|
||||
"name": "Axel Aurola"
|
||||
},
|
||||
{
|
||||
"name": "Mikael Sundell"
|
||||
},
|
||||
{
|
||||
"name": "Henrik Ervasti"
|
||||
"name": "Kaisa Lehtimäki"
|
||||
},
|
||||
{
|
||||
"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": "Timo Kaleva"
|
||||
},
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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'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'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'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'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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -40,7 +40,8 @@ const HonoraryPageView: React.FC = () => (
|
||||
<li>Keijo Nikoskinen 2011–2014</li>
|
||||
<li>Jussi Ryynänen 2014–2017</li>
|
||||
<li>Ville Viikari 2017–2020</li>
|
||||
<li>Anu Lehtovuori 2020–</li>
|
||||
<li>Anu Lehtovuori 2020–2026</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>
|
||||
|
||||
@@ -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
@@ -8,5 +8,5 @@
|
||||
},
|
||||
"skipJsErrors": true,
|
||||
"appCommand": "npm run serve",
|
||||
"appInitDelay": 10000
|
||||
"appInitDelay": 2000
|
||||
}
|
||||
|
||||
@@ -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/");
|
||||
|
||||
@@ -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) {
|
||||
if (logger.requests.length > 0 ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react-jsx",
|
||||
"jsx": "preserve",
|
||||
"lib": [
|
||||
"dom",
|
||||
"esnext"
|
||||
|
||||
Reference in New Issue
Block a user