Commit a90500c9 authored by blackheaven's avatar blackheaven
Browse files

Initial commit

parents
Loading
Loading
Loading
Loading

.babelrc

0 → 100644
+5 −0
Original line number Diff line number Diff line
{
    "presets": ["next/babel"],
    "plugins": ["babel-plugin-styled-components"]
}
 No newline at end of file

.gitignore

0 → 100644
+35 −0
Original line number Diff line number Diff line
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
node_modules
.pnp
.pnp.js

# testing
coverage

# next.js
.next/
out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env*.local

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts

README.md

0 → 100644
+34 −0
Original line number Diff line number Diff line
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

## Getting Started

First, run the development server:

```bash
npm run dev
# or
yarn dev
# or
pnpm dev
```

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!

## Deploy on Vercel

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.

components/Chat.tsx

0 → 100644
+240 −0
Original line number Diff line number Diff line

import { InfoOutlined, InputSharp, Star, StarBorderOutlined } from "@mui/icons-material";
import { Avatar } from "@mui/material";
import { useRouter } from "next/router";
import React from "react";
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useAuthState } from "react-firebase-hooks/auth";
import { useCollection, useDocument } from "react-firebase-hooks/firestore";
import styled from "styled-components";
import { auth, database } from "../firebase";
import { useStore } from "../utils/appState";
import ChatBase from "./ChatBase";
import { get, child, ref } from "firebase/database";
import ChatInput from "./ChatInput";
import Image from "next/image";
function Chat({ id }) {
    
    

   
    //channels
    
    const router = useRouter();
    const [user] = useAuthState(auth);
    // const [userData] = useDocument(db.collection("users").doc(user.uid));
    // const curProj = db.collection('projects').doc(pjid);
    const [init, setInit] = useState(true);
    const [cData, setCData] = useState(null);
    

    const dbRef = ref(database);
    const [opNick, setOpNick] = useState("Loading...");
    const [opUser, setOpuser]=useState(null);

    const [chatData, setChatData] = useState(null);
    const getUsername = (email:string) => {
        get(child(dbRef, 'users/')).then(res=>{
            const obUser = Object.values(res.val()).filter(user=>user['email'] === email[0]);
            setOpuser(obUser[0]);
            setOpNick(obUser[0]?.["displayName"])
        })
    }
    useEffect(()=>{
        if(!id) return; 
        get(child(dbRef, 'userRooms/' + user.uid + "/" + id + "/")).then(res=>{
            if(res.val()===null) return;

            getUsername(res.val()["userList"].filter(chatUser => user.email != chatUser));
            setChatData(res.val());
        })        
    }, [id])


    const chatCnt = useRef(15);

    //curProj.collection('projects').doc(pjid).collection('chats').doc(String(dmRoomId))
    return (
        <>
            {init && (
                    
                    <ChatContainer>
                        
                        <ChatInnerContainer height="10%">
                            <HeaderContainer>
                                <Header>
                                    <HeaderLeft>
                                        {opUser && <>
                                            {opUser["photoURL"] ? <>
                                            <Image src={opUser?.["photoURL"]} alt="상대방" width="30" height="30" style={{margin:"10px", borderRadius:"100px"}} layout="fixed"/>
                                            
                                            </> : <>
                                            <Avatar sx={{width:"30px", height:"30px", margin:"10px"}}/>

                                            </>
                                            }
                                        </>}

                                        <h4><strong>{id?opNick:"채팅할 상대를 클릭해주세요."}</strong></h4>
                                    </HeaderLeft>
<HeaderRight>
<button onClick={()=>auth.signOut()}>Log out</button>

</HeaderRight>
                                </Header>
                            </HeaderContainer>                            
                        </ChatInnerContainer>

                        <ChatInnerContainer height="90%">
                            {id && <ChatBase id={id} chatData={chatData} opUser={opUser} />}
                            {chatData && <ChatInput roomId={id} opUser={opUser} chatData={chatData} />}
                        </ChatInnerContainer>
                    </ChatContainer>
            )}        
        </>
                


        

    )
}
export default memo(Chat);

const SidebarInfo = styled.div`
    display:flex;
    align-items: center;
    width:100%;
    button {
    }


`;
const ImageContainer = styled.div`
    position:relative;
`
const SidebarInfoS = styled.div<{fSize:number}>`
    @media (max-width: 1300px) {
        > h2 {
            opacity: 0;
        }
    }
        @media (min-width: 769px) and (max-width:1300px) {
        width:200px;
        opacity: 0;
    }
        @media (min-width: 1301px) and (max-width:2200px) {
        width:200px;
        font-size: ${(p)=>(p.fSize * 1.4 - 25 + "px")};
    }
    display:flex;
    margin:5px;
    width:100%;
    transition-duration: 0.5s;
    transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55);
    justify-content: space-around;
    align-items: center;
    font-family: "Noto Sans KR";
    font-weight: 600;
    font-size:${(p)=>(p.fSize - 5 + "px")};
`

const HeaderAvatar = styled(Avatar)`
    top:0px;
    left:0px;
        transition-duration: 0.5s;
    transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55);
    @media (max-width: 1300px) {
        top:-10px;
        left:-5px;
        transition-duration: 0.5s;
    transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55);
    }
    cursor:pointer;
    margin:5px;
    &:hover {
        opacity:0.8;
    }

    
`

const ChatContainer = styled.div`
    box-sizing: border-box;
    flex-grow:2;
    width:100%;
    height:100%;
    position:relative;
    background-color: white;
    overflow:hidden;
`
const ChatInnerContainer = styled.div<{height:any}>`
    box-sizing: border-box;
    height:${p=>p.height};
    position:relative;

    background-color: #404040;
    overflow:hidden;
`
const HeaderRight = styled.div`
    align-items: center;
    >p {
        align-items: center;
        font-size:14px;
    }
    > p > .MuiSvgIcon-root {
        margin-right: 5px !important;
        font-size: 16px;
    }
    button{
        margin-right:10px;
        background:gray;
        color:white;
        border:none;
        border-radius: 10px;
        padding:5px;

    }

`

const HeaderLeft = styled.div`
    display:flex;
    align-items: center;
    padding:20px;
    font-size:30px;
    color:white;
    > h4 {
        display:flex;
        text-transform: lowercase;
        margin-right:10px;
    }

    > h4 > .MuiSvgIcon-root {
        margin-left: 10px;
        font-size: 18px;
    }
`
const HeaderContainer = styled.div`
    position:relative;
    background-color: black;


`
const Header = styled.div`
    position:absolute;
    z-index:1;
    width:100%;
    display:flex;
    justify-content: space-between;
    align-items: center;
    border-bottom: 1px solid lightgray;
    height:60px;
    background-color:#080808;
`
const HeaderMargin = styled.div`
    margin-top: 60px;
    position:relative;
`

+93 −0
Original line number Diff line number Diff line
import { useRef, useEffect, useState, useReducer } from "react";
import { useCallback } from "react";
import { memo } from "react";
import { useAuthState } from "react-firebase-hooks/auth";
import { useCollection } from "react-firebase-hooks/firestore";
import styled from "styled-components";
import { auth } from "../firebase";
import { database } from "../firebase";
import ChatInput from "./ChatInput";
import Message from "./Message";
import { useStore } from "../utils/appState";
import { ref, onValue, remove } from "firebase/database";
import {v4 as uuidv4} from 'uuid';
const ChatContainer = styled.div`


    position:relative;

    top:0;
    width:100%;
    height:90%;
    overflow-y:auto;
  &::-webkit-scrollbar {
    width: 20px;
    border:2px #404040;

  }
  &::-webkit-scrollbar-thumb {
    background-color: #a4a4a4;
    border-radius: 100px;
    background-clip: padding-box;
    border: 5px solid transparent;

  }
  &::-webkit-scrollbar-track {
    background-color: #404040;
  }

`

const ChatBase = ({id, chatData, opUser}) => {
    const [curUser] = useAuthState(auth);
    const {roomId} = useStore();
    const [messages, setMessages] = useState<any>([])
    const keys = useRef(null);

    const chatRef = useRef(null);
    useEffect(()=>{
        const starCountRef = ref(database, 'messages/' + roomId);
        onValue(starCountRef, (snapshot) => {
            const data = snapshot.val();
            keys.current = data&&Object.keys(data);
            setMessages(data&&Object.values(data));
        });
    }, [roomId])
    const deleteMessage = (id) =>{
        remove(ref(database, 'messages/'+roomId+"/"+id));
    }
    
    const focusMessage = () =>{
        chatRef?.current?.scrollIntoView({smooth:"true", block:"end"});
    }
    useEffect(() => {

        focusMessage();
    }, [roomId, messages])
    return <ChatContainer >
        <div ref={chatRef}>
        {!!messages&&<>
                {messages.reverse().map((msg, i)=>{
                    const {message, timestamp, user, userEmail, userImage, type} = msg;
                    return <Message
                    key={keys.current[i]}
                    deleteMessage={()=>{deleteMessage(keys.current[i])}}
                    message={message}
                    type={type}
                    timestamp={timestamp}
                    user={curUser}
                    userImage={userImage}
                    email={userEmail}
                    nickname={user}
                    />
                })}   
            </>}


        </div>

        </ChatContainer> 
}

export default memo(ChatBase);
 No newline at end of file