개인 프로젝트(고민 상담소)

개인 포트폴리오 고민 상담소 #6

해기97 2023. 8. 24. 20:43

저번 시간에 해야할 일들을 적어놓은걸 토대로 하나씩 부셔보자,,

 


일단 작성해놓은 건 아닌데 사이드메뉴에 로그인 했다면 로그인과 회원가입 버튼을 가리고 유저정보를 띄우자.

 

까먹고 작성해놓지 않았었는데 사이드메뉴를 조금 수정해줘야한다. 지금은 로그인을 했음에도 불구하고 회원가입 및 로그인이 계속 존재한다. 근데.. SPA의 경우 새로고침이 없는게 장점인걸로 아는데 로그인을 했다면 새로고침 해줘야하나..?

 

일단 만들어 보고 안되면 고민하자

 

현재 지금 모든걸 관리해주는 곳은 App.tsx가 아닌 Layout.tsx이므로 Layout에서 유저정보를 관리해주고있다.

거기서 관리해주는 유저정보를 토대로 유저정보가 존재한다면 사이드메뉴에 유저정보를

존재하지않는다면 사이드메뉴에 회원가입 및 로그인을 보여주면 될 것 같다. (이정돈 간단하다!)

 

        <Container $menuState={menuState}>
            <FontAwesomeIcon onClick={sideMenuBtn} icon={faXmark} />
            {/* <SideMenuUserInfo/> */}
            <SideMenuLogin/>
            <SideMenuCategory/>
        </Container>

지금은 사이드메뉴에 이런식으로 작성이되어있다. UserInfo는 잠시 주석처리를 해둔 뒤 로그인 및 회원가입을 띄워둔 상태였는데 유저정보를 기반으로 삼항연산자를 걸어주면 끝일 것 같은데..?

(여기서 조금 고민이 생겼는데 파이어베이스에서 user정보를 받아오는 메서드가 있는데 이걸 사용해야할지 로컬스토리지에 유저정보를 저장해둔 뒤 그걸 사용해야할지 모르겠다.. 일단 파이어베이스에서 가져오는 user정보를 사용해서 만들어 둔 뒤 다른분한테 물어보고 수정하는걸로 해야할 것 같다.)

 

export default function SideMenu(){
    const menuState = useAppSelector((state) => state.sideMenu);

    const [userUid,setUserUid] = useState<string>()

    const auth = getAuth()
    useEffectOnce(()=>{
        onAuthStateChanged(auth,(user)=>{
            if(user){
                setUserUid(user.uid)
            }else{
                setUserUid(undefined)
            }
        })
    })

    const sideMenuBtn = useSideMenuBtn()
    return(
        <Container $menuState={menuState}>
            <FontAwesomeIcon onClick={sideMenuBtn} icon={faXmark} />
            {userUid ? <SideMenuUserInfo/> : <SideMenuLogin/>}
            <SideMenuCategory/>
        </Container>
    )
}

일단은 파이어베이스에서 가져온 로그인 한 유저의 정보 중 uid를 뽑아와  uid가 존재한다면 사이드 메뉴에 유저 정보를 보여주고 없다면 로그인 및 회원가입을 보여주기로 했다. 테스트 해보니 제대로 작동도 하며 새로고침 또한 필요없다.

시험 해본 모습

일단 잘 작동되고 있으니 .. 사이드메뉴도 여기서 마무리 짓자.

 


글 수정 및 삭제를 하기 전 포스팅에 유저 정보를 담아둬야할거같다.

 

글 수정 및 삭제 기능을 만들기 전에 유저가 새로운 글을 포스팅 했을 때 데이터베이스에 타이틀, 본문, 닉네임(익명), 날짜, 등등을 보낼 때 유저의 uid를 같이 보내줘야 uid를 토대로 본인만 수정 및 삭제를 할 수 있을터이니..

 

한마디로 글 생성할 때 데이터베이스에 보낼 데이터를 제대로 정리를 해주자는 것이다.

 

이것도 뭐 간단하지않을까!

 

여기서.. 위 기능을 고민하다 생각난건데 유저 정보에서는 uid, 닉네임, 유저 프로필사진 경로 정도만 가져오면 되는데..

Layout에서 관리할 때 유저 정보가 존재할 때 store에 저장해두면 편하게 사용할 수 있지않을까?

 

일단 만들어보자,, 해보면 알겠지

 

Layout 컴포넌트에서 위와 같이 관리해주기로했다. 로그인해보니

깔끔하게 잘 들어가는걸 볼 수 있었다. 이제 이걸 가지고 데이터베이스에도 사용하고 사이드메뉴 프로필 사진에도 사용하고 뭐,, 기타등등 여기저기 사용하면 될 것 같다.

 

이제 이걸 가지고 글을 작성할 때 보내줄 데이터로 uid도 보내주게 바꿔놓자.

 

글 작성 기능을 훅으로 만들어놓았기에 uid 보내주는 것도 간단하게 추가해줄 수 있었다. (대박편함)

 

import { addDoc, collection } from "firebase/firestore/lite";
import { db } from "../api/firebase";

// type useWriteBtnProps = {
//     writeValue: ListItemType
// }

export default async function useWriteBtn(writeValue:any,userState:any){
    try{
        const docRef = await addDoc(collection(db,writeValue.category),{
            title: writeValue.title,
            content: writeValue.content,
            category: writeValue.category,
            userUid: userState.userUid
        })
        return docRef
    } catch(error){
        console.error(`${error}에러 발생 했따`)
    }
}

기존에는 writeValue만 매개변수로 받아왔었는데 지금은 userState도 추가되었을 뿐이다. 그리고 그곳에서 userState 중 Uid만 뽑아서 사용하면 되는 것..!

 

추후에 조건문으로 category가 free(잡담소) 라면 userPhoto도 같이 보내주는걸로 해주면 될 것 같다.

 

테스트중임

글 작성 해보고 데이터베이스를 한번 보기로했다.

 

유저 Uid도 잘 넘오온다!

잘 넘어오는걸 확인했으니 이제 이걸 토대로 수정 및 삭제를 만들어보자..!

 


이번엔 진짜 수정 및 삭제를 만들어보자.

 

이번엔 수정 및 삭제기능을 만들어보고 유저의 Uid가 일치하면 수정 버튼과 삭제버튼이 보이게 만들어줘야한다.

 

그러기위해 데이터베이스에 uid를 보낸 것

 

일단 uid 없이 수정부터 만들어보자.

 

아마 파이어베이스에는 데이터베이스를 수정하는 업데이트 메서드가 존재할텐데.. 공식문서를 확인해보고 만들어보면 될 것 같다.

 

일단 수정 페이지가 있어야하는데 기존에 글 생성 페이지와 똑같이 생겼기에 글 생성 페이지를 또 사용할 수 있는 방법이 뭐가있을 지 생각해보자,,

 

아무리 생각해도 생각이 안나서 그냥 복사해서 사용해야겠다.ㅋㅋ(에잉 ㅋㅋ)

다만 스타일의 경우 똑같으니 한곳에서 관리해주는 것이 좋을 것 같다.

 

일단 모든 컴포넌트를 복사해준 뒤 수정하기를 눌렀을 때 Edit을 관리해줄 store에 해당 게시글의 내용들이 모두 저장되게 해주어야할 것 같다.

 

다행히도 디테일페이지를 잘 만들어놔서 store에 보내줄 정보를 바로 구할 수 있었다.

 

export default function DetailPage(){
    const { id,category } = useParams()
    const detailData = useFetchDetailData({collectionName: category, dataId: id?.toString()})

    const navigate = useNavigate()

    const dispatch = useAppDispatch()

    const editButton = () =>{
        navigate(`/edit/${category}/${id}`)
        dispatch(onChangeEditTitle(detailData?.title))
        dispatch(onChangeEditContent(detailData?.content))
        dispatch(onChangeEditCategory(detailData?.category))
    }

    if (!detailData) {
    return (
        <PageContainer>
            <p>Loading...</p>
        </PageContainer>
    );
}

return (
    <PageContainer>
        <h1>{detailData.title}</h1>
        <p>{detailData.content}</p>

        <button onClick={editButton}>수정하기</button>
    </PageContainer>
);
}

수정하기 눌렀을 때 스토어에서 관리해주는 edit value값들에 그 페이지의 내용을 넘겨주니 제대로 받아오는 것도 확인이 됐고 이걸 토대로 수정만 하면된다.

 

여기서 파이어베이스 데이터를 수정하는 부분에서 공식문서를 보고 해결이 잘 안되서 GPT에게 물어보고 진행하기로 했다

 

일단 수정부분은 GPT의 도움으로 해결이 됐다.

 

import { doc, updateDoc } from 'firebase/firestore/lite'
import { db } from '../api/firebase'

export default async function useEditBtn
(editData: any,userState: any,category: any,id:any){

    try{
        const docRef = doc(db,category,id)
        await updateDoc(docRef,{
            content: editData.editContent,
            title: editData.editTitle,
            category: category
        })
        console.log(category)
    }catch(error){
        console.log(error)
        console.log(editData)
        console.log(category,id)
    }

}

doc로 컬렉션과 수정할 문서를 고르고 updateDoc라는 메서드를 사용해주면 완성이었다.

 

여기서 이 수정 기능을 만들 때 원래는 카테고리도 수정할 수 있게끔 만드려했는데 추후 문제가 생길 수도 있겠다 라는 생각에 카테고리는 수정을 할 수 없게 만들어뒀다.

 

(여기서 문제라고 생각한 이유는 익명 게시판에 작성해놓은걸 수정했다가 모르고 잡담 카테고리로 잘못 수정해버린다면 익명으로 남겼던 고민을 의도치않게 익명을 공개해버리는 셈이 되어버리니.. 카테고리 수정을 없애버렸다.)

 

파라미터로 수정할 내용과 유저정보 그리고 현재 카테고리 및 id값을 받아오며 수정 버튼에서 잘 사용만 해주면 된다.

 

const {id,category} = useParams()

    const navigate = useNavigate()

    const createBtn = useEditBtn;

    const handelEditBtn = async () => {
        await createBtn(editData, getUserState, category, id);
        navigate(`/${category}`)
    }

    return(
        <Container>
            <button onClick={handelEditBtn}>
                수정하기
            </button>
        </Container>
    )

이렇게 사용을 해주었고 결과적으로는 잘 작동한다.

잘 작동하니 일단 이정도로 완성을 해주고 삭제기능을 만들어주자.

 


삭제 기능 완성하기

 

삭제 기능 또한 공식문서에서 remove()?를 사용해주면 된다는 글이 써져있던거같은데 내가 이해를 잘 못하는건지.. 그걸 보고 완성을 못하겠어서 GPT의 도움으로 해결했다.

 

import { deleteDoc, doc } from "firebase/firestore/lite";
import { db } from "../api/firebase";

export default async function useDeleteBtn(category: any,id: any){

    const docRef = doc(db,category,id);

    try{
        await deleteDoc(docRef)
    }catch(error){
        console.error(error)
    }
}

여기서는 파라미터로 category와 id를 받아오며 수정 때와 같이 doc로 컬렉션과 문서를 지정해준 뒤

 

deleteDoc 라는 메서드를 사용해주면 끝이었다.

 

const deleteBtn = useDeleteBtn

const removeButton = () => {
    deleteBtn(category,id)
}

return (
    <PageContainer>
        <h1>{detailData.title}</h1>
        <p>{detailData.content}</p>

        <button onClick={editButton}>수정하기</button>
        <button onClick={removeButton}>삭제하기</button>

그러면 이렇게 삭제하기 버튼에 달아주기만 하면 끝이다.

 

근데 지금은 삭제를 누르면 냅다 지워져버리니.. 팝업창을 띄워주는 것이 좋을 듯 해서 만들어줘야할 것 같다.

 

팝업창의 경우는 직접 만들어주기로 했다. confirm을 사용해주면 금방 만들 수 있겠지만 그냥 만들어버리기로했다.

 

일단.. 이번 포스팅은 여기까지.. 작성하고 다음 포스팅에서 마저 이어가자..