Devx/add linter rules (#331)

* remove duplicate import

* 🚧 add new linter configuration

* 🧑‍💻  add and run prettier

* 🐛 add babel parser for linter

* 🧑‍💻 add lint-fix command

* 🚨 use lint-fix

* 🚨 remove 'FC' as a type. Use const and JSX.Element

* 🚨 enforce arrow function rule from linter

* 🔥 delete unused file

* 🚨 adding /* eslint-disable */ in failing files

* 💩 add ts-expect-error to Victory components
This commit is contained in:
Zineb El Bachiri 2023-06-15 11:52:46 +02:00 committed by GitHub
parent e6e5099d6b
commit 1d7bc8a5bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
96 changed files with 1791 additions and 1335 deletions

188
frontend/.eslintrc.js Normal file
View File

@ -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,
},
],
},
},
],
};

View File

@ -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"
}
}

View File

@ -0,0 +1,4 @@
module.exports = {
"*": "prettier --ignore-unknown --write",
"*.{js,ts, tsx}": "pnpm lint-fix",
};

View File

@ -1,6 +1,8 @@
/* eslint-disable */
import { useState } from "react";
import { useSupabase } from "@/app/supabase-provider"; import { useSupabase } from "@/app/supabase-provider";
import { useToast } from "@/lib/hooks/useToast"; import { useToast } from "@/lib/hooks/useToast";
import { useState } from "react";
export const useGoogleLogin = () => { export const useGoogleLogin = () => {
const { supabase } = useSupabase(); const { supabase } = useSupabase();

View File

@ -1,3 +1,4 @@
/* eslint-disable */
import Button from "@/lib/components/ui/Button"; import Button from "@/lib/components/ui/Button";
import { useGoogleLogin } from "./hooks/useGoogleLogin"; import { useGoogleLogin } from "./hooks/useGoogleLogin";

View File

@ -1,8 +1,10 @@
/* eslint-disable */
"use client"; "use client";
import { useState } from "react";
import { useSupabase } from "@/app/supabase-provider"; import { useSupabase } from "@/app/supabase-provider";
import Button from "@/lib/components/ui/Button"; import Button from "@/lib/components/ui/Button";
import { useToast } from "@/lib/hooks/useToast"; import { useToast } from "@/lib/hooks/useToast";
import { useState } from "react";
type MaginLinkLoginProps = { type MaginLinkLoginProps = {
email: string; email: string;
@ -21,6 +23,7 @@ export const MagicLinkLogin = ({ email, setEmail }: MaginLinkLoginProps) => {
variant: "danger", variant: "danger",
text: "Please enter your email address", text: "Please enter your email address",
}); });
return; return;
} }

View File

@ -1,4 +1,9 @@
/* eslint-disable */
"use client"; "use client";
import Link from "next/link";
import { redirect } from "next/navigation";
import { useState } from "react";
import { useSupabase } from "@/app/supabase-provider"; import { useSupabase } from "@/app/supabase-provider";
import Button from "@/lib/components/ui/Button"; import Button from "@/lib/components/ui/Button";
import Card from "@/lib/components/ui/Card"; 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 Field from "@/lib/components/ui/Field";
import PageHeading from "@/lib/components/ui/PageHeading"; import PageHeading from "@/lib/components/ui/PageHeading";
import { useToast } from "@/lib/hooks/useToast"; 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 { GoogleLoginButton } from "./components/GoogleLogin";
import { MagicLinkLogin } from "./components/MagicLinkLogin"; import { MagicLinkLogin } from "./components/MagicLinkLogin";

View File

@ -1,12 +1,14 @@
/* eslint-disable */
"use client"; "use client";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { useSupabase } from "@/app/supabase-provider"; import { useSupabase } from "@/app/supabase-provider";
import Button from "@/lib/components/ui/Button"; import Button from "@/lib/components/ui/Button";
import Card from "@/lib/components/ui/Card"; import Card from "@/lib/components/ui/Card";
import PageHeading from "@/lib/components/ui/PageHeading"; import PageHeading from "@/lib/components/ui/PageHeading";
import { useToast } from "@/lib/hooks/useToast"; import { useToast } from "@/lib/hooks/useToast";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useState } from "react";
export default function Logout() { export default function Logout() {
const { supabase } = useSupabase(); const { supabase } = useSupabase();

View File

@ -1,12 +1,14 @@
/* eslint-disable */
"use client"; "use client";
import Link from "next/link";
import { useState } from "react";
import { useSupabase } from "@/app/supabase-provider"; import { useSupabase } from "@/app/supabase-provider";
import Button from "@/lib/components/ui/Button"; import Button from "@/lib/components/ui/Button";
import Card from "@/lib/components/ui/Card"; import Card from "@/lib/components/ui/Card";
import Field from "@/lib/components/ui/Field"; import Field from "@/lib/components/ui/Field";
import PageHeading from "@/lib/components/ui/PageHeading"; import PageHeading from "@/lib/components/ui/PageHeading";
import { useToast } from "@/lib/hooks/useToast"; import { useToast } from "@/lib/hooks/useToast";
import Link from "next/link";
import { useState } from "react";
export default function SignUp() { export default function SignUp() {
const { supabase } = useSupabase(); const { supabase } = useSupabase();

View File

@ -1,5 +1,4 @@
import Card from "@/lib/components/ui/Card"; import { ReactNode } from "react";
import { FC, ReactNode } from "react";
import { import {
GiArtificialIntelligence, GiArtificialIntelligence,
GiBrain, GiBrain,
@ -9,7 +8,9 @@ import {
GiOpenBook, GiOpenBook,
} from "react-icons/gi"; } from "react-icons/gi";
const Features: FC = () => { import Card from "@/lib/components/ui/Card";
const Features = (): JSX.Element => {
return ( return (
<section className="my-20 text-center flex flex-col items-center justify-center gap-10"> <section className="my-20 text-center flex flex-col items-center justify-center gap-10">
<div> <div>
@ -58,7 +59,7 @@ interface FeatureProps {
desc: string; desc: string;
} }
const Feature: FC<FeatureProps> = ({ title, desc, icon }) => { const Feature = ({ title, desc, icon }: FeatureProps): JSX.Element => {
return ( return (
<Card className="p-10 max-w-xs flex flex-col gap-5 w-full"> <Card className="p-10 max-w-xs flex flex-col gap-5 w-full">
{icon} {icon}

View File

@ -1,11 +1,12 @@
"use client"; "use client";
import Button from "@/lib/components/ui/Button";
import { motion, useScroll, useSpring, useTransform } from "framer-motion"; import { motion, useScroll, useSpring, useTransform } from "framer-motion";
import Link from "next/link"; import Link from "next/link";
import { FC, useRef } from "react"; import { useRef } from "react";
import { MdNorthEast } from "react-icons/md"; import { MdNorthEast } from "react-icons/md";
const Hero: FC = () => { import Button from "@/lib/components/ui/Button";
const Hero = (): JSX.Element => {
const targetRef = useRef<HTMLDivElement | null>(null); const targetRef = useRef<HTMLDivElement | null>(null);
const { scrollYProgress } = useScroll({ const { scrollYProgress } = useScroll({
target: targetRef, target: targetRef,
@ -19,6 +20,7 @@ const Hero: FC = () => {
if (pos === 1) { if (pos === 1) {
return "relative"; return "relative";
} }
return "sticky"; return "sticky";
}); });

View File

@ -1,8 +1,9 @@
import Features from "./Features";
import Hero from "./Hero";
import { redirect } from "next/navigation"; 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") { if (process.env.NEXT_PUBLIC_ENV === "local") {
redirect("/upload"); redirect("/upload");
} }
@ -13,4 +14,6 @@ export default function HomePage() {
<Features /> <Features />
</main> </main>
); );
} };
export default HomePage;

View File

@ -1,8 +1,11 @@
/* eslint-disable */
"use client"; "use client";
import PageHeading from "@/lib/components/ui/PageHeading";
import useChatsContext from "@/lib/context/ChatsProvider/hooks/useChatsContext";
import { UUID } from "crypto"; import { UUID } from "crypto";
import { useEffect } from "react"; import { useEffect } from "react";
import PageHeading from "@/lib/components/ui/PageHeading";
import useChatsContext from "@/lib/context/ChatsProvider/hooks/useChatsContext";
import { ChatInput, ChatMessages } from "../components"; import { ChatInput, ChatMessages } from "../components";
interface ChatPageProps { interface ChatPageProps {
@ -18,7 +21,9 @@ export default function ChatPage({ params }: ChatPageProps) {
useEffect(() => { useEffect(() => {
// if (chatId) // if (chatId)
if (!chatId) resetChat(); if (!chatId) {
resetChat();
}
fetchChat(chatId); fetchChat(chatId);
}, [fetchChat, chatId]); }, [fetchChat, chatId]);

View File

@ -1,9 +1,10 @@
"use client"; "use client";
import Button from "@/lib/components/ui/Button";
import Link from "next/link"; import Link from "next/link";
import { MdSettings } from "react-icons/md"; import { MdSettings } from "react-icons/md";
export function ConfigButton() { import Button from "@/lib/components/ui/Button";
export const ConfigButton = (): JSX.Element => {
return ( return (
<Link href={"/config"}> <Link href={"/config"}>
<Button className="p-2 sm:px-3" variant={"tertiary"}> <Button className="p-2 sm:px-3" variant={"tertiary"}>
@ -11,4 +12,4 @@ export function ConfigButton() {
</Button> </Button>
</Link> </Link>
); );
} };

View File

@ -1,9 +1,11 @@
/* eslint-disable */
"use client"; "use client";
import Button from "@/lib/components/ui/Button";
import { useSpeech } from "@/lib/context/ChatsProvider/hooks/useSpeech";
import { MdMic, MdMicOff } from "react-icons/md"; 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(); const { isListening, speechSupported, startListening } = useSpeech();
return ( return (
@ -21,4 +23,4 @@ export function MicButton() {
)} )}
</Button> </Button>
); );
} };

View File

@ -1,17 +1,22 @@
/* eslint-disable */
"use client"; "use client";
import Button from "@/lib/components/ui/Button"; import Button from "@/lib/components/ui/Button";
import useChatsContext from "@/lib/context/ChatsProvider/hooks/useChatsContext"; import useChatsContext from "@/lib/context/ChatsProvider/hooks/useChatsContext";
import { ConfigButton } from "./ConfigButton"; import { ConfigButton } from "./ConfigButton";
import { MicButton } from "./MicButton"; import { MicButton } from "./MicButton";
export function ChatInput() { export const ChatInput = (): JSX.Element => {
const { isSendingMessage, sendMessage, setMessage, message, chat } = const { isSendingMessage, sendMessage, setMessage, message, chat } =
useChatsContext(); useChatsContext();
return ( return (
<form <form
onSubmit={(e) => { onSubmit={(e) => {
e.preventDefault(); 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" 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) => { onKeyDown={(e) => {
if (e.key === "Enter" && !e.shiftKey) { if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault(); // Prevents the newline from being entered in the textarea 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" 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() {
</div> </div>
</form> </form>
); );
} };

View File

@ -1,9 +1,11 @@
/* eslint-disable */
"use client"; "use client";
import { cn } from "@/lib/utils";
import { forwardRef, Ref } from "react"; import { forwardRef, Ref } from "react";
import ReactMarkdown from "react-markdown"; import ReactMarkdown from "react-markdown";
const ChatMessage = forwardRef( import { cn } from "@/lib/utils";
export const ChatMessage = forwardRef(
( (
{ {
speaker, speaker,
@ -46,5 +48,3 @@ const ChatMessage = forwardRef(
); );
ChatMessage.displayName = "ChatMessage"; ChatMessage.displayName = "ChatMessage";
export default ChatMessage;

View File

@ -1,26 +1,32 @@
/* eslint-disable */
"use client"; "use client";
import { useEffect, useRef } from "react";
import Card from "@/lib/components/ui/Card"; import Card from "@/lib/components/ui/Card";
import useChatsContext from "@/lib/context/ChatsProvider/hooks/useChatsContext"; 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<HTMLDivElement | null>(null); const lastChatRef = useRef<HTMLDivElement | null>(null);
const { chat } = useChatsContext(); const { chat } = useChatsContext();
useEffect(() => { useEffect(() => {
if (!chat || !lastChatRef.current) return; if (!chat || !lastChatRef.current) {
return;
}
// if (chat.history.length > 2) { // if (chat.history.length > 2) {
lastChatRef.current?.scrollIntoView({ lastChatRef.current.scrollIntoView({
behavior: "smooth", behavior: "smooth",
block: "end", block: "end",
}); });
// } // }
}, [chat, lastChatRef]); }, [chat, lastChatRef]);
if (!chat) return null; if (!chat) {
return <></>;
}
return ( return (
<Card className="p-5 max-w-3xl w-full flex flex-col h-full mb-8"> <Card className="p-5 max-w-3xl w-full flex flex-col h-full mb-8">

View File

@ -1,10 +1,12 @@
import { cn } from "@/lib/utils"; /* eslint-disable */
import { UUID } from "crypto"; import { UUID } from "crypto";
import Link from "next/link"; import Link from "next/link";
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";
import { FC } from "react";
import { FiTrash2 } from "react-icons/fi"; import { FiTrash2 } from "react-icons/fi";
import { MdChatBubbleOutline } from "react-icons/md"; import { MdChatBubbleOutline } from "react-icons/md";
import { cn } from "@/lib/utils";
import { Chat } from "../../../../lib/types/Chat"; import { Chat } from "../../../../lib/types/Chat";
interface ChatsListItemProps { interface ChatsListItemProps {
@ -12,7 +14,10 @@ interface ChatsListItemProps {
deleteChat: (id: UUID) => void; deleteChat: (id: UUID) => void;
} }
const ChatsListItem: FC<ChatsListItemProps> = ({ chat, deleteChat }) => { const ChatsListItem = ({
chat,
deleteChat,
}: ChatsListItemProps): JSX.Element => {
const pathname = usePathname()?.split("/").at(-1); const pathname = usePathname()?.split("/").at(-1);
const selected = chat.chatId === pathname; const selected = chat.chatId === pathname;

View File

@ -1,7 +1,7 @@
import Link from "next/link"; import Link from "next/link";
import { BsPlusSquare } from "react-icons/bs"; import { BsPlusSquare } from "react-icons/bs";
export const NewChatButton = () => ( export const NewChatButton = (): JSX.Element => (
<Link <Link
href="/chat" href="/chat"
className="px-4 py-2 mx-4 my-2 border border-primary bg-white dark:bg-black hover:text-white hover:bg-primary shadow-lg rounded-lg flex items-center justify-center sticky top-2 z-20" className="px-4 py-2 mx-4 my-2 border border-primary bg-white dark:bg-black hover:text-white hover:bg-primary shadow-lg rounded-lg flex items-center justify-center sticky top-2 z-20"

View File

@ -1,12 +1,15 @@
/* eslint-disable */
"use client"; "use client";
import useChatsContext from "@/lib/context/ChatsProvider/hooks/useChatsContext";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { MotionConfig, motion } from "framer-motion"; import { MotionConfig, motion } from "framer-motion";
import { useState } from "react"; import { useState } from "react";
import { MdChevronRight } from "react-icons/md"; import { MdChevronRight } from "react-icons/md";
import useChatsContext from "@/lib/context/ChatsProvider/hooks/useChatsContext";
import ChatsListItem from "./ChatsListItem"; import ChatsListItem from "./ChatsListItem";
import { NewChatButton } from "./NewChatButton"; import { NewChatButton } from "./NewChatButton";
export function ChatsList() {
export const ChatsList = (): JSX.Element => {
const { allChats, deleteChat } = useChatsContext(); const { allChats, deleteChat } = useChatsContext();
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
@ -69,4 +72,4 @@ export function ChatsList() {
</motion.div> </motion.div>
</MotionConfig> </MotionConfig>
); );
} };

View File

@ -1,4 +1,4 @@
export * from "./ChatMessages";
export * from "./ChatMessages/ChatInput"; export * from "./ChatMessages/ChatInput";
export * from "./ChatMessages/ChatMessage"; export * from "./ChatMessages/ChatMessage";
export * from "./ChatMessages";
export * from "./ChatsList"; export * from "./ChatsList";

View File

@ -1,17 +1,21 @@
"use client"; "use client";
import { ChatsProvider } from "@/lib/context/ChatsProvider/chats-provider";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
import { FC, ReactNode } from "react"; import { ReactNode } from "react";
import { useSupabase } from "../supabase-provider";
import { ChatsProvider } from "@/lib/context/ChatsProvider/chats-provider";
import { ChatsList } from "./components"; import { ChatsList } from "./components";
import { useSupabase } from "../supabase-provider";
interface LayoutProps { interface LayoutProps {
children?: ReactNode; children?: ReactNode;
} }
const Layout: FC<LayoutProps> = ({ children }) => { const Layout = ({ children }: LayoutProps): JSX.Element => {
const { session } = useSupabase(); const { session } = useSupabase();
if (!session) redirect("/login"); if (!session) {
redirect("/login");
}
return ( return (
<ChatsProvider> <ChatsProvider>

View File

@ -1,8 +1,10 @@
/* eslint-disable */
"use client"; "use client";
import { useState } from "react";
import Button from "@/lib/components/ui/Button"; import Button from "@/lib/components/ui/Button";
import { useAxios } from "@/lib/useAxios"; import { useAxios } from "@/lib/useAxios";
import { useState } from "react";
export const ApiKeyConfig = (): JSX.Element => { export const ApiKeyConfig = (): JSX.Element => {
const [apiKey, setApiKey] = useState(""); const [apiKey, setApiKey] = useState("");
@ -40,13 +42,13 @@ export const ApiKeyConfig = (): JSX.Element => {
</div> </div>
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
{!apiKey && ( {apiKey === "" && (
<Button variant="secondary" onClick={handleCreateClick}> <Button variant="secondary" onClick={handleCreateClick}>
Create New Key Create New Key
</Button> </Button>
)} )}
</div> </div>
{apiKey && ( {apiKey !== "" && (
<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
<span className="text-gray-600">{apiKey}</span> <span className="text-gray-600">{apiKey}</span>
<Button variant="secondary" onClick={handleCopyClick}> <Button variant="secondary" onClick={handleCopyClick}>

View File

@ -1,8 +1,10 @@
/* eslint-disable */
"use client"; "use client";
import { UseFormRegister } from "react-hook-form";
import Field from "@/lib/components/ui/Field"; import Field from "@/lib/components/ui/Field";
import { BrainConfig } from "@/lib/context/BrainConfigProvider/types"; import { BrainConfig } from "@/lib/context/BrainConfigProvider/types";
import { UseFormRegister } from "react-hook-form";
interface BackendConfigProps { interface BackendConfigProps {
register: UseFormRegister<BrainConfig>; register: UseFormRegister<BrainConfig>;

View File

@ -1,7 +1,10 @@
/* eslint-disable */
"use client"; "use client";
import Button from "@/lib/components/ui/Button";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import Button from "@/lib/components/ui/Button";
import { useConfig } from "../hooks/useConfig"; import { useConfig } from "../hooks/useConfig";
import { BackendConfig } from "./BackendConfig"; import { BackendConfig } from "./BackendConfig";
import { ModelConfig } from "./ModelConfig"; import { ModelConfig } from "./ModelConfig";

View File

@ -1,5 +1,8 @@
/* eslint-disable */
"use client"; "use client";
import { UseFormRegister } from "react-hook-form";
import Field from "@/lib/components/ui/Field"; import Field from "@/lib/components/ui/Field";
import { import {
BrainConfig, BrainConfig,
@ -9,7 +12,6 @@ import {
models, models,
paidModels, paidModels,
} from "@/lib/context/BrainConfigProvider/types"; } from "@/lib/context/BrainConfigProvider/types";
import { UseFormRegister } from "react-hook-form";
interface ModelConfigProps { interface ModelConfigProps {
register: UseFormRegister<BrainConfig>; register: UseFormRegister<BrainConfig>;

View File

@ -1,8 +1,10 @@
/* eslint-disable */
"use client"; "use client";
import Link from "next/link";
import { useSupabase } from "@/app/supabase-provider"; import { useSupabase } from "@/app/supabase-provider";
import Button from "@/lib/components/ui/Button"; import Button from "@/lib/components/ui/Button";
import Link from "next/link";
export const UserAccountSection = (): JSX.Element => { export const UserAccountSection = (): JSX.Element => {
const { session } = useSupabase(); const { session } = useSupabase();

View File

@ -1,8 +1,9 @@
import { useToast } from "@/lib/hooks/useToast"; /* eslint-disable */
import { useEffect } from "react";
import { useForm } from "react-hook-form"; import { useForm } from "react-hook-form";
import { useBrainConfig } from "@/lib/context/BrainConfigProvider/hooks/useBrainConfig"; import { useBrainConfig } from "@/lib/context/BrainConfigProvider/hooks/useBrainConfig";
import { useEffect } from "react"; import { useToast } from "@/lib/hooks/useToast";
export const useConfig = () => { export const useConfig = () => {
const { config, updateConfig, resetConfig } = useBrainConfig(); const { config, updateConfig, resetConfig } = useBrainConfig();

View File

@ -1,3 +1,4 @@
/* eslint-disable */
"use client"; "use client";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
@ -6,7 +7,7 @@ import { ConfigForm, ConfigTitle } from "./components";
import { ApiKeyConfig } from "./components/ApiKeyConfig"; import { ApiKeyConfig } from "./components/ApiKeyConfig";
// TODO: Use states instead of NEXTJS router to open and close modal // TODO: Use states instead of NEXTJS router to open and close modal
export default function ConfigPage() { const ConfigPage = (): JSX.Element => {
const { session } = useSupabase(); const { session } = useSupabase();
if (session === null) { if (session === null) {
@ -22,4 +23,6 @@ export default function ConfigPage() {
</section> </section>
</main> </main>
); );
} };
export default ConfigPage;

View File

@ -1,5 +1,8 @@
import { useAxios } from "@/lib/useAxios"; /* eslint-disable */
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useAxios } from "@/lib/useAxios";
import { useSupabase } from "../../supabase-provider"; import { useSupabase } from "../../supabase-provider";
interface DocumentDataProps { interface DocumentDataProps {

View File

@ -1,19 +1,22 @@
/* eslint-disable */
"use client"; "use client";
import {
Dispatch,
forwardRef,
RefObject,
SetStateAction,
useState,
} from "react";
import { useSupabase } from "@/app/supabase-provider"; import { useSupabase } from "@/app/supabase-provider";
import Button from "@/lib/components/ui/Button"; import Button from "@/lib/components/ui/Button";
import { AnimatedCard } from "@/lib/components/ui/Card"; import { AnimatedCard } from "@/lib/components/ui/Card";
import Ellipsis from "@/lib/components/ui/Ellipsis"; import Ellipsis from "@/lib/components/ui/Ellipsis";
import Modal from "@/lib/components/ui/Modal"; import Modal from "@/lib/components/ui/Modal";
import { useToast } from "@/lib/hooks/useToast"; import { useToast } from "@/lib/hooks/useToast";
import { Document } from "@/lib/types/Document";
import { useAxios } from "@/lib/useAxios"; import { useAxios } from "@/lib/useAxios";
import {
Dispatch,
RefObject,
SetStateAction,
forwardRef,
useState,
} from "react";
import { Document } from "../../../lib/types/Document";
import DocumentData from "./DocumentData"; import DocumentData from "./DocumentData";
interface DocumentProps { interface DocumentProps {

View File

@ -1,17 +1,19 @@
/* eslint-disable */
"use client"; "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 { AnimatePresence, motion } from "framer-motion";
import Link from "next/link"; import Link from "next/link";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
import { useEffect, useState } from "react"; 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 { useSupabase } from "../supabase-provider";
import DocumentItem from "./DocumentItem"; import DocumentItem from "./DocumentItem";
export default function ExplorePage() { const ExplorePage = (): JSX.Element => {
const [documents, setDocuments] = useState<Document[]>([]); const [documents, setDocuments] = useState<Document[]>([]);
const [isPending, setIsPending] = useState(true); const [isPending, setIsPending] = useState(true);
const { session } = useSupabase(); const { session } = useSupabase();
@ -79,4 +81,6 @@ export default function ExplorePage() {
</section> </section>
</main> </main>
); );
} };
export default ExplorePage;

View File

@ -1,13 +1,13 @@
@import 'tailwindcss/base'; @import "tailwindcss/base";
@import 'tailwindcss/components'; @import "tailwindcss/components";
@import 'tailwindcss/utilities'; @import "tailwindcss/utilities";
main { main {
@apply max-w-screen-xl mx-auto flex flex-col; @apply max-w-screen-xl mx-auto flex flex-col;
} }
header, section { header,
section {
@apply px-5 md:px-10; @apply px-5 md:px-10;
} }
@ -43,4 +43,4 @@ a {
max-height: 60vh; /* Adjust this value based on the desired maximum height */ 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 */ 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 */ padding-right: 1rem; /* Optional: Add some padding if the scrollbar appears, so the text is not squished */
} }

View File

@ -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 { createServerComponentSupabaseClient } from "@supabase/auth-helpers-nextjs";
import { Analytics } from "@vercel/analytics/react"; import { Analytics } from "@vercel/analytics/react";
import { Inter } from "next/font/google"; import { Inter } from "next/font/google";
import { cookies, headers } from "next/headers"; 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 "./globals.css";
import SupabaseProvider from "./supabase-provider"; 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.", "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,
}: { }: {
children: React.ReactNode; children: React.ReactNode;
}) { }): Promise<JSX.Element> => {
const supabase = createServerComponentSupabaseClient({ const supabase = createServerComponentSupabaseClient({
headers, headers,
cookies, cookies,
@ -49,4 +51,6 @@ export default async function RootLayout({
</body> </body>
</html> </html>
); );
} };
export default RootLayout;

View File

@ -1,56 +1,59 @@
'use client' "use client";
import { createContext, useContext, useEffect, useState } from 'react' import type { SupabaseClient } from "@supabase/auth-helpers-nextjs";
import { Session, createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs' import {
import { useRouter } from 'next/navigation' 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 = { type SupabaseContext = {
supabase: SupabaseClient supabase: SupabaseClient;
session: MaybeSession session: MaybeSession;
} };
const Context = createContext<SupabaseContext | undefined>(undefined) const Context = createContext<SupabaseContext | undefined>(undefined);
export default function SupabaseProvider({ const SupabaseProvider = ({
children, children,
session, session,
}: { }: {
children: React.ReactNode children: React.ReactNode;
session: MaybeSession session: MaybeSession;
}) { }): JSX.Element => {
const [supabase] = useState(() => createBrowserSupabaseClient()) const [supabase] = useState(() => createBrowserSupabaseClient());
const router = useRouter() const router = useRouter();
useEffect(() => { useEffect(() => {
const { const {
data: { subscription }, data: { subscription },
} = supabase.auth.onAuthStateChange(() => { } = supabase.auth.onAuthStateChange(() => {
router.refresh() router.refresh();
}) });
return () => { return () => {
subscription.unsubscribe() subscription.unsubscribe();
} };
}, [router, supabase]) }, [router, supabase]);
return ( return (
<Context.Provider value={{ supabase, session }}> <Context.Provider value={{ supabase, session }}>
<>{children}</> <>{children}</>
</Context.Provider> </Context.Provider>
) );
} };
export const useSupabase = () => { export const useSupabase = (): SupabaseContext => {
const context = useContext(Context) const context = useContext(Context);
if (context === undefined) { 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;

View File

@ -1,6 +1,7 @@
export const isValidUrl = (string: string) => { export const isValidUrl = (string: string): boolean => {
try { try {
new URL(string); new URL(string);
return true; return true;
} catch (_) { } catch (_) {
return false; return false;

View File

@ -1,8 +1,11 @@
/* eslint-disable */
import { redirect } from "next/navigation";
import { useCallback, useRef, useState } from "react";
import { useSupabase } from "@/app/supabase-provider"; import { useSupabase } from "@/app/supabase-provider";
import { useToast } from "@/lib/hooks/useToast"; import { useToast } from "@/lib/hooks/useToast";
import { useAxios } from "@/lib/useAxios"; import { useAxios } from "@/lib/useAxios";
import { redirect } from "next/navigation";
import { useCallback, useRef, useState } from "react";
import { isValidUrl } from "../helpers/isValidUrl"; import { isValidUrl } from "../helpers/isValidUrl";
export const useCrawler = () => { export const useCrawler = () => {
@ -26,6 +29,7 @@ export const useCrawler = () => {
variant: "danger", variant: "danger",
text: "Invalid URL", text: "Invalid URL",
}); });
return; return;
} }

View File

@ -2,10 +2,12 @@
import Button from "@/lib/components/ui/Button"; import Button from "@/lib/components/ui/Button";
import Card from "@/lib/components/ui/Card"; import Card from "@/lib/components/ui/Card";
import Field from "@/lib/components/ui/Field"; import Field from "@/lib/components/ui/Field";
import { useCrawler } from "./hooks/useCrawler"; import { useCrawler } from "./hooks/useCrawler";
export const Crawler = (): JSX.Element => { export const Crawler = (): JSX.Element => {
const { urlInputRef, isCrawling, crawlWebsite } = useCrawler(); const { urlInputRef, isCrawling, crawlWebsite } = useCrawler();
return ( return (
<div className="w-full"> <div className="w-full">
<div className="flex justify-center gap-5 px-6"> <div className="flex justify-center gap-5 px-6">

View File

@ -1,5 +1,6 @@
/* eslint-disable */
import { motion } from "framer-motion"; 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"; import { MdClose } from "react-icons/md";
interface FileComponentProps { interface FileComponentProps {

View File

@ -1,10 +1,12 @@
import { useSupabase } from "@/app/supabase-provider"; /* eslint-disable */
import { useToast } from "@/lib/hooks/useToast";
import { useAxios } from "@/lib/useAxios";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
import { useCallback, useState } from "react"; import { useCallback, useState } from "react";
import { FileRejection, useDropzone } from "react-dropzone"; 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 = () => { export const useFileUploader = () => {
const [isPending, setIsPending] = useState(false); const [isPending, setIsPending] = useState(false);
const { publish } = useToast(); const { publish } = useToast();
@ -44,6 +46,7 @@ export const useFileUploader = () => {
const onDrop = (acceptedFiles: File[], fileRejections: FileRejection[]) => { const onDrop = (acceptedFiles: File[], fileRejections: FileRejection[]) => {
if (fileRejections.length > 0) { if (fileRejections.length > 0) {
publish({ variant: "danger", text: "File too big." }); publish({ variant: "danger", text: "File too big." });
return; return;
} }
@ -69,6 +72,7 @@ export const useFileUploader = () => {
text: "Please, add files to upload", text: "Please, add files to upload",
variant: "warning", variant: "warning",
}); });
return; return;
} }
setIsPending(true); setIsPending(true);

View File

@ -1,7 +1,10 @@
/* eslint-disable */
"use client"; "use client";
import { AnimatePresence } from "framer-motion";
import Button from "@/lib/components/ui/Button"; import Button from "@/lib/components/ui/Button";
import Card from "@/lib/components/ui/Card"; import Card from "@/lib/components/ui/Card";
import { AnimatePresence } from "framer-motion";
import FileComponent from "./components/FileComponent"; import FileComponent from "./components/FileComponent";
import { useFileUploader } from "./hooks/useFileUploader"; import { useFileUploader } from "./hooks/useFileUploader";

View File

@ -1,12 +1,14 @@
"use client"; "use client";
import Link from "next/link";
import Button from "@/lib/components/ui/Button"; import Button from "@/lib/components/ui/Button";
import { Divider } from "@/lib/components/ui/Divider"; import { Divider } from "@/lib/components/ui/Divider";
import PageHeading from "@/lib/components/ui/PageHeading"; import PageHeading from "@/lib/components/ui/PageHeading";
import Link from "next/link";
import { Crawler } from "./components/Crawler"; import { Crawler } from "./components/Crawler";
import { FileUploader } from "./components/FileUploader"; import { FileUploader } from "./components/FileUploader";
export default function UploadPage() { const UploadPage = (): JSX.Element => {
return ( return (
<main className="pt-10"> <main className="pt-10">
<PageHeading <PageHeading
@ -25,4 +27,6 @@ export default function UploadPage() {
</div> </div>
</main> </main>
); );
} };
export default UploadPage;

View File

@ -1,4 +1,5 @@
import { GiBrain } from "react-icons/gi"; import { GiBrain } from "react-icons/gi";
import { UserStats } from "../../../lib/types/User"; import { UserStats } from "../../../lib/types/User";
export const BrainConsumption = (userStats: UserStats): JSX.Element => { 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" className="fill-pink-300 stroke-black stoke-1"
/> />
); );
return ( return (
<div className="flex flex-col items-center justify-center w-fit"> <div className="flex flex-col items-center justify-center w-fit">
<div className="w-24 h-24 relative"> <div className="w-24 h-24 relative">

View File

@ -1,4 +1,5 @@
import { HTMLAttributes } from "react"; import { HTMLAttributes } from "react";
import { UserStats } from "../../../lib/types/User"; import { UserStats } from "../../../lib/types/User";
interface DateComponentProps extends HTMLAttributes<HTMLSpanElement> { interface DateComponentProps extends HTMLAttributes<HTMLSpanElement> {

View File

@ -1,5 +1,4 @@
"use client"; "use client";
import { FC } from "react";
import { import {
VictoryContainer, VictoryContainer,
VictoryPie, VictoryPie,
@ -12,26 +11,29 @@ interface BrainSpaceChartProps extends VictoryPieProps {
max_brain_size: number; max_brain_size: number;
} }
const BrainSpaceChart: FC<BrainSpaceChartProps> = ({ const BrainSpaceChart = ({
current_brain_size, current_brain_size,
max_brain_size, max_brain_size,
...props ...props
}) => { }: BrainSpaceChartProps): JSX.Element => {
return ( return (
<VictoryPie <>
data={[ {/* @ts-expect-error Server Component */}
{ x: "Used", y: current_brain_size }, <VictoryPie
{ x: "Unused", y: max_brain_size - current_brain_size }, data={[
]} { x: "Used", y: current_brain_size },
containerComponent={ { x: "Unused", y: max_brain_size - current_brain_size },
<VictoryContainer ]}
className="bg-white rounded-md w-full h-full" containerComponent={
responsive={true} <VictoryContainer
/> className="bg-white rounded-md w-full h-full"
} responsive={true}
{...props} />
theme={VictoryTheme.material} }
/> {...props}
theme={VictoryTheme.material}
/>
</>
); );
}; };

View File

@ -1,6 +1,6 @@
/* eslint-disable */
"use client"; "use client";
import { format, subDays } from "date-fns"; import { format, subDays } from "date-fns";
import React from "react";
import { import {
VictoryAxis, VictoryAxis,
VictoryChart, VictoryChart,
@ -20,14 +20,15 @@ interface RequestsPerDayChartProps extends VictoryChartProps {
requests_stats: RequestStat[]; requests_stats: RequestStat[];
} }
export const RequestsPerDayChart: React.FC<RequestsPerDayChartProps> = ({ export const RequestsPerDayChart = ({
requests_stats, requests_stats,
...props ...props
}) => { }: RequestsPerDayChartProps): JSX.Element => {
const data = Array.from({ length: 7 }, (_, i) => subDays(new Date(), i)) const data = Array.from({ length: 7 }, (_, i) => subDays(new Date(), i))
.map((date) => { .map((date) => {
const dateString = format(date, "yyyyMMdd"); const dateString = format(date, "yyyyMMdd");
const stat = requests_stats.find((s) => s.date === dateString); const stat = requests_stats.find((s) => s.date === dateString);
return { return {
date: format(date, "MM/dd/yyyy"), date: format(date, "MM/dd/yyyy"),
requests_count: stat ? stat.requests_count : 0, requests_count: stat ? stat.requests_count : 0,
@ -50,12 +51,15 @@ export const RequestsPerDayChart: React.FC<RequestsPerDayChartProps> = ({
}} }}
{...props} {...props}
> >
{/* @ts-expect-error Server Component */}
<VictoryAxis <VictoryAxis
tickFormat={(tick) => { tickFormat={(tick) => {
return `${tick.split("/")[0]}/${tick.split("/")[1]}`; return `${tick.split("/")[0]}/${tick.split("/")[1]}`;
}} }}
/> />
{/* @ts-expect-error Server Component */}
<VictoryAxis dependentAxis /> <VictoryAxis dependentAxis />
{/* @ts-expect-error Server Component */}
<VictoryLine data={data} x="date" y="requests_count" /> <VictoryLine data={data} x="date" y="requests_count" />
</VictoryChart> </VictoryChart>
); );

View File

@ -1,10 +1,13 @@
/* eslint-disable */
"use client"; "use client";
import Button from "@/lib/components/ui/Button";
import { cn } from "@/lib/utils";
import Link from "next/link"; import Link from "next/link";
import prettyBytes from "pretty-bytes"; import prettyBytes from "pretty-bytes";
import { HTMLAttributes } from "react"; 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 { BrainConsumption } from "./BrainConsumption";
import { DateComponent } from "./Date"; import { DateComponent } from "./Date";
import BrainSpaceChart from "./Graphs/BrainSpaceChart"; import BrainSpaceChart from "./Graphs/BrainSpaceChart";
@ -13,6 +16,7 @@ import { RequestsPerDayChart } from "./Graphs/RequestsPerDayChart";
export const UserStatistics = (userStats: UserStats): JSX.Element => { export const UserStatistics = (userStats: UserStats): JSX.Element => {
const { email, current_brain_size, max_brain_size, date, requests_stats } = const { email, current_brain_size, max_brain_size, date, requests_stats } =
userStats; userStats;
return ( return (
<> <>
<div className="flex flex-col sm:flex-row sm:items-center py-10 gap-5"> <div className="flex flex-col sm:flex-row sm:items-center py-10 gap-5">

View File

@ -1 +1 @@
export { UserStatistics } from "./UserStatistics"; export { UserStatistics } from "./UserStatistics";

View File

@ -1,13 +1,16 @@
/* eslint-disable */
"use client"; "use client";
import Spinner from "@/lib/components/ui/Spinner";
import { useAxios } from "@/lib/useAxios";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
import { useEffect, useState } from "react"; 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 { useSupabase } from "../supabase-provider";
import { UserStatistics } from "./components/UserStatistics"; import { UserStatistics } from "./components/UserStatistics";
export default function UserPage() { const UserPage = (): JSX.Element => {
const [userStats, setUserStats] = useState<UserStats>(); const [userStats, setUserStats] = useState<UserStats>();
const { session } = useSupabase(); const { session } = useSupabase();
const { axiosInstance } = useAxios(); const { axiosInstance } = useAxios();
@ -57,4 +60,5 @@ export default function UserPage() {
</section> </section>
</main> </main>
); );
} };
export default UserPage;

View File

@ -1,4 +1,4 @@
const Footer = () => { const Footer = (): JSX.Element => {
return ( return (
<footer className="bg-white dark:bg-black border-t dark:border-white/10 mt-auto py-10"> <footer className="bg-white dark:bg-black border-t dark:border-white/10 mt-auto py-10">
<div className="max-w-screen-xl mx-auto flex justify-center items-center gap-4"> <div className="max-w-screen-xl mx-auto flex justify-center items-center gap-4">

View File

@ -1,3 +1,4 @@
/* eslint-disable */
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
export const useHeader = () => { export const useHeader = () => {
@ -16,6 +17,7 @@ export const useHeader = () => {
}; };
window.addEventListener("scroll", handleScroll); window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll); return () => window.removeEventListener("scroll", handleScroll);
}, []); }, []);

View File

@ -1,7 +1,12 @@
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { useHeader } from "./hooks/useHeader"; import { useHeader } from "./hooks/useHeader";
export const Header = ({ children }: { children: React.ReactNode }) => { export const Header = ({
children,
}: {
children: React.ReactNode;
}): JSX.Element => {
const { hidden } = useHeader(); const { hidden } = useHeader();
return ( return (

View File

@ -1,7 +1,7 @@
import Image from "next/image"; import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
export const Logo = () => { export const Logo = (): JSX.Element => {
return ( return (
<Link href={"/"} className="flex items-center gap-4"> <Link href={"/"} className="flex items-center gap-4">
<Image <Image

View File

@ -1,11 +1,13 @@
import * as Dialog from "@radix-ui/react-dialog"; import * as Dialog from "@radix-ui/react-dialog";
import { AnimatePresence, motion } from "framer-motion"; import { AnimatePresence, motion } from "framer-motion";
import { FC, useState } from "react"; import { useState } from "react";
import { MdClose, MdMenu } from "react-icons/md"; import { MdClose, MdMenu } from "react-icons/md";
import { NavItems } from "./NavItems"; import { NavItems } from "./NavItems";
export const MobileMenu: FC = () => { export const MobileMenu = (): JSX.Element => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
return ( return (
<Dialog.Root onOpenChange={setOpen} open={open}> <Dialog.Root onOpenChange={setOpen} open={open}>
<Dialog.Trigger asChild> <Dialog.Trigger asChild>

View File

@ -1,16 +1,19 @@
import Button from "@/lib/components/ui/Button";
import Link from "next/link"; import Link from "next/link";
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";
import Button from "@/lib/components/ui/Button";
export const AuthButtons = (): JSX.Element => { export const AuthButtons = (): JSX.Element => {
const pathname = usePathname(); const pathname = usePathname();
if (pathname === "/signup") if (pathname === "/signup") {
return ( return (
<Link href={"/login"}> <Link href={"/login"}>
<Button variant={"secondary"}>Login</Button> <Button variant={"secondary"}>Login</Button>
</Link> </Link>
); );
}
return ( return (
<Link href={"/signup"}> <Link href={"/signup"}>
<Button variant={"secondary"}>Register</Button> <Button variant={"secondary"}>Register</Button>

View File

@ -1,9 +1,11 @@
/* eslint-disable */
"use client"; "use client";
import Button from "@/lib/components/ui/Button"; import { useEffect, useLayoutEffect, useState } from "react";
import { FC, useEffect, useLayoutEffect, useState } from "react";
import { MdDarkMode, MdLightMode } from "react-icons/md"; import { MdDarkMode, MdLightMode } from "react-icons/md";
export const DarkModeToggle: FC = () => { import Button from "@/lib/components/ui/Button";
export const DarkModeToggle = (): JSX.Element => {
const [dark, setDark] = useState(false); const [dark, setDark] = useState(false);
useLayoutEffect(() => { useLayoutEffect(() => {

View File

@ -1,5 +1,6 @@
/* eslint-disable */
import Link from "next/link"; import Link from "next/link";
import { Dispatch, FC, ReactNode, SetStateAction } from "react"; import { Dispatch, ReactNode, SetStateAction } from "react";
interface NavLinkProps { interface NavLinkProps {
children: ReactNode; children: ReactNode;
@ -7,7 +8,11 @@ interface NavLinkProps {
setOpen?: Dispatch<SetStateAction<boolean>>; setOpen?: Dispatch<SetStateAction<boolean>>;
} }
export const NavLink: FC<NavLinkProps> = ({ children, to, setOpen }) => { export const NavLink = ({
children,
to,
setOpen,
}: NavLinkProps): JSX.Element => {
return ( return (
<li className="group relative"> <li className="group relative">
<Link onClick={() => setOpen && setOpen(false)} href={to}> <Link onClick={() => setOpen && setOpen(false)} href={to}>

View File

@ -1,10 +1,13 @@
/* eslint-disable */
"use client"; "use client";
import Link from "next/link";
import { Dispatch, HTMLAttributes, SetStateAction } from "react";
import { MdPerson, MdSettings } from "react-icons/md";
import { useSupabase } from "@/app/supabase-provider"; import { useSupabase } from "@/app/supabase-provider";
import Button from "@/lib/components/ui/Button"; import Button from "@/lib/components/ui/Button";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import Link from "next/link";
import { Dispatch, FC, HTMLAttributes, SetStateAction } from "react";
import { MdPerson, MdSettings } from "react-icons/md";
import { AuthButtons } from "./components/AuthButtons"; import { AuthButtons } from "./components/AuthButtons";
import { DarkModeToggle } from "./components/DarkModeToggle"; import { DarkModeToggle } from "./components/DarkModeToggle";
import { NavLink } from "./components/NavLink"; import { NavLink } from "./components/NavLink";
@ -13,11 +16,11 @@ interface NavItemsProps extends HTMLAttributes<HTMLUListElement> {
setOpen?: Dispatch<SetStateAction<boolean>>; setOpen?: Dispatch<SetStateAction<boolean>>;
} }
export const NavItems: FC<NavItemsProps> = ({ export const NavItems = ({
className, className,
setOpen, setOpen,
...props ...props
}) => { }: NavItemsProps): JSX.Element => {
const { session } = useSupabase(); const { session } = useSupabase();
const isUserLoggedIn = session?.user !== undefined; const isUserLoggedIn = session?.user !== undefined;

View File

@ -1,12 +1,11 @@
"use client"; "use client";
import { FC } from "react";
import { Header } from "./components/Header"; import { Header } from "./components/Header";
import { Logo } from "./components/Logo"; import { Logo } from "./components/Logo";
import { MobileMenu } from "./components/MobileMenu"; import { MobileMenu } from "./components/MobileMenu";
import { NavItems } from "./components/NavItems"; import { NavItems } from "./components/NavItems";
export const NavBar: FC = () => { export const NavBar = (): JSX.Element => {
return ( return (
<Header> <Header>
<Logo /> <Logo />

View File

@ -1,8 +1,10 @@
import { cn } from "@/lib/utils"; /* eslint-disable */
import { cva, type VariantProps } from "class-variance-authority"; import { cva, type VariantProps } from "class-variance-authority";
import { ButtonHTMLAttributes, FC, LegacyRef, forwardRef } from "react"; import { ButtonHTMLAttributes, forwardRef, LegacyRef } from "react";
import { FaSpinner } from "react-icons/fa"; import { FaSpinner } from "react-icons/fa";
import { cn } from "@/lib/utils";
const ButtonVariants = cva( const ButtonVariants = cva(
"px-8 py-3 text-sm disabled:opacity-80 text-center font-medium rounded-md focus:ring ring-primary/10 outline-none flex items-center justify-center gap-2 transition-opacity", "px-8 py-3 text-sm disabled:opacity-80 text-center font-medium rounded-md focus:ring ring-primary/10 outline-none flex items-center justify-center gap-2 transition-opacity",
{ {
@ -34,11 +36,18 @@ export interface ButtonProps
isLoading?: boolean; isLoading?: boolean;
} }
const Button: FC<ButtonProps> = forwardRef( const Button = forwardRef(
( (
{ className, children, variant, brightness, isLoading, ...props }, {
className,
children,
variant,
brightness,
isLoading,
...props
}: ButtonProps,
forwardedRef forwardedRef
) => { ): JSX.Element => {
return ( return (
<button <button
className={cn(ButtonVariants({ variant, brightness, className }))} className={cn(ButtonVariants({ variant, brightness, className }))}

View File

@ -1,12 +1,14 @@
/* eslint-disable */
"use client"; "use client";
import { cn } from "@/lib/utils";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import { FC, HTMLAttributes, LegacyRef, forwardRef } from "react"; import { forwardRef, HTMLAttributes, LegacyRef } from "react";
import { cn } from "@/lib/utils";
type CardProps = HTMLAttributes<HTMLDivElement>; type CardProps = HTMLAttributes<HTMLDivElement>;
const Card: FC<CardProps> = forwardRef( const Card = forwardRef(
({ children, className, ...props }, ref) => { ({ children, className, ...props }: CardProps, ref): JSX.Element => {
return ( return (
<div <div
ref={ref as LegacyRef<HTMLDivElement>} ref={ref as LegacyRef<HTMLDivElement>}

View File

@ -1,12 +1,14 @@
/* eslint-disable */
import { forwardRef, HTMLAttributes, LegacyRef } from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { FC, HTMLAttributes, LegacyRef, forwardRef } from "react";
type DividerProps = HTMLAttributes<HTMLDivElement> & { type DividerProps = HTMLAttributes<HTMLDivElement> & {
text?: string; text?: string;
}; };
const Divider: FC<DividerProps> = forwardRef( const Divider = forwardRef(
({ className, text, ...props }, ref) => { ({ className, text, ...props }: DividerProps, ref): JSX.Element => {
return ( return (
<div <div
ref={ref as LegacyRef<HTMLDivElement>} ref={ref as LegacyRef<HTMLDivElement>}

View File

@ -1,6 +1,9 @@
/* eslint-disable */
"use client"; "use client";
import { HTMLAttributes } from "react";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { FC, HTMLAttributes } from "react";
import Tooltip from "./Tooltip"; import Tooltip from "./Tooltip";
interface EllipsisProps extends HTMLAttributes<HTMLDivElement> { interface EllipsisProps extends HTMLAttributes<HTMLDivElement> {
@ -9,12 +12,12 @@ interface EllipsisProps extends HTMLAttributes<HTMLDivElement> {
tooltip?: boolean; tooltip?: boolean;
} }
const Ellipsis: FC<EllipsisProps> = ({ const Ellipsis = ({
children: originalContent, children: originalContent,
className, className,
maxCharacters, maxCharacters,
tooltip = false, tooltip = false,
}) => { }: EllipsisProps): JSX.Element => {
const renderedContent = const renderedContent =
originalContent.length > maxCharacters originalContent.length > maxCharacters
? `${originalContent.slice(0, maxCharacters)}...` ? `${originalContent.slice(0, maxCharacters)}...`

View File

@ -1,11 +1,13 @@
import { cn } from "@/lib/utils"; /* eslint-disable */
import { import {
DetailedHTMLProps, DetailedHTMLProps,
forwardRef,
InputHTMLAttributes, InputHTMLAttributes,
RefObject, RefObject,
forwardRef,
} from "react"; } from "react";
import { cn } from "@/lib/utils";
interface FieldProps interface FieldProps
extends DetailedHTMLProps< extends DetailedHTMLProps<
InputHTMLAttributes<HTMLInputElement>, InputHTMLAttributes<HTMLInputElement>,

View File

@ -1,8 +1,9 @@
"use client"; "use client";
import * as Dialog from "@radix-ui/react-dialog"; import * as Dialog from "@radix-ui/react-dialog";
import { AnimatePresence, motion } from "framer-motion"; import { AnimatePresence, motion } from "framer-motion";
import { FC, ReactNode, useState } from "react"; import { ReactNode, useState } from "react";
import { MdClose } from "react-icons/md"; import { MdClose } from "react-icons/md";
import Button from "./Button"; import Button from "./Button";
interface ModalProps { interface ModalProps {
@ -13,14 +14,15 @@ interface ModalProps {
CloseTrigger?: ReactNode; CloseTrigger?: ReactNode;
} }
const Modal: FC<ModalProps> = ({ const Modal = ({
title, title,
desc, desc,
children, children,
Trigger, Trigger,
CloseTrigger, CloseTrigger,
}) => { }: ModalProps): JSX.Element => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
return ( return (
<Dialog.Root onOpenChange={setOpen}> <Dialog.Root onOpenChange={setOpen}>
<Dialog.Trigger asChild> <Dialog.Trigger asChild>
@ -58,7 +60,7 @@ const Modal: FC<ModalProps> = ({
{children} {children}
<Dialog.Close asChild> <Dialog.Close asChild>
{CloseTrigger ? ( {CloseTrigger !== undefined ? (
CloseTrigger CloseTrigger
) : ( ) : (
<Button variant={"secondary"} className="self-end"> <Button variant={"secondary"} className="self-end">

View File

@ -1,15 +1,15 @@
import { FC } from "react";
interface PageHeadingProps { interface PageHeadingProps {
title: string; title: string;
subtitle?: string; subtitle?: string;
} }
const PageHeading: FC<PageHeadingProps> = ({ title, subtitle }) => { const PageHeading = ({ title, subtitle }: PageHeadingProps): JSX.Element => {
return ( return (
<div className="flex flex-col items-center justify-center px-5"> <div className="flex flex-col items-center justify-center px-5">
<h1 className="text-3xl font-bold text-center">{title}</h1> <h1 className="text-3xl font-bold text-center">{title}</h1>
{subtitle && <h2 className="opacity-50 text-center">{subtitle}</h2>} {subtitle !== undefined && (
<h2 className="opacity-50 text-center">{subtitle}</h2>
)}
</div> </div>
); );
}; };

View File

@ -1,7 +1,6 @@
import { FC } from "react";
import { FaSpinner } from "react-icons/fa"; import { FaSpinner } from "react-icons/fa";
const Spinner: FC = () => { const Spinner = (): JSX.Element => {
return <FaSpinner className="animate-spin m-5" />; return <FaSpinner className="animate-spin m-5" />;
}; };

View File

@ -1,8 +1,11 @@
/* eslint-disable */
"use client"; "use client";
import { cn } from "@/lib/utils";
import * as ToastPrimitive from "@radix-ui/react-toast"; import * as ToastPrimitive from "@radix-ui/react-toast";
import { AnimatePresence, motion } from "framer-motion"; import { AnimatePresence, motion } from "framer-motion";
import { ReactNode } from "react"; import { ReactNode } from "react";
import { cn } from "@/lib/utils";
import Button from "../../Button"; import Button from "../../Button";
import { ToastContext } from "../domain/ToastContext"; import { ToastContext } from "../domain/ToastContext";
import { ToastVariants } from "../domain/types"; import { ToastVariants } from "../domain/types";
@ -11,15 +14,21 @@ import { useToastBuilder } from "../hooks/useToastBuilder";
export const Toast = ({ export const Toast = ({
children, children,
...toastProviderProps ...toastProviderProps
}: { children?: ReactNode } & ToastPrimitive.ToastProviderProps) => { }: {
children?: ReactNode;
} & ToastPrimitive.ToastProviderProps): JSX.Element => {
const { publish, toasts, toggleToast } = useToastBuilder(); const { publish, toasts, toggleToast } = useToastBuilder();
return ( return (
<ToastPrimitive.Provider {...toastProviderProps}> <ToastPrimitive.Provider {...toastProviderProps}>
<ToastContext.Provider value={{ publish }}> <ToastContext.Provider value={{ publish }}>
{children} {children}
<AnimatePresence mode="popLayout"> <AnimatePresence mode="popLayout">
{toasts.map((toast) => { {toasts.map((toast) => {
if (!toast.open) return; if (toast.open !== true) {
return;
}
return ( return (
<ToastPrimitive.Root <ToastPrimitive.Root
open={toast.open} open={toast.open}

View File

@ -1,11 +1,14 @@
"use client"; "use client";
import * as ToastPrimitive from "@radix-ui/react-toast"; import * as ToastPrimitive from "@radix-ui/react-toast";
import { ReactNode } from "react"; import { ReactNode } from "react";
import { Toast } from "./Toast"; import { Toast } from "./Toast";
export const ToastProvider = ({ export const ToastProvider = ({
children, children,
...toastProviderProps ...toastProviderProps
}: { children?: ReactNode } & ToastPrimitive.ToastProviderProps) => { }: {
children?: ReactNode;
} & ToastPrimitive.ToastProviderProps): JSX.Element => {
return <Toast {...toastProviderProps}>{children}</Toast>; return <Toast {...toastProviderProps}>{children}</Toast>;
}; };

View File

@ -1,4 +1,5 @@
import { createContext } from "react"; import { createContext } from "react";
import { ToastPublisher } from "./types"; import { ToastPublisher } from "./types";
const publish: ToastPublisher = () => void 0; const publish: ToastPublisher = () => void 0;

View File

@ -1,4 +1,4 @@
import { VariantProps, cva } from "class-variance-authority"; import { cva, VariantProps } from "class-variance-authority";
export const ToastVariants = cva( export const ToastVariants = cva(
"bg-white dark:bg-black px-8 max-w-sm w-full py-5 border border-black/10 dark:border-white/25 rounded-xl shadow-xl flex items-center pointer-events-auto data-[swipe=end]:opacity-0 data-[state=closed]:opacity-0 transition-opacity", "bg-white dark:bg-black px-8 max-w-sm w-full py-5 border border-black/10 dark:border-white/25 rounded-xl shadow-xl flex items-center pointer-events-auto data-[swipe=end]:opacity-0 data-[state=closed]:opacity-0 transition-opacity",

View File

@ -1,5 +1,6 @@
export const generateToastUniqueId = () => { export const generateToastUniqueId = (): string => {
const timestamp = Date.now(); const timestamp = Date.now();
const random = Math.floor(Math.random() * 10000); const random = Math.floor(Math.random() * 10000);
return `${timestamp}-${random}`; return `${timestamp}-${random}`;
}; };

View File

@ -1,4 +1,6 @@
/* eslint-disable */
import { useState } from "react"; import { useState } from "react";
import { ToastContent, ToastData, ToastPublisher } from "../domain/types"; import { ToastContent, ToastData, ToastPublisher } from "../domain/types";
import { generateToastUniqueId } from "../helpers/generateToastUniqueId"; import { generateToastUniqueId } from "../helpers/generateToastUniqueId";
@ -12,6 +14,7 @@ export const useToastBuilder = () => {
if (toast.id === toastId) { if (toast.id === toastId) {
toast.open = value; toast.open = value;
} }
return toast; return toast;
}) })
); );

View File

@ -1,15 +1,16 @@
"use client"; "use client";
import * as TooltipPrimitive from "@radix-ui/react-tooltip"; import * as TooltipPrimitive from "@radix-ui/react-tooltip";
import { AnimatePresence, motion } from "framer-motion"; import { AnimatePresence, motion } from "framer-motion";
import { FC, ReactNode, useState } from "react"; import { ReactNode, useState } from "react";
interface TooltipProps { interface TooltipProps {
children?: ReactNode; children?: ReactNode;
tooltip?: ReactNode; tooltip?: ReactNode;
} }
const Tooltip: FC<TooltipProps> = ({ children, tooltip }) => { const Tooltip = ({ children, tooltip }: TooltipProps): JSX.Element => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
return ( return (
<TooltipPrimitive.Provider> <TooltipPrimitive.Provider>
<TooltipPrimitive.Root onOpenChange={setOpen} open={open}> <TooltipPrimitive.Root onOpenChange={setOpen} open={open}>

View File

@ -1,7 +1,10 @@
/* eslint-disable */
"use client"; "use client";
import { setEmptyStringsUndefined } from "@/lib/helpers/setEmptyStringsUndefined";
import { createContext, useEffect, useState } from "react"; import { createContext, useEffect, useState } from "react";
import { setEmptyStringsUndefined } from "@/lib/helpers/setEmptyStringsUndefined";
import { import {
getBrainConfigFromLocalStorage, getBrainConfigFromLocalStorage,
saveBrainConfigInLocalStorage, saveBrainConfigInLocalStorage,

View File

@ -1,3 +1,4 @@
/* eslint-disable */
import { BrainConfig } from "../types"; import { BrainConfig } from "../types";
const BRAIN_CONFIG_LOCAL_STORAGE_KEY = "userBrainConfig"; const BRAIN_CONFIG_LOCAL_STORAGE_KEY = "userBrainConfig";
@ -12,6 +13,9 @@ export const getBrainConfigFromLocalStorage = (): BrainConfig | undefined => {
const persistedBrainConfig = localStorage.getItem( const persistedBrainConfig = localStorage.getItem(
BRAIN_CONFIG_LOCAL_STORAGE_KEY BRAIN_CONFIG_LOCAL_STORAGE_KEY
); );
if (persistedBrainConfig === null) return; if (persistedBrainConfig === null) {
return;
}
return JSON.parse(persistedBrainConfig); return JSON.parse(persistedBrainConfig);
}; };

View File

@ -1,4 +1,6 @@
/* eslint-disable */
import { useContext } from "react"; import { useContext } from "react";
import { BrainConfigContext } from "../brain-config-provider"; import { BrainConfigContext } from "../brain-config-provider";
export const useBrainConfig = () => { export const useBrainConfig = () => {

View File

@ -20,8 +20,18 @@ export type ConfigContext = {
// export const openAiModels = ["gpt-3.5-turbo", "gpt-4"] as const; ## TODO activate GPT4 when not in demo mode // export const openAiModels = ["gpt-3.5-turbo", "gpt-4"] as const; ## TODO activate GPT4 when not in demo mode
export const openAiModels = ["gpt-3.5-turbo","gpt-3.5-turbo-0613","gpt-3.5-turbo-16k"] as const; export const openAiModels = [
export const openAiPaidModels = ["gpt-3.5-turbo","gpt-3.5-turbo-0613","gpt-3.5-turbo-16k","gpt-4","gpt-4-0613"] as const; "gpt-3.5-turbo",
"gpt-3.5-turbo-0613",
"gpt-3.5-turbo-16k",
] as const;
export const openAiPaidModels = [
"gpt-3.5-turbo",
"gpt-3.5-turbo-0613",
"gpt-3.5-turbo-16k",
"gpt-4",
"gpt-4-0613",
] as const;
export const anthropicModels = [ export const anthropicModels = [
// "claude-v1", // "claude-v1",
@ -39,7 +49,7 @@ export const models = [
...googleModels, ...googleModels,
] as const; ] as const;
export const paidModels = [...openAiPaidModels, ...googleModels] as const; export const paidModels = [...openAiPaidModels] as const;
export type PaidModels = (typeof paidModels)[number]; export type PaidModels = (typeof paidModels)[number];

View File

@ -1,6 +1,8 @@
/* eslint-disable */
"use client"; "use client";
import { createContext } from "react"; import { createContext } from "react";
import useChats from "./hooks/useChats"; import useChats from "./hooks/useChats";
import { ChatsState } from "./types"; import { ChatsState } from "./types";

View File

@ -1,9 +1,12 @@
import { useBrainConfig } from "@/lib/context/BrainConfigProvider/hooks/useBrainConfig"; /* eslint-disable */
import { useToast } from "@/lib/hooks/useToast";
import { useAxios } from "@/lib/useAxios";
import { UUID } from "crypto"; import { UUID } from "crypto";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { useBrainConfig } from "@/lib/context/BrainConfigProvider/hooks/useBrainConfig";
import { useToast } from "@/lib/hooks/useToast";
import { useAxios } from "@/lib/useAxios";
import { Chat, ChatMessage } from "../../../types/Chat"; import { Chat, ChatMessage } from "../../../types/Chat";
export default function useChats() { export default function useChats() {
@ -38,7 +41,9 @@ export default function useChats() {
const fetchChat = useCallback( const fetchChat = useCallback(
async (chatId?: UUID) => { async (chatId?: UUID) => {
if (!chatId) return; if (!chatId) {
return;
}
try { try {
console.log(`Fetching chat ${chatId}`); console.log(`Fetching chat ${chatId}`);
const response = await axiosInstance.get<Chat>(`/chat/${chatId}`); const response = await axiosInstance.get<Chat>(`/chat/${chatId}`);
@ -64,6 +69,7 @@ export default function useChats() {
options: Record<string, string | unknown>; options: Record<string, string | unknown>;
}) => { }) => {
fetchAllChats(); fetchAllChats();
return axiosInstance.post<ChatResponse>(`/chat`, options); return axiosInstance.post<ChatResponse>(`/chat`, options);
}; };
@ -78,7 +84,9 @@ export default function useChats() {
const sendMessage = async (chatId?: UUID, msg?: ChatMessage) => { const sendMessage = async (chatId?: UUID, msg?: ChatMessage) => {
setIsSendingMessage(true); setIsSendingMessage(true);
if (msg) setMessage(msg); if (msg) {
setMessage(msg);
}
const options: Record<string, unknown> = { const options: Record<string, unknown> = {
chat_id: chatId, chat_id: chatId,
model, model,
@ -101,6 +109,7 @@ export default function useChats() {
}); });
setMessage(["", ""]); setMessage(["", ""]);
setIsSendingMessage(false); setIsSendingMessage(false);
return; return;
} }
@ -114,6 +123,7 @@ export default function useChats() {
console.log("---- Creating a new chat ----"); console.log("---- Creating a new chat ----");
setAllChats((chats) => { setAllChats((chats) => {
console.log({ chats }); console.log({ chats });
return [...chats, newChat]; return [...chats, newChat];
}); });
setChat(newChat); setChat(newChat);

View File

@ -1,4 +1,6 @@
/* eslint-disable */
import { useContext } from "react"; import { useContext } from "react";
import { ChatsContext } from "../chats-provider"; import { ChatsContext } from "../chats-provider";
const useChatsContext = () => { const useChatsContext = () => {

View File

@ -1,5 +1,8 @@
import { isSpeechRecognitionSupported } from "@/lib/helpers/isSpeechRecognitionSupported"; /* eslint-disable */
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { isSpeechRecognitionSupported } from "@/lib/helpers/isSpeechRecognitionSupported";
import useChatsContext from "./useChatsContext"; import useChatsContext from "./useChatsContext";
export const useSpeech = () => { export const useSpeech = () => {

View File

@ -1,9 +1,10 @@
export function isSpeechRecognitionSupported() { export const isSpeechRecognitionSupported = (): boolean => {
if ( if (
typeof window !== "undefined" && typeof window !== "undefined" &&
("SpeechRecognition" in window || "webkitSpeechRecognition" in window) ("SpeechRecognition" in window || "webkitSpeechRecognition" in window)
) { ) {
return true; return true;
} }
return false; return false;
} };

View File

@ -1,6 +1,8 @@
import { ToastContext } from "@/lib/components/ui/Toast/domain/ToastContext"; /* eslint-disable */
import { useContext } from "react"; import { useContext } from "react";
import { ToastContext } from "@/lib/components/ui/Toast/domain/ToastContext";
export const useToast = () => { export const useToast = () => {
const { publish } = useContext(ToastContext); const { publish } = useContext(ToastContext);

View File

@ -1,4 +1,4 @@
export type Message = { export type Message = {
type: "success" | "error" | "warning"; type: "success" | "error" | "warning";
text: string; text: string;
}; };

View File

@ -1,20 +1,23 @@
/* eslint-disable */
import axios, { AxiosInstance } from "axios";
import { useSupabase } from "@/app/supabase-provider"; import { useSupabase } from "@/app/supabase-provider";
import axios from "axios";
import { useBrainConfig } from "./context/BrainConfigProvider/hooks/useBrainConfig"; import { useBrainConfig } from "./context/BrainConfigProvider/hooks/useBrainConfig";
const axiosInstance = axios.create({ const axiosInstance = axios.create({
baseURL: `${process.env.NEXT_PUBLIC_BACKEND_URL}`, baseURL: `${process.env.NEXT_PUBLIC_BACKEND_URL ?? ""}`,
}); });
export const useAxios = () => { export const useAxios = (): { axiosInstance: AxiosInstance } => {
const { session } = useSupabase(); const { session } = useSupabase();
const { const {
config: { backendUrl, openAiKey }, config: { backendUrl, openAiKey },
} = useBrainConfig(); } = useBrainConfig();
axiosInstance.interceptors.request.clear(); axiosInstance.interceptors.request.clear();
axiosInstance.interceptors.request.use( axiosInstance.interceptors.request.use(
async (config) => { (config) => {
config.headers["Authorization"] = "Bearer " + session?.access_token; config.headers["Authorization"] = `Bearer ${session?.access_token}`;
config.headers["Openai-Api-Key"] = openAiKey; config.headers["Openai-Api-Key"] = openAiKey;
config.baseURL = backendUrl ?? config.baseURL; config.baseURL = backendUrl ?? config.baseURL;

View File

@ -1,6 +1,6 @@
import clsx, { ClassValue } from "clsx"; import clsx, { ClassValue } from "clsx";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) { export const cn = (...inputs: ClassValue[]): string => {
return twMerge(clsx(inputs)); return twMerge(clsx(inputs));
} };

View File

@ -1,12 +1,12 @@
import { createMiddlewareSupabaseClient } from '@supabase/auth-helpers-nextjs' import { createMiddlewareSupabaseClient } from "@supabase/auth-helpers-nextjs";
import { NextResponse } from 'next/server' import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";
import type { NextRequest } from 'next/server'
// import type { Database } from '@/lib/database.types' // import type { Database } from '@/lib/database.types'
export async function middleware(req: NextRequest) { export const middleware = async (req: NextRequest): Promise<NextResponse> => {
const res = NextResponse.next() const res = NextResponse.next();
const supabase = createMiddlewareSupabaseClient({ req, res }) const supabase = createMiddlewareSupabaseClient({ req, res });
await supabase.auth.getSession() await supabase.auth.getSession();
return res
} return res;
};

View File

@ -7,9 +7,12 @@
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "next lint", "lint": "next lint",
"lint-fix": "eslint --fix .",
"test-type": "tsc --noEmit --emitDeclarationOnly false", "test-type": "tsc --noEmit --emitDeclarationOnly false",
"test": "yarn test-type", "test": "yarn test-type",
"precommit": "yarn lint && yarn test" "precommit": "yarn lint && yarn test",
"format-check": "prettier --check .",
"format-fix": "prettier --write ."
}, },
"dependencies": { "dependencies": {
"@emotion/react": "^11.11.0", "@emotion/react": "^11.11.0",
@ -35,9 +38,11 @@
"encoding": "^0.1.13", "encoding": "^0.1.13",
"eslint": "^8.41.0", "eslint": "^8.41.0",
"eslint-config-next": "13.4.2", "eslint-config-next": "13.4.2",
"eslint-plugin-prefer-arrow": "^1.2.3",
"framer-motion": "^10.12.12", "framer-motion": "^10.12.12",
"next": "13.4.2", "next": "13.4.2",
"postcss": "8.4.23", "postcss": "8.4.23",
"prettier": "^2.8.8",
"pretty-bytes": "^6.1.0", "pretty-bytes": "^6.1.0",
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",

View File

@ -1,3 +1,5 @@
export default function About() { const About = (): JSX.Element => {
return <div>About</div>; return <div>About</div>;
} };
export default About;

View File

@ -3,4 +3,4 @@ module.exports = {
tailwindcss: {}, tailwindcss: {},
autoprefixer: {}, autoprefixer: {},
}, },
} };

View File

@ -2,25 +2,23 @@
module.exports = { module.exports = {
darkMode: "class", darkMode: "class",
content: [ content: [
'./pages/**/*.{js,ts,jsx,tsx,mdx}', "./pages/**/*.{js,ts,jsx,tsx,mdx}",
'./components/**/*.{js,ts,jsx,tsx,mdx}', "./components/**/*.{js,ts,jsx,tsx,mdx}",
'./app/**/*.{js,ts,jsx,tsx,mdx}', "./app/**/*.{js,ts,jsx,tsx,mdx}",
'./lib/**/*.{js,ts,jsx,tsx,mdx}', "./lib/**/*.{js,ts,jsx,tsx,mdx}",
], ],
theme: { theme: {
extend: { extend: {
backgroundImage: { backgroundImage: {
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
'gradient-conic': "gradient-conic":
'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
}, },
colors: { colors: {
black: "#00121F", black: "#00121F",
primary: "#4F46E5", primary: "#4F46E5",
} },
}, },
}, },
plugins: [ plugins: [require("@tailwindcss/typography")],
require('@tailwindcss/typography'), };
],
}

View File

@ -0,0 +1,42 @@
{
"compilerOptions": {
"typeRoots": ["node_modules/@types"],
"composite": true,
"declaration": true,
"declarationMap": true,
"emitDeclarationOnly": true,
"incremental": true,
"noEmitOnError": true,
"skipLibCheck": true,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"isolatedModules": true,
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"strictNullChecks": true,
"target": "esnext",
"types": ["node", "vitest/globals"],
"lib": ["dom", "dom.iterable","es2020"],
"noUnusedLocals": true,
"noUnusedParameters": true,
"sourceMap": true,
"noImplicitReturns": true,
"noUncheckedIndexedAccess": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"plugins": [
{
"name": "next"
}
],
},
"ts-node": {
"compilerOptions": {
"module": "NodeNext"
},
"require": ["tsconfig-paths/register"]
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

View File

@ -1,9 +1,10 @@
{ {
"compilerOptions": { "compilerOptions": {
"typeRoots": ["node_modules/@types"], "lib": [
"target": "es5", "dom",
"lib": ["dom", "dom.iterable", "esnext"], "dom.iterable",
"esnext"
],
"allowJs": true, "allowJs": true,
"skipLibCheck": true, "skipLibCheck": true,
"strict": true, "strict": true,
@ -21,10 +22,18 @@
"name": "next" "name": "next"
} }
], ],
"strictNullChecks": true,
"paths": { "paths": {
"@/*": ["./*"] "@/*": ["./*"]
} }
}, },
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "include": [
"exclude": ["node_modules"] "next-env.d.ts",
".next/types/**/*.ts",
"**/*.ts",
"**/*.tsx"
],
"exclude": [
"node_modules"
]
} }

File diff suppressed because it is too large Load Diff