diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js new file mode 100644 index 000000000..82231f181 --- /dev/null +++ b/frontend/.eslintrc.js @@ -0,0 +1,188 @@ +/* eslint-disable max-lines */ +module.exports = { + plugins: ["prefer-arrow", "import"], + extends: [ + "next", + "next/core-web-vitals", + "eslint:recommended", + "plugin:import/recommended", + ], + ignorePatterns: ["**/node_modules/", "**/.next/"], + rules: { + "import/extensions": 0, + "import/no-unresolved": 0, + "import/prefer-default-export": 0, + "import/no-duplicates": "error", + complexity: ["error", 8], + "max-lines": ["error", 100], + "max-depth": ["error", 3], + "max-params": ["error", 4], + eqeqeq: ["error", "smart"], + "import/no-extraneous-dependencies": [ + "error", + { + devDependencies: true, + optionalDependencies: false, + peerDependencies: false, + }, + ], + "no-shadow": [ + "error", + { + hoist: "all", + }, + ], + "prefer-const": "error", + "import/order": [ + "error", + { + pathGroups: [{ pattern: "@lib/**", group: "unknown" }], + groups: [ + ["external", "builtin"], + "unknown", + "internal", + ["parent", "sibling", "index"], + ], + alphabetize: { + order: "asc", + caseInsensitive: false, + }, + "newlines-between": "always", + pathGroupsExcludedImportTypes: ["builtin"], + }, + ], + "import/namespace": "off", + "sort-imports": [ + "error", + { + ignoreCase: true, + ignoreDeclarationSort: true, + ignoreMemberSort: false, + memberSyntaxSortOrder: ["none", "all", "multiple", "single"], + }, + ], + "padding-line-between-statements": [ + "error", + { + blankLine: "always", + prev: "*", + next: "return", + }, + ], + "prefer-arrow/prefer-arrow-functions": [ + "error", + { + disallowPrototype: true, + singleReturnOnly: false, + classPropertiesAllowed: false, + }, + ], + "no-restricted-imports": [ + "error", + { + paths: [ + { + name: "lodash", + message: "Please use lodash/{module} import instead", + }, + { + name: "aws-sdk", + message: "Please use aws-sdk/{module} import instead", + }, + { + name: ".", + message: "Please use explicit import file", + }, + ], + }, + ], + curly: ["error", "all"], + }, + root: true, + env: { + es6: true, + node: true, + browser: true, + }, + parserOptions: { + ecmaVersion: 9, + sourceType: "module", + babelOptions: { + presets: [require.resolve("next/babel")], + }, + }, + overrides: [ + { + files: ["**/*.ts?(x)"], + extends: [ + "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/recommended-requiring-type-checking", + "plugin:import/typescript", + ], + parser: "@typescript-eslint/parser", + parserOptions: { + project: "./tsconfig.eslint.json", + tsconfigRootDir: __dirname, + sourceType: "module", + }, + rules: { + "@typescript-eslint/prefer-optional-chain": "error", + "no-shadow": "off", + "@typescript-eslint/no-shadow": "error", + "@typescript-eslint/prefer-nullish-coalescing": "error", + "@typescript-eslint/strict-boolean-expressions": [ + "error", + { + allowString: false, + allowNumber: false, + allowNullableObject: true, + }, + ], + "@typescript-eslint/ban-ts-comment": [ + "error", + { + "ts-ignore": "allow-with-description", + minimumDescriptionLength: 10, + }, + ], + "@typescript-eslint/explicit-function-return-type": 0, + "@typescript-eslint/explicit-member-accessibility": 0, + "@typescript-eslint/camelcase": 0, + "@typescript-eslint/interface-name-prefix": 0, + "@typescript-eslint/explicit-module-boundary-types": "error", + "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/no-unused-vars": "error", + "@typescript-eslint/ban-types": [ + "error", + { + types: { + FC: "Use `const MyComponent = (props: Props): JSX.Element` instead", + SFC: "Use `const MyComponent = (props: Props): JSX.Element` instead", + FunctionComponent: + "Use `const MyComponent = (props: Props): JSX.Element` instead", + "React.FC": + "Use `const MyComponent = (props: Props): JSX.Element` instead", + "React.SFC": + "Use `const MyComponent = (props: Props): JSX.Element` instead", + "React.FunctionComponent": + "Use `const MyComponent = (props: Props): JSX.Element` instead", + }, + extendDefaults: true, + }, + ], + "@typescript-eslint/no-unnecessary-boolean-literal-compare": "error", + "@typescript-eslint/no-unnecessary-condition": "error", + "@typescript-eslint/no-unnecessary-type-arguments": "error", + "@typescript-eslint/prefer-string-starts-ends-with": "error", + "@typescript-eslint/switch-exhaustiveness-check": "error", + "@typescript-eslint/restrict-template-expressions": [ + "error", + { + allowNumber: true, + allowBoolean: true, + }, + ], + }, + }, + ], +}; diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json deleted file mode 100644 index 52dd97ae3..000000000 --- a/frontend/.eslintrc.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": [ - "next/core-web-vitals", - "eslint:recommended", - "plugin:@typescript-eslint/recommended" - ], - "plugins": ["@typescript-eslint"], - "parser": "@typescript-eslint/parser", - "rules": { - "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": "error", - "@typescript-eslint/no-explicit-any": "error" - } -} diff --git a/frontend/.lintstagedrc.js b/frontend/.lintstagedrc.js new file mode 100644 index 000000000..268d825d6 --- /dev/null +++ b/frontend/.lintstagedrc.js @@ -0,0 +1,4 @@ +module.exports = { + "*": "prettier --ignore-unknown --write", + "*.{js,ts, tsx}": "pnpm lint-fix", +}; diff --git a/frontend/app/(auth)/login/components/GoogleLogin/hooks/useGoogleLogin.ts b/frontend/app/(auth)/login/components/GoogleLogin/hooks/useGoogleLogin.ts index 28caf2edf..509a855e8 100644 --- a/frontend/app/(auth)/login/components/GoogleLogin/hooks/useGoogleLogin.ts +++ b/frontend/app/(auth)/login/components/GoogleLogin/hooks/useGoogleLogin.ts @@ -1,6 +1,8 @@ +/* eslint-disable */ +import { useState } from "react"; + import { useSupabase } from "@/app/supabase-provider"; import { useToast } from "@/lib/hooks/useToast"; -import { useState } from "react"; export const useGoogleLogin = () => { const { supabase } = useSupabase(); diff --git a/frontend/app/(auth)/login/components/GoogleLogin/index.tsx b/frontend/app/(auth)/login/components/GoogleLogin/index.tsx index 8578caf25..b1afc2841 100644 --- a/frontend/app/(auth)/login/components/GoogleLogin/index.tsx +++ b/frontend/app/(auth)/login/components/GoogleLogin/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable */ import Button from "@/lib/components/ui/Button"; import { useGoogleLogin } from "./hooks/useGoogleLogin"; diff --git a/frontend/app/(auth)/login/components/MagicLinkLogin/index.tsx b/frontend/app/(auth)/login/components/MagicLinkLogin/index.tsx index 9fc30d05e..5978e775b 100644 --- a/frontend/app/(auth)/login/components/MagicLinkLogin/index.tsx +++ b/frontend/app/(auth)/login/components/MagicLinkLogin/index.tsx @@ -1,8 +1,10 @@ +/* eslint-disable */ "use client"; +import { useState } from "react"; + import { useSupabase } from "@/app/supabase-provider"; import Button from "@/lib/components/ui/Button"; import { useToast } from "@/lib/hooks/useToast"; -import { useState } from "react"; type MaginLinkLoginProps = { email: string; @@ -21,6 +23,7 @@ export const MagicLinkLogin = ({ email, setEmail }: MaginLinkLoginProps) => { variant: "danger", text: "Please enter your email address", }); + return; } diff --git a/frontend/app/(auth)/login/page.tsx b/frontend/app/(auth)/login/page.tsx index 9f2bd17d0..5c85ef20d 100644 --- a/frontend/app/(auth)/login/page.tsx +++ b/frontend/app/(auth)/login/page.tsx @@ -1,4 +1,9 @@ +/* eslint-disable */ "use client"; +import Link from "next/link"; +import { redirect } from "next/navigation"; +import { useState } from "react"; + import { useSupabase } from "@/app/supabase-provider"; import Button from "@/lib/components/ui/Button"; import Card from "@/lib/components/ui/Card"; @@ -6,9 +11,7 @@ import { Divider } from "@/lib/components/ui/Divider"; import Field from "@/lib/components/ui/Field"; import PageHeading from "@/lib/components/ui/PageHeading"; import { useToast } from "@/lib/hooks/useToast"; -import Link from "next/link"; -import { redirect } from "next/navigation"; -import { useState } from "react"; + import { GoogleLoginButton } from "./components/GoogleLogin"; import { MagicLinkLogin } from "./components/MagicLinkLogin"; diff --git a/frontend/app/(auth)/logout/page.tsx b/frontend/app/(auth)/logout/page.tsx index 732cb53b9..6d345ff44 100644 --- a/frontend/app/(auth)/logout/page.tsx +++ b/frontend/app/(auth)/logout/page.tsx @@ -1,12 +1,14 @@ +/* eslint-disable */ "use client"; +import Link from "next/link"; +import { useRouter } from "next/navigation"; +import { useState } from "react"; + import { useSupabase } from "@/app/supabase-provider"; import Button from "@/lib/components/ui/Button"; import Card from "@/lib/components/ui/Card"; import PageHeading from "@/lib/components/ui/PageHeading"; import { useToast } from "@/lib/hooks/useToast"; -import Link from "next/link"; -import { useRouter } from "next/navigation"; -import { useState } from "react"; export default function Logout() { const { supabase } = useSupabase(); diff --git a/frontend/app/(auth)/signup/page.tsx b/frontend/app/(auth)/signup/page.tsx index a3f49ba4d..6e897bf96 100644 --- a/frontend/app/(auth)/signup/page.tsx +++ b/frontend/app/(auth)/signup/page.tsx @@ -1,12 +1,14 @@ +/* eslint-disable */ "use client"; +import Link from "next/link"; +import { useState } from "react"; + import { useSupabase } from "@/app/supabase-provider"; import Button from "@/lib/components/ui/Button"; import Card from "@/lib/components/ui/Card"; import Field from "@/lib/components/ui/Field"; import PageHeading from "@/lib/components/ui/PageHeading"; import { useToast } from "@/lib/hooks/useToast"; -import Link from "next/link"; -import { useState } from "react"; export default function SignUp() { const { supabase } = useSupabase(); diff --git a/frontend/app/(home)/Features.tsx b/frontend/app/(home)/Features.tsx index cb41aa3b0..679c4cf56 100644 --- a/frontend/app/(home)/Features.tsx +++ b/frontend/app/(home)/Features.tsx @@ -1,5 +1,4 @@ -import Card from "@/lib/components/ui/Card"; -import { FC, ReactNode } from "react"; +import { ReactNode } from "react"; import { GiArtificialIntelligence, GiBrain, @@ -9,7 +8,9 @@ import { GiOpenBook, } from "react-icons/gi"; -const Features: FC = () => { +import Card from "@/lib/components/ui/Card"; + +const Features = (): JSX.Element => { return (
@@ -58,7 +59,7 @@ interface FeatureProps { desc: string; } -const Feature: FC = ({ title, desc, icon }) => { +const Feature = ({ title, desc, icon }: FeatureProps): JSX.Element => { return ( {icon} diff --git a/frontend/app/(home)/Hero.tsx b/frontend/app/(home)/Hero.tsx index 5f57255fd..10fe6d2c0 100644 --- a/frontend/app/(home)/Hero.tsx +++ b/frontend/app/(home)/Hero.tsx @@ -1,11 +1,12 @@ "use client"; -import Button from "@/lib/components/ui/Button"; import { motion, useScroll, useSpring, useTransform } from "framer-motion"; import Link from "next/link"; -import { FC, useRef } from "react"; +import { useRef } from "react"; import { MdNorthEast } from "react-icons/md"; -const Hero: FC = () => { +import Button from "@/lib/components/ui/Button"; + +const Hero = (): JSX.Element => { const targetRef = useRef(null); const { scrollYProgress } = useScroll({ target: targetRef, @@ -19,6 +20,7 @@ const Hero: FC = () => { if (pos === 1) { return "relative"; } + return "sticky"; }); diff --git a/frontend/app/(home)/page.tsx b/frontend/app/(home)/page.tsx index 8f7904f51..cdc77f61c 100644 --- a/frontend/app/(home)/page.tsx +++ b/frontend/app/(home)/page.tsx @@ -1,8 +1,9 @@ -import Features from "./Features"; -import Hero from "./Hero"; import { redirect } from "next/navigation"; -export default function HomePage() { +import Features from "./Features"; +import Hero from "./Hero"; + +const HomePage = (): JSX.Element => { if (process.env.NEXT_PUBLIC_ENV === "local") { redirect("/upload"); } @@ -13,4 +14,6 @@ export default function HomePage() { ); -} +}; + +export default HomePage; diff --git a/frontend/app/chat/[chatId]/page.tsx b/frontend/app/chat/[chatId]/page.tsx index 9d4394a25..3344d1caf 100644 --- a/frontend/app/chat/[chatId]/page.tsx +++ b/frontend/app/chat/[chatId]/page.tsx @@ -1,8 +1,11 @@ +/* eslint-disable */ "use client"; -import PageHeading from "@/lib/components/ui/PageHeading"; -import useChatsContext from "@/lib/context/ChatsProvider/hooks/useChatsContext"; import { UUID } from "crypto"; import { useEffect } from "react"; + +import PageHeading from "@/lib/components/ui/PageHeading"; +import useChatsContext from "@/lib/context/ChatsProvider/hooks/useChatsContext"; + import { ChatInput, ChatMessages } from "../components"; interface ChatPageProps { @@ -18,7 +21,9 @@ export default function ChatPage({ params }: ChatPageProps) { useEffect(() => { // if (chatId) - if (!chatId) resetChat(); + if (!chatId) { + resetChat(); + } fetchChat(chatId); }, [fetchChat, chatId]); diff --git a/frontend/app/chat/components/ChatMessages/ChatInput/ConfigButton.tsx b/frontend/app/chat/components/ChatMessages/ChatInput/ConfigButton.tsx index 19f98cb54..5378da152 100644 --- a/frontend/app/chat/components/ChatMessages/ChatInput/ConfigButton.tsx +++ b/frontend/app/chat/components/ChatMessages/ChatInput/ConfigButton.tsx @@ -1,9 +1,10 @@ "use client"; -import Button from "@/lib/components/ui/Button"; import Link from "next/link"; import { MdSettings } from "react-icons/md"; -export function ConfigButton() { +import Button from "@/lib/components/ui/Button"; + +export const ConfigButton = (): JSX.Element => { return ( ); -} +}; diff --git a/frontend/app/chat/components/ChatMessages/ChatInput/MicButton.tsx b/frontend/app/chat/components/ChatMessages/ChatInput/MicButton.tsx index 7a01802a6..99e8697b0 100644 --- a/frontend/app/chat/components/ChatMessages/ChatInput/MicButton.tsx +++ b/frontend/app/chat/components/ChatMessages/ChatInput/MicButton.tsx @@ -1,9 +1,11 @@ +/* eslint-disable */ "use client"; -import Button from "@/lib/components/ui/Button"; -import { useSpeech } from "@/lib/context/ChatsProvider/hooks/useSpeech"; import { MdMic, MdMicOff } from "react-icons/md"; -export function MicButton() { +import Button from "@/lib/components/ui/Button"; +import { useSpeech } from "@/lib/context/ChatsProvider/hooks/useSpeech"; + +export const MicButton = (): JSX.Element => { const { isListening, speechSupported, startListening } = useSpeech(); return ( @@ -21,4 +23,4 @@ export function MicButton() { )} ); -} +}; diff --git a/frontend/app/chat/components/ChatMessages/ChatInput/index.tsx b/frontend/app/chat/components/ChatMessages/ChatInput/index.tsx index d37904c2e..e07954f60 100644 --- a/frontend/app/chat/components/ChatMessages/ChatInput/index.tsx +++ b/frontend/app/chat/components/ChatMessages/ChatInput/index.tsx @@ -1,17 +1,22 @@ +/* eslint-disable */ "use client"; import Button from "@/lib/components/ui/Button"; import useChatsContext from "@/lib/context/ChatsProvider/hooks/useChatsContext"; + import { ConfigButton } from "./ConfigButton"; import { MicButton } from "./MicButton"; -export function ChatInput() { +export const ChatInput = (): JSX.Element => { const { isSendingMessage, sendMessage, setMessage, message, chat } = useChatsContext(); + return (
{ e.preventDefault(); - if (!isSendingMessage) sendMessage(chat?.chatId); + if (!isSendingMessage) { + sendMessage(chat?.chatId); + } }} className="sticky bottom-0 p-5 bg-white dark:bg-black rounded-t-md border border-black/10 dark:border-white/25 border-b-0 w-full max-w-3xl flex items-center justify-center gap-2 z-20" > @@ -22,7 +27,9 @@ export function ChatInput() { onKeyDown={(e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); // Prevents the newline from being entered in the textarea - if (!isSendingMessage) sendMessage(chat?.chatId); // Call the submit function here + if (!isSendingMessage) { + sendMessage(chat?.chatId); + } // Call the submit function here } }} className="w-full p-2 border border-gray-300 dark:border-gray-500 outline-none rounded dark:bg-gray-800" @@ -41,4 +48,4 @@ export function ChatInput() {
); -} +}; diff --git a/frontend/app/chat/components/ChatMessages/ChatMessage.tsx b/frontend/app/chat/components/ChatMessages/ChatMessage.tsx index 4f77d7626..13ac54d18 100644 --- a/frontend/app/chat/components/ChatMessages/ChatMessage.tsx +++ b/frontend/app/chat/components/ChatMessages/ChatMessage.tsx @@ -1,9 +1,11 @@ +/* eslint-disable */ "use client"; -import { cn } from "@/lib/utils"; import { forwardRef, Ref } from "react"; import ReactMarkdown from "react-markdown"; -const ChatMessage = forwardRef( +import { cn } from "@/lib/utils"; + +export const ChatMessage = forwardRef( ( { speaker, @@ -46,5 +48,3 @@ const ChatMessage = forwardRef( ); ChatMessage.displayName = "ChatMessage"; - -export default ChatMessage; diff --git a/frontend/app/chat/components/ChatMessages/index.tsx b/frontend/app/chat/components/ChatMessages/index.tsx index 54ce7d09d..65d863975 100644 --- a/frontend/app/chat/components/ChatMessages/index.tsx +++ b/frontend/app/chat/components/ChatMessages/index.tsx @@ -1,26 +1,32 @@ +/* eslint-disable */ "use client"; +import { useEffect, useRef } from "react"; + import Card from "@/lib/components/ui/Card"; import useChatsContext from "@/lib/context/ChatsProvider/hooks/useChatsContext"; -import { FC, useEffect, useRef } from "react"; -import ChatMessage from "./ChatMessage"; +import { ChatMessage } from "./ChatMessage"; -export const ChatMessages: FC = () => { +export const ChatMessages = (): JSX.Element => { const lastChatRef = useRef(null); const { chat } = useChatsContext(); useEffect(() => { - if (!chat || !lastChatRef.current) return; + if (!chat || !lastChatRef.current) { + return; + } // if (chat.history.length > 2) { - lastChatRef.current?.scrollIntoView({ + lastChatRef.current.scrollIntoView({ behavior: "smooth", block: "end", }); // } }, [chat, lastChatRef]); - if (!chat) return null; + if (!chat) { + return <>; + } return ( diff --git a/frontend/app/chat/components/ChatsList/ChatsListItem.tsx b/frontend/app/chat/components/ChatsList/ChatsListItem.tsx index 0c19077e6..aa61a9d50 100644 --- a/frontend/app/chat/components/ChatsList/ChatsListItem.tsx +++ b/frontend/app/chat/components/ChatsList/ChatsListItem.tsx @@ -1,10 +1,12 @@ -import { cn } from "@/lib/utils"; +/* eslint-disable */ import { UUID } from "crypto"; import Link from "next/link"; import { usePathname } from "next/navigation"; -import { FC } from "react"; import { FiTrash2 } from "react-icons/fi"; import { MdChatBubbleOutline } from "react-icons/md"; + +import { cn } from "@/lib/utils"; + import { Chat } from "../../../../lib/types/Chat"; interface ChatsListItemProps { @@ -12,7 +14,10 @@ interface ChatsListItemProps { deleteChat: (id: UUID) => void; } -const ChatsListItem: FC = ({ chat, deleteChat }) => { +const ChatsListItem = ({ + chat, + deleteChat, +}: ChatsListItemProps): JSX.Element => { const pathname = usePathname()?.split("/").at(-1); const selected = chat.chatId === pathname; diff --git a/frontend/app/chat/components/ChatsList/NewChatButton.tsx b/frontend/app/chat/components/ChatsList/NewChatButton.tsx index 37010273a..b8a37abc5 100644 --- a/frontend/app/chat/components/ChatsList/NewChatButton.tsx +++ b/frontend/app/chat/components/ChatsList/NewChatButton.tsx @@ -1,7 +1,7 @@ import Link from "next/link"; import { BsPlusSquare } from "react-icons/bs"; -export const NewChatButton = () => ( +export const NewChatButton = (): JSX.Element => ( { const { allChats, deleteChat } = useChatsContext(); const [open, setOpen] = useState(false); @@ -69,4 +72,4 @@ export function ChatsList() { ); -} +}; diff --git a/frontend/app/chat/components/index.ts b/frontend/app/chat/components/index.ts index 78f7307d4..032236074 100644 --- a/frontend/app/chat/components/index.ts +++ b/frontend/app/chat/components/index.ts @@ -1,4 +1,4 @@ +export * from "./ChatMessages"; export * from "./ChatMessages/ChatInput"; export * from "./ChatMessages/ChatMessage"; -export * from "./ChatMessages"; export * from "./ChatsList"; diff --git a/frontend/app/chat/layout.tsx b/frontend/app/chat/layout.tsx index 21c7ca9a4..eebeef863 100644 --- a/frontend/app/chat/layout.tsx +++ b/frontend/app/chat/layout.tsx @@ -1,17 +1,21 @@ "use client"; -import { ChatsProvider } from "@/lib/context/ChatsProvider/chats-provider"; import { redirect } from "next/navigation"; -import { FC, ReactNode } from "react"; -import { useSupabase } from "../supabase-provider"; +import { ReactNode } from "react"; + +import { ChatsProvider } from "@/lib/context/ChatsProvider/chats-provider"; + import { ChatsList } from "./components"; +import { useSupabase } from "../supabase-provider"; interface LayoutProps { children?: ReactNode; } -const Layout: FC = ({ children }) => { +const Layout = ({ children }: LayoutProps): JSX.Element => { const { session } = useSupabase(); - if (!session) redirect("/login"); + if (!session) { + redirect("/login"); + } return ( diff --git a/frontend/app/config/components/ApiKeyConfig.tsx b/frontend/app/config/components/ApiKeyConfig.tsx index 9a11f958e..7e68ee9ca 100644 --- a/frontend/app/config/components/ApiKeyConfig.tsx +++ b/frontend/app/config/components/ApiKeyConfig.tsx @@ -1,8 +1,10 @@ +/* eslint-disable */ "use client"; +import { useState } from "react"; + import Button from "@/lib/components/ui/Button"; import { useAxios } from "@/lib/useAxios"; -import { useState } from "react"; export const ApiKeyConfig = (): JSX.Element => { const [apiKey, setApiKey] = useState(""); @@ -40,13 +42,13 @@ export const ApiKeyConfig = (): JSX.Element => {
- {!apiKey && ( + {apiKey === "" && ( )}
- {apiKey && ( + {apiKey !== "" && (
{apiKey}
); -} +}; + +export default ConfigPage; diff --git a/frontend/app/explore/DocumentItem/DocumentData.tsx b/frontend/app/explore/DocumentItem/DocumentData.tsx index 214f0a4ea..86c752eaa 100644 --- a/frontend/app/explore/DocumentItem/DocumentData.tsx +++ b/frontend/app/explore/DocumentItem/DocumentData.tsx @@ -1,5 +1,8 @@ -import { useAxios } from "@/lib/useAxios"; +/* eslint-disable */ import { useEffect, useState } from "react"; + +import { useAxios } from "@/lib/useAxios"; + import { useSupabase } from "../../supabase-provider"; interface DocumentDataProps { diff --git a/frontend/app/explore/DocumentItem/index.tsx b/frontend/app/explore/DocumentItem/index.tsx index 6ac070f2a..51857386c 100644 --- a/frontend/app/explore/DocumentItem/index.tsx +++ b/frontend/app/explore/DocumentItem/index.tsx @@ -1,19 +1,22 @@ +/* eslint-disable */ "use client"; +import { + Dispatch, + forwardRef, + RefObject, + SetStateAction, + useState, +} from "react"; + import { useSupabase } from "@/app/supabase-provider"; import Button from "@/lib/components/ui/Button"; import { AnimatedCard } from "@/lib/components/ui/Card"; import Ellipsis from "@/lib/components/ui/Ellipsis"; import Modal from "@/lib/components/ui/Modal"; import { useToast } from "@/lib/hooks/useToast"; +import { Document } from "@/lib/types/Document"; import { useAxios } from "@/lib/useAxios"; -import { - Dispatch, - RefObject, - SetStateAction, - forwardRef, - useState, -} from "react"; -import { Document } from "../../../lib/types/Document"; + import DocumentData from "./DocumentData"; interface DocumentProps { diff --git a/frontend/app/explore/page.tsx b/frontend/app/explore/page.tsx index 20457860f..a432a76c4 100644 --- a/frontend/app/explore/page.tsx +++ b/frontend/app/explore/page.tsx @@ -1,17 +1,19 @@ +/* eslint-disable */ "use client"; -import Button from "@/lib/components/ui/Button"; -import Spinner from "@/lib/components/ui/Spinner"; - -import { Document } from "@/lib/types/Document"; -import { useAxios } from "@/lib/useAxios"; import { AnimatePresence, motion } from "framer-motion"; import Link from "next/link"; import { redirect } from "next/navigation"; import { useEffect, useState } from "react"; + +import Button from "@/lib/components/ui/Button"; +import Spinner from "@/lib/components/ui/Spinner"; +import { Document } from "@/lib/types/Document"; +import { useAxios } from "@/lib/useAxios"; + import { useSupabase } from "../supabase-provider"; import DocumentItem from "./DocumentItem"; -export default function ExplorePage() { +const ExplorePage = (): JSX.Element => { const [documents, setDocuments] = useState([]); const [isPending, setIsPending] = useState(true); const { session } = useSupabase(); @@ -79,4 +81,6 @@ export default function ExplorePage() { ); -} +}; + +export default ExplorePage; diff --git a/frontend/app/globals.css b/frontend/app/globals.css index 98b73c447..d0455af44 100644 --- a/frontend/app/globals.css +++ b/frontend/app/globals.css @@ -1,13 +1,13 @@ -@import 'tailwindcss/base'; -@import 'tailwindcss/components'; -@import 'tailwindcss/utilities'; - +@import "tailwindcss/base"; +@import "tailwindcss/components"; +@import "tailwindcss/utilities"; main { @apply max-w-screen-xl mx-auto flex flex-col; } -header, section { +header, +section { @apply px-5 md:px-10; } @@ -43,4 +43,4 @@ a { max-height: 60vh; /* Adjust this value based on the desired maximum height */ overflow-y: auto; /* Enable vertical scroll if the content exceeds the maximum height */ padding-right: 1rem; /* Optional: Add some padding if the scrollbar appears, so the text is not squished */ -} \ No newline at end of file +} diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx index 7e5b1f72e..e7b925d7c 100644 --- a/frontend/app/layout.tsx +++ b/frontend/app/layout.tsx @@ -1,11 +1,13 @@ -import Footer from "@/lib/components/Footer"; -import { NavBar } from "@/lib/components/NavBar"; -import { ToastProvider } from "@/lib/components/ui/Toast"; import { createServerComponentSupabaseClient } from "@supabase/auth-helpers-nextjs"; import { Analytics } from "@vercel/analytics/react"; import { Inter } from "next/font/google"; import { cookies, headers } from "next/headers"; -import { BrainConfigProvider } from "../lib/context/BrainConfigProvider/brain-config-provider"; + +import Footer from "@/lib/components/Footer"; +import { NavBar } from "@/lib/components/NavBar"; +import { ToastProvider } from "@/lib/components/ui/Toast"; +import { BrainConfigProvider } from "@/lib/context/BrainConfigProvider/brain-config-provider"; + import "./globals.css"; import SupabaseProvider from "./supabase-provider"; @@ -17,11 +19,11 @@ export const metadata = { "Quivr is your second brain in the cloud, designed to easily store and retrieve unstructured information.", }; -export default async function RootLayout({ +const RootLayout = async ({ children, }: { children: React.ReactNode; -}) { +}): Promise => { const supabase = createServerComponentSupabaseClient({ headers, cookies, @@ -49,4 +51,6 @@ export default async function RootLayout({ ); -} +}; + +export default RootLayout; diff --git a/frontend/app/supabase-provider.tsx b/frontend/app/supabase-provider.tsx index 6a7097246..94fb93931 100644 --- a/frontend/app/supabase-provider.tsx +++ b/frontend/app/supabase-provider.tsx @@ -1,56 +1,59 @@ -'use client' +"use client"; -import { createContext, useContext, useEffect, useState } from 'react' -import { Session, createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs' -import { useRouter } from 'next/navigation' +import type { SupabaseClient } from "@supabase/auth-helpers-nextjs"; +import { + createBrowserSupabaseClient, + Session, +} from "@supabase/auth-helpers-nextjs"; +import { useRouter } from "next/navigation"; +import { createContext, useContext, useEffect, useState } from "react"; -import type { SupabaseClient } from '@supabase/auth-helpers-nextjs' - - -type MaybeSession = Session | null +type MaybeSession = Session | null; type SupabaseContext = { - supabase: SupabaseClient - session: MaybeSession -} + supabase: SupabaseClient; + session: MaybeSession; +}; -const Context = createContext(undefined) +const Context = createContext(undefined); -export default function SupabaseProvider({ +const SupabaseProvider = ({ children, session, }: { - children: React.ReactNode - session: MaybeSession -}) { - const [supabase] = useState(() => createBrowserSupabaseClient()) - const router = useRouter() + children: React.ReactNode; + session: MaybeSession; +}): JSX.Element => { + const [supabase] = useState(() => createBrowserSupabaseClient()); + const router = useRouter(); useEffect(() => { const { data: { subscription }, } = supabase.auth.onAuthStateChange(() => { - router.refresh() - }) + router.refresh(); + }); return () => { - subscription.unsubscribe() - } - }, [router, supabase]) + subscription.unsubscribe(); + }; + }, [router, supabase]); return ( <>{children} - ) -} + ); +}; -export const useSupabase = () => { - const context = useContext(Context) +export const useSupabase = (): SupabaseContext => { + const context = useContext(Context); if (context === undefined) { - throw new Error('useSupabase must be used inside SupabaseProvider') + throw new Error("useSupabase must be used inside SupabaseProvider"); } - return context -} + return context; +}; + +export default SupabaseProvider; diff --git a/frontend/app/upload/components/Crawler/helpers/isValidUrl.ts b/frontend/app/upload/components/Crawler/helpers/isValidUrl.ts index 908f9b1c8..3f86d1ad5 100644 --- a/frontend/app/upload/components/Crawler/helpers/isValidUrl.ts +++ b/frontend/app/upload/components/Crawler/helpers/isValidUrl.ts @@ -1,6 +1,7 @@ -export const isValidUrl = (string: string) => { +export const isValidUrl = (string: string): boolean => { try { new URL(string); + return true; } catch (_) { return false; diff --git a/frontend/app/upload/components/Crawler/hooks/useCrawler.ts b/frontend/app/upload/components/Crawler/hooks/useCrawler.ts index f334fc6bb..6be8d5282 100644 --- a/frontend/app/upload/components/Crawler/hooks/useCrawler.ts +++ b/frontend/app/upload/components/Crawler/hooks/useCrawler.ts @@ -1,8 +1,11 @@ +/* eslint-disable */ +import { redirect } from "next/navigation"; +import { useCallback, useRef, useState } from "react"; + import { useSupabase } from "@/app/supabase-provider"; import { useToast } from "@/lib/hooks/useToast"; import { useAxios } from "@/lib/useAxios"; -import { redirect } from "next/navigation"; -import { useCallback, useRef, useState } from "react"; + import { isValidUrl } from "../helpers/isValidUrl"; export const useCrawler = () => { @@ -26,6 +29,7 @@ export const useCrawler = () => { variant: "danger", text: "Invalid URL", }); + return; } diff --git a/frontend/app/upload/components/Crawler/index.tsx b/frontend/app/upload/components/Crawler/index.tsx index 0284e4930..71599a946 100644 --- a/frontend/app/upload/components/Crawler/index.tsx +++ b/frontend/app/upload/components/Crawler/index.tsx @@ -2,10 +2,12 @@ import Button from "@/lib/components/ui/Button"; import Card from "@/lib/components/ui/Card"; import Field from "@/lib/components/ui/Field"; + import { useCrawler } from "./hooks/useCrawler"; export const Crawler = (): JSX.Element => { const { urlInputRef, isCrawling, crawlWebsite } = useCrawler(); + return (
diff --git a/frontend/app/upload/components/FileUploader/components/FileComponent.tsx b/frontend/app/upload/components/FileUploader/components/FileComponent.tsx index fbaa1ccdd..a0f90c7bf 100644 --- a/frontend/app/upload/components/FileUploader/components/FileComponent.tsx +++ b/frontend/app/upload/components/FileUploader/components/FileComponent.tsx @@ -1,5 +1,6 @@ +/* eslint-disable */ import { motion } from "framer-motion"; -import { Dispatch, RefObject, SetStateAction, forwardRef } from "react"; +import { Dispatch, forwardRef, RefObject, SetStateAction } from "react"; import { MdClose } from "react-icons/md"; interface FileComponentProps { diff --git a/frontend/app/upload/components/FileUploader/hooks/useFileUploader.ts b/frontend/app/upload/components/FileUploader/hooks/useFileUploader.ts index 201980eac..d7eb25266 100644 --- a/frontend/app/upload/components/FileUploader/hooks/useFileUploader.ts +++ b/frontend/app/upload/components/FileUploader/hooks/useFileUploader.ts @@ -1,10 +1,12 @@ -import { useSupabase } from "@/app/supabase-provider"; -import { useToast } from "@/lib/hooks/useToast"; -import { useAxios } from "@/lib/useAxios"; +/* eslint-disable */ import { redirect } from "next/navigation"; import { useCallback, useState } from "react"; import { FileRejection, useDropzone } from "react-dropzone"; +import { useSupabase } from "@/app/supabase-provider"; +import { useToast } from "@/lib/hooks/useToast"; +import { useAxios } from "@/lib/useAxios"; + export const useFileUploader = () => { const [isPending, setIsPending] = useState(false); const { publish } = useToast(); @@ -44,6 +46,7 @@ export const useFileUploader = () => { const onDrop = (acceptedFiles: File[], fileRejections: FileRejection[]) => { if (fileRejections.length > 0) { publish({ variant: "danger", text: "File too big." }); + return; } @@ -69,6 +72,7 @@ export const useFileUploader = () => { text: "Please, add files to upload", variant: "warning", }); + return; } setIsPending(true); diff --git a/frontend/app/upload/components/FileUploader/index.tsx b/frontend/app/upload/components/FileUploader/index.tsx index 417daa180..c4bfb1df5 100644 --- a/frontend/app/upload/components/FileUploader/index.tsx +++ b/frontend/app/upload/components/FileUploader/index.tsx @@ -1,7 +1,10 @@ +/* eslint-disable */ "use client"; +import { AnimatePresence } from "framer-motion"; + import Button from "@/lib/components/ui/Button"; import Card from "@/lib/components/ui/Card"; -import { AnimatePresence } from "framer-motion"; + import FileComponent from "./components/FileComponent"; import { useFileUploader } from "./hooks/useFileUploader"; diff --git a/frontend/app/upload/page.tsx b/frontend/app/upload/page.tsx index dd7e12e5e..909013365 100644 --- a/frontend/app/upload/page.tsx +++ b/frontend/app/upload/page.tsx @@ -1,12 +1,14 @@ "use client"; +import Link from "next/link"; + import Button from "@/lib/components/ui/Button"; import { Divider } from "@/lib/components/ui/Divider"; import PageHeading from "@/lib/components/ui/PageHeading"; -import Link from "next/link"; + import { Crawler } from "./components/Crawler"; import { FileUploader } from "./components/FileUploader"; -export default function UploadPage() { +const UploadPage = (): JSX.Element => { return (
); -} +}; + +export default UploadPage; diff --git a/frontend/app/user/components/BrainConsumption.tsx b/frontend/app/user/components/BrainConsumption.tsx index 7703d20b5..fae35dd0a 100644 --- a/frontend/app/user/components/BrainConsumption.tsx +++ b/frontend/app/user/components/BrainConsumption.tsx @@ -1,4 +1,5 @@ import { GiBrain } from "react-icons/gi"; + import { UserStats } from "../../../lib/types/User"; export const BrainConsumption = (userStats: UserStats): JSX.Element => { @@ -27,6 +28,7 @@ export const BrainConsumption = (userStats: UserStats): JSX.Element => { className="fill-pink-300 stroke-black stoke-1" /> ); + return (
diff --git a/frontend/app/user/components/Date.tsx b/frontend/app/user/components/Date.tsx index 58f2d9984..23a8d7201 100644 --- a/frontend/app/user/components/Date.tsx +++ b/frontend/app/user/components/Date.tsx @@ -1,4 +1,5 @@ import { HTMLAttributes } from "react"; + import { UserStats } from "../../../lib/types/User"; interface DateComponentProps extends HTMLAttributes { diff --git a/frontend/app/user/components/Graphs/BrainSpaceChart.tsx b/frontend/app/user/components/Graphs/BrainSpaceChart.tsx index 87809c3fd..c0147f7cd 100644 --- a/frontend/app/user/components/Graphs/BrainSpaceChart.tsx +++ b/frontend/app/user/components/Graphs/BrainSpaceChart.tsx @@ -1,5 +1,4 @@ "use client"; -import { FC } from "react"; import { VictoryContainer, VictoryPie, @@ -12,26 +11,29 @@ interface BrainSpaceChartProps extends VictoryPieProps { max_brain_size: number; } -const BrainSpaceChart: FC = ({ +const BrainSpaceChart = ({ current_brain_size, max_brain_size, ...props -}) => { +}: BrainSpaceChartProps): JSX.Element => { return ( - - } - {...props} - theme={VictoryTheme.material} - /> + <> + {/* @ts-expect-error Server Component */} + + } + {...props} + theme={VictoryTheme.material} + /> + ); }; diff --git a/frontend/app/user/components/Graphs/RequestsPerDayChart.tsx b/frontend/app/user/components/Graphs/RequestsPerDayChart.tsx index 3563a2c61..66a2bf211 100644 --- a/frontend/app/user/components/Graphs/RequestsPerDayChart.tsx +++ b/frontend/app/user/components/Graphs/RequestsPerDayChart.tsx @@ -1,6 +1,6 @@ +/* eslint-disable */ "use client"; import { format, subDays } from "date-fns"; -import React from "react"; import { VictoryAxis, VictoryChart, @@ -20,14 +20,15 @@ interface RequestsPerDayChartProps extends VictoryChartProps { requests_stats: RequestStat[]; } -export const RequestsPerDayChart: React.FC = ({ +export const RequestsPerDayChart = ({ requests_stats, ...props -}) => { +}: RequestsPerDayChartProps): JSX.Element => { const data = Array.from({ length: 7 }, (_, i) => subDays(new Date(), i)) .map((date) => { const dateString = format(date, "yyyyMMdd"); const stat = requests_stats.find((s) => s.date === dateString); + return { date: format(date, "MM/dd/yyyy"), requests_count: stat ? stat.requests_count : 0, @@ -50,12 +51,15 @@ export const RequestsPerDayChart: React.FC = ({ }} {...props} > + {/* @ts-expect-error Server Component */} { return `${tick.split("/")[0]}/${tick.split("/")[1]}`; }} /> + {/* @ts-expect-error Server Component */} + {/* @ts-expect-error Server Component */} ); diff --git a/frontend/app/user/components/UserStatistics.tsx b/frontend/app/user/components/UserStatistics.tsx index f265cc4ac..45956c6e4 100644 --- a/frontend/app/user/components/UserStatistics.tsx +++ b/frontend/app/user/components/UserStatistics.tsx @@ -1,10 +1,13 @@ +/* eslint-disable */ "use client"; -import Button from "@/lib/components/ui/Button"; -import { cn } from "@/lib/utils"; import Link from "next/link"; import prettyBytes from "pretty-bytes"; import { HTMLAttributes } from "react"; -import { UserStats } from "../../../lib/types/User"; + +import Button from "@/lib/components/ui/Button"; +import { UserStats } from "@/lib/types/User"; +import { cn } from "@/lib/utils"; + import { BrainConsumption } from "./BrainConsumption"; import { DateComponent } from "./Date"; import BrainSpaceChart from "./Graphs/BrainSpaceChart"; @@ -13,6 +16,7 @@ import { RequestsPerDayChart } from "./Graphs/RequestsPerDayChart"; export const UserStatistics = (userStats: UserStats): JSX.Element => { const { email, current_brain_size, max_brain_size, date, requests_stats } = userStats; + return ( <>
diff --git a/frontend/app/user/components/index.ts b/frontend/app/user/components/index.ts index bd486c54c..79885d5c5 100644 --- a/frontend/app/user/components/index.ts +++ b/frontend/app/user/components/index.ts @@ -1 +1 @@ -export { UserStatistics } from "./UserStatistics"; \ No newline at end of file +export { UserStatistics } from "./UserStatistics"; diff --git a/frontend/app/user/page.tsx b/frontend/app/user/page.tsx index 4b55bdf7e..ed7b6cd72 100644 --- a/frontend/app/user/page.tsx +++ b/frontend/app/user/page.tsx @@ -1,13 +1,16 @@ +/* eslint-disable */ "use client"; -import Spinner from "@/lib/components/ui/Spinner"; -import { useAxios } from "@/lib/useAxios"; import { redirect } from "next/navigation"; import { useEffect, useState } from "react"; -import { UserStats } from "../../lib/types/User"; + +import Spinner from "@/lib/components/ui/Spinner"; +import { UserStats } from "@/lib/types/User"; +import { useAxios } from "@/lib/useAxios"; + import { useSupabase } from "../supabase-provider"; import { UserStatistics } from "./components/UserStatistics"; -export default function UserPage() { +const UserPage = (): JSX.Element => { const [userStats, setUserStats] = useState(); const { session } = useSupabase(); const { axiosInstance } = useAxios(); @@ -57,4 +60,5 @@ export default function UserPage() { ); -} +}; +export default UserPage; diff --git a/frontend/lib/components/Footer/index.tsx b/frontend/lib/components/Footer/index.tsx index 70c723151..79fb241da 100644 --- a/frontend/lib/components/Footer/index.tsx +++ b/frontend/lib/components/Footer/index.tsx @@ -1,4 +1,4 @@ -const Footer = () => { +const Footer = (): JSX.Element => { return (