Merge branch 'update-react' into 'master'

Update React & Next.js

See merge request sahkoinsinoorikilta/vtmk/web2.0-frontend!109
This commit is contained in:
Ilari Ojakorpi
2023-02-12 08:01:22 +00:00
34 changed files with 1841 additions and 828 deletions
+3 -1
View File
@@ -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));
+1739 -768
View File
File diff suppressed because it is too large Load Diff
+20 -14
View File
@@ -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,37 @@
"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.1.6",
"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",
"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"
}
} }
} }
+1
View File
@@ -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 -1
View File
@@ -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";
+1
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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";
+1 -1
View File
@@ -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 {
+1
View File
@@ -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`
+1 -1
View File
@@ -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";
+5 -1
View File
@@ -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>
+1
View File
@@ -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 }) => (
+5 -1
View File
@@ -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
View File
@@ -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}
/>
); );
} }
+1
View File
@@ -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)`
+1
View File
@@ -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> = ({
+1
View File
@@ -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`
+6 -4
View File
@@ -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>
); );
+7 -12
View File
@@ -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>
+3 -3
View File
@@ -109,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>
@@ -185,14 +186,14 @@ 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>
)} )}
@@ -204,5 +205,4 @@ const ContactsPageView: React.FC = () => (
</> </>
); );
export default ContactsPageView; export default ContactsPageView;
@@ -9,7 +9,7 @@ import JobAdList from "./JobAdList";
import BoardJson from "../ContactsPage/board.json"; 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_INFO = BoardJson.roles.filter(role => { return role.name_fi === "Yrityssuhdemestari"})[0].representatives[0]; const CORPORATE_MASTER_INFO = BoardJson.roles.filter((role) => role.name_fi === "Yrityssuhdemestari")[0].representatives[0];
interface CorporatePageViewProps { interface CorporatePageViewProps {
jobAds: JobAd[]; jobAds: JobAd[];
+1 -1
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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,
+1 -1
View File
@@ -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,
+1 -1
View File
@@ -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";
+5 -1
View File
@@ -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}
+1
View File
@@ -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 }) => {
+5 -1
View File
@@ -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 -1
View File
@@ -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",