미새문지

24.09.19 day67 작업 일지 본문

개발 TIL

24.09.19 day67 작업 일지

문미새 2024. 9. 19. 23:58
728x90

주말과 추석을 쭉 쉬고 블로그 쓰려니까 너무 힘들다. 다시 열심히 해야될듯..

프로젝트를 슬슬 마무리를 지으려고 해서 추석 때 틈틈히 작업을 좀 해두었고  오늘부터 다시 재희님과 작업을 병행하며 데이터를 연동했다.

먼저 휴일에 메인페이지 하단의 배너 슬라이드 부분을 구현했다.

import { useEffect, useState } from "react";
import styled from "styled-components";
import ad1 from "../../../img/adBanner/1.jpg";
import ad2 from "../../../img/adBanner/2.jpg";
import ad3 from "../../../img/adBanner/3.jpg";
import ad4 from "../../../img/adBanner/4.jpg";
import ad5 from "../../../img/adBanner/5.jpg";
import ad6 from "../../../img/adBanner/6.jpg";

const AdBox = () => {
  const images = [ad1, ad2, ad3, ad4, ad5, ad6];
  const [currentIndex, setCurrentIndex] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setCurrentIndex((prevIndex) => (prevIndex + 1) % images.length);
    }, 3000);

    return () => clearInterval(interval);
  }, [images.length]);

  const handleDotClick = (index: number) => {
    setCurrentIndex(index);
  };

  return (
    <>
      <AdBoxWrapper>
        <BannerTrack currentIndex={currentIndex}>
          {images.map((image, index) => (
            <BannerBox key={index}>
              <img src={image} alt={`ad-banner-${index + 1}`} />
            </BannerBox>
          ))}
        </BannerTrack>
        <DotWrapper>
          {images.map((_, index) => (
            <Dot
              key={index}
              isActive={index === currentIndex}
              onClick={() => handleDotClick(index)}
            />
          ))}
        </DotWrapper>
      </AdBoxWrapper>
    </>
  );
};

export default AdBox;

const AdBoxWrapper = styled.div`
  width: 100%;
  height: 180px;
  overflow: hidden;
  position: relative;
  margin-bottom: 30px;
`;

const BannerTrack = styled.div<{ currentIndex: number }>`
  display: flex;
  width: 100%;
  height: 100%;
  transform: translateX(${(props) => -props.currentIndex * 100}%);
  transition: transform 0.5s ease-in-out;
`;

const BannerBox = styled.div`
  min-width: 100%;
  height: 100%;

  img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
`;

const DotWrapper = styled.div`
  position: absolute;
  bottom: 10px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 5px;
`;

const Dot = styled.div<{ isActive: boolean }>`
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background-color: ${(props) => (props.isActive ? "#000" : "#ccc")};
  transition: background-color 0.3s ease;
  cursor: pointer;
`;

이미지를 여러 개 가져와서 배열에 담아 일정 시간마다 이미지를 변경한다. 코드에선 3초마다 이미지의 index를 +1하며 부드러운 움직임을 위해 css로 transform을 이용해 해당 인덱스가 바뀔 때마다 100%의 width값을 밀어낸다. 그리고 transition을 이용해 해당 애니메이션을 부드럽게 해준다.

그리고 배너 하단의 점들을 이용해 현재 배너가 몇 번째인지 알 수 있게 하고 특정 점을 클릭하면 해당 배너로 이동된다.

 

추가적으로 로그인/회원가입을 갈 수 있는 경로가 없어 마이페이지에 로그인한 유저의 토큰이 없다면 

이런식으로 로그인하러갈 수 있게 버튼을 만들어줬다. 반대로 토큰이 있다면 해당 유저의 프로필이 보이게

해당 기능을 만들면서 api를 통해 서버에서 유저 데이터를 가져와 마이페이지 데이터를 연동했다.

import { useEffect, useState } from "react";
import "../../scss/mypage/profile.scss";
import CommonTag from "../common/commonTag";
import axios from "axios";
import { useNavigate } from "react-router-dom";

interface userProfile {
  username: string;
  email: string;
  gender: string;
  password: string;
  birth_date: string;
  profileImg: string;
  problem: string[];
}

const Profile: React.FC = () => {
  const [profile, setProfile] = useState<userProfile | null>(null);
  const backPort = process.env.REACT_APP_BACKEND_PORT;
  const navigate = useNavigate();
  const [hasToken, setHasToken] = useState<boolean>(false);
  const userKey = sessionStorage.getItem("userKey");

  useEffect(() => {
    const token = sessionStorage.getItem("authToken");

    if (token) {
      setHasToken(true);
      axios
        .get(`${backPort}/api/user/${userKey}`, {
          headers: {
            Authorization: `Bearer ${token}`,
          },
        })
        .then((response) => {
          setProfile(response.data);
        })
        .catch((error) => {
          console.error("프로필 조회 실패", error);
          setProfile(null);
        });
    } else {
      setHasToken(false);
    }
  }, [backPort]);

  const moveProfileEdit = () => {
    navigate("/mypage/profileEdit", { state: { profile } });
  };

  return (
    <>
      <div className="profileWrapper">
        {hasToken ? (
          <>
            <div className="profileImg">
              <div>
                <img
                  src={profile?.profileImg}
                  alt={`${profile?.username} 프로필 이미지`}
                />
              </div>
              <p>{profile?.username}</p>
            </div>
            <div className="selectFilter">
              {/* {profile?.trouble.map((item, index) => (
                <CommonTag key={index} tagName={item} />
              ))} */}
            </div>
            <button onClick={moveProfileEdit}>프로필 수정</button>
          </>
        ) : (
          <div className="goLoginBox">
            <p>로그인 또는 회원가입을 해주세요.</p>
            <button onClick={() => navigate("/login")}>로그인하러 가기</button>
          </div>
        )}
      </div>
    </>
  );
};
export default Profile;

 

이 후 연휴가 끝나고 본격적으로 재희님과 데이터 작업을 시작했다.

먼저 테스트를 위해 토큰을 삭제하거나 해야하는데 로그아웃 버튼이 없어 세션에 저장된 값을 제거하여 로그아웃 기능을 구현했다.

그리고 루틴 페이지에서 루틴 추가버튼이 우측 하단에 있어야 했으나 display: sticky로 설정한 탓에 루틴 데이터가 없으면 상단으로 올라가버려 너무 이상하게 보이더라. fixed는 확대나 축소를 했을 시 해당 부모 div를 벗어나버려 이상하게 보이기 때문에 absolute를 통해 해당 버튼을 고정해줬다. 이래도 너무 확대하거나하면 틀어지지만 그 정도는 괜찮을 듯 하고 나중에 모든 기능을 다 구현하고 추가적인 수정이 있을 때 건드는 게 맞는 것 같아 뒤로 미뤄뒀다.

.addRoutineBtn {
  width: 60px;
  height: 60px;
  border: none;
  border-radius: 50%;
  background-color: #ffa4e4;
  position: absolute;
  bottom: 20px;
  right: 20px;
  // margin-right: 3%;
  font-size: 65px;
  color: white;
  cursor: pointer;
  opacity: 0.8;
  z-index: 1000;
  display: flex;
  justify-content: center;
  align-items: center;

  &:hover {
    opacity: 1;
  }

  span {
    transform: translate(3%, -8%);
  }
}

 

재희넴과 회의와 모각코를 하며 여러가지 api 데이터를 수정했다.

루틴 페이지에서 특정 루틴을 클릭했을 때 루틴 상세 페이지로 넘어가야 하지만 구현이 안되어있었다. 이 부분을 재희님이 필요한 데이터를 수정해 api로 쏴주면서 상세 페이지로 넘어갈 수 있게 구현했다.

problem과 tag의 경우엔 현재 서버에서 코드를 수정중이라 UI를 위해 다른 데이터를 넣어놨다. 이런식으로 데이터가 주어지고 이제 해당 item_key로 루틴 제품의 데이터도 가져와 화면에 뿌려주면 될 것 같다.

 

제품의 경우에도 구현이 안되어있다가 이번에 데이터를 수정하며 어느정도 구현해놨다.

현재 제품의 브랜드와 이미지는 서버에서 추가적으로 작업할 게 있어 보류해뒀고 나머지는 데이터를 가져온 걸 볼 수 있다.

필터 부분도 기존의 제품을 가져온 api 뒤에 param으로 메인과 서브 필터 값을 같이 보내주면 되는데 이 부분은 필터를 어떻게 전달할지 회의를 해야 하여 내일 수정할 것 같다.

 

특정 제품을 클릭했을 때

이미지와 브랜드를 제외하고 데이터를 받아온 걸 볼 수 있다. 아무래도 이미지가 없다보니 심심한 느낌이 드는데 데이터 연동이 된 것을 확인했기 때문에 나중엔 데이터만 추가해 받아오면 될 것이다.

제품 효과 박스는 현재 어떻게 할지 고민중이다. 데이터 크롤링을 한다고 해도 저 부분은 직접 넣어줘야 해서 좀 까다롭다.

 

현재 루틴 추가 페이지에서 기존에는 제품을 가져올 때 테스트로 item_key를 넣어 가져왔지만 이 부분을 수정 중이다.

이제 item_key대신 텍스트를 입력하며 해당 텍스트가 들어있는 제품이 있으면 api를 통해 서버에서 제품들을 가져와 화면에 보여주고 해당 제품 클릭 시 제품의 텍스트가 들어가는 방식으로 작업할 계획이다.

다들 코드들이 좀 길어져서 블로그에 전부 넣기가 좀 애매하고 api 연동 부분은 특정 값을 제외하면 어느정도 비슷하기 때문에 짧게 하기 위해 넣지 않았다.

 

 

728x90

'개발 TIL' 카테고리의 다른 글

24.09.23 day69 작업 일지  (1) 2024.09.23
24.09.20 day68 작업 일지  (0) 2024.09.20
24.09.13 day66 작업 일지  (0) 2024.09.13
24.09.11 day65 작업 일지  (2) 2024.09.11
24.09.10 day64 작업 일지  (0) 2024.09.10