[팀 프로젝트] 게시글 작성 기능 구현

Hyowmls·2024년 7월 23일
0
post-thumbnail
post-custom-banner

게시글 작성 페이지에서 글을 작성하고 supabase에 업데이트 되도록 구현했다

이미지 업로드

imagesuseState([]) 로 상태관리를 하고 있다
이미지는 최대 5개까지 등록이 가능해서 이미지의 개수가 5개 이상이면 alert창을 띄우도록 구현했다

  const handleImageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    if (e.target.files) {
      const imageFiles = Array.from(e.target.files);
      const newImages = [...images, ...imageFiles];
      if (newImages.length <= 5) {
        setImages(newImages);
      } else {
        alert('이미지는 최대 5까지만 등록이 가능합니다');
      }
    }
  };

이미지를 등록하지 않은 상태의 UI이다. 여기서 구현하고 싶은 것들이 있었다

  • 등록한 이미지 미리보기
  • 이미지를 등록하면 UI에 아이콘이 안보이고 이미지들이 가로로 나열되어 보인다
  • 아래 텍스트를 클릭했을때 이미지 등록이 가능해야한다

    3번 같은 경우에는 처음에 p 태그를 사용했는데 내가 원하는대로 구현이 되지 않았다.
    그래서 label 태그로 텍스트와 input 태그를 묶어서 구현을 했다


URL.createObjectURL() - 보통 로컬환경에서 이미지를 업로드하기 때문에 임의로 URL주소를 만들어 src에 넣어줬다

// 이미지 섹션 컴포넌트 코드
      <div className="w-full border-2 border-slate-400 my-[20px] rounded-md p-4">
        <div className="flex flex-col items-center justify-center">
          <div className="flex flex-wrap mt-4">
            {images.map((image, index) => (
              <div key={index} className="relative w-[100px] h-[100px] mr-2 mb-2">
                <img
                  src={URL.createObjectURL(image)}
                  alt={`preview ${index}`}
                  className="w-full h-full object-cover rounded-md cursor-pointer"
                  onClick={() => handleImageDelete(index)}
                />
              </div>
            ))}
          </div>
          {images.length < 1 && (
            <label 
              className="w-[60px] h-[60px] flex items-center justify-center relative rounded-full mt-4 cursor-pointer"
              style={{backgroundImage : "url('../images/image_select.jpeg')", backgroundSize : 'cover', backgroundPosition : 'center'}}
            >
              <input
                type="file"
                multiple
                className="opacity-0 absolute inset-0 w-full h-full cursor-pointer"
                onChange={handleImageChange}
              />
            </label>
          )}
          <label className="my-4 underline underline-offset-4 text-blue-600 cursor-pointer">
            이미지를 첨부해주세요. (1개 이상 필수, 최대 5개까지 첨부 가능)
            <input type="file" multiple className="hidden" onChange={handleImageChange} />
          </label>
        </div>
      </div>

supabase storage 이미지 업로드

예전에 테이블에 이미지url을 넣어본 경험이 있어서 코드를 참고하며 구현했다
1. supabase storage 버킷에 이미지를 업로드한다
2. storage 버킷에 있는 이미지의 publicUrl을 배열에 담아준다
3. publicUrl을 담은 배열을 supabase 테이블에 저장한다

    const uploadedImageUrls = [];
    for (let image of images) {
      const fileExt = image.name.split('.').pop();
      const fileName = `${Date.now()}-${Math.random()}.${fileExt}`;
      const filePath = `request_post_image/${fileName}`;

      const { error: storageError } = await supabase.storage.from('request_post_image').upload(filePath, image);
      if (storageError) {
        alert('스토리지 업로드 실패');
      } else {
        const { data } = await supabase.storage.from('request_post_image').getPublicUrl(filePath);
        if (data.publicUrl) {
          uploadedImageUrls.push(data.publicUrl);
        } else {
          alert('URL 가져오기 실패');
          return;
        }
      }
    }

supabase 데이터 업데이트

테이블에 있는 post_img 컬럼은 text[] 로 지정했다
위에서 publicUrl을 담은 배열을 post_img에 저장한다

    const { data, error } = await supabase
      .from('Request Posts')
      .insert([
        {
          user_id: crypto.randomUUID(),
          title,
          content: description,
          lang_category: language,
          price: '0',
          post_img: uploadedImageUrls
        }
      ]);

개선 사항

브라우저에서 내용을 입력하고 등록하기 버튼을 누르면 게시물이 저장되었다는 메세지가 나오기까지 약간의 딜레이 시간이 있다

  • 딜레이 시간을 최소화 할 수 있도록 데이터를 업데이트 하는 방식에 대해 고민

코드 리팩토링

  • 현재 빠르게 기능을 구현하기 위해 page.tsx 파일에 코드를 모두 적어둠
  • 컴포넌트 단위로 코드를 분리해야함
post-custom-banner

0개의 댓글