diff --git a/.eslintrc.json b/.eslintrc.json index bffb357..4d765f2 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,3 @@ { - "extends": "next/core-web-vitals" + "extends": ["next/core-web-vitals", "prettier"] } diff --git a/README.md b/README.md index 965a122..b6340dc 100644 --- a/README.md +++ b/README.md @@ -36,3 +36,12 @@ You can check out [the Next.js GitHub repository](https://github.com/vercel/next The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. + +## Code formatting and linter + +Before committing, in the main directory run: + +``` +npx prettier --write . +npx eslint . +``` diff --git a/components/ArrowBack.tsx b/components/ArrowBack.tsx new file mode 100644 index 0000000..234c87f --- /dev/null +++ b/components/ArrowBack.tsx @@ -0,0 +1,16 @@ +import Arrow from "../public/arrow.svg"; + +export default function ArrowBack({ + ...props +}: React.HTMLAttributes) { + return ( +
+ +
+ ); +} diff --git a/components/Avatar.tsx b/components/Avatar.tsx new file mode 100644 index 0000000..72b4dc9 --- /dev/null +++ b/components/Avatar.tsx @@ -0,0 +1,26 @@ +interface Props { + src: string; + size: "sm" | "md" | "lg"; +} + +export default function Avatar({ src, size }: Props) { + const getClassName = () => { + let retval = "rounded-full"; + switch (size) { + case "sm": + return retval + " h-12 w-12"; + case "md": + return retval + " h-24 w-24"; + case "lg": + return retval + " h-36 w-36"; + default: + return retval; + } + }; + + return ( +
+ +
+ ); +} diff --git a/components/Chat.tsx b/components/Chat.tsx new file mode 100644 index 0000000..309f3c1 --- /dev/null +++ b/components/Chat.tsx @@ -0,0 +1,181 @@ +import { User } from "@/types/backendTypes"; +import { getTime } from "@/utils/getTime"; +import Camera from "../public/camera.svg"; +import Dots from "../public/dots.svg"; +import Phone from "../public/phone.svg"; +import Star from "../public/star.svg"; +import Smile from "../public/smile.svg"; +import PaperPlane from "../public/paperPlane.svg"; +import Avatar from "./Avatar"; +import ArrowBack from "./ArrowBack"; +import { Dispatch, FormEvent, useEffect, useRef, useState } from "react"; +import { conversations } from "@/lib/conversations"; +import Link from "next/link"; +import { Action } from "./Layout"; +import IntroBetaLogo from "../public/IntroBetaLogo.svg"; + +interface Props { + user?: User; + toggleShowUserDetails: () => void; + dispatch: Dispatch; +} + +export default function Chat({ user, toggleShowUserDetails, dispatch }: Props) { + const [input, setInput] = useState(); + const chatWindow = useRef(null); + const inputRef = useRef(null); + const conversation = user + ? conversations.getConversation(user?.login.uuid) + : undefined; + + const handleSubmit = (event: FormEvent) => { + event.preventDefault(); + const data = new FormData(event.currentTarget); + const content = data.get("msg-content")?.toString().trim(); + if (!content || !user) return; + conversations.addMessage(user.login.uuid, { + authorId: conversations.getMyId(), + content, + }); + setInput(""); + if (!inputRef.current) return; + inputRef.current.value = ""; + inputRef.current.focus(); + dispatch({ + type: "setActiveConversationLength", + payload: { length: conversation?.messages.length ?? 0 }, + }); + }; + + useEffect(() => { + if (!chatWindow.current) return; + chatWindow.current.scrollTop = chatWindow.current.scrollHeight; + }, [user?.login.uuid, input]); + + useEffect(() => { + if (conversation && conversation?.numberOfUnreadMessages > 0) { + conversations.markAsRead(conversation.id); + } + }); + + return ( +
+ {user ? ( + <> +
+
+ + + +
+

+ {user?.name.first} {user?.name.last} +

+
+
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+
+
+
    + {conversation?.messages.map((msg, index) => ( +
  • + {msg.authorId == user?.login.uuid ? ( + <> + +
    +
    +
    +
    +
    +
    + {msg.content} +
    +
    +
    +

    + {getTime(new Date(msg.timestamp))} +

    +
    +
    + + ) : ( +
    +
    +
    +
    + {msg.content} +
    +
    +
    +
    +
    +
    +

    + {getTime(new Date(msg.timestamp))} +

    +
    +
    +
    + )} +
  • + ))} +
+
+
+
+ +
+
+
inputRef.current?.focus()} + > +