Compare commits
55 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b2355576b1 | |||
| f23c2ed68d | |||
| 77c9052d1b | |||
| 0db4837fe1 | |||
| 2799c80f56 | |||
| 8af519ac9a | |||
| 3350d33c82 | |||
| 5a097080ee | |||
| 433d9c67d7 | |||
| d538e6c92e | |||
| 1be914f37f | |||
| 521df27aa1 | |||
| 8bf38f512c | |||
| 3ffe8a1e17 | |||
| 32e541533f | |||
| 9f33c667d3 | |||
| 0e4e02e1b3 | |||
| cfc7dd11f5 | |||
| 63df5e6f5f | |||
| bdcf4840f5 | |||
| 0dc349161e | |||
| d101931020 | |||
| b4d41cd6a7 | |||
| ea82b493d5 | |||
| fe8f9328fa | |||
| 71d19d44cf | |||
| 4146af7207 | |||
| c243e76324 | |||
| 659d0e63a0 | |||
| 2c6c1d1e67 | |||
| eeb2f949c6 | |||
| 894e630664 | |||
| 56c13dbf64 | |||
| 9c0e1a0e61 | |||
| 3b2d0596c9 | |||
| 2395321825 | |||
| 05b045c2fc | |||
| faf12816bb | |||
| e7ef69d75f | |||
| 03e6131fe8 | |||
| 87f803ca3e | |||
| dd3eded4a1 | |||
| efacbe9c40 | |||
| c7a1502a26 | |||
| 59a4f3567e | |||
| 0ad59bfba6 | |||
| 6aa0b3fe19 | |||
| 88d5e57858 | |||
| 07efb4caed | |||
| ce29f5a311 | |||
| e1d4a300c5 | |||
| 90f33048d7 | |||
| c55c7699c7 | |||
| 2e37072703 | |||
| aa90d97007 |
+4
-10
@@ -86,9 +86,8 @@ publish:dev:
|
|||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
script:
|
script:
|
||||||
- docker info
|
|
||||||
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
|
|
||||||
- docker build . -t "$IMAGE_NAME":latest --build-arg SENTRY_AUTH_TOKEN="$SENTRY_AUTH_TOKEN" --build-arg NEXT_PUBLIC_DEPLOY_ENV=development --build-arg NEXT_PUBLIC_API_URL=https://api.dev.sahkoinsinoorikilta.fi/api --build-arg NEXT_PUBLIC_SITE_URL=https://dev.sahkoinsinoorikilta.fi
|
- docker build . -t "$IMAGE_NAME":latest --build-arg SENTRY_AUTH_TOKEN="$SENTRY_AUTH_TOKEN" --build-arg NEXT_PUBLIC_DEPLOY_ENV=development --build-arg NEXT_PUBLIC_API_URL=https://api.dev.sahkoinsinoorikilta.fi/api --build-arg NEXT_PUBLIC_SITE_URL=https://dev.sahkoinsinoorikilta.fi
|
||||||
|
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
|
||||||
- docker push "$IMAGE_NAME":latest
|
- docker push "$IMAGE_NAME":latest
|
||||||
|
|
||||||
publish:prod:
|
publish:prod:
|
||||||
@@ -99,9 +98,8 @@ publish:prod:
|
|||||||
only:
|
only:
|
||||||
- production
|
- production
|
||||||
script:
|
script:
|
||||||
- docker info
|
|
||||||
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
|
|
||||||
- docker build . -t "$IMAGE_NAME":prod --build-arg SENTRY_AUTH_TOKEN="$SENTRY_AUTH_TOKEN"
|
- docker build . -t "$IMAGE_NAME":prod --build-arg SENTRY_AUTH_TOKEN="$SENTRY_AUTH_TOKEN"
|
||||||
|
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
|
||||||
- docker push "$IMAGE_NAME":prod
|
- docker push "$IMAGE_NAME":prod
|
||||||
|
|
||||||
deploy:dev:
|
deploy:dev:
|
||||||
@@ -120,11 +118,9 @@ deploy:dev:
|
|||||||
- echo "$DEV_TLSCACERT" > ~/.docker/ca.pem
|
- echo "$DEV_TLSCACERT" > ~/.docker/ca.pem
|
||||||
- echo "$DEV_TLSCERT" > ~/.docker/cert.pem
|
- echo "$DEV_TLSCERT" > ~/.docker/cert.pem
|
||||||
- echo "$DEV_TLSKEY" > ~/.docker/key.pem
|
- echo "$DEV_TLSKEY" > ~/.docker/key.pem
|
||||||
- docker login -u gitlab-ci-token -p "$CI_BUILD_TOKEN" "$CI_REGISTRY"
|
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
|
||||||
script:
|
script:
|
||||||
- docker stack deploy --with-registry-auth -c stack-compose-dev.yml "$SERVICE_NAME"
|
- docker stack deploy --with-registry-auth -c stack-compose-dev.yml "$SERVICE_NAME"
|
||||||
after_script:
|
|
||||||
- docker logout "$CI_REGISTRY"
|
|
||||||
|
|
||||||
deploy:prod:
|
deploy:prod:
|
||||||
stage: deploy
|
stage: deploy
|
||||||
@@ -142,8 +138,6 @@ deploy:prod:
|
|||||||
- echo "$TLSCACERT" > ~/.docker/ca.pem
|
- echo "$TLSCACERT" > ~/.docker/ca.pem
|
||||||
- echo "$TLSCERT" > ~/.docker/cert.pem
|
- echo "$TLSCERT" > ~/.docker/cert.pem
|
||||||
- echo "$TLSKEY" > ~/.docker/key.pem
|
- echo "$TLSKEY" > ~/.docker/key.pem
|
||||||
- docker login -u gitlab-ci-token -p "$CI_BUILD_TOKEN" "$CI_REGISTRY"
|
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
|
||||||
script:
|
script:
|
||||||
- docker stack deploy --with-registry-auth -c stack-compose.yml "$SERVICE_NAME"
|
- docker stack deploy --with-registry-auth -c stack-compose.yml "$SERVICE_NAME"
|
||||||
after_script:
|
|
||||||
- docker logout "$CI_REGISTRY"
|
|
||||||
|
|||||||
@@ -5,14 +5,25 @@ This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next
|
|||||||
* **[React](https://facebook.github.io/react/)** (17.x)
|
* **[React](https://facebook.github.io/react/)** (17.x)
|
||||||
* **[Typescript](https://www.typescriptlang.org/)** (4.x)
|
* **[Typescript](https://www.typescriptlang.org/)** (4.x)
|
||||||
* **[Next.js](https://nextjs.org/)** (12.x)
|
* **[Next.js](https://nextjs.org/)** (12.x)
|
||||||
* [Testcafe](https://devexpress.github.io/testcafe/) - E2E Testing framework
|
* **[Testcafe](https://devexpress.github.io/testcafe/)** - E2E Testing framework
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
1. Clone/download repo
|
|
||||||
2. Install node v16 ([`nvm`](https://github.com/nvm-sh/nvm))
|
Install node v16 with **[Node Version Manager](https://github.com/nvm-sh/nvm#installing-and-updating)**.
|
||||||
3. `cp .env.local.example .env.local`
|
|
||||||
4. `npm install`
|
Set up your SSH key authentication in GitLab Profile Settings. Then clone the repository and checkout the master branch:
|
||||||
|
```bash
|
||||||
|
git clone git@gitlab.com:sahkoinsinoorikilta/vtmk/web2.0-frontend.git
|
||||||
|
cd web2.0-frontend
|
||||||
|
git checkout master
|
||||||
|
```
|
||||||
|
|
||||||
|
Create local env file for development and install dependencies:
|
||||||
|
```bash
|
||||||
|
cp .env.local.example .env.local
|
||||||
|
npm install
|
||||||
|
```
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -16,7 +16,6 @@ const sentryWebpackPluginOptions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
module.exports = withBundleAnalyzer(withSentryConfig({
|
module.exports = withBundleAnalyzer(withSentryConfig({
|
||||||
target: "server",
|
|
||||||
images: {
|
images: {
|
||||||
domains: [
|
domains: [
|
||||||
"api.sahkoinsinoorikilta.fi",
|
"api.sahkoinsinoorikilta.fi",
|
||||||
@@ -24,4 +23,7 @@ module.exports = withBundleAnalyzer(withSentryConfig({
|
|||||||
"api.dev.sahkoinsinoorikilta.fi",
|
"api.dev.sahkoinsinoorikilta.fi",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
sentry: {
|
||||||
|
hideSourceMaps: true, // Hide source maps, see: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#configure-source-maps
|
||||||
|
}
|
||||||
}, sentryWebpackPluginOptions));
|
}, sentryWebpackPluginOptions));
|
||||||
|
|||||||
Generated
+2234
-1105
File diff suppressed because it is too large
Load Diff
+21
-14
@@ -37,9 +37,9 @@
|
|||||||
"@types/jest": "^27.4.1",
|
"@types/jest": "^27.4.1",
|
||||||
"@types/js-cookie": "^3.0.1",
|
"@types/js-cookie": "^3.0.1",
|
||||||
"@types/node": "^16.11.36",
|
"@types/node": "^16.11.36",
|
||||||
"@types/react": "^17.0.19",
|
"@types/react": "^18.0.15",
|
||||||
"@types/react-csv": "^1.1.2",
|
"@types/react-csv": "^1.1.3",
|
||||||
"@types/react-dom": "^17.0.9",
|
"@types/react-dom": "^18.0.6",
|
||||||
"@types/shortid": "^0.0.29",
|
"@types/shortid": "^0.0.29",
|
||||||
"@types/styled-components": "^5.1.25",
|
"@types/styled-components": "^5.1.25",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.18.0",
|
"@typescript-eslint/eslint-plugin": "^5.18.0",
|
||||||
@@ -48,11 +48,11 @@
|
|||||||
"eslint": "^8.13.0",
|
"eslint": "^8.13.0",
|
||||||
"eslint-config-airbnb": "^19.0.4",
|
"eslint-config-airbnb": "^19.0.4",
|
||||||
"eslint-config-airbnb-typescript": "^17.0.0",
|
"eslint-config-airbnb-typescript": "^17.0.0",
|
||||||
"eslint-config-next": "^12.1.4",
|
"eslint-config-next": "^13.1.6",
|
||||||
"eslint-plugin-import": "^2.26.0",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
"husky": "^7.0.4",
|
"husky": "^7.0.4",
|
||||||
"jest": "^27.5.1",
|
"jest": "^27.5.1",
|
||||||
"next-sitemap": "^2.5.19",
|
"next-sitemap": "^3.1.11",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"postcss-jsx": "^0.36.4",
|
"postcss-jsx": "^0.36.4",
|
||||||
"postcss-syntax": "^0.36.2",
|
"postcss-syntax": "^0.36.2",
|
||||||
@@ -64,31 +64,38 @@
|
|||||||
"typescript": "^4.6.3"
|
"typescript": "^4.6.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@next/bundle-analyzer": "^12.1.4",
|
"@next/bundle-analyzer": "^12.2.3",
|
||||||
"@rjsf/core": "^4.1.1",
|
"@rjsf/core": "^4.2.0",
|
||||||
"@sentry/nextjs": "^6.19.6",
|
"@sentry/nextjs": "^7.34.0",
|
||||||
"axios": "^0.26.1",
|
"axios": "^0.26.1",
|
||||||
"date-fns": "^2.28.0",
|
"date-fns": "^2.28.0",
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
"js-cookie": "^3.0.1",
|
"js-cookie": "^3.0.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"next": "^12.1.4",
|
"next": "^13.4.19",
|
||||||
"normalize.css": "^8.0.1",
|
"normalize.css": "^8.0.1",
|
||||||
"react": "^17.0.2",
|
"react": "^18.2.0",
|
||||||
"react-csv": "^2.2.2",
|
"react-csv": "^2.2.2",
|
||||||
"react-dnd": "15.0.2",
|
"react-dnd": "15.0.2",
|
||||||
"react-dnd-html5-backend": "15.0.2",
|
"react-dnd-html5-backend": "15.0.2",
|
||||||
"react-dnd-touch-backend": "15.0.2",
|
"react-dnd-touch-backend": "15.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^18.2.0",
|
||||||
"react-is": "^17.0.2",
|
"react-is": "^18.2.0",
|
||||||
"react-markdown": "^8.0.2",
|
"react-markdown": "^8.0.3",
|
||||||
"react-mde": "^11.5.0",
|
"react-mde": "^11.5.0",
|
||||||
"react-toastify": "^8.2.0",
|
"react-toastify": "^9.0.7",
|
||||||
"rehype-raw": "^6.1.1",
|
"rehype-raw": "^6.1.1",
|
||||||
"rehype-sanitize": "^5.0.1",
|
"rehype-sanitize": "^5.0.1",
|
||||||
"sharp": "^0.30.3",
|
"sharp": "^0.30.3",
|
||||||
"shortid": "^2.2.16",
|
"shortid": "^2.2.16",
|
||||||
|
"stripe": "^13.6.0",
|
||||||
"styled-components": "^5.3.5",
|
"styled-components": "^5.3.5",
|
||||||
"swr": "^1.2.2"
|
"swr": "^1.2.2"
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"react-mde": {
|
||||||
|
"react": "$react",
|
||||||
|
"react-dom": "$react-dom"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ const Panel = styled.div<{ $visible?: boolean }>`
|
|||||||
|
|
||||||
interface AccordionProps {
|
interface AccordionProps {
|
||||||
title: string;
|
title: string;
|
||||||
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Accordion: React.FC<AccordionProps> = ({ title, children }) => {
|
const Accordion: React.FC<AccordionProps> = ({ title, children }) => {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/legacy/image";
|
||||||
|
|
||||||
const Icon = "/img/add-icon.png";
|
const Icon = "/img/add-icon.png";
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ interface ButtonProps {
|
|||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
buttonStyle: "hero" | "filled" | "filter" | "bordered";
|
buttonStyle: "hero" | "filled" | "filter" | "bordered";
|
||||||
selected?: boolean;
|
selected?: boolean;
|
||||||
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StyledButton = styled.button<{ $selected?: boolean }>`
|
const StyledButton = styled.button<{ $selected?: boolean }>`
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/legacy/image";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import colors from "@theme/colors";
|
import colors from "@theme/colors";
|
||||||
import Link from "@components/Link";
|
import Link from "@components/Link";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/legacy/image";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import colors from "@theme/colors";
|
import colors from "@theme/colors";
|
||||||
|
|
||||||
@@ -18,8 +18,8 @@ const Row = styled.div`
|
|||||||
|
|
||||||
const ImageContainer = styled.div`
|
const ImageContainer = styled.div`
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 125px;
|
height: 8rem;
|
||||||
width: 125px;
|
width: 8rem;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
@@ -35,13 +35,19 @@ const Info = styled.div`
|
|||||||
margin-left: -20px;
|
margin-left: -20px;
|
||||||
min-width: 150px;
|
min-width: 150px;
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
|
padding-top: 10px;
|
||||||
color: ${colors.darkBlue};
|
color: ${colors.darkBlue};
|
||||||
|
|
||||||
& > p {
|
& > p {
|
||||||
font-size: 1.0rem;
|
font-size: 1rem;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
& > a {
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
& > h3 {
|
& > h3 {
|
||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@@ -76,7 +82,7 @@ const ContactCard: React.FC<ContactCardProps> = ({
|
|||||||
<h3>{name}</h3>
|
<h3>{name}</h3>
|
||||||
<p>{role_fi || role_en}</p>
|
<p>{role_fi || role_en}</p>
|
||||||
{phone ? <p>{phone}</p> : null}
|
{phone ? <p>{phone}</p> : null}
|
||||||
{email ? <p>{email}</p> : null}
|
{email ? <a href={`mailto:${email}`}>{email}</a> : null}
|
||||||
</Info>
|
</Info>
|
||||||
</Row>
|
</Row>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Image, { ImageProps } from "next/image";
|
import Image, { ImageProps } from "next/legacy/image";
|
||||||
import styled, { keyframes, Keyframes } from "styled-components";
|
import styled, { keyframes, Keyframes } from "styled-components";
|
||||||
|
|
||||||
interface CrossFadeImagesProps {
|
interface CrossFadeImagesProps {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ interface DropDownBoxProps {
|
|||||||
onMouseEnter: () => void;
|
onMouseEnter: () => void;
|
||||||
onMouseLeave: () => void;
|
onMouseLeave: () => void;
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Box = styled.div`
|
const Box = styled.div`
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ const Events: React.FC<EventsProps> = ({ events, lang }) => {
|
|||||||
const pageLinkText = t("Kaikki tapahtumat");
|
const pageLinkText = t("Kaikki tapahtumat");
|
||||||
const pageLinkDesc = `${t("löydät tapahtumakalenterista")}\xa0›`;
|
const pageLinkDesc = `${t("löydät tapahtumakalenterista")}\xa0›`;
|
||||||
|
|
||||||
|
const googleCalendarText = t("Lisää killan");
|
||||||
|
const googleCalendarDesc = `${t("Google-kalenteri")}\xa0›`;
|
||||||
|
|
||||||
const locale = isFi ? "fi-FI" : "en-GB";
|
const locale = isFi ? "fi-FI" : "en-GB";
|
||||||
|
|
||||||
const filteredEvents = events.map((e) => ({
|
const filteredEvents = events.map((e) => ({
|
||||||
@@ -62,6 +65,9 @@ const Events: React.FC<EventsProps> = ({ events, lang }) => {
|
|||||||
<PageLink to="/kilta/toiminta#tapahtumat" desc={pageLinkDesc}>
|
<PageLink to="/kilta/toiminta#tapahtumat" desc={pageLinkDesc}>
|
||||||
{pageLinkText}
|
{pageLinkText}
|
||||||
</PageLink>
|
</PageLink>
|
||||||
|
<PageLink to="https://calendar.google.com/calendar/u/0?cid=Y19mYjhhNWUwMjVjMjhkMTg5YTkzMWYyN2U5N2M4ODBmMGFhNTdmN2M1NDFlYzVhNjdlZDM4NzliYTVhNDEwNWI1QGdyb3VwLmNhbGVuZGFyLmdvb2dsZS5jb20" desc={googleCalendarDesc}>
|
||||||
|
{googleCalendarText}
|
||||||
|
</PageLink>
|
||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
</CardSection>
|
</CardSection>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/legacy/image";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { Link } from "@components/index";
|
import { Link } from "@components/index";
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,11 @@ const Container = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Hero: React.FC = ({ children }) => (
|
type HeroProps = {
|
||||||
|
children: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Hero: React.FC<HeroProps> = ({ children }) => (
|
||||||
<Container>
|
<Container>
|
||||||
{children}
|
{children}
|
||||||
</Container>
|
</Container>
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ type Colors = "darkBlue" | "lightTurquoise";
|
|||||||
|
|
||||||
interface HeroAsideProps {
|
interface HeroAsideProps {
|
||||||
bgColor: Colors;
|
bgColor: Colors;
|
||||||
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Color combos
|
// TODO: Color combos
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import breakpoints from "@theme/breakpoints";
|
|||||||
interface HeroPrimarySectionProps {
|
interface HeroPrimarySectionProps {
|
||||||
header: string;
|
header: string;
|
||||||
text?: string;
|
text?: string;
|
||||||
|
children?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Section = styled.section`
|
const Section = styled.section`
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ const Item = styled.div`
|
|||||||
|
|
||||||
interface HeroSecondarySectionItemProps {
|
interface HeroSecondarySectionItemProps {
|
||||||
note?: string;
|
note?: string;
|
||||||
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const HeroSecondarySectionItem: React.FC<HeroSecondarySectionItemProps> = ({ note, children }) => (
|
export const HeroSecondarySectionItem: React.FC<HeroSecondarySectionItemProps> = ({ note, children }) => (
|
||||||
@@ -52,6 +53,7 @@ const Items = styled.div`
|
|||||||
|
|
||||||
interface HeroSecondarySectionProps {
|
interface HeroSecondarySectionProps {
|
||||||
heading: string;
|
heading: string;
|
||||||
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const HeroSecondarySection: React.FC<HeroSecondarySectionProps> = ({ heading, children }) => (
|
const HeroSecondarySection: React.FC<HeroSecondarySectionProps> = ({ heading, children }) => (
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ const Box = styled.div`
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const InfoBox: React.FC = ({ children }) => (
|
type InfoBoxProps = {
|
||||||
|
children?: React.ReactNode
|
||||||
|
};
|
||||||
|
|
||||||
|
const InfoBox: React.FC<InfoBoxProps> = ({ children }) => (
|
||||||
<Box>
|
<Box>
|
||||||
{children}
|
{children}
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
+18
-8
@@ -2,6 +2,7 @@ import React from "react";
|
|||||||
import NextJSLink, { LinkProps } from "next/link";
|
import NextJSLink, { LinkProps } from "next/link";
|
||||||
|
|
||||||
interface Props extends Omit<LinkProps, "href" | "as"> {
|
interface Props extends Omit<LinkProps, "href" | "as"> {
|
||||||
|
children?: React.ReactNode;
|
||||||
to: string;
|
to: string;
|
||||||
template?: string;
|
template?: string;
|
||||||
target?: string;
|
target?: string;
|
||||||
@@ -15,18 +16,27 @@ const Link: React.FC<Props> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
if (template) {
|
if (template) {
|
||||||
return (
|
return (
|
||||||
<NextJSLink href={template} passHref={passHref} as={to} {...props}>
|
<NextJSLink
|
||||||
{/* eslint-disable-next-line jsx-a11y/anchor-has-content */}
|
href={template}
|
||||||
<a onClick={onClick} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} {...props} />
|
passHref={passHref}
|
||||||
</NextJSLink>
|
as={to}
|
||||||
|
{...props}
|
||||||
|
onClick={onClick}
|
||||||
|
onMouseEnter={onMouseEnter}
|
||||||
|
onMouseLeave={onMouseLeave}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (to.startsWith("/") || to.startsWith("#")) {
|
if (to.startsWith("/") || to.startsWith("#")) {
|
||||||
return (
|
return (
|
||||||
<NextJSLink href={to} passHref={passHref} {...props}>
|
<NextJSLink
|
||||||
{/* eslint-disable-next-line jsx-a11y/anchor-has-content */}
|
href={to}
|
||||||
<a onClick={onClick} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} {...props} />
|
passHref={passHref}
|
||||||
</NextJSLink>
|
{...props}
|
||||||
|
onClick={onClick}
|
||||||
|
onMouseEnter={onMouseEnter}
|
||||||
|
onMouseLeave={onMouseLeave}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Link } from "@components/index";
|
|||||||
|
|
||||||
interface NavbarChildLinkProps {
|
interface NavbarChildLinkProps {
|
||||||
to: string;
|
to: string;
|
||||||
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StyledLink = styled(Link)`
|
const StyledLink = styled(Link)`
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ interface NavbarDropdownLinkProps {
|
|||||||
to: string;
|
to: string;
|
||||||
text: string;
|
text: string;
|
||||||
exploded?: boolean; // if exploded, show items directly underneath without a dropdown menu
|
exploded?: boolean; // if exploded, show items directly underneath without a dropdown menu
|
||||||
|
children?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const NavbarDropdownLink: React.FC<NavbarDropdownLinkProps> = ({
|
const NavbarDropdownLink: React.FC<NavbarDropdownLinkProps> = ({
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export const renderNavigationItems = (mobile = false): JSX.Element => (
|
|||||||
<NavbarChildLink to="/kilta/kunnianosoitukset">Kunnianosoitukset</NavbarChildLink>
|
<NavbarChildLink to="/kilta/kunnianosoitukset">Kunnianosoitukset</NavbarChildLink>
|
||||||
<NavbarChildLink to="https://static.sahkoinsinoorikilta.fi">Dokumenttiarkisto</NavbarChildLink>
|
<NavbarChildLink to="https://static.sahkoinsinoorikilta.fi">Dokumenttiarkisto</NavbarChildLink>
|
||||||
<NavbarChildLink to="https://sik.kuvat.fi">Kuvagalleria</NavbarChildLink>
|
<NavbarChildLink to="https://sik.kuvat.fi">Kuvagalleria</NavbarChildLink>
|
||||||
|
<NavbarChildLink to="/kilta/liity">Jäseneksi</NavbarChildLink>
|
||||||
</NavbarDropdownLink>
|
</NavbarDropdownLink>
|
||||||
<NavbarDropdownLink to="/opinnot_ja_ura" text="Opinnot ja ura" exploded={mobile} />
|
<NavbarDropdownLink to="/opinnot_ja_ura" text="Opinnot ja ura" exploded={mobile} />
|
||||||
<NavbarDropdownLink to="/yritysyhteistyo" text="Yritysyhteistyö" exploded={mobile} />
|
<NavbarDropdownLink to="/yritysyhteistyo" text="Yritysyhteistyö" exploded={mobile} />
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import Link from "@components/Link";
|
|||||||
interface PageLinkProps {
|
interface PageLinkProps {
|
||||||
to: string;
|
to: string;
|
||||||
desc: string;
|
desc: string;
|
||||||
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const StyledPageLink = styled.div`
|
const StyledPageLink = styled.div`
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
|
const StyledSelect = styled.select`
|
||||||
|
padding: 0.25rem;
|
||||||
|
margin: 0.5rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const SelectWrapper = styled.div`
|
||||||
|
padding: 0.5rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export { StyledSelect, SelectWrapper };
|
||||||
+6
-4
@@ -1,5 +1,5 @@
|
|||||||
import React, {
|
import React, {
|
||||||
createContext, useContext, useReducer,
|
createContext, useContext, useMemo, useReducer,
|
||||||
} from "react";
|
} from "react";
|
||||||
import fi from "./locales/fi/common.json";
|
import fi from "./locales/fi/common.json";
|
||||||
import en from "./locales/en/common.json";
|
import en from "./locales/en/common.json";
|
||||||
@@ -67,8 +67,7 @@ const Reducer = (state: Store, action: Lang) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const LocaleContext = createContext(initialState);
|
const LocaleContext = createContext(initialState);
|
||||||
|
const LocaleStore: React.FC<{ children?: React.ReactNode }> = ({ children }) => {
|
||||||
const LocaleStore: React.FC = ({ children }) => {
|
|
||||||
const [state, dispatch] = useReducer(Reducer, initialState);
|
const [state, dispatch] = useReducer(Reducer, initialState);
|
||||||
const changeLanguage = (action: Lang) => {
|
const changeLanguage = (action: Lang) => {
|
||||||
dispatch(action);
|
dispatch(action);
|
||||||
@@ -78,8 +77,11 @@ const LocaleStore: React.FC = ({ children }) => {
|
|||||||
// Just ignore if fails to store value in user's browser
|
// Just ignore if fails to store value in user's browser
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const localeValue = useMemo(() => ({ ...state, changeLanguage }), [state]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LocaleContext.Provider value={{ ...state, changeLanguage }}>
|
<LocaleContext.Provider value={localeValue}>
|
||||||
{children}
|
{children}
|
||||||
</LocaleContext.Provider>
|
</LocaleContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
"Se aukeaa":
|
"Se aukeaa":
|
||||||
"Signup opens at",
|
"Signup opens at",
|
||||||
|
|
||||||
"Ilmoittauminen sulkeutuu":
|
"Ilmoittautuminen sulkeutuu":
|
||||||
"Signup closes at",
|
"Signup closes at",
|
||||||
|
|
||||||
"Ilmoittauminen on umpeutunut!":
|
"Ilmoittauminen on umpeutunut!":
|
||||||
|
|||||||
+7
-12
@@ -1,12 +1,12 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Document, {
|
import Document, {
|
||||||
Html, Head, Main, NextScript, DocumentContext, DocumentInitialProps,
|
Html, Head, Main, NextScript, DocumentContext,
|
||||||
} from "next/document";
|
} from "next/document";
|
||||||
import { ServerStyleSheet } from "styled-components";
|
import { ServerStyleSheet } from "styled-components";
|
||||||
import Favicons from "@components/Favicons";
|
import Favicons from "@components/Favicons";
|
||||||
|
|
||||||
export default class MyDocument extends Document<{ styleTags: unknown }> {
|
export default class MyDocument extends Document {
|
||||||
static getInitialProps = async (ctx: DocumentContext): Promise<DocumentInitialProps> => {
|
static async getInitialProps(ctx: DocumentContext) {
|
||||||
const sheet = new ServerStyleSheet();
|
const sheet = new ServerStyleSheet();
|
||||||
const originalRenderPage = ctx.renderPage;
|
const originalRenderPage = ctx.renderPage;
|
||||||
try {
|
try {
|
||||||
@@ -16,20 +16,15 @@ export default class MyDocument extends Document<{ styleTags: unknown }> {
|
|||||||
const initialProps = await Document.getInitialProps(ctx);
|
const initialProps = await Document.getInitialProps(ctx);
|
||||||
return {
|
return {
|
||||||
...initialProps,
|
...initialProps,
|
||||||
styles: (
|
styles: [initialProps.styles, sheet.getStyleElement()],
|
||||||
<>
|
|
||||||
{initialProps.styles}
|
|
||||||
{sheet.getStyleElement()}
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
} finally {
|
} finally {
|
||||||
sheet.seal();
|
sheet.seal();
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
const { styleTags } = this.props;
|
const { styles } = this.props;
|
||||||
return (
|
return (
|
||||||
<Html lang="fi">
|
<Html lang="fi">
|
||||||
<Head>
|
<Head>
|
||||||
@@ -37,7 +32,7 @@ export default class MyDocument extends Document<{ styleTags: unknown }> {
|
|||||||
<Favicons />
|
<Favicons />
|
||||||
</Head>
|
</Head>
|
||||||
<body>
|
<body>
|
||||||
{styleTags}
|
{styles}
|
||||||
<Main />
|
<Main />
|
||||||
<NextScript />
|
<NextScript />
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { NextPage } from "next";
|
import { NextPage } from "next";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { formatRelative } from "date-fns";
|
import { formatRelative } from "date-fns";
|
||||||
@@ -10,6 +10,7 @@ import AddLink from "@components/AddLink";
|
|||||||
import Event from "@models/Event";
|
import Event from "@models/Event";
|
||||||
import EventApi from "@api/eventApi";
|
import EventApi from "@api/eventApi";
|
||||||
import { fetcher, APIPath, API } from "@api/backend";
|
import { fetcher, APIPath, API } from "@api/backend";
|
||||||
|
import { StyledSelect, SelectWrapper } from "@components/Select";
|
||||||
|
|
||||||
const URL = "/admin/events";
|
const URL = "/admin/events";
|
||||||
|
|
||||||
@@ -37,42 +38,100 @@ const Renderer: React.FC = () => {
|
|||||||
const api: API = { path: APIPath.EVENTS, authenticated: true };
|
const api: API = { path: APIPath.EVENTS, authenticated: true };
|
||||||
const { data: events, error } = useSWR<Event[]>(api, fetcher);
|
const { data: events, error } = useSWR<Event[]>(api, fetcher);
|
||||||
|
|
||||||
|
const [sort, setSort] = useState<string>("start_time");
|
||||||
|
const [order, setOrder] = useState<string>("descending");
|
||||||
|
const [filter, setFilter] = useState<string>("all");
|
||||||
|
|
||||||
|
const eventSort = (a, b) => {
|
||||||
|
let result = 0;
|
||||||
|
if (order === "descending") {
|
||||||
|
if (["start_time", "end_time"].includes(sort)) {
|
||||||
|
result = new Date(b[sort]).getTime() - new Date(a[sort]).getTime();
|
||||||
|
} else if (sort === "id") {
|
||||||
|
result = b[sort] - a[sort];
|
||||||
|
}
|
||||||
|
} else if (order === "ascending") {
|
||||||
|
if (["start_time", "end_time"].includes(sort)) {
|
||||||
|
result = new Date(a[sort]).getTime() - new Date(b[sort]).getTime();
|
||||||
|
} else if (sort === "id") {
|
||||||
|
result = a[sort] - b[sort];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const dateFilter = (a) => {
|
||||||
|
let result = true;
|
||||||
|
|
||||||
|
if (filter === "upcoming") {
|
||||||
|
result = new Date(a.end_time).getTime() > Date.now();
|
||||||
|
} else if (filter === "past") {
|
||||||
|
result = new Date(a.end_time).getTime() < Date.now();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
}, [sort, order, filter, events]);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
Failed loading events
|
Failed loading events.
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!events?.length) {
|
if (!events?.length) {
|
||||||
return <div>No events.</div>;
|
return <div>No events.</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<table>
|
<div>
|
||||||
<thead>
|
<SelectWrapper>
|
||||||
<tr>
|
Sort by:
|
||||||
<th>Title</th>
|
<StyledSelect name="" onChange={(e) => setSort(e.target.value)}>
|
||||||
<th>Start time</th>
|
<option value="start_time">Start time</option>
|
||||||
<th>End time</th>
|
<option value="end_time">End time</option>
|
||||||
</tr>
|
<option value="id">Creation order</option>
|
||||||
</thead>
|
</StyledSelect>
|
||||||
<tbody>
|
Order:
|
||||||
{events.map((event) => (
|
<StyledSelect name="" onChange={(e) => setOrder(e.target.value)}>
|
||||||
<tr key={event.id}>
|
<option value="descending">Descending</option>
|
||||||
<td><Link to={`${URL}/${event.id}`}>{event.title_fi}</Link></td>
|
<option value="ascending">Ascending</option>
|
||||||
<td>{formatRelative(new Date(event.start_time), new Date())}</td>
|
</StyledSelect>
|
||||||
<td>{formatRelative(new Date(event.end_time), new Date())}</td>
|
Filter:
|
||||||
<td>
|
<StyledSelect name="" onChange={(e) => setFilter(e.target.value)}>
|
||||||
<StyledButton $colorOverride="red" buttonStyle="filled" onClick={() => confirmDelete(event)}>
|
<option value="all">All</option>
|
||||||
Delete
|
<option value="upcoming">Upcoming</option>
|
||||||
</StyledButton>
|
<option value="past">Past</option>
|
||||||
</td>
|
</StyledSelect>
|
||||||
|
</SelectWrapper>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Title</th>
|
||||||
|
<th>Start time</th>
|
||||||
|
<th>End time</th>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
</thead>
|
||||||
</tbody>
|
<tbody>
|
||||||
</table>
|
{events.sort(eventSort).filter(dateFilter).map((event) => (
|
||||||
|
<tr key={event.id}>
|
||||||
|
<td><Link to={`${URL}/${event.id}`}>{event.title_fi}</Link></td>
|
||||||
|
<td>{formatRelative(new Date(event.start_time), new Date())}</td>
|
||||||
|
<td>{formatRelative(new Date(event.end_time), new Date())}</td>
|
||||||
|
<td>
|
||||||
|
<StyledButton $colorOverride="red" buttonStyle="filled" onClick={() => confirmDelete(event)}>
|
||||||
|
Delete
|
||||||
|
</StyledButton>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { NextPage } from "next";
|
import { NextPage } from "next";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { formatRelative } from "date-fns";
|
import { formatRelative } from "date-fns";
|
||||||
@@ -10,6 +10,7 @@ import AddLink from "@components/AddLink";
|
|||||||
import Post from "@models/Feed";
|
import Post from "@models/Feed";
|
||||||
import PostApi from "@api/feedApi";
|
import PostApi from "@api/feedApi";
|
||||||
import { fetcher, APIPath, API } from "@api/backend";
|
import { fetcher, APIPath, API } from "@api/backend";
|
||||||
|
import { SelectWrapper, StyledSelect } from "@components/Select";
|
||||||
|
|
||||||
const URL = "/admin/feed";
|
const URL = "/admin/feed";
|
||||||
|
|
||||||
@@ -37,6 +38,21 @@ const Renderer: React.FC = () => {
|
|||||||
const api: API = { path: APIPath.FEED, authenticated: true };
|
const api: API = { path: APIPath.FEED, authenticated: true };
|
||||||
const { data: feed, error } = useSWR<Post[]>(api, fetcher);
|
const { data: feed, error } = useSWR<Post[]>(api, fetcher);
|
||||||
|
|
||||||
|
const [order, setOrder] = useState<string>("descending");
|
||||||
|
|
||||||
|
const feedSort = (a, b) => {
|
||||||
|
let result = 0;
|
||||||
|
if (order === "descending") {
|
||||||
|
result = new Date(b.publish_time).getTime() - new Date(a.publish_time).getTime();
|
||||||
|
} else if (order === "ascending") {
|
||||||
|
result = new Date(a.publish_time).getTime() - new Date(b.publish_time).getTime();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
}, [order, feed]);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
return (
|
return (
|
||||||
@@ -52,29 +68,38 @@ const Renderer: React.FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<table>
|
<div>
|
||||||
<thead>
|
<SelectWrapper>
|
||||||
<tr>
|
Order:
|
||||||
<th>Title</th>
|
<StyledSelect name="" onChange={(e) => setOrder(e.target.value)}>
|
||||||
<th>Description</th>
|
<option value="descending">Descending</option>
|
||||||
<th>Publish time</th>
|
<option value="ascending">Ascending</option>
|
||||||
</tr>
|
</StyledSelect>
|
||||||
</thead>
|
</SelectWrapper>
|
||||||
<tbody>
|
<table>
|
||||||
{feed.map((post) => (
|
<thead>
|
||||||
<tr key={post.id}>
|
<tr>
|
||||||
<td><Link to={`${URL}/${post.id}`}>{post.title_fi}</Link></td>
|
<th>Title</th>
|
||||||
<td>{post.description_fi}</td>
|
<th>Description</th>
|
||||||
<td>{formatRelative(new Date(post.publish_time), new Date())}</td>
|
<th>Publish time</th>
|
||||||
<td>
|
|
||||||
<StyledButton $colorOverride="red" buttonStyle="filled" onClick={() => confirmDelete(post)}>
|
|
||||||
Delete
|
|
||||||
</StyledButton>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
</thead>
|
||||||
</tbody>
|
<tbody>
|
||||||
</table>
|
{feed.sort(feedSort).map((post) => (
|
||||||
|
<tr key={post.id}>
|
||||||
|
<td><Link to={`${URL}/${post.id}`}>{post.title_fi}</Link></td>
|
||||||
|
<td>{post.description_fi}</td>
|
||||||
|
<td>{formatRelative(new Date(post.publish_time), new Date())}</td>
|
||||||
|
<td>
|
||||||
|
<StyledButton $colorOverride="red" buttonStyle="filled" onClick={() => confirmDelete(post)}>
|
||||||
|
Delete
|
||||||
|
</StyledButton>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { NextPage } from "next";
|
import { NextPage } from "next";
|
||||||
|
import useSWR from "swr";
|
||||||
import { formatRelative } from "date-fns";
|
import { formatRelative } from "date-fns";
|
||||||
import { toast } from "react-toastify";
|
import { toast } from "react-toastify";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
@@ -8,6 +9,8 @@ import { Button, Link } from "@components/index";
|
|||||||
import AddLink from "@components/AddLink";
|
import AddLink from "@components/AddLink";
|
||||||
import { SignupForm } from "@models/Signup";
|
import { SignupForm } from "@models/Signup";
|
||||||
import SignupApi from "@api/signupApi";
|
import SignupApi from "@api/signupApi";
|
||||||
|
import { fetcher, APIPath, API } from "@api/backend";
|
||||||
|
import { SelectWrapper, StyledSelect } from "@components/Select";
|
||||||
|
|
||||||
const URL = "/admin/signups";
|
const URL = "/admin/signups";
|
||||||
|
|
||||||
@@ -31,57 +34,117 @@ const confirmDelete = async (signup: SignupForm) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderData = (signupForms: SignupForm[]) => {
|
const Renderer: React.FC = () => {
|
||||||
if (!signupForms || signupForms.length === 0) {
|
const api: API = { path: APIPath.SIGNUP_FORMS, authenticated: true };
|
||||||
|
const { data: signupForms, error } = useSWR<SignupForm[]>(api, fetcher);
|
||||||
|
|
||||||
|
const [sort, setSort] = useState<string>("start_time");
|
||||||
|
const [order, setOrder] = useState<string>("descending");
|
||||||
|
const [filter, setFilter] = useState<string>("all");
|
||||||
|
|
||||||
|
const signupFormSort = (a, b) => {
|
||||||
|
let result = 0;
|
||||||
|
if (order === "descending") {
|
||||||
|
if (["start_time", "end_time"].includes(sort)) {
|
||||||
|
result = new Date(b[sort]).getTime() - new Date(a[sort]).getTime();
|
||||||
|
} else if (sort === "id") {
|
||||||
|
result = b[sort] - a[sort];
|
||||||
|
}
|
||||||
|
} else if (order === "ascending") {
|
||||||
|
if (["start_time", "end_time"].includes(sort)) {
|
||||||
|
result = new Date(a[sort]).getTime() - new Date(b[sort]).getTime();
|
||||||
|
} else if (sort === "id") {
|
||||||
|
result = a[sort] - b[sort];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
const dateFilter = (a) => {
|
||||||
|
let result = true;
|
||||||
|
|
||||||
|
if (filter === "upcoming") {
|
||||||
|
result = new Date(a.end_time).getTime() > Date.now();
|
||||||
|
} else if (filter === "past") {
|
||||||
|
result = new Date(a.end_time).getTime() < Date.now();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
}, [sort, order, filter, signupForms]);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
console.error(error);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
Failed loading events.
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!signupForms?.length) {
|
||||||
return <div>No signup forms.</div>;
|
return <div>No signup forms.</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<table>
|
<div>
|
||||||
<thead>
|
<SelectWrapper>
|
||||||
<tr>
|
Sort by:
|
||||||
<th>Title</th>
|
<StyledSelect name="" onChange={(e) => setSort(e.target.value)}>
|
||||||
<th>Start time</th>
|
<option value="start_time">Start time</option>
|
||||||
<th>End time</th>
|
<option value="end_time">End time</option>
|
||||||
<th>Sign-ups</th>
|
<option value="id">Creation order</option>
|
||||||
<th>Send email</th>
|
</StyledSelect>
|
||||||
</tr>
|
Order:
|
||||||
</thead>
|
<StyledSelect name="" onChange={(e) => setOrder(e.target.value)}>
|
||||||
<tbody>
|
<option value="descending">Descending</option>
|
||||||
{signupForms.map((signupForm) => (
|
<option value="ascending">Ascending</option>
|
||||||
<tr key={signupForm.id}>
|
</StyledSelect>
|
||||||
<td><Link to={`${URL}/${signupForm.id}`}>{signupForm.title_fi}</Link></td>
|
Filter:
|
||||||
<td>{formatRelative(new Date(signupForm.start_time), new Date())}</td>
|
<StyledSelect name="" onChange={(e) => setFilter(e.target.value)}>
|
||||||
<td>{formatRelative(new Date(signupForm.end_time), new Date())}</td>
|
<option value="all">All</option>
|
||||||
<td><Link to={`${URL}/${signupForm.id}/list`}>View</Link></td>
|
<option value="upcoming">Upcoming</option>
|
||||||
<td><Link to={`${URL}/${signupForm.id}/email`}>Send</Link></td>
|
<option value="past">Past</option>
|
||||||
<td>
|
</StyledSelect>
|
||||||
<StyledButton $colorOverride="red" buttonStyle="filled" onClick={() => confirmDelete(signupForm)}>
|
</SelectWrapper>
|
||||||
Delete
|
<table>
|
||||||
</StyledButton>
|
<thead>
|
||||||
</td>
|
<tr>
|
||||||
|
<th>Title</th>
|
||||||
|
<th>Start time</th>
|
||||||
|
<th>End time</th>
|
||||||
|
<th>Sign-ups</th>
|
||||||
|
<th>Send email</th>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
</thead>
|
||||||
</tbody>
|
<tbody>
|
||||||
</table>
|
{signupForms.sort(signupFormSort).filter(dateFilter).map((signupForm) => (
|
||||||
|
<tr key={signupForm.id}>
|
||||||
|
<td><Link to={`${URL}/${signupForm.id}`}>{signupForm.title_fi}</Link></td>
|
||||||
|
<td>{formatRelative(new Date(signupForm.start_time), new Date())}</td>
|
||||||
|
<td>{formatRelative(new Date(signupForm.end_time), new Date())}</td>
|
||||||
|
<td><Link to={`${URL}/${signupForm.id}/list`}>View</Link></td>
|
||||||
|
<td><Link to={`${URL}/${signupForm.id}/email`}>Send</Link></td>
|
||||||
|
<td>
|
||||||
|
<StyledButton $colorOverride="red" buttonStyle="filled" onClick={() => confirmDelete(signupForm)}>
|
||||||
|
Delete
|
||||||
|
</StyledButton>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const AdminSignupPage: NextPage = () => {
|
const AdminSignupPage: NextPage = () => (
|
||||||
const [forms, setForms] = useState<SignupForm[]>(null);
|
<AdminListCommon>
|
||||||
|
<h1>Sign-up forms</h1>
|
||||||
useEffect(() => {
|
<AddLink text="Create signup form" to={`${URL}/create`} data-e2e="create-signup" />
|
||||||
SignupApi.getForms(true)
|
<Renderer />
|
||||||
.then((res) => setForms(res));
|
</AdminListCommon>
|
||||||
}, []);
|
);
|
||||||
|
|
||||||
return (
|
|
||||||
<AdminListCommon>
|
|
||||||
<h1>Sign-up forms</h1>
|
|
||||||
<AddLink text="Create signup form" to={`${URL}/create`} data-e2e="create-signup" />
|
|
||||||
{renderData(forms)}
|
|
||||||
</AdminListCommon>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AdminSignupPage;
|
export default AdminSignupPage;
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { NextPage } from "next";
|
||||||
|
import Head from "next/head";
|
||||||
|
import JoinPageView from "@views/JoinPage/JoinPageView";
|
||||||
|
import PageWrapper from "@views/common/PageWrapper";
|
||||||
|
|
||||||
|
const JoinPage: NextPage = () => (
|
||||||
|
<>
|
||||||
|
<Head>
|
||||||
|
<link rel="canonical" href={`${process.env.NEXT_PUBLIC_SITE_URL}/kilta/liity`} />
|
||||||
|
</Head>
|
||||||
|
<PageWrapper>
|
||||||
|
<JoinPageView />
|
||||||
|
</PageWrapper>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default JoinPage;
|
||||||
@@ -111,13 +111,13 @@ const ActualPageView: React.FC<ActualPageViewProps> = ({ events, feed }) => (
|
|||||||
<div>
|
<div>
|
||||||
<h6 id="elepaja">Rakenna kaikkea elektroniikkaan liittyvää</h6>
|
<h6 id="elepaja">Rakenna kaikkea elektroniikkaan liittyvää</h6>
|
||||||
<p>
|
<p>
|
||||||
Elepaja on sähköinsinöörikillan ylläpitämä elektroniikkapaja, jossa opiskelijat pääsevät soveltamaan koulussa oppimiaan taitojaan käytännön projekteissa.
|
SIK-PAJA on sähköinsinöörikillan ylläpitämä elektroniikkapaja, jossa opiskelijat pääsevät soveltamaan koulussa oppimiaan taitojaan käytännön projekteissa.
|
||||||
Opiskelijat ovat aikojen saatossa rakentaneet pajalla mitä monimuotoisempia projekteja kuten ensimmäisiä ledivilkkujaan, teslakäämejä, robotteja ja radiolähettimiä.
|
Opiskelijat ovat aikojen saatossa rakentaneet pajalla mitä monimuotoisempia projekteja kuten ensimmäisiä ledivilkkujaan, teslakäämejä, robotteja ja radiolähettimiä.
|
||||||
Jos elektroniikan rakentelu kiinnostaa tai tarvitset jonkun projektin kanssa apua niin tule ihmeessä käymään elepajalla.
|
Jos elektroniikan rakentelu kiinnostaa tai tarvitset jonkun projektin kanssa apua niin tule ihmeessä käymään elepajalla.
|
||||||
Pajan varustukseen kuluu perustyökalut, piirilevyn syövytysvälineet, kolvit, komponentit, pylväsporakone sekä laaja valikoima mittauslaitteita.
|
Pajan varustukseen kuluu perustyökalut, kolvit, komponentit sekä laaja valikoima mittauslaitteita.
|
||||||
Ota siis kola ja tule nauttimaan elepajan mukavasta ilmapiiristä Elepajan uusissa tiloissa kanditaattikeskuksessa ruokala alvarin alla.
|
Tule tutustumaan toimintaamme Kandidaattikeskuksessa ruokala Alvarin alapuolella sijaitseviin tiloihimme.
|
||||||
{" "}
|
{" "}
|
||||||
<Link to="https://elepaja.fi/tg">Tästä</Link> pääset liittymään elepajan Telegram-ryhmään.
|
<Link to="https://t.me/sikpaja">Tästä</Link> pääset liittymään pajan Telegram-ryhmään.
|
||||||
</p>
|
</p>
|
||||||
<h6 id="urheilu">Urheilua ja lajikokeiluja</h6>
|
<h6 id="urheilu">Urheilua ja lajikokeiluja</h6>
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@@ -5,35 +5,35 @@ import colors from "@theme/colors";
|
|||||||
import ContactCard from "@components/ContactCard";
|
import ContactCard from "@components/ContactCard";
|
||||||
|
|
||||||
import BoardJson from "./board.json";
|
import BoardJson from "./board.json";
|
||||||
import HvtmkJson from "./hvtmk.json";
|
// import HvtmkJson from "./hvtmk.json";
|
||||||
import MtmkJson from "./mtmk.json";
|
// import MtmkJson from "./mtmk.json";
|
||||||
import NtmkJson from "./ntmk.json";
|
// import NtmkJson from "./ntmk.json";
|
||||||
import OptmkJson from "./optmk.json";
|
// import OptmkJson from "./optmk.json";
|
||||||
import OtmkJson from "./otmk.json";
|
// import OtmkJson from "./otmk.json";
|
||||||
import EPtmkJson from "./eptmk.json";
|
// import EPtmkJson from "./eptmk.json";
|
||||||
import SstmkJson from "./sstmk.json";
|
// import SstmkJson from "./sstmk.json";
|
||||||
import ShntmkJson from "./shntmk.json";
|
// import ShntmkJson from "./shntmk.json";
|
||||||
import ShtmkJson from "./shtmk.json";
|
// import ShtmkJson from "./shtmk.json";
|
||||||
import TtmkJson from "./ttmk.json";
|
// import TtmkJson from "./ttmk.json";
|
||||||
import UtmkJson from "./utmk.json";
|
// import UtmkJson from "./utmk.json";
|
||||||
import YtmkJson from "./ytmk.json";
|
// import YtmkJson from "./ytmk.json";
|
||||||
import Others from "./others.json";
|
// import Others from "./others.json";
|
||||||
|
|
||||||
const orderedCommittees = [
|
const orderedCommittees = [
|
||||||
BoardJson,
|
BoardJson,
|
||||||
HvtmkJson,
|
// HvtmkJson,
|
||||||
MtmkJson,
|
// MtmkJson,
|
||||||
NtmkJson,
|
// NtmkJson,
|
||||||
OptmkJson,
|
// OptmkJson,
|
||||||
OtmkJson,
|
// OtmkJson,
|
||||||
EPtmkJson,
|
// EPtmkJson,
|
||||||
SstmkJson,
|
// SstmkJson,
|
||||||
ShntmkJson,
|
// ShntmkJson,
|
||||||
ShtmkJson,
|
// ShtmkJson,
|
||||||
TtmkJson,
|
// TtmkJson,
|
||||||
UtmkJson,
|
// UtmkJson,
|
||||||
YtmkJson,
|
// YtmkJson,
|
||||||
Others,
|
// Others,
|
||||||
];
|
];
|
||||||
|
|
||||||
const blankProfile = "/img/blank_profile.png";
|
const blankProfile = "/img/blank_profile.png";
|
||||||
@@ -91,7 +91,6 @@ const Container = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const ContactContainer = styled.div`
|
const ContactContainer = styled.div`
|
||||||
margin-top: -13rem;
|
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
@media (max-width: 950px) {
|
@media (max-width: 950px) {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
@@ -110,6 +109,7 @@ const TitleContainer = styled.div`
|
|||||||
|
|
||||||
const CommitteeContainer: React.FC<{
|
const CommitteeContainer: React.FC<{
|
||||||
committee: Committee;
|
committee: Committee;
|
||||||
|
children: React.ReactNode;
|
||||||
}> = ({ committee, children }) => (
|
}> = ({ committee, children }) => (
|
||||||
<Container>
|
<Container>
|
||||||
<TitleContainer>
|
<TitleContainer>
|
||||||
@@ -172,7 +172,6 @@ const ContactsPageView: React.FC = () => (
|
|||||||
</aside>
|
</aside>
|
||||||
</TextSection>
|
</TextSection>
|
||||||
<ContactContainer>
|
<ContactContainer>
|
||||||
|
|
||||||
{orderedCommittees.map((json) => (
|
{orderedCommittees.map((json) => (
|
||||||
<React.Fragment key={json.slug}>
|
<React.Fragment key={json.slug}>
|
||||||
{(json.slug !== "board") && (
|
{(json.slug !== "board") && (
|
||||||
@@ -187,17 +186,16 @@ const ContactsPageView: React.FC = () => (
|
|||||||
<BlueLink to="mailto:hallitus@sahkoinsinoorikilta.fi">
|
<BlueLink to="mailto:hallitus@sahkoinsinoorikilta.fi">
|
||||||
hallitus@sahkoinsinoorikilta.fi
|
hallitus@sahkoinsinoorikilta.fi
|
||||||
</BlueLink>
|
</BlueLink>
|
||||||
{". Hallituksen yksittäisiin jäseniin saat yhteyden etunimi.sukunimi@sahkoinsinoorikilta.fi osoitteista."}
|
. Hallituksen yksittäisiin jäseniin saat yhteyden etunimi.sukunimi@sahkoinsinoorikilta.fi osoitteista.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{"Hallitukselle voi myös lähettää palautetta täyttämällä "}
|
{"Hallitukselle voi myös lähettää palautetta täyttämällä "}
|
||||||
<BlueLink to="https://docs.google.com/forms/d/e/1FAIpQLSeD8Hm66uvwr7Xa2WGgOCfI2RS1NrZsmISf2QBKUcJf_stv8g/viewform?usp=sf_link">
|
<BlueLink to="https://docs.google.com/forms/d/e/1FAIpQLSeD8Hm66uvwr7Xa2WGgOCfI2RS1NrZsmISf2QBKUcJf_stv8g/viewform?usp=sf_link">
|
||||||
palautelomakkeen
|
palautelomakkeen
|
||||||
</BlueLink>
|
</BlueLink>
|
||||||
{", lomakkeen vastauksia käydään läpi hallituksen kokouksissa."}
|
, lomakkeen vastauksia käydään läpi hallituksen kokouksissa.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
)}
|
)}
|
||||||
</CommitteeContainer>
|
</CommitteeContainer>
|
||||||
</TextSection>
|
</TextSection>
|
||||||
@@ -207,5 +205,4 @@ const ContactsPageView: React.FC = () => (
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
export default ContactsPageView;
|
export default ContactsPageView;
|
||||||
|
|||||||
@@ -8,10 +8,10 @@
|
|||||||
"name_en": "Chairman of the Board",
|
"name_en": "Chairman of the Board",
|
||||||
"representatives": [
|
"representatives": [
|
||||||
{
|
{
|
||||||
"name": "Mikko Suhonen",
|
"name": "Otto Julkunen",
|
||||||
"phone_number": null,
|
"phone_number": null,
|
||||||
"email": null,
|
"email": "otto.julkunen@sahkoinsinoorikilta.fi",
|
||||||
"image": "https://static.sahkoinsinoorikilta.fi/img/board/mikko.jpg"
|
"image": "https://static.sahkoinsinoorikilta.fi/img/board/ottom.jpg"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -20,10 +20,10 @@
|
|||||||
"name_en": "Secretary",
|
"name_en": "Secretary",
|
||||||
"representatives": [
|
"representatives": [
|
||||||
{
|
{
|
||||||
"name": "Emilia Kortelainen",
|
"name": "Karoliina Talvikangas",
|
||||||
"phone_number": null,
|
"phone_number": null,
|
||||||
"email": null,
|
"email": "karoliina.talvikangas@sahkoinsinoorikilta.fi",
|
||||||
"image": "https://static.sahkoinsinoorikilta.fi/img/board/emilia.jpg"
|
"image": "https://static.sahkoinsinoorikilta.fi/img/board/karoliina.jpg"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -32,10 +32,10 @@
|
|||||||
"name_en": "Treasurer",
|
"name_en": "Treasurer",
|
||||||
"representatives": [
|
"representatives": [
|
||||||
{
|
{
|
||||||
"name": "Esko Väänänen",
|
"name": "Ville Lairila",
|
||||||
"phone_number": null,
|
"phone_number": null,
|
||||||
"email": null,
|
"email": "ville.lairila@sahkoinsinoorikilta.fi",
|
||||||
"image": "https://static.sahkoinsinoorikilta.fi/img/board/esko.jpg"
|
"image": "https://static.sahkoinsinoorikilta.fi/img/board/ville.jpg"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -44,10 +44,10 @@
|
|||||||
"name_en": "",
|
"name_en": "",
|
||||||
"representatives": [
|
"representatives": [
|
||||||
{
|
{
|
||||||
"name": "Melisa Dönmez",
|
"name": "Aaron Löfgren",
|
||||||
"phone_number": null,
|
"phone_number": null,
|
||||||
"email": null,
|
"email": "aaron.lofgren@sahkoinsinoorikilta.fi",
|
||||||
"image": "https://static.sahkoinsinoorikilta.fi/img/board/melisa.jpg"
|
"image": "https://static.sahkoinsinoorikilta.fi/img/board/aaron.jpg"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -56,10 +56,10 @@
|
|||||||
"name_en": "",
|
"name_en": "",
|
||||||
"representatives": [
|
"representatives": [
|
||||||
{
|
{
|
||||||
"name": "Eveliina Ahonen",
|
"name": "Kasper Skog",
|
||||||
"phone_number": null,
|
"phone_number": null,
|
||||||
"email": null,
|
"email": "kasper.skog@sahkoinsinoorikilta.fi",
|
||||||
"image": "https://static.sahkoinsinoorikilta.fi/img/board/eveliina.jpg"
|
"image": "https://static.sahkoinsinoorikilta.fi/img/board/kasper.jpg"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -68,10 +68,10 @@
|
|||||||
"name_en": "",
|
"name_en": "",
|
||||||
"representatives": [
|
"representatives": [
|
||||||
{
|
{
|
||||||
"name": "Sakke Kangas",
|
"name": "Roni Vallius",
|
||||||
"phone_number": null,
|
"phone_number": null,
|
||||||
"email": null,
|
"email": "roni.vallius@sahkoinsinoorikilta.fi",
|
||||||
"image": "https://static.sahkoinsinoorikilta.fi/img/board/sakke.jpg"
|
"image": "https://static.sahkoinsinoorikilta.fi/img/board/roni.jpg"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -80,22 +80,10 @@
|
|||||||
"name_en": "",
|
"name_en": "",
|
||||||
"representatives": [
|
"representatives": [
|
||||||
{
|
{
|
||||||
"name": "Eero Ketonen",
|
"name": "Elina Huttunen",
|
||||||
"phone_number": null,
|
"phone_number": null,
|
||||||
"email": null,
|
"email": "elina.huttunen@sahkoinsinoorikilta.fi",
|
||||||
"image": "https://static.sahkoinsinoorikilta.fi/img/board/eero.jpg"
|
"image": "https://static.sahkoinsinoorikilta.fi/img/board/elina.jpg"
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name_fi": "ISOvastaava",
|
|
||||||
"name_en": "",
|
|
||||||
"representatives": [
|
|
||||||
{
|
|
||||||
"name": "Salla Lyytikäinen",
|
|
||||||
"phone_number": null,
|
|
||||||
"email": null,
|
|
||||||
"image": "https://static.sahkoinsinoorikilta.fi/img/board/salla.jpg"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -104,10 +92,10 @@
|
|||||||
"name_en": "",
|
"name_en": "",
|
||||||
"representatives": [
|
"representatives": [
|
||||||
{
|
{
|
||||||
"name": "Sofia Öhman",
|
"name": "Julia Pykälä-aho",
|
||||||
"phone_number": null,
|
"phone_number": null,
|
||||||
"email": null,
|
"email": "julia.pykalaaho@sahkoinsinoorikilta.fi",
|
||||||
"image": "https://static.sahkoinsinoorikilta.fi/img/board/sofia.jpg"
|
"image": "https://static.sahkoinsinoorikilta.fi/img/board/julia.jpg"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -116,22 +104,22 @@
|
|||||||
"name_en": "",
|
"name_en": "",
|
||||||
"representatives": [
|
"representatives": [
|
||||||
{
|
{
|
||||||
"name": "Iikka Huttu",
|
"name": "Juulia Härkönen",
|
||||||
"phone_number": null,
|
"phone_number": null,
|
||||||
"email": null,
|
"email": "juulia.harkonen@sahkoinsinoorikilta.fi",
|
||||||
"image": "https://static.sahkoinsinoorikilta.fi/img/board/iikka.jpg"
|
"image": "https://static.sahkoinsinoorikilta.fi/img/board/juulia.jpg"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name_fi": "Teknologiamestari",
|
"name_fi": "Pajamestari",
|
||||||
"name_en": "",
|
"name_en": "",
|
||||||
"representatives": [
|
"representatives": [
|
||||||
{
|
{
|
||||||
"name": "Ilari Ojakorpi",
|
"name": "Tommi Sytelä",
|
||||||
"phone_number": null,
|
"phone_number": null,
|
||||||
"email": null,
|
"email": "tommi.sytela@sahkoinsinoorikilta.fi",
|
||||||
"image": "https://static.sahkoinsinoorikilta.fi/img/board/ilari.jpg"
|
"image": "https://static.sahkoinsinoorikilta.fi/img/board/tommi.jpg"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -140,10 +128,10 @@
|
|||||||
"name_en": "",
|
"name_en": "",
|
||||||
"representatives": [
|
"representatives": [
|
||||||
{
|
{
|
||||||
"name": "Heidi Mäkitalo",
|
"name": "Pyry Vaara",
|
||||||
"phone_number": null,
|
"phone_number": null,
|
||||||
"email": null,
|
"email": "pyry.vaara@sahkoinsinoorikilta.fi",
|
||||||
"image": "https://static.sahkoinsinoorikilta.fi/img/board/heidi.jpg"
|
"image": "https://static.sahkoinsinoorikilta.fi/img/board/pyry.jpg"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -152,10 +140,22 @@
|
|||||||
"name_en": "",
|
"name_en": "",
|
||||||
"representatives": [
|
"representatives": [
|
||||||
{
|
{
|
||||||
"name": "Tommi Oinonen",
|
"name": "Nette Levijoki",
|
||||||
"phone_number": null,
|
"phone_number": null,
|
||||||
"email": null,
|
"email": "nette.levijoki@sahkoinsinoorikilta.fi",
|
||||||
"image": "https://static.sahkoinsinoorikilta.fi/img/board/tommmi.jpg"
|
"image": "https://static.sahkoinsinoorikilta.fi/img/board/nette.jpg"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name_fi": "Excursiomestari",
|
||||||
|
"name_en": "",
|
||||||
|
"representatives": [
|
||||||
|
{
|
||||||
|
"name": "Visa Kurvi",
|
||||||
|
"phone_number": null,
|
||||||
|
"email": "visa.kurvi@sahkoinsinoorikilta.fi",
|
||||||
|
"image": "https://static.sahkoinsinoorikilta.fi/img/board/visa.jpg"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,10 @@ import JobAd from "@models/JobAd";
|
|||||||
import CorporatePageHero from "./CorporatePageHero";
|
import CorporatePageHero from "./CorporatePageHero";
|
||||||
import JobAdList from "./JobAdList";
|
import JobAdList from "./JobAdList";
|
||||||
|
|
||||||
|
import BoardJson from "../ContactsPage/board.json";
|
||||||
|
|
||||||
const EXCURSION_RULES = "https://static.sahkoinsinoorikilta.fi/saannot/excursiosaannot.pdf";
|
const EXCURSION_RULES = "https://static.sahkoinsinoorikilta.fi/saannot/excursiosaannot.pdf";
|
||||||
const CORPORATE_MASTER_MAIL = "tommi.oinonen@sahkoinsinoorikilta.fi";
|
const CORPORATE_MASTER_INFO = BoardJson.roles.filter((role) => role.name_fi === "Yrityssuhdemestari")[0].representatives[0];
|
||||||
|
|
||||||
interface CorporatePageViewProps {
|
interface CorporatePageViewProps {
|
||||||
jobAds: JobAd[];
|
jobAds: JobAd[];
|
||||||
@@ -63,11 +65,9 @@ const CorporatePageView: React.FC<CorporatePageViewProps> = ({ jobAds }) => (
|
|||||||
|
|
||||||
<h6>Potentiaalin Tasaus</h6>
|
<h6>Potentiaalin Tasaus</h6>
|
||||||
<p>
|
<p>
|
||||||
Kiltamme viettää perinteikkäitä vuosijuhliaan helmikuun kolmantena lauantaina.
|
Kiltamme viettää perinteikästä vuosijuhlaansa helmikuun kolmantena lauantaina.
|
||||||
Potentiaalin Tasaus on kiltamme juhlavin ja rakkain tapahtuma.
|
Potentiaalin Tasaus on kiltamme juhlavin ja rakkain tapahtuma.
|
||||||
Yrityksillä on mahdollisuus osallistua vuosijuhliin niin pienellä kuin suurellakin panoksella.
|
Yrityksillä on mahdollisuus osallistua vuosijuhliin niin pienellä kuin suurellakin panoksella!
|
||||||
Killan 100-vuotisjuhla PoTa100 lähestyy myös kovaa vauhtia.
|
|
||||||
Jos yrityksesi on kiinnostunut 100-vuotisjuhlasta, kannattaa ohjautua osoitteeseen <Link to="https://sik100.fi">sik100.fi</Link>.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h6>Killan nettisivut ja työpaikkamainokset</h6>
|
<h6>Killan nettisivut ja työpaikkamainokset</h6>
|
||||||
@@ -92,15 +92,15 @@ const CorporatePageView: React.FC<CorporatePageViewProps> = ({ jobAds }) => (
|
|||||||
<TextSection>
|
<TextSection>
|
||||||
<h3>Olethan yhteydessä!</h3>
|
<h3>Olethan yhteydessä!</h3>
|
||||||
<div>
|
<div>
|
||||||
<p>Yllämainituista mahdollisuuksista, sekä muista ideoista kiinnostuneena, voit olla yhteydessä Yrityssuhdemestariimme Tommiin.</p>
|
<p>Yllämainituista mahdollisuuksista, sekä muista ideoista kiinnostuneena, voit olla yhteydessä Yrityssuhdemestariimme.</p>
|
||||||
<h6>Yrityssuhdemestari</h6>
|
<h6>Yrityssuhdemestari</h6>
|
||||||
<p>Tommi Oinonen <br />044 299 3439<br /> <a href={`mailto:${CORPORATE_MASTER_MAIL}`}>{CORPORATE_MASTER_MAIL}</a></p>
|
<p>{CORPORATE_MASTER_INFO.name} <br /> <a href={`mailto:${CORPORATE_MASTER_INFO.email}`}>{CORPORATE_MASTER_INFO.email}</a></p>
|
||||||
</div>
|
</div>
|
||||||
</TextSection>
|
</TextSection>
|
||||||
|
|
||||||
<CTASection
|
<CTASection
|
||||||
bgColor="orange1"
|
bgColor="orange1"
|
||||||
link="https://sosso.fi/wp-content/uploads/2022/01/sossomediakortti22.pdf"
|
link="https://sosso.fi/wp-content/uploads/2023/01/sossomediakortti23.pdf"
|
||||||
linkText="Killan lehden mediakortin löydät täältä ›"
|
linkText="Killan lehden mediakortin löydät täältä ›"
|
||||||
>
|
>
|
||||||
Mainos Sössöön?
|
Mainos Sössöön?
|
||||||
@@ -110,7 +110,7 @@ const CorporatePageView: React.FC<CorporatePageViewProps> = ({ jobAds }) => (
|
|||||||
<h3 id="tyopaikat">Työpaikkailmoitukset</h3>
|
<h3 id="tyopaikat">Työpaikkailmoitukset</h3>
|
||||||
<div>
|
<div>
|
||||||
<JobAdList jobAds={jobAds} />
|
<JobAdList jobAds={jobAds} />
|
||||||
<p>Voit saada yrityksesi työpaikkailmoituksen listalle lähettämällä sen osoitteeseen <a href={`mailto:${CORPORATE_MASTER_MAIL}`}>{CORPORATE_MASTER_MAIL}</a></p>
|
<p>Voit saada yrityksesi työpaikkailmoituksen listalle lähettämällä sen osoitteeseen <a href={`mailto:${CORPORATE_MASTER_INFO.email}`}>{CORPORATE_MASTER_INFO.email}</a></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</TextSection>
|
</TextSection>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/legacy/image";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import rehypeRaw from "rehype-raw";
|
import rehypeRaw from "rehype-raw";
|
||||||
import rehypeSanitize from "rehype-sanitize";
|
import rehypeSanitize from "rehype-sanitize";
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/legacy/image";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import rehypeRaw from "rehype-raw";
|
import rehypeRaw from "rehype-raw";
|
||||||
import rehypeSanitize from "rehype-sanitize";
|
import rehypeSanitize from "rehype-sanitize";
|
||||||
|
|||||||
@@ -13,24 +13,24 @@ const FreshmenPageHero: React.FC = () => (
|
|||||||
<HeroAside bgColor="lightTurquoise">
|
<HeroAside bgColor="lightTurquoise">
|
||||||
<HeroAsideItem
|
<HeroAsideItem
|
||||||
header="Lue killan fuksiopas"
|
header="Lue killan fuksiopas"
|
||||||
link="https://static.sahkoinsinoorikilta.fi/FTMK/Fuksiopas2022.pdf"
|
link="https://static.sahkoinsinoorikilta.fi/FTMK/Fuksiopas2023.pdf"
|
||||||
linkText="lue fuksiopas täältä!"
|
linkText="lue fuksiopas täältä!"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<HeroAsideItem
|
<HeroAsideItem
|
||||||
header="Seuraa killan tiedotusta"
|
header="Seuraa killan tiedotusta"
|
||||||
link="https://t.me/+ubTeGSYKTvg3NmVk"
|
link="https://t.me/+AB-JMbAxM2c0MDc0"
|
||||||
linkText="Liity killan Telegram-ryhmiin"
|
linkText="Liity killan Telegram-ryhmään!"
|
||||||
/>
|
/>
|
||||||
<HeroAsideItem
|
<HeroAsideItem
|
||||||
header="Kaikki kunnossa opiskelua varten?"
|
header="Kaikki kunnossa opiskelua varten?"
|
||||||
link="https://into.aalto.fi/pages/viewpage.action?pageId=1183171"
|
link="https://www.aalto.fi/fi/ohjelmat/sahkotekniikan-kandidaattiohjelma/opintojen-aloittaminen"
|
||||||
linkText="Lue korkeakoulun tietopaketti"
|
linkText="Lue korkeakoulun tietopaketti"
|
||||||
/>
|
/>
|
||||||
<HeroAsideItem
|
<HeroAsideItem
|
||||||
header="ISO-ryhmät ja ISO-henkilöt?"
|
header="Fuksiryhmät ja ISOt?"
|
||||||
link="#isot"
|
link="#isot"
|
||||||
linkText="Tsekkaa ISO-henkilöiden tiedot"
|
linkText="Tietoa fuksiryhmistä"
|
||||||
/>
|
/>
|
||||||
</HeroAside>
|
</HeroAside>
|
||||||
</Hero>
|
</Hero>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/legacy/image";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import {
|
import {
|
||||||
CTASection, TextSection, InfoBox, PageLink, Link,
|
CTASection, TextSection, InfoBox, PageLink, Link,
|
||||||
@@ -7,8 +7,8 @@ import {
|
|||||||
import FreshmenPageHero from "./FreshmenPageHero";
|
import FreshmenPageHero from "./FreshmenPageHero";
|
||||||
|
|
||||||
const FUKSI_POINTS_LINK = "https://static.sahkoinsinoorikilta.fi/FTMK/Fuksipisteohje.pdf";
|
const FUKSI_POINTS_LINK = "https://static.sahkoinsinoorikilta.fi/FTMK/Fuksipisteohje.pdf";
|
||||||
const TG_GROUP_CHAT_LINK = "https://t.me/+1PqQHRVMjiAxMTU0";
|
const TG_GROUP_CHAT_LINK = "https://t.me/+6rAKYPVaCmg4ZTlk";
|
||||||
const TG_NOTIFICATIONS_LINK = "https://t.me/+Ln8TvQ-_id9kZTU0";
|
const TG_NOTIFICATIONS_LINK = "https://t.me/+57BnXcTlsuU0YWQ0";
|
||||||
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}`;
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ const FreshmenPageView: React.FC = () => (
|
|||||||
|
|
||||||
<ImageContainer>
|
<ImageContainer>
|
||||||
<Image
|
<Image
|
||||||
src="https://static.sahkoinsinoorikilta.fi/uus_webi/fuksikipparit-2022.jpg"
|
src="https://static.sahkoinsinoorikilta.fi/uus_webi/fuksikipparit-2023.jpg"
|
||||||
alt="Kipparit"
|
alt="Kipparit"
|
||||||
layout="responsive"
|
layout="responsive"
|
||||||
width={100}
|
width={100}
|
||||||
@@ -69,7 +69,7 @@ const FreshmenPageView: React.FC = () => (
|
|||||||
|
|
||||||
<h6>Fuksikapteenit</h6>
|
<h6>Fuksikapteenit</h6>
|
||||||
<p>
|
<p>
|
||||||
Me olemme fuksikapteenisi <strong>Melisa</strong> ja <strong>Eveliina</strong> ja tulemme olemaan tukenasi sekä valvomassa suorituksiasi fuksivuoden seikkailuissa kohti teekkarilakkia, jonka voit ansaita mahdollisesti järjestettävänä Wappuna ensi keväällä.
|
Me olemme fuksikapteenisi <strong>Aaron</strong> ja <strong>Kasper</strong> ja tulemme olemaan tukenasi sekä valvomassa suorituksiasi fuksivuoden seikkailuissa kohti teekkarilakkia, jonka voit ansaita mahdollisesti järjestettävänä Wappuna ensi keväällä.
|
||||||
Jos sinulla on mitään kysymyksiä, ota ihmeessä meihin yhteyttä esimerkiksi <Link to={TG_GROUP_CHAT_LINK} target="_blank">Telegramissa</Link> tai <a href={EMAIL_LINK_MAILTO}>sähköpostitse</a>.
|
Jos sinulla on mitään kysymyksiä, ota ihmeessä meihin yhteyttä esimerkiksi <Link to={TG_GROUP_CHAT_LINK} target="_blank">Telegramissa</Link> tai <a href={EMAIL_LINK_MAILTO}>sähköpostitse</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@@ -79,14 +79,14 @@ 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 29.08.2022-02.09.2022, mutta jo ennen sitä sinulla on mahdollisuus tulla tutustumaan meihin, muihin fuksiehin ja ISOihin rennon Varaslähtöön. Varaslähtö fuksivuoteen järjestetään 20.8.2022. Siitä lisää Telegram-ryhmissä!
|
Orientaatioviikko järjestetään 28.8.-1.9.2023, mutta jo ennen sitä sinulla on mahdollisuus tulla tutustumaan meihin, muihin fuksiehin ja ISOihin rennon Varaslähtöön. Varaslähtö fuksivuoteen järjestetään 19.8.2023. Siitä lisää Telegram-ryhmissä!
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h6>Melisa Dönmez</h6>
|
<h6>Aaron Löfgren</h6>
|
||||||
<p>044 239 2385 <br />melisa.donmez (ät) sahkoinsinoorikilta.fi <br />@melisadonmez</p>
|
<p>040 484 5418<br />aaron.lofgren (ät) sahkoinsinoorikilta.fi <br />@aaronlofgren</p>
|
||||||
|
|
||||||
<h6>Eveliina Ahonen</h6>
|
<h6>Kasper Skog</h6>
|
||||||
<p>050 911 8818 <br />eveliina.ahonen (ät) sahkoinsinoorikilta.fi <br />@ahoonen</p>
|
<p>040 667 5266<br />kasper.skog (ät) sahkoinsinoorikilta.fi <br />@Skooogi</p>
|
||||||
</div>
|
</div>
|
||||||
<aside>
|
<aside>
|
||||||
<div>
|
<div>
|
||||||
@@ -103,14 +103,14 @@ const FreshmenPageView: React.FC = () => (
|
|||||||
<div>
|
<div>
|
||||||
<InfoBox>
|
<InfoBox>
|
||||||
<h6>Killan Fuksiopas</h6>
|
<h6>Killan Fuksiopas</h6>
|
||||||
<Link to="https://static.sahkoinsinoorikilta.fi/FTMK/Fuksiopas2022.pdf" target="_blank">
|
<Link to="https://static.sahkoinsinoorikilta.fi/FTMK/Fuksiopas2023.pdf" target="_blank">
|
||||||
<FopasImage
|
<FopasImage
|
||||||
src="https://static.sahkoinsinoorikilta.fi/FTMK/Fuksiopas2022-kansi.jpg"
|
src="https://static.sahkoinsinoorikilta.fi/FTMK/Fuksiopas2023-kansi.png"
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
Ennen opintojen alkua on hyvä tutustua killan fuksioppaaseen. Sitä pääset selailemaan <Link to="https://static.sahkoinsinoorikilta.fi/FTMK/Fuksiopas2022.pdf" target="_blank"> tästä.</Link>
|
Ennen opintojen alkua on hyvä tutustua killan fuksioppaaseen. Sitä pääset selailemaan <Link to="https://static.sahkoinsinoorikilta.fi/FTMK/Fuksiopas2023.pdf" target="_blank"> tästä.</Link>
|
||||||
</p>
|
</p>
|
||||||
<br />
|
<br />
|
||||||
<h6>Telegram?</h6>
|
<h6>Telegram?</h6>
|
||||||
@@ -123,12 +123,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-2022.jpg"
|
src="https://static.sahkoinsinoorikilta.fi/FTMK/sik-fuksit-2023.jpg"
|
||||||
/>
|
/>
|
||||||
<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-2022-tiedotus.jpg"
|
src="https://static.sahkoinsinoorikilta.fi/FTMK/sik-fuksit-2023-tiedotus.jpg"
|
||||||
/>
|
/>
|
||||||
<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>
|
||||||
@@ -144,13 +144,13 @@ const FreshmenPageView: React.FC = () => (
|
|||||||
</CTASection>
|
</CTASection>
|
||||||
|
|
||||||
<TextSection>
|
<TextSection>
|
||||||
<h3 id="isot">Isoryhmät</h3>
|
<h3 id="isot">Fuksiryhmät ja ISO-toiminta</h3>
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
SIK:n fuksit nauttivat hurmaavien ISOhenkilöidensä opastuksesta ja hellästä huolenpidosta omissa fuksiryhmissään.
|
SIK:n fuksit nauttivat hurmaavien ISOjen opastuksesta ja hellästä huolenpidosta omissa fuksiryhmissään.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
ISOt ovat hiukan vanhempia opiskelijoita ja kiltalaisia, joiden tehtävänä on olla tukenasi fuksivuoden ajan. Ensimmäisenä päivänä teidät jaetaan noin kymmenen hengen fuksiryhmiin ja jokaiseen ryhmään kuuluu kolmesta viiteen ISOa, joista yksi toimii opintoISOna. ISOilta voit kysyä mitä vain opiskeluun ja opiskelijaelämään liittyen. Vaikka he eivät tietäisi vastausta, he luultavimmin osaavat auttaa sinua vastausten löytämisessä.
|
ISOt ovat hiukan vanhempia opiskelijoita ja kiltalaisia, joiden tehtävänä on olla tukenasi fuksivuoden ajan. Ensimmäisenä päivänä teidät jaetaan noin kymmenen hengen fuksiryhmiin ja jokaiseen ryhmään kuuluu kolmesta viiteen ISOa, joista yksi toimii opintoISOna. ISOilta voit kysyä mitä vain opiskeluun ja opiskelijaelämään liittyen. Vaikka he eivät tietäisi vastausta, he luultavimmin osaavat auttaa sinua vastausten löytämisessä.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Kuten sanottu ISOt tukevat sinua koko fuksivuoden ajan, mutta eniten tulet näkemään heitä Orientaatioviikolla, jolloin he kulkevat fuksiryhmäsi kanssa ympäri Otaniemeä ja avaavat ovia teekkariuden saloihin. He auttavat sinua myös löytämään opintojen aloittamiseen tarvittavat asiat ja tukevat esimerkiksi lukujärjestyksen tekemisessä ja kirjastokortin, sekä matkakortin ja opiskelijakortin hankkimisessa.
|
Kuten sanottu ISOt tukevat sinua koko fuksivuoden ajan, mutta eniten tulet näkemään heitä Orientaatioviikolla, jolloin he kulkevat fuksiryhmäsi kanssa ympäri Otaniemeä ja avaavat ovia teekkariuden saloihin. He auttavat sinua myös löytämään opintojen aloittamiseen tarvittavat asiat ja tukevat esimerkiksi lukujärjestyksen tekemisessä ja kirjastokortin, sekä matkakortin ja opiskelijakortin hankkimisessa.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/legacy/image";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import {
|
import {
|
||||||
Divider,
|
Divider,
|
||||||
@@ -24,6 +24,7 @@ const Fingrid = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/fingr
|
|||||||
const Okmetic = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/okmetic.jpg";
|
const Okmetic = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/okmetic.jpg";
|
||||||
const Nokia = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/nokia.jpg";
|
const Nokia = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/nokia.jpg";
|
||||||
const Granlund = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/granlund.jpg";
|
const Granlund = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/granlund.jpg";
|
||||||
|
const GE = "https://static.sahkoinsinoorikilta.fi/img/corporate_logos/GE.png";
|
||||||
|
|
||||||
interface FrontPageViewProps {
|
interface FrontPageViewProps {
|
||||||
events: Event[];
|
events: Event[];
|
||||||
@@ -87,16 +88,16 @@ const FrontPageView: React.FC<FrontPageViewProps> = ({ events, feed }) => (
|
|||||||
<h6>Yhteistyössä:</h6>
|
<h6>Yhteistyössä:</h6>
|
||||||
<SponsorReel>
|
<SponsorReel>
|
||||||
<div>
|
<div>
|
||||||
<Link to="https://new.abb.com/fi/uralle">
|
<Link to="https://new.abb.com/fi/">
|
||||||
<Image src={ABB} alt="ABB" layout="responsive" width={200} height={100} objectFit="contain" />
|
<Image src={ABB} alt="ABB" layout="responsive" width={200} height={100} objectFit="contain" />
|
||||||
</Link>
|
</Link>
|
||||||
<Link to="https://www.caruna.fi/tietoa-meista/tyonhakijalle/tyonantajalupaus">
|
<Link to="https://caruna.fi/">
|
||||||
<Image src={Caruna} alt="Caruna" layout="responsive" width={200} height={100} objectFit="contain" />
|
<Image src={Caruna} alt="Caruna" layout="responsive" width={200} height={100} objectFit="contain" />
|
||||||
</Link>
|
</Link>
|
||||||
<Link to="https://www.nokia.com/fi_fi/">
|
<Link to="https://www.nokia.com/">
|
||||||
<Image src={Nokia} alt="Nokia" layout="responsive" width={200} height={100} objectFit="contain" />
|
<Image src={Nokia} alt="Nokia" layout="responsive" width={200} height={100} objectFit="contain" />
|
||||||
</Link>
|
</Link>
|
||||||
<Link to="https://www.ensto.com/fi">
|
<Link to="https://www.ensto.com/fi/">
|
||||||
<Image src={Ensto} alt="Ensto" layout="responsive" width={200} height={100} objectFit="contain" />
|
<Image src={Ensto} alt="Ensto" layout="responsive" width={200} height={100} objectFit="contain" />
|
||||||
</Link>
|
</Link>
|
||||||
<Link to="https://www.esett.com/">
|
<Link to="https://www.esett.com/">
|
||||||
@@ -111,6 +112,9 @@ const FrontPageView: React.FC<FrontPageViewProps> = ({ events, feed }) => (
|
|||||||
<Link to="https://www.granlund.fi/">
|
<Link to="https://www.granlund.fi/">
|
||||||
<Image src={Granlund} alt="Granlund" layout="responsive" width={200} height={100} objectFit="contain" />
|
<Image src={Granlund} alt="Granlund" layout="responsive" width={200} height={100} objectFit="contain" />
|
||||||
</Link>
|
</Link>
|
||||||
|
<Link to="https://www.gehealthcare.fi/">
|
||||||
|
<Image src={GE} alt="GE" layout="responsive" width={200} height={100} objectFit="contain" />
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<Link to="/yritysyhteistyo">Haluatko kuulla lisää yhteistyöstä kanssamme?</Link>
|
<Link to="/yritysyhteistyo">Haluatko kuulla lisää yhteistyöstä kanssamme?</Link>
|
||||||
</SponsorReel>
|
</SponsorReel>
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ const HonoraryPageView: React.FC = () => (
|
|||||||
<li>Tapani Jokinen 1996–</li>
|
<li>Tapani Jokinen 1996–</li>
|
||||||
<li>Kaj G. Lindén 1999–</li>
|
<li>Kaj G. Lindén 1999–</li>
|
||||||
<li>Jorma Kyyrä 2011–</li>
|
<li>Jorma Kyyrä 2011–</li>
|
||||||
|
<li>Seppo Saastamoinen 2022-</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>Oltermannit</h2>
|
<h2>Oltermannit</h2>
|
||||||
<p>Oltermanni on yhdyshenkilö killan ja opettajakunnan välillä. Valtuusto valitsee oltermannin kolmeksi vuodeksi kerrallaan.</p>
|
<p>Oltermanni on yhdyshenkilö killan ja opettajakunnan välillä. Valtuusto valitsee oltermannin kolmeksi vuodeksi kerrallaan.</p>
|
||||||
@@ -82,6 +83,8 @@ const HonoraryPageView: React.FC = () => (
|
|||||||
<li>2019 Ville Kapanen</li>
|
<li>2019 Ville Kapanen</li>
|
||||||
<li>2020 Anni Parkkila, Aliisa Pietilä</li>
|
<li>2020 Anni Parkkila, Aliisa Pietilä</li>
|
||||||
<li>2021 Essi Jukkala</li>
|
<li>2021 Essi Jukkala</li>
|
||||||
|
<li>2022 Erna Virtanen, Tuukka Syrjänen</li>
|
||||||
|
<li>2023 Emmaleena Ahonen</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>Standaari</h2>
|
<h2>Standaari</h2>
|
||||||
<p>Standaari voidaan hallituksen päätöksellä lahjoittaa killan toimintaan myönteisesti vaikuttaneille tahoille. Standaarit on numeroitu lahjoittamisjärjestyksessä.</p>
|
<p>Standaari voidaan hallituksen päätöksellä lahjoittaa killan toimintaan myönteisesti vaikuttaneille tahoille. Standaarit on numeroitu lahjoittamisjärjestyksessä.</p>
|
||||||
@@ -100,6 +103,7 @@ const HonoraryPageView: React.FC = () => (
|
|||||||
<li>2013 Martti Valtonen</li>
|
<li>2013 Martti Valtonen</li>
|
||||||
<li>2016 ABB Oy</li>
|
<li>2016 ABB Oy</li>
|
||||||
<li>2021 Elektroteknologsektionens Kalle Anka-Kommitté</li>
|
<li>2021 Elektroteknologsektionens Kalle Anka-Kommitté</li>
|
||||||
|
<li>2023 Tekniikan akateemiset TEK, Automaatio- ja systeemitekniikan kilta ry</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h2>Kultaiset ansiomerkit</h2>
|
<h2>Kultaiset ansiomerkit</h2>
|
||||||
<p>
|
<p>
|
||||||
@@ -195,6 +199,20 @@ const HonoraryPageView: React.FC = () => (
|
|||||||
<li>2021 Tuukka Syrjänen</li>
|
<li>2021 Tuukka Syrjänen</li>
|
||||||
<li>2021 Timi Tiira</li>
|
<li>2021 Timi Tiira</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li>2022 Elias Hirvonen</li>
|
||||||
|
<li>2022 Emmaleena Ahonen</li>
|
||||||
|
<li>2022 Jonna Tammikivi</li>
|
||||||
|
<li>2022 Leo Kivikunnas</li>
|
||||||
|
<li>2022 Sini Huhtinen</li>
|
||||||
|
<li>2022 Ukko Kasvi</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li>2023 Sasu Saalasti</li>
|
||||||
|
<li>2023 Ville Kaakinen</li>
|
||||||
|
<li>2023 Mikael Liimatainen</li>
|
||||||
|
<li>2023 Jami Hyytiäinen</li>
|
||||||
|
</ul>
|
||||||
<h2>Hopeiset ansiomerkit</h2>
|
<h2>Hopeiset ansiomerkit</h2>
|
||||||
<p>Killan hallitus voi myöntää hopeitosen 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ää hopeitosen 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>
|
<ul>
|
||||||
@@ -544,6 +562,22 @@ const HonoraryPageView: React.FC = () => (
|
|||||||
<li>2021 Sofia Öhman</li>
|
<li>2021 Sofia Öhman</li>
|
||||||
<li>2021 Suvi Karanta</li>
|
<li>2021 Suvi Karanta</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li>2022 Aaro Niskanen</li>
|
||||||
|
<li>2022 Aaro Rasilainen</li>
|
||||||
|
<li>2022 Aino Suomi</li>
|
||||||
|
<li>2022 Eino Tyrvänen</li>
|
||||||
|
<li>2022 Henry Gustafsson</li>
|
||||||
|
<li>2022 Johannes Ora</li>
|
||||||
|
<li>2022 Niilo Ojala</li>
|
||||||
|
<li>2022 Oliver Hiekkamies</li>
|
||||||
|
<li>2022 Oskari Ponkala</li>
|
||||||
|
<li>2022 Otto Julkunen</li>
|
||||||
|
<li>2022 Pyry Vaara</li>
|
||||||
|
<li>2022 Toni Lyttinen</li>
|
||||||
|
<li>2022 Tuomas Pajunpää</li>
|
||||||
|
<li>2022 Ville-Pekka Laakkonen</li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</TextSection>
|
</TextSection>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ const InEnglishPageView: React.FC<InEnglishPageViewProps> = ({ events, feed }) =
|
|||||||
<p>Balance your studies and get connected</p>
|
<p>Balance your studies and get connected</p>
|
||||||
<div>
|
<div>
|
||||||
<h6>Build everything related to electronics</h6>
|
<h6>Build everything related to electronics</h6>
|
||||||
<p>Elepaja is an electronics workshop run by the guild, where students get to apply skills they have learned at school in practical projects. Over time, students have built diverse projects in the workshop, such as their first LED flashlights, tesla windings, robots and radio transmitters. If you are interested in building electronics or you need help with a project, then come visit the workshop located at Otakaari 1 h023b. The workshop is equipped with basic tools such as circuit boards, etching tools, soldering tools, various components, column drill and a wide range of measuring equipment. You can join <Link to="https://elepaja.fi/tg">elepaja's Telegram group here</Link>.</p>
|
<p>SIK-PAJA is an electronics workshop run by the guild, where students get to apply skills they have learned at school in practical projects. Over time, students have built diverse projects in the workshop, such as their first LED overall badges, tesla windings, robots and radio transmitters. If you are interested in building electronics or you need help with a project, then come visit the workshop located at Otakaari 1 h023b. The workshop is equipped with basic tools such as circuit boards, etching tools, soldering tools, various components and a wide range of measuring equipment. You can join <Link to="https://t.me/sikpaja">sikpaja's Telegram group here</Link>.</p>
|
||||||
<h6>Sports events</h6>
|
<h6>Sports events</h6>
|
||||||
<p>The committee of Well Being runs many things in our guild. One of these is providing sports events to the guild members. In cooperation with other guilds, we regularly organize opportunities to play floorball and other sports. Sports tryouts are available throughout the year and are organized in co-operation with various sports organizations in Otaniemi. Keep your eyes open in the <Link to="#events">events</Link> section and join the <Link to="https://t.me/joinchat/DJRXxkKd0SMj0e9pBPXF1A/"> sports Telegram group.</Link></p>
|
<p>The committee of Well Being runs many things in our guild. One of these is providing sports events to the guild members. In cooperation with other guilds, we regularly organize opportunities to play floorball and other sports. Sports tryouts are available throughout the year and are organized in co-operation with various sports organizations in Otaniemi. Keep your eyes open in the <Link to="#events">events</Link> section and join the <Link to="https://t.me/joinchat/DJRXxkKd0SMj0e9pBPXF1A/"> sports Telegram group.</Link></p>
|
||||||
<h6>Culture from culinarism to theater</h6>
|
<h6>Culture from culinarism to theater</h6>
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { TextSection, Link } from "@components/index";
|
||||||
|
import Button from "@components/Button";
|
||||||
|
import Stripe from "stripe";
|
||||||
|
|
||||||
|
const stripe = new Stripe(
|
||||||
|
"", // <--- API AVAIN
|
||||||
|
{ apiVersion: "2023-08-16" },
|
||||||
|
);
|
||||||
|
|
||||||
|
const paymentIntentTest = async () => {
|
||||||
|
const intent = await stripe.paymentIntents.create({
|
||||||
|
amount: 8,
|
||||||
|
currency: "eur",
|
||||||
|
});
|
||||||
|
return intent;
|
||||||
|
};
|
||||||
|
|
||||||
|
const JoinPageView: React.FC = () => (
|
||||||
|
<TextSection>
|
||||||
|
<h1>Liity jäseneksi ja maksa jäsenmaksu</h1>
|
||||||
|
<p>
|
||||||
|
Killan jäsenhakemuksen voi täyttää <Link to="https://api.sahkoinsinoorikilta.fi/members/application">täältä.</Link> Muistakaa
|
||||||
|
myös maksaa jäsenmaksu!
|
||||||
|
<Button onClick={paymentIntentTest} buttonStyle="hero">
|
||||||
|
Payment intent testi
|
||||||
|
</Button>
|
||||||
|
</p>
|
||||||
|
</TextSection>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default JoinPageView;
|
||||||
@@ -112,7 +112,7 @@ const SignUpPageView: React.FC<SignUpPageViewProps> = ({
|
|||||||
const questions = signUpForm.questions.map((q) => signupFormQuestionToQuestion(q, i18n.language));
|
const questions = signUpForm.questions.map((q) => signupFormQuestionToQuestion(q, i18n.language));
|
||||||
form = (
|
form = (
|
||||||
<>
|
<>
|
||||||
<p>{`${t("Ilmoittauminen sulkeutuu")} ${endDateStr}`}.</p>
|
<p>{`${t("Ilmoittautuminen sulkeutuu")} ${endDateStr}`}.</p>
|
||||||
<FormWrapper
|
<FormWrapper
|
||||||
schema={buildFormSchema(questions, formTitle) as unknown}
|
schema={buildFormSchema(questions, formTitle) as unknown}
|
||||||
uiSchema={buildUISchema(questions)}
|
uiSchema={buildUISchema(questions)}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/legacy/image";
|
||||||
import {
|
import {
|
||||||
CTASection, TextSection, PageLink, Link,
|
CTASection, TextSection, PageLink, Link,
|
||||||
} from "@components/index";
|
} from "@components/index";
|
||||||
|
|||||||
@@ -21,7 +21,11 @@ const Main = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const AdminListCommon: React.FC = ({ children }) => (
|
type AdminListCommonProps = {
|
||||||
|
children: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
const AdminListCommon: React.FC<AdminListCommonProps> = ({ children }) => (
|
||||||
<AdminPageWrapper requiresAuthentication>
|
<AdminPageWrapper requiresAuthentication>
|
||||||
<Main>
|
<Main>
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ const useShouldRedirect = (enabled = true) => {
|
|||||||
|
|
||||||
type PageProps = {
|
type PageProps = {
|
||||||
requiresAuthentication: boolean;
|
requiresAuthentication: boolean;
|
||||||
|
children: React.ReactNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
const AdminPageWrapper: React.FC<PageProps> = ({ requiresAuthentication, children }) => {
|
const AdminPageWrapper: React.FC<PageProps> = ({ requiresAuthentication, children }) => {
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ import React from "react";
|
|||||||
import Header from "@components/Header";
|
import Header from "@components/Header";
|
||||||
import Footer from "@components/Footer/Footer";
|
import Footer from "@components/Footer/Footer";
|
||||||
|
|
||||||
const PageWrapper: React.FC = ({ children }) => (
|
type PageWrapperProps = {
|
||||||
|
children: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
const PageWrapper: React.FC<PageWrapperProps> = ({ children }) => (
|
||||||
<>
|
<>
|
||||||
<Header />
|
<Header />
|
||||||
{children}
|
{children}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Selector } from "testcafe";
|
import { Selector } from "testcafe";
|
||||||
import {
|
import {
|
||||||
getSiteRoot, getPageUrl, generateTestForm, deleteEvent, deleteForm, doLogin, generateAccessToken, getPostRequestLogger,
|
getSiteRoot, getPageUrl, generateTestForm, deleteEvent, deleteForm, doLogin, generateAccessToken, getPostRequestLogger, waitForLogger,
|
||||||
} from "../utils";
|
} from "../utils";
|
||||||
|
|
||||||
const LOGGER = getPostRequestLogger("events/");
|
const LOGGER = getPostRequestLogger("events/");
|
||||||
@@ -78,6 +78,8 @@ test("Logged in user can create event", async (t) => {
|
|||||||
await t.click(submit);
|
await t.click(submit);
|
||||||
|
|
||||||
const parsed = JSON.parse(LOGGER.requests[0].response.body as string);
|
const parsed = JSON.parse(LOGGER.requests[0].response.body as string);
|
||||||
|
|
||||||
|
await waitForLogger(LOGGER);
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
t.fixtureCtx.eventId = parsed.id;
|
t.fixtureCtx.eventId = parsed.id;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { Selector } from "testcafe";
|
import { Selector } from "testcafe";
|
||||||
import {
|
import {
|
||||||
getSiteRoot, getPageUrl, deleteForm, doLogin, generateAccessToken, getPostRequestLogger,
|
getSiteRoot, getPageUrl, deleteForm, doLogin, generateAccessToken, getPostRequestLogger, waitForLogger
|
||||||
} from "../utils";
|
} from "../utils";
|
||||||
|
|
||||||
const LOGGER = getPostRequestLogger("signupForm/");
|
const LOGGER = getPostRequestLogger("signupForm/");
|
||||||
@@ -97,6 +97,8 @@ test("Logged in user can create signup", async (t) => {
|
|||||||
await t.click(submit);
|
await t.click(submit);
|
||||||
|
|
||||||
const parsed = JSON.parse(LOGGER.requests[0].response.body as string);
|
const parsed = JSON.parse(LOGGER.requests[0].response.body as string);
|
||||||
|
|
||||||
|
await waitForLogger(LOGGER);
|
||||||
// eslint-disable-next-line no-param-reassign
|
// eslint-disable-next-line no-param-reassign
|
||||||
t.fixtureCtx.formId = parsed.id;
|
t.fixtureCtx.formId = parsed.id;
|
||||||
|
|
||||||
|
|||||||
@@ -157,3 +157,12 @@ export const generateTestEvent = async (formIds = [], jwt_access: string) => (
|
|||||||
);
|
);
|
||||||
|
|
||||||
export const sleep = async (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
|
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++) {
|
||||||
|
await sleep(100);
|
||||||
|
if (logger.requests.length > 0 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
@@ -59,7 +59,7 @@
|
|||||||
"./src/**/*",
|
"./src/**/*",
|
||||||
"./types/**/*",
|
"./types/**/*",
|
||||||
"./tests/testcafe/**/*",
|
"./tests/testcafe/**/*",
|
||||||
"next-sitemap.js",
|
"next-sitemap.config.js",
|
||||||
"next.config.js",
|
"next.config.js",
|
||||||
"jest.config.js",
|
"jest.config.js",
|
||||||
".eslintrc.js",
|
".eslintrc.js",
|
||||||
|
|||||||
Reference in New Issue
Block a user