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";
+3 -3
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,
@@ -147,10 +147,10 @@ const FreshmenPageView: React.FC = () => (
<h3 id="isot">Isoryhmät</h3> <h3 id="isot">Isoryhmät</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 ISOhenkilöidensä 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 -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",