Merge master into production (SSG build fixes)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
einstein
2026-05-26 19:19:35 +03:00
15 changed files with 213 additions and 123 deletions
@@ -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
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/sh #!/bin/sh
. "$(dirname "$0")/_/husky.sh" . "$(dirname "$0")/_/husky.sh"
# npm run lint ##sori tää o liia haisuli npm run lint:es
+3
View File
@@ -93,6 +93,9 @@
"swr": "^1.2.2", "swr": "^1.2.2",
"uuid": "^13.0.0" "uuid": "^13.0.0"
}, },
"engines": {
"node": "16"
},
"overrides": { "overrides": {
"react-mde": { "react-mde": {
"react": "$react", "react": "$react",
+3
View File
@@ -1,8 +1,11 @@
import axios, { AxiosInstance, AxiosRequestConfig } from "axios"; import axios, { AxiosInstance, AxiosRequestConfig } from "axios";
import { getAccessTokenCookie } from "@utils/auth"; import { getAccessTokenCookie } from "@utils/auth";
const API_TIMEOUT_MS = 10000;
const axiosInstance: AxiosInstance = axios.create({ const axiosInstance: AxiosInstance = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL, baseURL: process.env.NEXT_PUBLIC_API_URL,
timeout: API_TIMEOUT_MS,
}); });
export enum APIPath { export enum APIPath {
+26 -29
View File
@@ -14,14 +14,13 @@ interface InitialProps {
const EventPage: NextPage<InitialProps> = ({ event }) => { const EventPage: NextPage<InitialProps> = ({ event }) => {
const router = useRouter(); const router = useRouter();
const { id } = router.query;
if (router.isFallback) return <LoadingView />; if (router.isFallback) return <LoadingView />;
return ( return (
<> <>
<Head> <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> </Head>
<PageWrapper> <PageWrapper>
<EventPageView event={event} /> <EventPageView event={event} />
@@ -30,36 +29,34 @@ const EventPage: NextPage<InitialProps> = ({ event }) => {
); );
}; };
export const getStaticPaths: GetStaticPaths = async () => { export const getStaticPaths: GetStaticPaths = async () => ({
const allEvents = await EventApi.getEvents(); paths: [],
const paths = allEvents.map((e: Event) => ({ fallback: "blocking",
params: { });
id: String(e.id),
},
}
));
return {
paths,
fallback: true,
};
};
export const getStaticProps: GetStaticProps<InitialProps> = async ({ params }) => { export const getStaticProps: GetStaticProps<InitialProps> = async ({ params }) => {
const { id } = params; const id = Number(params?.id);
let notFound = false; if (!id) {
let event: Event; return {
try { notFound: true,
event = await EventApi.getEvent(Number(id)); revalidate: 10,
} catch (err) { };
notFound = true; }
try {
const event = await EventApi.getEvent(id);
return {
props: {
event,
},
revalidate: 10, // Required for deleting hidden pages
};
} catch {
return {
notFound: true,
revalidate: 10,
};
} }
return {
props: {
event,
},
revalidate: 10, // Required for deleting hidden pages
notFound,
};
}; };
export default EventPage; export default EventPage;
+25 -29
View File
@@ -14,14 +14,13 @@ interface InitialProps {
const FeedPage: NextPage<InitialProps> = ({ post }) => { const FeedPage: NextPage<InitialProps> = ({ post }) => {
const router = useRouter(); const router = useRouter();
const { id } = router.query;
if (router.isFallback) return <LoadingView />; if (router.isFallback) return <LoadingView />;
return ( return (
<> <>
<Head> <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> </Head>
<PageWrapper> <PageWrapper>
<FeedPageView post={post} /> <FeedPageView post={post} />
@@ -30,37 +29,34 @@ const FeedPage: NextPage<InitialProps> = ({ post }) => {
); );
}; };
export const getStaticPaths: GetStaticPaths = async () => { export const getStaticPaths: GetStaticPaths = async () => ({
const feed = await FeedApi.getFeed(); paths: [],
const paths = feed.map((post: Post) => ({ fallback: "blocking",
params: { });
id: String(post.id),
},
}
));
return {
paths,
fallback: true,
};
};
export const getStaticProps: GetStaticProps<InitialProps> = async ({ params }) => { export const getStaticProps: GetStaticProps<InitialProps> = async ({ params }) => {
const { id } = params; const id = Number(params?.id);
let notFound = false; if (!id) {
let post: Post; return {
try { notFound: true,
post = await FeedApi.getPost(Number(id)); revalidate: 10,
} catch (err) { };
notFound = true;
} }
return { try {
props: { const post = await FeedApi.getPost(id);
post, return {
}, props: {
revalidate: 10, // Required for deleting hidden pages post,
notFound, },
}; revalidate: 10, // Required for deleting hidden pages
};
} catch {
return {
notFound: true,
revalidate: 10,
};
}
}; };
export default FeedPage; export default FeedPage;
+7 -4
View File
@@ -44,12 +44,15 @@ const InEnglishPage: NextPage<InitialProps> = ({ initialEvents, initialFeed }) =
}; };
export const getStaticProps: GetStaticProps<InitialProps> = async () => { export const getStaticProps: GetStaticProps<InitialProps> = async () => {
const initialEvents = await fetcher<Event[]>(eventApi); const [eventsResult, feedResult] = await Promise.allSettled([
const initialFeed = await fetcher<Post[]>(feedApi); fetcher<Event[]>(eventApi),
fetcher<Post[]>(feedApi),
]);
return { return {
props: { props: {
initialEvents, initialEvents: eventsResult.status === "fulfilled" ? eventsResult.value : [],
initialFeed, initialFeed: feedResult.status === "fulfilled" ? feedResult.value : [],
}, },
revalidate: 10, revalidate: 10,
}; };
+7 -4
View File
@@ -43,12 +43,15 @@ const FrontPage: NextPage<InitialProps> = ({ initialEvents, initialFeed }) => {
}; };
export const getStaticProps: GetStaticProps<InitialProps> = async () => { export const getStaticProps: GetStaticProps<InitialProps> = async () => {
const initialEvents = fetcher<Event[]>(eventApi); const [eventsResult, feedResult] = await Promise.allSettled([
const initialFeed = fetcher<Post[]>(feedApi); fetcher<Event[]>(eventApi),
fetcher<Post[]>(feedApi),
]);
return { return {
props: { props: {
initialEvents: await initialEvents, initialEvents: eventsResult.status === "fulfilled" ? eventsResult.value : [],
initialFeed: await initialFeed, initialFeed: feedResult.status === "fulfilled" ? feedResult.value : [],
}, },
revalidate: 10, revalidate: 10,
}; };
+7 -6
View File
@@ -3,9 +3,7 @@ import { NextPage, GetStaticProps } from "next";
import Head from "next/head"; import Head from "next/head";
import useSWR from "swr"; import useSWR from "swr";
import Event from "@models/Event"; import Event from "@models/Event";
import EventApi from "@api/eventApi";
import Post from "@models/Feed"; import Post from "@models/Feed";
import FeedApi from "@api/feedApi";
import ActualPageView from "@views/ActualPage/ActualPageView"; import ActualPageView from "@views/ActualPage/ActualPageView";
import PageWrapper from "@views/common/PageWrapper"; import PageWrapper from "@views/common/PageWrapper";
import { fetcher, APIPath, API } from "@api/backend"; import { fetcher, APIPath, API } from "@api/backend";
@@ -40,12 +38,15 @@ const ActualPage: NextPage<InitialProps> = ({ initialEvents, initialFeed }) => {
}; };
export const getStaticProps: GetStaticProps<InitialProps> = async () => { export const getStaticProps: GetStaticProps<InitialProps> = async () => {
const initialEvents = await EventApi.getEvents(); const [eventsResult, feedResult] = await Promise.allSettled([
const initialFeed = await FeedApi.getFeed(); fetcher<Event[]>(eventApi),
fetcher<Post[]>(feedApi),
]);
return { return {
props: { props: {
initialEvents, initialEvents: eventsResult.status === "fulfilled" ? eventsResult.value : [],
initialFeed, initialFeed: feedResult.status === "fulfilled" ? feedResult.value : [],
}, },
revalidate: 10, revalidate: 10,
}; };
+27 -30
View File
@@ -47,8 +47,7 @@ const SignUpPage: NextPage<InitialProps> = ({ initialForm }) => {
} }
const onSubmit = async ({ formData }: ISubmitEvent<any>) => { const onSubmit = async ({ formData }: ISubmitEvent<any>) => {
// for bot detection
//for bot detection
if (honeypot !== "") { if (honeypot !== "") {
console.log("bot cought in honeypot cought lacking"); console.log("bot cought in honeypot cought lacking");
@@ -88,7 +87,7 @@ const SignUpPage: NextPage<InitialProps> = ({ initialForm }) => {
onChange={noop} onChange={noop}
onSubmit={onSubmit} onSubmit={onSubmit}
/> />
{/* 3. HONEYPOT INPUT FIELD */} {/* 3. HONEYPOT INPUT FIELD */}
<div <div
style={ style={
{ {
@@ -113,36 +112,34 @@ const SignUpPage: NextPage<InitialProps> = ({ initialForm }) => {
); );
}; };
export const getStaticPaths: GetStaticPaths = async () => { export const getStaticPaths: GetStaticPaths = async () => ({
const allForms = await SignupApi.getForms(); paths: [],
const paths = allForms.map((e: SignupForm) => ({ fallback: "blocking",
params: { });
id: String(e.id),
},
}
));
return {
paths,
fallback: true,
};
};
export const getStaticProps: GetStaticProps<InitialProps> = async ({ params }) => { export const getStaticProps: GetStaticProps<InitialProps> = async ({ params }) => {
const { id } = params; const id = Number(params?.id);
let notFound = false; if (!id) {
let initialForm: SignupForm; return {
try { notFound: true,
initialForm = await SignupApi.getForm(Number(id)); revalidate: 10,
} catch { };
notFound = true; }
try {
const initialForm = await SignupApi.getForm(id);
return {
props: {
initialForm,
},
revalidate: 10, // Required for deleting hidden pages
};
} catch {
return {
notFound: true,
revalidate: 10,
};
} }
return {
props: {
initialForm,
},
revalidate: 10, // Required for deleting hidden pages
notFound,
};
}; };
export default SignUpPage; export default SignUpPage;
+5 -2
View File
@@ -30,10 +30,13 @@ const CorporatePage: NextPage<InitialProps> = ({ initialJobAds }) => {
}; };
export const getStaticProps: GetStaticProps<InitialProps> = async () => { export const getStaticProps: GetStaticProps<InitialProps> = async () => {
const initialJobAds = await fetcher<JobAd[]>(jobAdApi); const jobAdsResult = await Promise.allSettled([
fetcher<JobAd[]>(jobAdApi),
]);
return { return {
props: { props: {
initialJobAds, initialJobAds: jobAdsResult[0].status === "fulfilled" ? jobAdsResult[0].value : [],
}, },
revalidate: 10, revalidate: 10,
}; };
@@ -11,6 +11,8 @@ const TG_GROUP_CHAT_LINK = "https://t.me/+U8dQfkCWBaIxMDc0";
const TG_NOTIFICATIONS_LINK = "https://t.me/+IcZONKWXiNNkODRk"; const TG_NOTIFICATIONS_LINK = "https://t.me/+IcZONKWXiNNkODRk";
const EMAIL_LINK = "ftmk@sahkoinsinoorikilta.fi"; const EMAIL_LINK = "ftmk@sahkoinsinoorikilta.fi";
const EMAIL_LINK_MAILTO = `mailto:${EMAIL_LINK}`; 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` const ImageContainer = styled.div`
width: 100%; width: 100%;
@@ -59,7 +61,7 @@ const ForFreshmenPageView: React.FC = () => (
<ImageContainer> <ImageContainer>
<Image <Image
src="https://static.sahkoinsinoorikilta.fi/FTMK/IMG_6539.JPG" src="https://static.sahkoinsinoorikilta.fi/FTMK/kipparit-26.jpg"
alt="Kipparit" alt="Kipparit"
layout="responsive" layout="responsive"
width={100} width={100}
@@ -128,12 +130,12 @@ const ForFreshmenPageView: React.FC = () => (
SIK fuksis have a group chat, which you can join by scanning the QR code below: SIK fuksis have a group chat, which you can join by scanning the QR code below:
</p> </p>
<QRImages <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>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> <p>Also join the notifications channel for SIK fuksis, to stay in the loop!:</p>
<QRImages <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> <p>or <Link to={TG_NOTIFICATIONS_LINK} target="_blank">press me!</Link></p>
</InfoBox> </InfoBox>
@@ -11,6 +11,8 @@ const TG_GROUP_CHAT_LINK = "https://t.me/+oNrBDLI5cXZhNDEx";
const TG_NOTIFICATIONS_LINK = "https://t.me/sikhotline2526"; const TG_NOTIFICATIONS_LINK = "https://t.me/sikhotline2526";
const EMAIL_LINK = "ftmk@sahkoinsinoorikilta.fi"; const EMAIL_LINK = "ftmk@sahkoinsinoorikilta.fi";
const EMAIL_LINK_MAILTO = `mailto:${EMAIL_LINK}`; 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` const ImageContainer = styled.div`
width: 100%; width: 100%;
@@ -76,7 +78,7 @@ const ForIntlPageView: React.FC = () => (
<ImageContainer> <ImageContainer>
<Image <Image
src="https://static.sahkoinsinoorikilta.fi/FTMK/Captains2025.jpg" src="https://static.sahkoinsinoorikilta.fi/FTMK/Captains2026.jpg"
alt="Kipparit" alt="Kipparit"
layout="responsive" layout="responsive"
width={100} width={100}
@@ -102,9 +104,9 @@ const ForIntlPageView: React.FC = () => (
having just as much fun as we are. Always remember that as a teekkari in Otaniemi, you&apos;re never alone. having just as much fun as we are. Always remember that as a teekkari in Otaniemi, you&apos;re never alone.
</p> </p>
<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. 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> </p>
<h6>Apollo Ailus</h6> <h6>Apollo Ailus</h6>
@@ -149,12 +151,12 @@ const ForIntlPageView: React.FC = () => (
SIK fuksis have a group chat, which you can join by scanning the QR code below: SIK fuksis have a group chat, which you can join by scanning the QR code below:
</p> </p>
<QRImages <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>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> <p>Also join the notifications channel for SIK fuksis, to stay in the loop!:</p>
<QRImages <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> <p>or <Link to={TG_NOTIFICATIONS_LINK} target="_blank">press me!</Link></p>
</InfoBox> </InfoBox>
+7 -5
View File
@@ -11,6 +11,8 @@ const TG_GROUP_CHAT_LINK = "https://t.me/+U8dQfkCWBaIxMDc0";
const TG_NOTIFICATIONS_LINK = "https://t.me/+IcZONKWXiNNkODRk"; const TG_NOTIFICATIONS_LINK = "https://t.me/+IcZONKWXiNNkODRk";
const EMAIL_LINK = "ftmk@sahkoinsinoorikilta.fi"; const EMAIL_LINK = "ftmk@sahkoinsinoorikilta.fi";
const EMAIL_LINK_MAILTO = `mailto:${EMAIL_LINK}`; 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` const ImageContainer = styled.div`
width: 100%; width: 100%;
@@ -58,7 +60,7 @@ const FreshmenPageView: React.FC = () => (
<ImageContainer> <ImageContainer>
<Image <Image
src="https://static.sahkoinsinoorikilta.fi/FTMK/IMG_6539.JPG" src="https://static.sahkoinsinoorikilta.fi/FTMK/kipparit-26.jpg"
alt="Kipparit" alt="Kipparit"
layout="responsive" layout="responsive"
width={100} width={100}
@@ -80,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ää. Ajan myötä palapelin palat muodostavat sinun näköisesi kuvan ja pääset itse vaikuttamaan siihen, miltä lopputulos näyttää.
</p> </p>
<p> <p>
Orientaatioviikko järjestetään 24.-28.8.2025, mutta jo ennen sitä sinulla on mahdollisuus tulla tutustumaan meihin, muihin fukseihin ja ISOihin rentoon Varaslähtöön. Orientaatioviikko järjestetään 24.-28.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 15.8.2025. Siitä lisää Telegram-ryhmissä! Varaslähtö fuksivuoteen järjestetään lauantaina 15.8.2026. Siitä lisää Telegram-ryhmissä!
</p> </p>
<h6>Aura Friman</h6> <h6>Aura Friman</h6>
@@ -126,12 +128,12 @@ const FreshmenPageView: React.FC = () => (
SIK:n fukseilla on oma Telegram-ryhmä, jonne pääset liitymään tästä: SIK:n fukseilla on oma Telegram-ryhmä, jonne pääset liitymään tästä:
</p> </p>
<QRImages <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>tai <Link to={TG_GROUP_CHAT_LINK} target="_blank">tästä</Link></p>
<p>Liity myös samalla SIK-fuksien tiedotuskanavalle tästä:</p> <p>Liity myös samalla SIK-fuksien tiedotuskanavalle tästä:</p>
<QRImages <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> <p>tai <Link to={TG_NOTIFICATIONS_LINK} target="_blank">tästä</Link></p>
</InfoBox> </InfoBox>
+5 -5
View File
@@ -236,11 +236,11 @@ const HonoraryPageView: React.FC = () => (
<li>2025 Iikka Huttu</li> <li>2025 Iikka Huttu</li>
<li>2025 Heidi Mäkitalo</li> <li>2025 Heidi Mäkitalo</li>
</ul> </ul>
<ul> <ul>
<li>2026 Aaron Löfgren</li> <li>2026 Aaron Löfgren</li>
<li>2025 Elina Huttunen</li> <li>2025 Elina Huttunen</li>
<li>2026 Karoliina Talvikangas</li> <li>2026 Karoliina Talvikangas</li>
<li>2026 Tommi Sytelä</li> <li>2026 Tommi Sytelä</li>
</ul> </ul>
<h2>Hopeiset ansiomerkit</h2> <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> <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>