Skip to content

goyomi/save_pets

 
 

Repository files navigation

🦴 Happy-Paw



🐾 해피포 (Happy-Paw) : 반려동물 통합 커뮤니티 서비스

배포 URL 테스트 ID 테스트 PW
https://happy4.netlify.app/ [email protected] happypawpw



0. 목차

  1. 프로젝트 소개
  2. 개발 환경
  3. 협업 환경
  4. 역할 분담
  5. 프로젝트 구현
  6. 핵심 코드
  7. 트러블 슈팅



1. 프로젝트 소개

  • 🐱 반려동물의 정보를 공유하는 커뮤니티를 구축합니다.
  • 🛍️ 원하는 물품을 판매하거나 구매하는 서비스를 제공합니다.
  • 🧤 사용자들 끼리 팔로우 기능을 통해 서로의 소식을 공유할 수 있습니다.
  • 🖼️ 글과 사진을 함께 업로드하여 반려 동물들의 일상을 자랑하고 공유할 수 있습니다.
  • 🧡 다른 사용자들의 글에 좋아요를 누르고 댓글을 작성할 수 있습니다.
  • 🗺️ 지도기능을 통해 내주변의 반려동물 카페, 병원, 호텔을 찾을 수 있습니다.



2. 개발 환경

2-1. 개발기간



2-2. 기술스택

Front-End Back-End Co-work & etc
제공된 API 사용




3. 협업 환경

3-1. 협업 컨벤션

3-1-1. 폴더 구조

🐾 HappyPaw
├─ 📦 public
│  ├─ ⭐ favicon.ico
│  └─ 📃 index.html
├─ 📦 src
│  ├─ 📂 api
│  ├─ 📂 assets
│  │  ├─ 📂 icon
│  │  └─ 📂 splash
│  ├─ 📂 components
│  │  ├─ 📂 common
│  │  │  ├─ 📂 Button
│  │  │  ├─ 📂 Carousel
│  │  │  ├─ 📂 Header
│  │  │  ├─ 📂 Input
│  │  │  ├─ 📂 MainLayout
│  │  │  ├─ 📂 Modal
│  │  │  ├─ 📂 TabMenu
│  │  │  └─ 📂 Wrapper
│  │  ├─ 📂 Follow
│  │  ├─ 📂 Post
│  │  ├─ 📂 Product
│  │  ├─ 📂 Profile
│  │  └─ 📂 Skeleton
│  ├─ 📂 context
│  ├─ 📂 hooks
│  ├─ 📂 pages
│  │  ├─ 📂 ChatPage
│  │  ├─ 📂 ErrorPage
│  │  ├─ 📂 FollowListPage
│  │  ├─ 📂 HomePage
│  │  ├─ 📂 JoinPage
│  │  ├─ 📂 LoginPage
│  │  ├─ 📂 MapPage
│  │  ├─ 📂 PostPage
│  │  ├─ 📂 ProductPage
│  │  ├─ 📂 ProfilePage
│  │  ├─ 📂 SearchPage
│  │  └─ 📂 SplashPage
│  ├─ 📂 routes
│  ├─ 📂 styles
|  ├─ 📜 App.js
|  └─ 📜 index.js


3-1-2. 코드 컨벤션

  • 타입은 종류 중 하나만 선택하며, 영어 소문자로 시작한다.
  • 주제는 한글로 간단명료하게 작성한다.
  • 주제의 마지막 문자로 .(마침표)를 사용하지 않는다.
  • 주제는 '-다', '-음'과 같은 어미로 끝내지 않고, 과거형을 사용하지 않는다.
    • 올바르지 않은 예 ) feat: 카카오 로그인 연동 기능을 추가했다, 혹은 추가함 (#3)
    • 옳은 예 ) feat: 카카오 로그인 연동 기능 추가 (#3)
  • 주제는 소스 코드를 보지 않고도 변경 사항이 무엇인지 알 수 있도록 작성해야 한다.
    • 올바르지 않은 예 ) design: CSS 조정 (#4)
    • 옳은 예 ) design: text box와 layout frame 사이에 left padding 추가 (#4)
  • 커밋 메시지는 제삼자가 봤을 때 무엇을 했는지 파악할 수 있게 자세히 작성한다.
  • 커밋 메시지는 어떻게 보단 무엇과 왜를 설명한다.
  • 한 커밋에는 한 가지 기능만 담는다.
    • 예 ) 화면 개발의 경우 : 컴포넌트 단위로 커밋
    • 예2 ) 기능 개발의 경우 : 각 기능 단위로 커밋


3-1-3. 커밋 메세지

- fix: 올바르지 않은 동작을 고친 경우
- feat: 새로운 기능을 추가한 경우
- refactor: 내부 로직은 변경하지 않고 코드를 개선한 경우
- style: 코드 개선과 상관없이 사소하게 코드를 수정한 경우
- design: 사용자 UI를 추가, 수정한 경우 (마크업, 퍼블리싱 작업)
- add: 폴더, 파일 등을 추가한 경우
- move: 폴더, 파일, 코드 등의 위치를 이동한 경우
- rename: 폴더명, 파일명 등을 수정한 경우
- remove: 폴더, 파일, 코드 등을 삭제한 경우
- assets: 에셋을 추가, 수정한 경우
- docs: 문서를 추가, 수정한 경우
- chore: 위의 모든 경우에 포함되지 않는 기타 수정사항


3-2. 협업 방식

- 공통 이슈만들고, 공유하고 싶은 문제가 있는 경우 이슈로 작성하여 공유하고 작업한 이력 남기기

스크린샷 2023-09-11 204309


- GitHub Project Board를 이용한 전체 진도 상황 공유

스크린샷 2023-09-11 202111


- 다른 팀원 코드의 BUG 찾는 경우 이슈 작성 후 Assignees 지정

스크린샷 2023-09-11 202412


- Common 컴포넌트 폴더를 따로 관리하여 코드 재사용율 높이기

스크린샷 2023-09-11 203732


- 페이지의 디자인의 일관성과 쉬운 유지보수를 위해 ThemeProvider를 사용

const colors = {
  primary: '#374259',
  secondary: '#b1b5bb',
  third: '#F2D8D8',
  gray: '#dbdbdb',
  bgGray: '#f2f2f2',
  txtColor: '#767676',
  warning: '#FD7A6E',
  white: '#fff',
};

const theme = { colors };

export default theme;


3-3. Git Branch 전략

- 소규모 프로젝트 방식 채택

그림1




4. 역할 분담

4-1. 팀원 소개

정현빈 박지윤 이상용 김미정
팀장 팀원 팀원 팀원
hyeonbinnn JiyunPark1301 yongisadragon goyomi


4-2. 역할 분담

해피포 마인드맵


5. 프로젝트 구현

5-1. 전체 UI

Frame 1



5-2. PC & Mobile

제목 없음



5-3. 페이지 기능

스플래시 로그인 회원가입 & 프로필 설정
스플래시 로그인 회원가입 프로필


계정 검색 팔로우 & 팔로잉
홈 계정 검색 팔로우 팔로잉


게시글 업로드 게시글 수정 게시글 삭제
게시글작성 게시글수정 게시글삭제


댓글 작성 댓글 삭제 댓글 신고
댓글작성 댓글삭제 댓글신고


상품 등록 상품 수정 상품 삭제
상품등록 상품수정 상품삭제


프로필 수정 404 지도
프로필 수정 404 지도



6. 핵심 코드

실시간 이메일, 계정 ID 중복 검사 실행

useEffect(() => {
  if (!['email', 'accountname'].includes(id)) return;

  if (
    (id === 'email' && !EMAIL_REGEX.test(formData.email)) ||
    (id === 'accountname' && !ID_REGEX.test(formData.accountname)) ||
    formData['accountname'] === userAccountname
    // 프로필 수정 페이지에서 현재 로그인한 유저의 accountname인 경우 이미 가입된 계정이라는 에러 메세지를 보여주지 않기 위함
  ) {
    return;
  }

  const errorMsg = id === 'email' ? '이미 가입된 이메일 주소 입니다.' : '이미 가입된 계정ID 입니다.';

  const timer = setTimeout(() => {
    checkDuplication(errorMsg);
  }, 300);

  return () => {
    clearTimeout(timer);
  };
}, [formData.email, formData.accountname]);
  • emailaccountname만 중복 검사를 진행하기 때문에 id가 다른 값이 되면 return을 합니다.
    그 다음 formData.email, formData.accountname이 변경될 때마다 실행이 됩니다.

  • 조건문을 통해 입력된 이메일과 계정 ID의 형식이 올바른지 확인한 뒤, formData.accountname이 현재 로그인한 사용자의 계정 ID와 일치하지 않는지 확인 후, 만약 조건에 해당하지 않는다면 함수를 종료합니다.

  • 그 이외에, 중복된 이메일 또는 계정 ID 에러 메시지를 설정하고, 300밀리초 후에 checkDuplication 함수를 호출합니다.
    timer 변수에는 setTimeout 함수로 생성된 타이머 ID가 저장되며, clearTimeout을 사용하여 타이머 취소가 가능합니다.

  • useEffect의 반환 함수는 해당 이펙트가 정리(clean-up)될 때 실행하고, 여기서 타이머를 취소하기 위해 clearTimeout을 호출합니다.
    디바운싱 기능을 적용함으로써 사용자가 입력할 때마다 서버요청을 하지 않기에 통신 비용이 발생하지 않습니다.



이미지 업로드를 위한 커스텀 훅

import { useState } from 'react';
import { uploadImages } from '../api/image';

const ALLOWED_EXTENSIONS = ['.jpg', '.gif', '.png', '.jpeg', '.bmp', '.tif', '.heic'];
const MAX_SIZE = 10 * 1024 * 1024;

const useImagesUpload = () => {
  const [images, setImages] = useState([]);

  const onUpload = async (files, length) => {
    if (images.length + length > 3) return alert('이미지는 최대 3개까지 업로드 할 수 있습니다.');

    const formData = new FormData();
    for (let i = 0; i < length; i++) {
      const file = files[i];

      const fileExtension = file.name.split('.').pop().toLowerCase();
      if (ALLOWED_EXTENSIONS.includes(`.${fileExtension}`) && file.size <= MAX_SIZE) {
        formData.append('image', file);
      }
    }

    try {
      const data = await uploadImages(formData);
      const filenames = data.map((data) => data.filename);
      setImages((prev) => [...prev, ...filenames]);
    } catch (error) {
      console.log(error.message);
    }
  };

  const onDelete = (index) => {
    setImages((prevImages) => {
      const updatedImages = [...prevImages];
      updatedImages.splice(index, 1);
      return updatedImages;
    });

    alert('삭제되었습니다.');
  };

  return { images, onUpload, onDelete };
};

export default useImagesUpload;
  • 이미지 업로드는 특성상 회원가입 시 프로필 설정, 프로필 수정, 게시글 작성, 상품 등록 등 여러 페이지에서 반복적으로 사용됩니다. 그래서 여러 이미지를 업로드 할 수 있는 상태를 선언하고, 새롭게 들어오는 이미지들과 기존 이미지를 합친 값이 3이 넘으면 더 이상 업로드 할 수 없도록 구현합니다.

  • FormData 객체를 생성하고, files 배열을 순회하면서 허용되는 확장자 목록과 이미지 사이즈를 검사한 뒤, 통과한다면 formDataimage 라는 키 값으로 파일을 추가할 수 있습니다.

  • 그 다음 uploadImages 함수를 통해 서버에 이미지를 업로드하고, 서버 응답에서 파일명을 추출하여 상태를 업데이트하고, setImages 함수를 사용해 이전 상태값인 prev 배열과 새로운 파일명 배열인 filenames를 합쳐서 상태를 갱신합니다.

  • 이렇게 함으로써, 이미지 업로드 후의 상태값을 업데이트하고 React 컴포넌트가 리렌더링될 수 있도록 합니다.




7. 트러블 슈팅

반복되는 API 요청 작업을 줄이기 위해 파일 분리하기

const BASE_URL = 'https://api.mandarin.weniv.co.kr';

export const request = async (url, options) => {
  try {
    const response = await fetch(`${BASE_URL}/${url}`, {
      ...options,
      headers: {
        'Content-Type': 'application/json',
        ...options.headers,
      },
    });

    if (response.ok) {
      const data = await response.json();
      return data;
    }
  } catch (err) {
    console.log(err);
  }
};

export const imageRequest = async (url, options) => {
  try {
    const response = await fetch(`${BASE_URL}/${url}`, { ...options });

    if (response.ok) {
      const data = await response.json();
      return data;
    }
  } catch (err) {
    console.log(err);
  }
};
  • 가장 기본이 되는 request 함수를 만들어 줍니다. 그 다음, 로그인은 auth.js , 게시글은 post.js , 상품은 product.js 등 기능별로 파일을 만듭니다.


import { request } from './request';

// 회원가입
export const join = async (state, formData, image) => {
  return await request('user', {
    method: 'POST',
    body: JSON.stringify({ user: { ...state, ...formData, image } }),
  });
};

// 로그인
export const login = async (email, password) => {
  return await request('user/login', {
    method: 'POST',
    body: JSON.stringify({ user: { email, password } }),
  });
};

// 토큰 검증
// ...

// 이미 존재하는 이메일(또는 계정)인지 검사
export const validateForm = async (id, formData) => {
  return await request(`user/${id}valid`, {
    method: 'POST',
    body: JSON.stringify({ user: { [id]: formData[id] } }),
  });
};
  • 파일 내에서 필요한 요청들 즉, auth.js는 회원가입, 로그인 등 post.js는 게시글 불러오기, 업로드, 수정, 삭제, 신고 등 각각의 함수로 만들어 줍니다.

  • 그리고 각각의 함수를 사용할 때는 먼저 import 해주고, api를 가져온 후 필요한 인자 값들을 넘겨주면 됩니다.



화면 캡처 2023-12-14 201943





About

반려동물 통합 커뮤니티 서비스

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 99.4%
  • Other 0.6%