diff --git a/package.json b/package.json index fa08063..2293f88 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@fortawesome/react-fontawesome": "^0.2.0", "@heroicons/vue": "^2.1.1", "autoprefixer": "^10.4.16", + "date-fns": "^3.3.1", "postcss": "^8.4.33", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/src/components/Chat.tsx b/src/components/Chat.tsx new file mode 100644 index 0000000..53bf01e --- /dev/null +++ b/src/components/Chat.tsx @@ -0,0 +1,122 @@ +import { useEffect, useState } from "react"; +import { currentPage, Pages } from "./VerticalMenu" +import { RecoilRoot, useRecoilState } from 'recoil' +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { faPaperPlane } from '@fortawesome/free-solid-svg-icons' +import { formatDistance } from 'date-fns' +import { ja } from 'date-fns/locale/ja' + +export default function Chat() { + const [page, _] = useRecoilState(currentPage); + const [name, setName] = useState(""); + const [body, setBody] = useState(""); + const [messages, setMessages] = useState(); + const [alert, setAlert] = useState(""); + + interface Message { + name: string + body: string + createdAt: string + } + + useEffect(() => { + if (page === Pages.Chat) { + updateChat(); + } + }, [page]); + + async function submit() { + await fetch( + "https://bbs.yude.workers.dev/api/message", + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + mode: 'cors', + body: JSON.stringify({ + name: name, + body: body, + }) + } + ) + .then( + (res) => res.text() + ) + .then ( + async (text) => { + if (text.includes("Success")) { + await showAlert("送信しました。"); + } + } + ) + await new Promise(s => setTimeout(s, 800)); + updateChat(); + } + + const updateChat = () => { + fetch( + "https://bbs.yude.workers.dev/api/messages", + ) + .then((res) => res.json()) + .then((data) => setMessages(data)); + } + const updateName = (e: any) => { + setName(e.target.value); + } + const updateBody = (e: any) => { + setBody(e.target.value); + } + + async function showAlert(alert: string) { + setAlert(alert); + await new Promise(s => setTimeout(s, 1500)); + setAlert(""); + } + + return ( + +
+ +
+ {alert} +
+
+
+
+ + +
+
+ + +
+ +
+ +
+ { + messages && + messages.map((message, index) => { + return ( +
+

+ {message.name} さん,{" "} + { + formatDistance(Date.parse(message.createdAt), new Date(), { addSuffix: true, locale: ja }) + } +

+

{message.body}

+
+ ) + }) + } +
+
+ ) +} + \ No newline at end of file diff --git a/src/components/ContentRenderer.tsx b/src/components/ContentRenderer.tsx index 3f56ac0..5d6b13b 100644 --- a/src/components/ContentRenderer.tsx +++ b/src/components/ContentRenderer.tsx @@ -5,11 +5,10 @@ import Links from "./Links" import Keys from "./Keys" import Spotify from "./Spotify" import Services from "./Services" +import Chat from "./Chat" import { currentPage, Pages } from "./VerticalMenu" - - export default function ContentRenderer() { const [page, _] = useRecoilState(currentPage); return ( @@ -18,6 +17,7 @@ export default function ContentRenderer() { { page === Pages.Links && } { page === Pages.Keys && } { page === Pages.Services && } + { page === Pages.Chat && } ) } diff --git a/src/components/VerticalMenu.tsx b/src/components/VerticalMenu.tsx index 912bc8b..09769e6 100644 --- a/src/components/VerticalMenu.tsx +++ b/src/components/VerticalMenu.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' -import { faUser, faStar} from '@fortawesome/free-regular-svg-icons' +import { faUser, faStar, faComments } from '@fortawesome/free-regular-svg-icons' import { faLink, faKey } from '@fortawesome/free-solid-svg-icons' import { RecoilRoot, atom, useRecoilState } from 'recoil' @@ -11,6 +11,7 @@ export enum Pages { Activities = 3, Spotify = 4, Services = 5, + Chat = 6, } export const currentPage = atom({ @@ -52,6 +53,13 @@ export default function VerticalMenu() { {" "}

サービス

+
  • {setPage(Pages.Chat)}} + > + {" "} +

    チャット

    +
  • )