diff --git a/.eslintrc.json b/.eslintrc.json index bffb357..faf7038 100755 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,15 @@ { - "extends": "next/core-web-vitals" + "extends": [ + "next/core-web-vitals", + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "prettier" //Prettier should be placed last, so it gets the chance to override other configs + ], + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"], + "root": true, + "rules": { + "no-unused-vars": "off", //Base rule is disabled as it can report incorrect errors + "@typescript-eslint/no-unused-vars": "error" + } } diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..8efe3dc --- /dev/null +++ b/.prettierignore @@ -0,0 +1,38 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# editors +.idea \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1 @@ +{} diff --git a/app/[locale]/callback/Result.tsx b/app/[locale]/callback/Result.tsx index 7203e81..f45544b 100644 --- a/app/[locale]/callback/Result.tsx +++ b/app/[locale]/callback/Result.tsx @@ -4,12 +4,13 @@ import { useContext, useEffect, useRef } from "react"; import { AppContext } from "@/context/AppContext"; import Link from "next/link"; import { useTranslation } from "@/context/useTranslation"; +import { StrapiBaseType } from "@/utils/models"; type Props = { locale: string; isValid: boolean; paymentStatus: string; - content: any; + content?: StrapiBaseType<{onError: string; onCancel: string; onSuccess: string}>; } const CallbackResult = ({ locale, isValid, paymentStatus, content}: Props) => { @@ -22,6 +23,7 @@ const CallbackResult = ({ locale, isValid, paymentStatus, content}: Props) => { reset(); } },[isValid, paymentStatus, reset]); + if(!content) return
Error on rendering callback page
let result =

{content.attributes.onSuccess}

if(isValid === undefined) return

Loading...

if (!isValid) result =
diff --git a/app/[locale]/callback/page.tsx b/app/[locale]/callback/page.tsx index ca11c0d..03af183 100644 --- a/app/[locale]/callback/page.tsx +++ b/app/[locale]/callback/page.tsx @@ -25,7 +25,7 @@ type Props = { params: { locale: string }, - searchParams: Record; + searchParams: Record; } const CallbackPage = async ({params: {locale}, searchParams}: Props) => { diff --git a/app/[locale]/contact/ContactForm.tsx b/app/[locale]/contact/ContactForm.tsx index 54100df..8857b8c 100644 --- a/app/[locale]/contact/ContactForm.tsx +++ b/app/[locale]/contact/ContactForm.tsx @@ -3,7 +3,7 @@ import { ChangeEvent, FormEvent, useContext, useEffect, useState } from 'react'; import { fetchAPI } from '@/lib/api'; import { AppContext } from '@/context/AppContext'; -import { ContactForm} from '@/utils/models'; +import { ContactForm, Customer} from '@/utils/models'; import { useRouter } from 'next/navigation'; import Link from 'next/link'; import { getContactForm } from '@/utils/helpers'; @@ -23,7 +23,7 @@ const Form = ({locale}: Props) => { populate: ['contactForm','itemTypes'] })) const {customer, refreshFields, isEmpty, items} = useContext(AppContext); - const [inputFields, setInputFields] = useState>(customer.attributes); + const [inputFields, setInputFields] = useState(customer.attributes); useEffect(() => { setInputFields(customer.attributes); },[customer]); @@ -35,7 +35,7 @@ const Form = ({locale}: Props) => { const contactForm = getContactForm(contactForms || [], items); const handleSubmit = async (e: FormEvent) => { e.preventDefault(); - const updateFields: any = {...inputFields}; + const updateFields: Partial = {...inputFields}; updateFields.locale = locale; delete updateFields.createdAt; delete updateFields.updatedAt; @@ -72,8 +72,8 @@ const Form = ({locale}: Props) => { className='tx-input mt-2' type={field.type} onChange={(event: ChangeEvent) => handleChange(event, field.fieldName, field.type)} - value={inputFields[field.fieldName] || ''} - checked={inputFields[field.fieldName] || false} + value={String(inputFields[field.fieldName]) || ''} + checked={!!inputFields[field.fieldName] || false} required={field.required} /> diff --git a/app/[locale]/edit/[orderUid]/Component.tsx b/app/[locale]/edit/[orderUid]/Component.tsx index e145e16..a03e377 100644 --- a/app/[locale]/edit/[orderUid]/Component.tsx +++ b/app/[locale]/edit/[orderUid]/Component.tsx @@ -5,7 +5,6 @@ import { ChangeEvent, FormEvent, useEffect, useState } from 'react'; import { fetchAPI } from '@/lib/api'; import { initialCustomer } from '@/context/AppContext'; import { ContactForm,Customer, Order, StrapiBaseType } from '@/utils/models'; -import { useRouter } from 'next/navigation'; import Link from 'next/link'; import { getContactForm } from '@/utils/helpers'; import { useTranslation } from "@/context/useTranslation"; @@ -26,11 +25,10 @@ type Props = { const Form = ({contactForms, global, locale, orderUid}: Props) => { const { translation } = useTranslation(locale); - const router = useRouter(); const [isLoading, setLoading] = useState(false); const {data: customer, mutate: refreshFields} = useSWR(`/customers/findByOrderUid/${orderUid}`, fetchAPI); - const {data: orders, mutate: mutateOrders} = useSWR(customer ? `/orders/findByCustomerUid/${customer.attributes.uid}` : null, fetchAPI); - const [inputFields, setInputFields] = useState>(customer?.attributes || initialCustomer); + const {data: orders} = useSWR(customer ? `/orders/findByCustomerUid/${customer.attributes.uid}` : null, fetchAPI); + const [inputFields, setInputFields] = useState(customer?.attributes || initialCustomer.attributes); const updateHasEnded = new Date(global.attributes.updateEnd) <= new Date(); useEffect(() => { if(!customer) return; @@ -42,7 +40,7 @@ const Form = ({contactForms, global, locale, orderUid}: Props) => { const handleSubmit = async (e: FormEvent) => { setLoading(true); e.preventDefault(); - const updateFields: any = {...inputFields}; + const updateFields: Partial = {...inputFields}; updateFields.locale = locale; delete updateFields.createdAt; delete updateFields.updatedAt; @@ -57,7 +55,7 @@ const Form = ({contactForms, global, locale, orderUid}: Props) => { }), }); } catch(error) { - + // Error in updating the field } refreshFields(); setLoading(false); @@ -84,8 +82,8 @@ const Form = ({contactForms, global, locale, orderUid}: Props) => { className='tx-input mt-2' type={field.type} onChange={(event: ChangeEvent) => handleChange(event, field.fieldName, field.type)} - value={inputFields[field.fieldName] || ''} - checked={inputFields[field.fieldName] || false} + value={String(inputFields[field.fieldName]) || ''} + checked={!!inputFields[field.fieldName] || false} required={field.required} /> diff --git a/app/[locale]/edit/[orderUid]/page.tsx b/app/[locale]/edit/[orderUid]/page.tsx index 981a64e..7b2256b 100644 --- a/app/[locale]/edit/[orderUid]/page.tsx +++ b/app/[locale]/edit/[orderUid]/page.tsx @@ -23,14 +23,16 @@ const getData = async (locale: string) => { type Props = { params: { - locale: string + locale: string; + orderUid: string; } } -const EditPage = async ({params: {locale}}: Props) => { +const EditPage = async ({params: {locale, orderUid}}: Props) => { const data = await getData(locale) return { +const RootLayout = async ({children}: PropType) => { return ( diff --git a/components/Group.tsx b/components/Group.tsx index 1712a85..79713da 100644 --- a/components/Group.tsx +++ b/components/Group.tsx @@ -18,7 +18,7 @@ const GroupComponent = ({onChange}: PropTypes) => { const {data: groupData} = useSWR('/groups', fetchAPI); const groups = useMemo(() => (groupData ||[]).map(group => group.attributes.name),[groupData]) const [dropdownIndex, setDropdownIndex] = useState(-1); - const [isFocused, setFocused] = useState(false); + const [, setFocused] = useState(false); const filteredGroups = useMemo(() => { const g = groups.filter(group => { if(newGroupName.length === 0) return false; diff --git a/context/AppContext.tsx b/context/AppContext.tsx index 1bac04b..9f64dba 100644 --- a/context/AppContext.tsx +++ b/context/AppContext.tsx @@ -1,7 +1,7 @@ "use client"; import { - createContext, useState, useEffect, FC, useCallback, useRef, useMemo + createContext, useState, useEffect, FC, useCallback, useMemo } from "react"; import useSWR from "swr"; import { fetchAPI } from "../lib/api"; @@ -33,7 +33,7 @@ export const initialCustomer = { startYear: '', updatedAt: '', uid: '', - } + }, }; const appContextDefault: Required = { customer: initialCustomer, @@ -124,6 +124,7 @@ const AppProvider: FC = ({ children }) => { newOrder.attributes.items = {data:filteredItems}; mutateOrder(newOrder); } catch(error) { + // Error in deleting an item } }; @@ -144,6 +145,7 @@ const AppProvider: FC = ({ children }) => { newOrder.attributes.items = {data: newItems}; mutateOrder(newOrder); } catch(error) { + // Error in adding an item } } const refreshFields = async () => { diff --git a/package-lock.json b/package-lock.json index 3a065bd..6482c48 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,9 +24,12 @@ "@types/node": "^20.2.5", "@types/react": "^18.2.7", "@types/react-dom": "^18.2.4", + "@typescript-eslint/eslint-plugin": "^6.7.0", "autoprefixer": "^10.4.8", - "eslint": "8.18.0", + "eslint": "^8.18.0", + "eslint-config-prettier": "^9.0.0", "postcss": "^8.4.14", + "prettier": "^3.0.3", "tailwindcss": "^3.1.8", "typescript": "4.7.4" } @@ -61,6 +64,30 @@ "node": ">=6.9.0" } }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.1.tgz", + "integrity": "sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", @@ -367,6 +394,12 @@ "@types/unist": "^2" } }, + "node_modules/@types/json-schema": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "dev": true + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -425,11 +458,52 @@ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" }, + "node_modules/@types/semver": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw==", + "dev": true + }, "node_modules/@types/unist": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.8.tgz", "integrity": "sha512-d0XxK3YTObnWVp6rZuev3c49+j4Lo8g4L1ZRm9z5L0xpoZycUPshHgczK5gsUMaZOstjVYYi09p5gYvUtfChYw==" }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.0.tgz", + "integrity": "sha512-gUqtknHm0TDs1LhY12K2NA3Rmlmp88jK9Tx8vGZMfHeNMLE3GH2e9TRub+y+SOjuYgtOmok+wt1AyDPZqxbNag==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.7.0", + "@typescript-eslint/type-utils": "6.7.0", + "@typescript-eslint/utils": "6.7.0", + "@typescript-eslint/visitor-keys": "6.7.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/@typescript-eslint/parser": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.0.tgz", @@ -473,6 +547,33 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.0.tgz", + "integrity": "sha512-f/QabJgDAlpSz3qduCyQT0Fw7hHpmhOzY/Rv6zO3yO+HVIdPfIWhrQoAyG+uZVtWAIS85zAyzgAFfyEr+MgBpg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.7.0", + "@typescript-eslint/utils": "6.7.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/@typescript-eslint/types": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.0.tgz", @@ -511,6 +612,31 @@ } } }, + "node_modules/@typescript-eslint/utils": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.0.tgz", + "integrity": "sha512-MfCq3cM0vh2slSikQYqK2Gq52gvOhe57vD2RM3V4gQRZYX4rDPnKLu5p6cm89+LJiGlwEXU8hkYxhqqEC/V3qA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.7.0", + "@typescript-eslint/types": "6.7.0", + "@typescript-eslint/typescript-estree": "6.7.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, "node_modules/@typescript-eslint/visitor-keys": { "version": "6.7.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.0.tgz", @@ -1542,6 +1668,18 @@ } } }, + "node_modules/eslint-config-prettier": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", + "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", @@ -2206,6 +2344,12 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -3966,6 +4110,21 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", diff --git a/package.json b/package.json index 44f013e..6b55a94 100644 --- a/package.json +++ b/package.json @@ -27,9 +27,12 @@ "@types/node": "^20.2.5", "@types/react": "^18.2.7", "@types/react-dom": "^18.2.4", + "@typescript-eslint/eslint-plugin": "^6.7.0", "autoprefixer": "^10.4.8", - "eslint": "8.18.0", + "eslint": "^8.18.0", + "eslint-config-prettier": "^9.0.0", "postcss": "^8.4.14", + "prettier": "^3.0.3", "tailwindcss": "^3.1.8", "typescript": "4.7.4" }, diff --git a/utils/models.ts b/utils/models.ts index 0d4ec68..7f51373 100644 --- a/utils/models.ts +++ b/utils/models.ts @@ -111,5 +111,5 @@ export type Customer = StrapiBaseType<{ email: string; uid: string; locale: string; - [key: string]: string | number; + [key: string]: string | number | boolean; }> \ No newline at end of file