diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 27fa0faa..38276ad8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,10 +28,10 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Log in to the Container registry - uses: docker/login-action@cf8514a65188af1d4f94f8c28a7a4153af1088ce + uses: docker/login-action@b4bedf8053341df3b5a9f9e0f2cf4e79e27360c6 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -39,7 +39,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@0f8c876bafbf5dbce05c36682ec68e9a0274a48a + uses: docker/metadata-action@879dcbb708d40f8b8679d4f7941b938a086e23a7 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} @@ -86,10 +86,10 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Log in to the Container registry - uses: docker/login-action@cf8514a65188af1d4f94f8c28a7a4153af1088ce + uses: docker/login-action@b4bedf8053341df3b5a9f9e0f2cf4e79e27360c6 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -97,7 +97,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@0f8c876bafbf5dbce05c36682ec68e9a0274a48a + uses: docker/metadata-action@879dcbb708d40f8b8679d4f7941b938a086e23a7 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index f7867826..801a698e 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -7,7 +7,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-node@v3 with: diff --git a/package-lock.json b/package-lock.json index 8358ede3..6f7a8fce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,7 @@ "@typescript-eslint/eslint-plugin": "^5.42.0", "@typescript-eslint/parser": "^5.62.0", "@typescript-eslint/typescript-estree": "^6.8.0", - "eslint": "8.47.0", + "eslint": "8.52.0", "eslint-config-next": "^13.5.6", "eslint-plugin-import": "^2.28.0" } @@ -1894,9 +1894,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.47.0.tgz", - "integrity": "sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", + "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -1993,11 +1993,11 @@ "integrity": "sha512-D2sFFtI/GXfUpCT6r35sGgcbKYWjTtLpMRspSVMh5cRBfUTn+hdqP2UH0PyvGuTf4qDkmFyq4Yst83MWh0rYGQ==" }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", + "@humanwhocodes/object-schema": "^2.0.1", "debug": "^4.1.1", "minimatch": "^3.0.5" }, @@ -2018,9 +2018,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==" }, "node_modules/@jest/schemas": { "version": "29.6.0", @@ -2935,6 +2935,11 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -4276,17 +4281,18 @@ } }, "node_modules/eslint": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.47.0.tgz", - "integrity": "sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==", + "version": "8.52.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", + "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "^8.47.0", - "@humanwhocodes/config-array": "^0.11.10", + "@eslint/js": "8.52.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", diff --git a/package.json b/package.json index 39a3f053..b839c01b 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@typescript-eslint/eslint-plugin": "^5.42.0", "@typescript-eslint/parser": "^5.62.0", "@typescript-eslint/typescript-estree": "^6.8.0", - "eslint": "8.47.0", + "eslint": "8.52.0", "eslint-config-next": "^13.5.6", "eslint-plugin-import": "^2.28.0" }, diff --git a/src/components/check.tsx b/src/components/check.tsx index 8d68f945..5284e361 100644 --- a/src/components/check.tsx +++ b/src/components/check.tsx @@ -52,7 +52,7 @@ const ProductSearch = () => { setShowInvalid(false); setLoading(true); - + try { const data = await VeganCheck.getProductByBarcode( barcode, @@ -178,13 +178,16 @@ const ProductSearch = () => { > {t("enterbarcode")}
+ {t("enterbarcode")} setBarcode(barcode)} handleSubmit={(barcode) => handleSubmit(barcode)} /> + { +const SupportOption = () => { const t = useTranslations("More"); const [icon, setIcon] = useState("icon-paypal"); const [vendor, setVendor] = useState("PayPal"); diff --git a/src/components/elements/contents/oledmode.tsx b/src/components/elements/contents/oledmode.tsx index aa15dddc..de253d9b 100644 --- a/src/components/elements/contents/oledmode.tsx +++ b/src/components/elements/contents/oledmode.tsx @@ -1,14 +1,16 @@ -import { useTranslations } from 'next-intl'; -import React, { useState, useEffect } from 'react'; +import { useTranslations } from "next-intl"; +import { useState, useEffect } from "react"; -const OLEDMode: React.FC = () => { - const t = useTranslations('More'); +const OLEDMode = () => { + const t = useTranslations("More"); const [isChecked, setIsChecked] = useState(false); const [error, setError] = useState(false); const setThemeColorAttribute = (color: string) => { - const themeColorElement = document.querySelector('meta[name="theme-color"][media="(prefers-color-scheme: dark)"]'); - + const themeColorElement = document.querySelector( + 'meta[name="theme-color"][media="(prefers-color-scheme: dark)"]' + ); + if (themeColorElement) { themeColorElement.setAttribute("content", color); } @@ -16,7 +18,10 @@ const OLEDMode: React.FC = () => { useEffect(() => { const localStorageValue = localStorage.getItem("oled"); - if (localStorageValue === "true" && window.matchMedia('(prefers-color-scheme: dark)').matches) { + if ( + localStorageValue === "true" && + window.matchMedia("(prefers-color-scheme: dark)").matches + ) { document.documentElement.setAttribute("data-theme", "oled"); setThemeColorAttribute("#000"); setIsChecked(true); @@ -24,14 +29,17 @@ const OLEDMode: React.FC = () => { }, []); const handleClick = () => { - if (!isChecked && !window.matchMedia('(prefers-color-scheme: dark)').matches) { + if ( + !isChecked && + !window.matchMedia("(prefers-color-scheme: dark)").matches + ) { setError(true); return; } if (!isChecked) { document.documentElement.setAttribute("data-theme", "oled"); setThemeColorAttribute("#000"); - localStorage.setItem('oled', 'true'); + localStorage.setItem("oled", "true"); } else { localStorage.clear(); document.documentElement.removeAttribute("data-theme"); @@ -42,11 +50,19 @@ const OLEDMode: React.FC = () => { }; return ( - + + ); }; diff --git a/src/components/elements/modalwrapper.tsx b/src/components/elements/modalwrapper.tsx index a5a72ce5..c4023463 100644 --- a/src/components/elements/modalwrapper.tsx +++ b/src/components/elements/modalwrapper.tsx @@ -9,9 +9,18 @@ interface ModalProps { children: React.ReactNode; } -const ModalWrapper: React.FC = ({ children, id, buttonType, buttonClass, buttonText }) => { +const ModalWrapper = ({ + children, + id, + buttonType, + buttonClass, + buttonText, +}: ModalProps) => { const [isOpen, setIsOpen] = useState(false); - const modalRoot = typeof document !== 'undefined' ? document.getElementById("modal-root") : null; + const modalRoot = + typeof document !== "undefined" + ? document.getElementById("modal-root") + : null; useEffect(() => { const handleEscapeKeyPress = (event: KeyboardEvent) => { @@ -23,9 +32,9 @@ const ModalWrapper: React.FC = ({ children, id, buttonType, buttonCl const handleTouchStart = (event: TouchEvent) => { const touchStartY = event.touches[0].clientY; let touchEndY; - + document.body.addEventListener("touchend", handleTouchEnd); - + function handleTouchEnd(event: TouchEvent) { touchEndY = event.changedTouches[0].clientY; if (touchEndY - touchStartY > 10) { @@ -34,7 +43,6 @@ const ModalWrapper: React.FC = ({ children, id, buttonType, buttonCl document.body.removeEventListener("touchend", handleTouchEnd); } }; - document.addEventListener("keydown", handleEscapeKeyPress); document.addEventListener("touchstart", handleTouchStart); @@ -91,15 +99,12 @@ const ModalWrapper: React.FC = ({ children, id, buttonType, buttonCl {buttonText} )} - {isOpen && modalRoot && + {isOpen && + modalRoot && createPortal(
diff --git a/src/components/elements/share.tsx b/src/components/elements/share.tsx index 5894d854..96cbe17a 100644 --- a/src/components/elements/share.tsx +++ b/src/components/elements/share.tsx @@ -9,7 +9,7 @@ interface ShareButtonProps { barcode: string; } -const ShareButton: React.FC = ({ productName, barcode }) => { +const ShareButton = ({ productName, barcode }: ShareButtonProps) => { const t = useTranslations("Check"); const [showButton, setShowButton] = useState(false); @@ -91,7 +91,9 @@ const ShareButton: React.FC = ({ productName, barcode }) => { text, url, }) - .catch((err) => {console.error(err)}); + .catch((err) => { + console.error(err); + }); }} > {t("share")} diff --git a/src/components/elements/shortcutinstall.tsx b/src/components/elements/shortcutinstall.tsx index d815d98c..cbbd95c0 100644 --- a/src/components/elements/shortcutinstall.tsx +++ b/src/components/elements/shortcutinstall.tsx @@ -1,13 +1,13 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import Image from "next/image"; import { useTranslations } from "next-intl"; -import { useState, useEffect, FC } from "react"; +import { useState, useEffect } from "react"; interface ExtendedWindow extends Window { MSStream?: any; } -const Shortcut: FC = () => { +const Shortcut = () => { const t = useTranslations("ShortcutPrompt"); const [showShortcut, setShowShortcut] = useState(false); @@ -16,7 +16,8 @@ const Shortcut: FC = () => { const windowWithMSStream = window as ExtendedWindow; const isIOS: boolean = - /iPad|iPhone|iPod/.test(navigator.userAgent) && !windowWithMSStream.MSStream; + /iPad|iPhone|iPod/.test(navigator.userAgent) && + !windowWithMSStream.MSStream; if ( !window.matchMedia("(display-mode: standalone)").matches && diff --git a/src/components/ingredientscheck.tsx b/src/components/ingredientscheck.tsx index f9d514e7..a9902501 100644 --- a/src/components/ingredientscheck.tsx +++ b/src/components/ingredientscheck.tsx @@ -5,11 +5,6 @@ import React, { useState, FormEvent } from "react"; import ModalWrapper from "@/components/elements/modalwrapper"; -export interface FlaggedItem { - item: string; - index: number; -} - const IngredientsCheck = () => { const t = useTranslations("Ingredients"); const [flagged, setFlagged] = useState([]); diff --git a/src/components/translation.tsx b/src/components/translation.ts similarity index 100% rename from src/components/translation.tsx rename to src/components/translation.ts diff --git a/src/models/FlaggedItem.ts b/src/models/FlaggedItem.ts new file mode 100644 index 00000000..34190d2c --- /dev/null +++ b/src/models/FlaggedItem.ts @@ -0,0 +1,4 @@ +export type FlaggedItem = { + item: string; + index: number; +}; diff --git a/src/pages/404.tsx b/src/pages/404.tsx index 8a4b404b..23166144 100644 --- a/src/pages/404.tsx +++ b/src/pages/404.tsx @@ -1,17 +1,27 @@ -import { GetStaticPropsContext } from 'next' -import { useTranslations } from 'next-intl'; +import { GetStaticPropsContext } from "next"; +import { useTranslations } from "next-intl"; import Container from "@/components/elements/container"; import Nav from "@/components/nav"; export default function NotFound() { - const t = useTranslations('404'); + const t = useTranslations("404"); return ( <>