ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 4. Chat UI
    사이드프로젝트 2024. 7. 22. 14:02

    https://www.youtube.com/watch?v=-xXASlyU0Ck&t=2007s

    이 동영상을 보며 만드는 챗 웹 실습예제

     

    다음으로 이어서 채팅 UI를 만든다.

    import ChatHeader from "@/components/ChatHeader";
    import { Button } from "@/components/ui/button";
    import InitUser from "@/lib/store/InitUser";
    import { createClient } from "@/utils/supabase/server"; // supabase 객체 불러오기. // 서버 컴포넌트니깐 서버에서 임포트해온다.
    import React from "react";
    
    const page = async () => {
      const supabase = createClient(); // supabase 객체 불러오기.
    
      // const session = await supabase.auth.getSession();
      // console.log(session.data.session?.user);
    
      const user = (await supabase.auth.getUser()).data.user;
      // console.log("user: ", user);
    
      return (
        <>
          <div className="max-w-3xl mx-auto md:py-10 h-screen">
            <div className="h-full border rounded-md flex flex-col">
              <ChatHeader user={user} />
              {/* 이제 zustand를 통해 user의 state management를 하기 때문에 ChatHeader에 user props를 안넘겨줘도 되지만, 굳이 지울 필요도 없으므로 남겨준다. */}
              <div className="flex-1 bg-slate-500"></div>	// 새로 추가
              <div className="p-5"></div>	// 새로 추가
            </div>
          </div>
          <InitUser user={user} />
          {/* user state 관리를 시작할 수 있도록. */}
        </>
      );
    };
    
    export default page;

    저번까지 만들었던 app/page.tsx 에 div 두개를 추가해줬다. 

    그리고, Input을 추가해주기 위해 shadCn에서 Input을 검색해, 인스톨 명령어를 복사해주고 설치해준다.

    npx shadcn-ui@latest add input

     

    이제 좀 꾸며준다. 아직 DB랑 연결을 시켜서 뭘 한다거나 그러진 않고, 퍼블리싱을 해준다.

    import ChatHeader from "@/components/ChatHeader";
    import { Button } from "@/components/ui/button";
    import { Input } from "@/components/ui/input";
    import InitUser from "@/lib/store/InitUser";
    import { createClient } from "@/utils/supabase/server"; // supabase 객체 불러오기. // 서버 컴포넌트니깐 서버에서 임포트해온다.
    import React from "react";
    
    const page = async () => {
      const supabase = createClient(); // supabase 객체 불러오기.
    
      // const session = await supabase.auth.getSession();
      // console.log(session.data.session?.user);
    
      const user = (await supabase.auth.getUser()).data.user;
      // console.log("user: ", user);
    
      return (
        <>
          <div className="max-w-3xl mx-auto md:py-10 h-screen">
            <div className="h-full border rounded-md flex flex-col">
              <ChatHeader user={user} />
              {/* 이제 zustand를 통해 user의 state management를 하기 때문에 ChatHeader에 user props를 안넘겨줘도 되지만, 굳이 지울 필요도 없으므로 남겨준다. */}
              <div className="flex-1  flex flex-col p-5">
                <div className="flex-1"></div>
                <div>
                  <div className="flex gap-2">
                    <div className="h-10 w-10 bg-green-500 rounded-full"></div>
                    <div className="flex-1">
                      <div className="flex items-center gap-1">
                        <h1 className="font-bold">Jaehyeon</h1>
                        <h1 className="text-sm text-gray-400">
                          {new Date().toDateString()}
                        </h1>
                      </div>
                      <p className="text-gray-300">
                        Lorem ipsum dolor, sit amet consectetur adipisicing elit.
                        Quisquam minus dolorum voluptatibus perferendis nesciunt ex
                        odit rem est a maiores!
                      </p>
                    </div>
                  </div>
                </div>
              </div>
              <div className="p-5">
                <Input placeholder="send message" />
              </div>
            </div>
          </div>
          <InitUser user={user} />
          {/* user state 관리를 시작할 수 있도록. */}
        </>
      );
    };
    
    export default page;

    이렇게 하면 이런 화면이 나온다.

     

    잘 나온다. 그럼 메세지를 여러개 만들어본다.

    html을 복사해서 여러개 붙여넣는 게 아니라, DB에서 배열로 받아와서 map으로 뿌려줄거기때문에 위에서 만든 div를 배열로 여러개로 뿌려줘본다. 

    그리고 추가로 css 몇개 추가해줬다.

    import ChatHeader from "@/components/ChatHeader";
    import { Button } from "@/components/ui/button";
    import { Input } from "@/components/ui/input";
    import InitUser from "@/lib/store/InitUser";
    import { createClient } from "@/utils/supabase/server"; // supabase 객체 불러오기. // 서버 컴포넌트니깐 서버에서 임포트해온다.
    import React from "react";
    
    const page = async () => {
      const supabase = createClient(); // supabase 객체 불러오기.
    
      // const session = await supabase.auth.getSession();
      // console.log(session.data.session?.user);
    
      const user = (await supabase.auth.getUser()).data.user;
      // console.log("user: ", user);
    
      return (
        <>
          <div className="max-w-3xl mx-auto md:py-10 h-screen">
            <div className="h-full border rounded-md flex flex-col">
              <ChatHeader user={user} />
              {/* 이제 zustand를 통해 user의 state management를 하기 때문에 ChatHeader에 user props를 안넘겨줘도 되지만, 굳이 지울 필요도 없으므로 남겨준다. */}
              <div className="flex-1  flex flex-col p-5 h-full overflow-y-auto">
                <div className="flex-1"></div>
                <div className="space-y-7">
                  {Array.from({ length: 15 }, (v, i) => i).map((value) => {
                    return (
                      <div className="flex gap-2" key={value}>
                        <div className="h-10 w-10 bg-green-500 rounded-full"></div>
                        <div className="flex-1">
                          <div className="flex items-center gap-1">
                            <h1 className="font-bold">Jaehyeon</h1>
                            <h1 className="text-sm text-gray-400">
                              {new Date().toDateString()}
                            </h1>
                          </div>
                          <p className="text-gray-300">
                            Lorem ipsum dolor, sit amet consectetur adipisicing
                            elit. Quisquam minus dolorum voluptatibus perferendis
                            nesciunt ex odit rem est a maiores!
                          </p>
                        </div>
                      </div>
                    );
                  })}
                </div>
              </div>
              <div className="p-5">
                <Input placeholder="send message" />
              </div>
            </div>
          </div>
          <InitUser user={user} />
          {/* user state 관리를 시작할 수 있도록. */}
        </>
      );
    };
    
    export default page;

     

    ChatHeader.tsx

    "use client";
    
    import React from "react";
    import { Button } from "./ui/button";
    import { createClient } from "@/utils/supabase/client";
    import { User } from "@supabase/supabase-js";
    import { useRouter } from "next/navigation"; // 주의할 점. next/navigation에서 임포트한다.
    
    const ChatHeader = ({ user }: { user: User | null }) => {
      const router = useRouter();
    
      // props로 UserResponse를 받는다.
      const handleLoginWithGithub = () => {
        const supabase = createClient();
        supabase.auth.signInWithOAuth({
          provider: "github",
          options: {
            redirectTo: location.origin + "/auth/callback",
          },
        });
      };
    
      const handleLogout = async () => {
        const supabase = createClient();
        await supabase.auth.signOut();
        // const { error } = await supabase.auth.signOut();
        router.refresh();
      };
    
      return (
        <div className="h-20">
          <div className="p-5 border-b flex items-center justify-between h-full">
            <div>
              <h1 className="text-xl font-bold">Daily Chat</h1>
              <div className="flex items-center gap-1">
                <div className="h-4 w-4 bg-green-500 rounded-full animate-pulse"></div>
                <h1 className="text-sm text-gray-400">2 Online</h1>
              </div>
            </div>
            {user ? ( // user가 있으면 (로그인했으면) 로그아웃 버튼 표시, 없으면 (로그인 안했으면) 로그인 버튼 표시
              <Button onClick={handleLogout}>Logout</Button>
            ) : (
              <Button onClick={handleLoginWithGithub}>Login</Button>
            )}
          </div>
        </div>
      );
    };
    
    export default ChatHeader;

     

    Github : https://github.com/Wunhyeon/Next-Supabase-Chat/tree/4.ChatUI

     

    GitHub - Wunhyeon/Next-Supabase-Chat

    Contribute to Wunhyeon/Next-Supabase-Chat development by creating an account on GitHub.

    github.com

     

    댓글

Designed by Tistory.