チャットApp(chatroomのビュー)
今回はチャットルームの見た目を整えていきます。その為に最初にチャットルームを作った時点で1つか2つメッセージがないと見た目がわからないのでチャットルームを作る[username].tsxをまず編集します。
[username].tsx
const createChatroom = async() => {
const owner:string = user.displayName;
const date = Date.now();
const chatroom:ChatroomType = {
owner: owner,
roomname: "",
member: [],
chats: [
{
text: `ここは、${ user.displayName }のチャットルームだよ!下のフォームから投稿してね!`,
date: date,
uid : "chat-bot",
username: "chat-bot",
photoURL: "",
},
{
text: "了解したよ!",
date: date,
uid : user.uid,
username: user.displayName,
photoURL: user.photoURL,
}
],
}
const msg = await setChatroomToFirestore(chatroom, user.uid);
console.log(msg);
const [getmsg, temp] = await getChatroomFromFirestore(user.uid);
if (getmsg === "get chatroom successfully!") {
// ボタンを表示するcssクラスを付与
setRoomExist(true);
} else {
setRoomExist(false);
}
}
編集した関数の部分だけ載せてます。chatsというプロパティの中に2つメッセージを入れただけです。一つはボット的な扱いでもう一つは自分のメッセージです。
チャットルームのディレクトリ構造は上のようになっています。前回話しましたが、ログインしていない状態でチャットルームにアクセスするとsignin.tsxにリダイレクトします。メインはindex.tsxになるのでそこのコードを紹介していきます。
index.tsx
import { useState, useEffect } from "react";
import { useRouter } from "next/router";
import BasicHead from "../../../components/atom/head";
import TitleLogo from "../../../components/atom/logo";
import BasicButton from "../../../components/atom/button";
import BasicH2 from "../../../components/atom/basicH2";
import UserField from "../../../components/compo/userField";
import ChatContainer from "../../../components/compo/chatContainer";
import Styles from "../../../styles/chatroom.module.css";
import { activeUserExist, getActiveUser } from "../../../functions/auth";
import { getChatroomFromFirestore, ChatroomType } from "../../../functions/database";
export default function Room() {
const [ user, setUser] = useState<firebase.User>();
const [ room, setRoom] = useState<ChatroomType>();
const router = useRouter();
// userの存在を確認
const checkUser = async() => {
if (await activeUserExist()) {
const usr = getActiveUser();
setUser(usr);
} else {
console.log("no user");
}
}
// roomの存在を確認
const checkroom = async() => {
const path = location.pathname.split("/chatroom/")[1];
const [msg, rm] = await getChatroomFromFirestore(path);
if (msg === "get chatroom successfully!") {
setRoom(rm);
}
}
useEffect(() => {
(async() => {
await checkUser();
await checkroom();
})();
}, []);
const chatArea = () => {
if (room) {
return (
<>
<div className={ Styles.roomname }>
<BasicH2>{ room.owner } のチャットルーム</BasicH2>
</div>
<div className={ Styles.chatarea }>
<div className={ Styles.chatareaInner }>
<div>
<ChatContainer
chats={ room.chats }
user={ user.uid }
/>
</div>
</div>
</div>
</>
);
}
return (
<div className={ Styles.chatareaInner }>
<BasicH2>
このチャットルームは存在しないか、オーナーがログアウトして消去された可能性があります。
</BasicH2>
</div>
);
}
if (!user) {
return (
<div>
<BasicHead />
<div className={ Styles.title }>
<TitleLogo />
</div>
<div className={ Styles.container }>
<BasicH2>どうやらあなたはログインが済んでいないようです。ここから匿名ログインをしてください</BasicH2>
<BasicButton
fullWidth ={ true }
onclick ={ () => router.push("/chatroom/[roomid]/signin", location.pathname + "/signin") }
>匿名ログイン</BasicButton>
</div>
</div>
);
}
return (
<div>
<BasicHead />
<main>
<div className={ Styles.title }>
<TitleLogo />
</div>
<div className={ Styles.toProfile }>
<BasicButton
onclick={ () => router.push("/profile/[username]", "/profile/" + user.displayName) }
>
プロフィールページへ
</BasicButton>
</div>
<div className={ Styles.area }>
{ chatArea() }
</div>
<div className={ Styles.userField }>
<UserField
user={ user }
/>
</div>
</main>
</div>
);
}
前回ある程度説明していたと思います。今回追加したのはchatArea関数だと思うのでそこを紹介します。この関数は指定のchatroomをfirestoreから読み込みます。指定のchatroomがあればChatContainerコンポーネントを、なければその旨を伝えるメッセージを表示します。それではChatContainerについて説明します。
ChatContainer.tsx
import { FC } from "react";
import { ChatType } from "../../functions/database";
import ChatBalloon from "./chatballoon";
import { makeStyles, createStyles } from "@material-ui/core";
const useStyles = makeStyles(() => createStyles({
container: {
}
}))
type Props = {
chats: ChatType[],
user: string,
}
/**
* 一つ一つの書き込みを順番に表示する領域
* @param param0
*/
const ChatContainer:FC<Props> = ({ chats, user }) => {
const classes = useStyles();
return (
<div className={ classes.container }>
{ chats.map(chat => {
if (chat.uid === user) {
return (
<ChatBalloon
chat ={ chat }
who ={ "me" }
/>
);
} else {
return (
<ChatBalloon
chat ={ chat }
who ={ "you" }
/>
);
}
})}
</div>
);
}
export default ChatContainer;
これは親のコンポーネントからroomの中のchatsとuserの情報を受け取りチャットのメッセージを表示する領域のコンポーネントです。
普通チャットと言えば自分のメッセージが右側、自分以外のメッセージが左側に表示されます。なので読み込んだchatプロパティのuidがuserのuidと一致するか動画でChatBalloonコンポーネントのwhoを"me"と "you"に分けて渡します。
ChatBalloon.tsx
import { FC } from "react";
import ContainerDiv from "../atom/containerDiv";
import BasicParagraph from "../atom/basicP";
import UserIcon from "../atom/userIcon";
import { ChatType } from "../../functions/database";
import { makeStyles, createStyles } from "@material-ui/core";
const useStyles = makeStyles(() => createStyles({
container: {
display: "inline-block",
marginTop: "1rem",
marginBottom: "1rem",
width: "97%",
height: "auto",
boxSizing: "border-box",
},
pContainer: {
width: "calc(100% - 100px)",
float: "left",
boxSizing: "border-box",
},
userArea: {
width: "100px",
float: "left",
textAlign: "center",
},
date: {
marginTop: "10px",
float: "right",
},
}));
type Props = {
chat: ChatType,
who: "me" | "you",
}
/**
* ユーザアイコン、チャットの内容を表示するコンポーネント
* @param param0
*/
const ChatBalloon:FC<Props> = ({
chat, who
}) => {
const classes = useStyles();
const date = new Date(chat.date);
if (who === "you") {
return (
<div className={ classes.container }>
<div className={ classes.userArea }>
<UserIcon
image={ chat.photoURL }
alt ={ chat.username }
width={ 70 }
height={ 70 }
/>
{ chat.username }
</div>
<div className={ classes.pContainer }>
<ContainerDiv
fullwidth={ true }
>
<BasicParagraph>
{ chat.text }
</BasicParagraph>
</ContainerDiv>
<div className={ classes.date }>
<BasicParagraph>
{ date.toLocaleString() }
</BasicParagraph>
</div>
</div>
</div>
);
}
return (
<div className={ classes.container }>
<div className={ classes.pContainer }>
<ContainerDiv
fullwidth={ true }
>
<BasicParagraph>
{ chat.text }
</BasicParagraph>
</ContainerDiv>
<div className={ classes.date }>
<BasicParagraph>
{ date.toLocaleString() }
</BasicParagraph>
</div>
</div>
<div className={ classes.userArea }>
<UserIcon
image={ chat.photoURL }
alt ={ chat.username }
width={ 70 }
height={ 70 }
/>
{ chat.username }
</div>
</div>
);
}
export default ChatBalloon;
これはchatとwho情報を受け取って、よくあるメッセージ・ユーザアイコン・ユーザネームを表示する領域です。
これを実行するとこのようになります。
見た目は良さそうですね。次回は書き込むフォームを作っていこうと思います。
この記事が気に入ったらサポートをしてみませんか?