From 17713d4f9deef80b398cc702851b74b4cd4cc75d Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 25 May 2026 18:56:26 +0300 Subject: [PATCH 1/3] picutre updates for 2026 fuksis --- .github/agents/eslint-setup-fixer.agent.md | 78 +++++++++++++++++++ .husky/pre-push | 2 +- package.json | 3 + .../ForFreshmenPage/ForFreshmenPageView.tsx | 12 +-- .../ForInternationalPage/ForIntlPageView.tsx | 12 +-- src/views/FreshmenPage/FreshmenPageView.tsx | 12 +-- 6 files changed, 103 insertions(+), 16 deletions(-) create mode 100644 .github/agents/eslint-setup-fixer.agent.md diff --git a/.github/agents/eslint-setup-fixer.agent.md b/.github/agents/eslint-setup-fixer.agent.md new file mode 100644 index 0000000..f0be863 --- /dev/null +++ b/.github/agents/eslint-setup-fixer.agent.md @@ -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 diff --git a/.husky/pre-push b/.husky/pre-push index 67c623e..ad2ddcf 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -1,4 +1,4 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" -# npm run lint ##sori tää o liia haisuli +npm run lint:es diff --git a/package.json b/package.json index ac5c8ca..0c96051 100644 --- a/package.json +++ b/package.json @@ -93,6 +93,9 @@ "swr": "^1.2.2", "uuid": "^13.0.0" }, + "engines": { + "node": "16" + }, "overrides": { "react-mde": { "react": "$react", diff --git a/src/views/ForFreshmenPage/ForFreshmenPageView.tsx b/src/views/ForFreshmenPage/ForFreshmenPageView.tsx index e9cdfc4..2ee7627 100644 --- a/src/views/ForFreshmenPage/ForFreshmenPageView.tsx +++ b/src/views/ForFreshmenPage/ForFreshmenPageView.tsx @@ -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,7 +61,7 @@ const ForFreshmenPageView: React.FC = () => ( Kipparit ( 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.

- 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!

Teemu Heikkinen
@@ -128,12 +130,12 @@ const ForFreshmenPageView: React.FC = () => ( SIK fuksis have a group chat, which you can join by scanning the QR code below:

or press me!

Also join the notifications channel for SIK fuksis, to stay in the loop!:

or press me!

diff --git a/src/views/ForInternationalPage/ForIntlPageView.tsx b/src/views/ForInternationalPage/ForIntlPageView.tsx index 272f87c..5cc1d64 100644 --- a/src/views/ForInternationalPage/ForIntlPageView.tsx +++ b/src/views/ForInternationalPage/ForIntlPageView.tsx @@ -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,7 +78,7 @@ const ForIntlPageView: React.FC = () => ( Kipparit ( having just as much fun as we are. Always remember that as a teekkari in Otaniemi, you're never alone.

- 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!

Apollo Ailus
@@ -149,12 +151,12 @@ const ForIntlPageView: React.FC = () => ( SIK fuksis have a group chat, which you can join by scanning the QR code below:

or press me!

Also join the notifications channel for SIK fuksis, to stay in the loop!:

or press me!

diff --git a/src/views/FreshmenPage/FreshmenPageView.tsx b/src/views/FreshmenPage/FreshmenPageView.tsx index 52a31db..72be452 100644 --- a/src/views/FreshmenPage/FreshmenPageView.tsx +++ b/src/views/FreshmenPage/FreshmenPageView.tsx @@ -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,7 +60,7 @@ const FreshmenPageView: React.FC = () => ( Kipparit ( Ajan myötä palapelin palat muodostavat sinun näköisesi kuvan ja pääset itse vaikuttamaan siihen, miltä lopputulos näyttää.

- 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ä!

Teemu Heikkinen
@@ -126,12 +128,12 @@ const FreshmenPageView: React.FC = () => ( SIK:n fukseilla on oma Telegram-ryhmä, jonne pääset liitymään tästä:

tai tästä

Liity myös samalla SIK-fuksien tiedotuskanavalle tästä:

tai tästä

From 1df9b22fa3b9274f63e5208bd064a828340c33b7 Mon Sep 17 00:00:00 2001 From: Your Name Date: Mon, 25 May 2026 18:57:55 +0300 Subject: [PATCH 2/3] lint fixes --- src/pages/signup/[id].tsx | 5 ++--- src/views/HonoraryPage/HonoraryPageView.tsx | 10 +++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/pages/signup/[id].tsx b/src/pages/signup/[id].tsx index 2721202..9c759f6 100644 --- a/src/pages/signup/[id].tsx +++ b/src/pages/signup/[id].tsx @@ -47,8 +47,7 @@ const SignUpPage: NextPage = ({ initialForm }) => { } const onSubmit = async ({ formData }: ISubmitEvent) => { - - //for bot detection + // for bot detection if (honeypot !== "") { console.log("bot cought in honeypot cought lacking"); @@ -88,7 +87,7 @@ const SignUpPage: NextPage = ({ initialForm }) => { onChange={noop} onSubmit={onSubmit} /> - {/* 3. HONEYPOT INPUT FIELD */} + {/* 3. HONEYPOT INPUT FIELD */}
(
  • 2025 Iikka Huttu
  • 2025 Heidi Mäkitalo
  • -
      -
    • 2026 Aaron Löfgren
    • -
    • 2025 Elina Huttunen
    • -
    • 2026 Karoliina Talvikangas
    • -
    • 2026 Tommi Sytelä
    • +
        +
      • 2026 Aaron Löfgren
      • +
      • 2025 Elina Huttunen
      • +
      • 2026 Karoliina Talvikangas
      • +
      • 2026 Tommi Sytelä

      Hopeiset ansiomerkit

      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.

      From 6af5d7fa1fcd5641ea0651891b28114e7538cc6c Mon Sep 17 00:00:00 2001 From: einstein Date: Tue, 26 May 2026 18:47:04 +0300 Subject: [PATCH 3/3] Fix CI build SSG timeouts - Add backend request timeout to prevent hanging builds - Make getStaticProps resilient to API failures - Avoid build-time crawling for dynamic routes (blocking fallback) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/api/backend.ts | 3 ++ src/pages/events/[id].tsx | 55 +++++++++++++++++------------------ src/pages/feed/[id].tsx | 54 ++++++++++++++++------------------ src/pages/in_english.tsx | 11 ++++--- src/pages/index.tsx | 11 ++++--- src/pages/kilta/toiminta.tsx | 13 +++++---- src/pages/signup/[id].tsx | 52 ++++++++++++++++----------------- src/pages/yritysyhteistyo.tsx | 7 +++-- 8 files changed, 105 insertions(+), 101 deletions(-) diff --git a/src/api/backend.ts b/src/api/backend.ts index d6700f0..87a82d9 100644 --- a/src/api/backend.ts +++ b/src/api/backend.ts @@ -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 { diff --git a/src/pages/events/[id].tsx b/src/pages/events/[id].tsx index 408a4bb..6567fc8 100644 --- a/src/pages/events/[id].tsx +++ b/src/pages/events/[id].tsx @@ -14,14 +14,13 @@ interface InitialProps { const EventPage: NextPage = ({ event }) => { const router = useRouter(); - const { id } = router.query; if (router.isFallback) return ; return ( <> - + @@ -30,36 +29,34 @@ const EventPage: NextPage = ({ 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 = async ({ params }) => { - const { id } = params; - let notFound = false; - let event: Event; - try { - event = await EventApi.getEvent(Number(id)); - } catch (err) { - notFound = true; + const id = Number(params?.id); + if (!id) { + return { + notFound: true, + revalidate: 10, + }; + } + + try { + const event = await EventApi.getEvent(id); + return { + props: { + event, + }, + revalidate: 10, // Required for deleting hidden pages + }; + } catch { + return { + notFound: true, + revalidate: 10, + }; } - return { - props: { - event, - }, - revalidate: 10, // Required for deleting hidden pages - notFound, - }; }; export default EventPage; diff --git a/src/pages/feed/[id].tsx b/src/pages/feed/[id].tsx index b791266..8bf9993 100644 --- a/src/pages/feed/[id].tsx +++ b/src/pages/feed/[id].tsx @@ -14,14 +14,13 @@ interface InitialProps { const FeedPage: NextPage = ({ post }) => { const router = useRouter(); - const { id } = router.query; if (router.isFallback) return ; return ( <> - + @@ -30,37 +29,34 @@ const FeedPage: NextPage = ({ 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 = async ({ params }) => { - const { id } = params; - let notFound = false; - let post: Post; - try { - post = await FeedApi.getPost(Number(id)); - } catch (err) { - notFound = true; + const id = Number(params?.id); + if (!id) { + return { + notFound: true, + revalidate: 10, + }; } - return { - props: { - post, - }, - revalidate: 10, // Required for deleting hidden pages - notFound, - }; + try { + const post = await FeedApi.getPost(id); + return { + props: { + post, + }, + revalidate: 10, // Required for deleting hidden pages + }; + } catch { + return { + notFound: true, + revalidate: 10, + }; + } }; export default FeedPage; diff --git a/src/pages/in_english.tsx b/src/pages/in_english.tsx index 393f8fd..78db8f1 100644 --- a/src/pages/in_english.tsx +++ b/src/pages/in_english.tsx @@ -44,12 +44,15 @@ const InEnglishPage: NextPage = ({ initialEvents, initialFeed }) = }; export const getStaticProps: GetStaticProps = async () => { - const initialEvents = await fetcher(eventApi); - const initialFeed = await fetcher(feedApi); + const [eventsResult, feedResult] = await Promise.allSettled([ + fetcher(eventApi), + fetcher(feedApi), + ]); + return { props: { - initialEvents, - initialFeed, + initialEvents: eventsResult.status === "fulfilled" ? eventsResult.value : [], + initialFeed: feedResult.status === "fulfilled" ? feedResult.value : [], }, revalidate: 10, }; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 5b93a16..b3ccefd 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -43,12 +43,15 @@ const FrontPage: NextPage = ({ initialEvents, initialFeed }) => { }; export const getStaticProps: GetStaticProps = async () => { - const initialEvents = fetcher(eventApi); - const initialFeed = fetcher(feedApi); + const [eventsResult, feedResult] = await Promise.allSettled([ + fetcher(eventApi), + fetcher(feedApi), + ]); + return { props: { - initialEvents: await initialEvents, - initialFeed: await initialFeed, + initialEvents: eventsResult.status === "fulfilled" ? eventsResult.value : [], + initialFeed: feedResult.status === "fulfilled" ? feedResult.value : [], }, revalidate: 10, }; diff --git a/src/pages/kilta/toiminta.tsx b/src/pages/kilta/toiminta.tsx index b4d4577..73d42c9 100644 --- a/src/pages/kilta/toiminta.tsx +++ b/src/pages/kilta/toiminta.tsx @@ -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 = ({ initialEvents, initialFeed }) => { }; export const getStaticProps: GetStaticProps = async () => { - const initialEvents = await EventApi.getEvents(); - const initialFeed = await FeedApi.getFeed(); + const [eventsResult, feedResult] = await Promise.allSettled([ + fetcher(eventApi), + fetcher(feedApi), + ]); + return { props: { - initialEvents, - initialFeed, + initialEvents: eventsResult.status === "fulfilled" ? eventsResult.value : [], + initialFeed: feedResult.status === "fulfilled" ? feedResult.value : [], }, revalidate: 10, }; diff --git a/src/pages/signup/[id].tsx b/src/pages/signup/[id].tsx index 9c759f6..6d43741 100644 --- a/src/pages/signup/[id].tsx +++ b/src/pages/signup/[id].tsx @@ -112,36 +112,34 @@ const SignUpPage: NextPage = ({ initialForm }) => { ); }; -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 = async ({ params }) => { - const { id } = params; - let notFound = false; - let initialForm: SignupForm; - try { - initialForm = await SignupApi.getForm(Number(id)); - } catch { - notFound = true; + const id = Number(params?.id); + if (!id) { + return { + notFound: true, + revalidate: 10, + }; + } + + try { + const initialForm = await SignupApi.getForm(id); + return { + props: { + initialForm, + }, + revalidate: 10, // Required for deleting hidden pages + }; + } catch { + return { + notFound: true, + revalidate: 10, + }; } - return { - props: { - initialForm, - }, - revalidate: 10, // Required for deleting hidden pages - notFound, - }; }; export default SignUpPage; diff --git a/src/pages/yritysyhteistyo.tsx b/src/pages/yritysyhteistyo.tsx index 6ae3c24..8676797 100644 --- a/src/pages/yritysyhteistyo.tsx +++ b/src/pages/yritysyhteistyo.tsx @@ -30,10 +30,13 @@ const CorporatePage: NextPage = ({ initialJobAds }) => { }; export const getStaticProps: GetStaticProps = async () => { - const initialJobAds = await fetcher(jobAdApi); + const jobAdsResult = await Promise.allSettled([ + fetcher(jobAdApi), + ]); + return { props: { - initialJobAds, + initialJobAds: jobAdsResult[0].status === "fulfilled" ? jobAdsResult[0].value : [], }, revalidate: 10, };