본문 바로가기

React

수정, 삭제, 완료 API 연결

import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { fundingCreate } from '../../../api/api'; // 펀딩 생성 API import
import { useParams } from 'react-router-dom';
import CreateModal from './Modal/CreateModal';
import Navbar from '../../../components/Navbar'; // 추가된 코드
import { useDispatch, useSelector } from 'react-redux'; // 추가된 코드
import { userLogout } from '../../../redux/authSlice'; // 추가된 코드
import {
    MainContainer,
    LeftContainer,
    Logo,
    P,
    Button,
    RightContainer,
    NavbarDiv,
    ProducImgtDiv,
    InputTag,
    FundingImg,
    Body,
    FundingDiv,
    SponserDiv,
    RadioInput,
    SponserComment,
    TogetherDiv,
    SponsorComment,
    ImgText,
} from './FundingCreateStyles';

// 펀딩 생성 페이지 컴포넌트
const FundingCreate = () => {
    const navigate = useNavigate(); // React Router의 네비게이션 기능을 사용하기 위한 hook
    const { id } = useParams(); // URL 매개변수(id)를 가져옴
    const [itemImage, setItemImage] = useState(false);
    const [isFundingModalOpen, setIsFundingModalOpen] = useState(false); // 모달 창의 열림 여부 상태 변수
    const isLoggedIn = useSelector((state) => state.auth.isLoggedIn); // 추가된 코드
    const dispatch = useDispatch(); // 추가된 코드

    // 펀딩 생성 페이지에서 사용될 상태 변수 초기화
    const [createData, setCreateData] = useState({
        itemName: '',
        targetAmount: '',
        publicFlag: true,
        showName: '',
        title: '',
        content: '',
        endDate: '',
    });

    // 펀딩 이미지를 클릭했을 때 모달을 열고 이미지를 설정하는 함수
    const handleFundingModalClick = (e) => {
        setIsFundingModalOpen(true);
    };

    // 모달을 닫는 함수
    const closeModal = () => {
        setIsFundingModalOpen(false);
    };

    // 모달 내에서 이미지를 선택하고 설정하는 함수
    const handleImageSelection = (itemImage) => {
        setItemImage(itemImage);
        setIsFundingModalOpen(false); // 이미지 선택 후 모달을 닫습니다.
    };

    // 각 입력값에 대한 상태 업데이트 핸들러
    const handleItemNameChange = (e) => {
        setCreateData({ ...createData, itemName: e.target.value });
    };
    const handleTargetAmountChange = (e) => {
        setCreateData({ ...createData, targetAmount: e.target.value });
    };
    const handleShowNameChange = (e) => {
        setCreateData({ ...createData, showName: e.target.value });
    };
    const handleTitleChange = (e) => {
        setCreateData({ ...createData, title: e.target.value });
    };
    const handleContentChange = (e) => {
        setCreateData({ ...createData, content: e.target.value });
    };
    const handleEndDateChange = (e) => {
        setCreateData({ ...createData, endDate: e.target.value });
    };
    const handlePublicFlagChange = (e) => {
        // 업데이트: 한 번에 하나의 옵션만 선택했는지 확인하세요.
        const value = e.target.value === 'true' ? true : false;
        setCreateData({ ...createData, publicFlag: value });
    };
    // 펀딩 생성 요청 처리 함수
    const handleFundingClick = async () => {
        try {
            if (
                itemImage === '' ||
                createData.itemName === '' ||
                createData.targetAmount === '' ||
                createData.publicFlag === '' ||
                createData.showName === '' ||
                createData.title === '' ||
                createData.content === '' ||
                createData.endDate === ''
            ) {
                alert('내용을 입력해주세요');
                return;
            }
            // 펀딩 생성 API 호출 및 데이터 전송
            const response = await fundingCreate({
                id,
                itemImage,
                itemName: createData.itemName,
                targetAmount: createData.targetAmount,
                publicFlag: createData.publicFlag,
                showName: createData.showName,
                title: createData.title,
                content: createData.content,
                endDate: createData.endDate,
            });
            console.log('펀딩 생성 성공:', response);
            navigate(`/fundingdetail/${response.id}`);
        } catch (error) {
            if (error.response) {
                const statusCode = error.response.status;
                const errorMessage = error.response.data.message;
                if (statusCode === 400) {
                    // alert(errorMessage);
                    alert('펀딩 생성 실패 :', errorMessage);
                }
            }
        }
    };

    // 추가된 코드
    const handleLogoutClick = () => {
        dispatch(userLogout()); // 로그아웃 액션 디스패치
        navigate('/');
    };

    return (
        <MainContainer>
            <LeftContainer>
                <Logo>😉 Giftipie</Logo>
                <P pt="25px" fs="16px" fw="800" pb="5px">
                    기프티파이에서
                </P>
                <P fs="16px" fw="800" pb="5px">
                    정말 원하는 선물을
                </P>
                <P fs="16px" fw="800">
                    주고 받아요
                </P>
                <Button onClick={() => navigate('/')} mt="20px" w="180px" h="50px" fs="16px" color="white" bc="orange">
                    펀딩 시작하기
                </Button>
            </LeftContainer>

            <RightContainer>
                {/* 추가된 코드 */}
                <NavbarDiv>
                    <Navbar isLoggedIn={isLoggedIn} handleLogoutClick={handleLogoutClick} />
                </NavbarDiv>

                <Body>
                    <form
                        onSubmit={(e) => {
                            e.preventDefault();
                        }}
                    >
                        <FundingDiv>
                            <P pb="10px" fs="16px" fw="900">
                                펀딩 생성페이지
                            </P>
                            <P pb="20px" fs="10px" fw="900">
                                펀딩 생성 페이지에 상품명과 이미지가 노출돼요.
                            </P>
                            <ProducImgtDiv>
                                <SponsorComment mt="10px" pointer="pointer" onClick={handleFundingModalClick}>
                                    <FundingImg src={itemImage} h="90px" w="80px" />
                                    <ImgText>상품 링크 URL</ImgText>
                                </SponsorComment>
                                <div>
                                    <InputTag
                                        type="text"
                                        value={createData.itemName}
                                        onChange={handleItemNameChange}
                                        placeholder="상품명을 입력해주세요"
                                        h="40px"
                                        w="97%"
                                        ml="10px"
                                        mb="10px"
                                        pl="10px"
                                    />
                                    <InputTag
                                        type="text"
                                        value={createData.targetAmount}
                                        onChange={handleTargetAmountChange}
                                        placeholder="가격을 입력해주세요"
                                        h="40px"
                                        w="97%"
                                        ml="10px"
                                        pl="10px"
                                    />
                                </div>
                            </ProducImgtDiv>
                            {/* 모달 컴포넌트 표시 여부 확인 후 표시 */}
                            {isFundingModalOpen && (
                                <CreateModal closeModal={closeModal} handleImageSelection={handleImageSelection} />
                            )}
                            {/* 펀딩 내용 및 공개 여부 입력 폼 */}
                            <SponserDiv>
                                <SponserComment mt="50px">
                                    <P pb="10px" fs="16px" fw="900">
                                        펀딩 내용
                                    </P>
                                    <P pb="20px" fs="13px" fw="900">
                                        공개 방식
                                    </P>
                                    <SponserDiv>
                                        <RadioInput
                                            value="true"
                                            checked={createData.publicFlag === true}
                                            onChange={handlePublicFlagChange}
                                            type="radio"
                                            mb="21px"
                                        />
                                        <P pb="20px" fs="13px" fw="900" pl="20px">
                                            공개
                                        </P>
                                        <P pb="20px" fs="10px" fw="900" pl="42px">
                                            누구나 볼 수 있어요
                                        </P>
                                    </SponserDiv>

                                    {/* 여기까지*/}
                                    <SponserDiv>
                                        <RadioInput
                                            value="false"
                                            checked={createData.publicFlag === false}
                                            onChange={handlePublicFlagChange}
                                            type="radio"
                                            mb="21px"
                                        />
                                        <P pb="20px" fs="13px" fw="900" pl="20px">
                                            비공개
                                        </P>
                                        <P pb="20px" fs="10px" fw="900" pl="30px">
                                            링크를 통해서만 방문할 수 있어요
                                        </P>
                                    </SponserDiv>
                                </SponserComment>
                            </SponserDiv>
                            <P pt="30px" pb="5px" fs="13px" fw="800">
                                보여줄 이름
                            </P>
                            <InputTag
                                type="text"
                                value={createData.showName}
                                onChange={handleShowNameChange}
                                placeholder="이름을 입력해주세요"
                                h="40px"
                                w="97%"
                                mb="10px"
                                pl="10px"
                            />
                            <P pt="10px" pb="5px" fs="13px" fw="800">
                                제목
                            </P>
                            <InputTag
                                type="text"
                                value={createData.title}
                                onChange={handleTitleChange}
                                placeholder="제목을 입력해주세요"
                                h="40px"
                                w="97%"
                                mb="10px"
                                pl="10px"
                            />
                            <P pt="10px" pb="5px" fs="13px" fw="800">
                                본문
                            </P>
                            <InputTag
                                type="text"
                                value={createData.content}
                                onChange={handleContentChange}
                                placeholder="본문을 입력해주세요"
                                h="90px"
                                w="97%"
                                mb="10px"
                                pl="10px"
                                pb="50px"
                            />
                            <P pt="10px" pb="5px" fs="13px" fw="800">
                                마감일 설정
                            </P>
                            <InputTag
                                type="date"
                                value={createData.endDate}
                                onChange={handleEndDateChange}
                                h="40px"
                                w="97%"
                                pl="10px"
                                pt="10px"
                            />
                        </FundingDiv>

                        <TogetherDiv>
                            <P pl="130px" fs="14px" fw="800">
                                펀딩 금액은 계좌로 전달돼요
                            </P>
                            <P pl="95px" fs="14px" fw="800">
                                펀딩에 성공하면 카톡으로 알림이 가요
                            </P>
                        </TogetherDiv>

                        <Button
                            onClick={handleFundingClick}
                            w="442px"
                            h="60px"
                            mt="10px"
                            color="white"
                            fs="19px"
                            bc="gray"
                        >
                            펀딩 등록하기
                        </Button>
                    </form>
                </Body>
            </RightContainer>
        </MainContainer>
    );
};

export default FundingCreate;
import axios from "axios";

export const instance = axios.create({
  baseURL: process.env.REACT_APP_API_URL,
  withCredentials: true, // Cookies에 브라우저가 자동으로 쿠키를 넣어줌
  headers: {
    "Access-Control-Allow-Origin": `${process.env.REACT_APP_API_URL}`,
  },
});

// 회원가입 API
export const signup = async (userData) => {
  try {
    const response = await instance.post("/api/signup", userData);

    if (response.status === 201) {
      const { code, message } = response.data;

      if (code === 2000) {
        alert(message);
        console.log("가입 성공! 환영합니다.");
      } else {
        console.error("올바르지 않은 응답 형식 또는 값");
        throw new Error("회원가입 처리 중 오류가 발생했습니다.");
      }
    }

    return response.data;
  } catch (error) {
    console.error("회원가입 오류:", error);

    if (error.response && error.response.status === 400) {
      const { code, message } = error.response.data;

      if (code === 4000) {
        alert(message);
      } else {
        console.error("올바르지 않은 응답 형식 또는 값");
        alert("회원가입 처리 중 오류가 발생했습니다.");
      }
    }

    throw error;
  }
};

// 로그인 API
export const login = async (credentials) => {
  try {
    const response = await instance.post("/api/login", credentials);

    if (response.status === 200) {
      const { code, message, result } = response.data;

      if (code === 2000 && result) {
        alert(message);
      } else {
        console.error("올바르지 않은 응답 형식 또는 값");
        throw new Error("로그인 처리 중 오류가 발생했습니다.");
      }
    }

    return response.data;
  } catch (error) {
    console.error("로그인 오류:", error);

    if (error.response && error.response.status === 401) {
      const { code, message } = error.response.data;

      if (code === 4000) {
        alert(message);
      } else {
        console.error("올바르지 않은 응답 형식 또는 값");
        alert("로그인 처리 중 오류가 발생했습니다.");
      }
    }

    throw error;
  }
};

// 펀딩 생성페이지 API
export const fundingCreate = async (fundingData) => {
  try {
    const response = await instance.post("/api/funding/create", fundingData); // 펀딩 생성 요청
    console.log("펀딩 생성페이지 API", response);
    return response.data; // 응답 데이터 반환
  } catch (error) {
    throw error; // 실패 시 예외 처리
  }
};

// 펀딩 생성페이지 모달창(ItemLink) API
export const modalItemLink = async (LinkData) => {
  try {
    const response = await instance.post("/api/funding/addLink", LinkData); // 모달창(ItemLink) API 호출
    return response.data; // 응답 데이터 반환
  } catch (error) {
    throw error; // 실패 시 예외 처리
  }
};

// 펀딩 상세페이지 API
export const fetchFundingDetail = async (id) => {
  try {
    const response = await instance.get(`/api/funding/${id}`); // 펀딩 상세페이지 요청
    console.log("펀딩 상세페이지 API", response);
    return response.data; // 응답 데이터 반환
  } catch (error) {
    console.error("펀딩 상세페이지 API 호출 오류:", error); // 오류 로깅
    throw error; // 에러 다시 throw 또는 다른 적절한 처리를 수행
  }
};

// 펀딩 후원자 상세페이지 API
export const fetchSponsorDetail = async (id) => {
  try {
    const response = await instance.get(`/api/fundingsponsordetail/${id}`); // 펀딩 후원자 상세페이지 요청
    if (response.status === 200) {
      alert("후원자 상세페이지입니다.");
      return response.data; // 응답 데이터 반환
    }
  } catch (error) {
    console.error("펀딩 상세페이지 API 호출 오류:", error); // 오류 로깅
    throw error; // 에러 다시 throw 또는 다른 적절한 처리를 수행
  }
};

// 펀딩 수정페이지 불러오기 API - get
export const FundingModifyGet = async (id, data) => {
  try {
    const response = await instance.get(`/api/funding/${id}`, data); // 펀딩 수정페이지 요청
    console.log("펀딩 불러오기 API", response);
    if (response.status === 200) {
      return response.data; // 응답 데이터 반환
    }
  } catch (error) {
    console.error("API 호출 중 에러 발생:", error); // 오류 로깅
    throw error; // 에러 다시 throw
  }
};

// 펀딩 수정페이지 API - 변경버튼 - patch
export const updateFundingModify = async (id, data) => {
  try {
    const response = await instance.patch(`/api/funding/${id}/update`, data); // 펀딩 수정페이지 요청
    console.log("펀딩 수정 API", response);
    if (response.status === 200) {
      return response.data; // 응답 데이터 반환
    }
  } catch (error) {
    throw error; // 실패 시 예외 처리
  }
};

// 펀딩 수정페이지 - 상품링크 변경 모달창(ItemLink) API
export const modalLinkModify = async (linkModifyData) => {
  try {
    const response = await instance.post(
      "/api/funding/modifyLink",
      linkModifyData
    ); // 모달창(ItemLink) API 호출
    if (response.status === 200) {
      return response.data; // 응답 데이터 반환
    }
  } catch (error) {
    if (error.response) {
      const statusCode = error.response.status;
      const errorMessage = error.response.data.message;
      if (statusCode === 400) {
        alert(errorMessage);
      }
    }
  }
};

// 펀딩 수정페이지 - 삭제하기 버튼 API - delete 
export const deleteFundingModify = async (id, data) => {
  try {
    const response = await instance.delete(`/api/funding/${id}`, data);
    console.log("펀딩 삭제 API", response);
    if (response.status === 200) {
      return response.data; // 응답 데이터 반환
    }
  } catch (error) {
    if (error.response) {
      const statusCode = error.response.status;
      const errorMessage = error.response.data.message;
      if (statusCode === 400) {
        alert(errorMessage);
      }
    }
  }
};

// 펀딩 수정페이지 API - 종료버튼 API - patch
export const completeFundingModify = async (id, data) => {
  try {
    const response = await instance.patch(`/api/funding/${id}/finish`, data); // 펀딩 수정페이지 요청
    console.log("펀딩 종료 API", response);
    if (response.status === 200) {
      return response.data; // 응답 데이터 반환
    }
  } catch (error) {
    throw error; // 실패 시 예외 처리
  }
};
import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { useParams } from "react-router-dom";
import { fetchFundingDetail } from "../../../api/api"; // 펀딩 상세 정보를 가져오는 API 함수 import
import Navbar from "../../../components/Navbar"; // 추가된 코드
import { useDispatch, useSelector } from "react-redux"; // 추가된 코드
import { userLogout } from "../../../redux/authSlice"; // 추가된 코드
import {
    MainContainer,
    LeftContainer,
    Logo,
    P,
    Button,
    RightContainer,
    NavbarDiv,
    NavbarBtn,
    NavigateBtn,
    Body,
    BannerImg,
    FundingDiv,
    SponserDiv,
    SponserComment,
    SponsorImg,
    ProgressBar,
    Progress,
    BetweenDiv,
    TogetherDiv,
} from './FundingDetailStyles';

// 펀딩 상세 페이지 컴포넌트
const FundingDetail = () => {
  const navigate = useNavigate(); // React Router의 네비게이션 기능을 사용하기 위한 hook
  const { id } = useParams(); // URL 매개변수(id)를 가져옴
  const isLoggedIn = useSelector((state) => state.auth.isLoggedIn); // 추가된 코드
  const dispatch = useDispatch(); // 추가된 코드

    // 펀딩 상세 정보를 담는 상태 변수 초기화
    const [detailData, setDetailData] = useState({
        // 초기 상태를 명세서에 따라 설정
        // FundingCreate에서 받아올 Data 초기값
        itemImage: '',
        itemName: '',
        targetAmount: 0,
        publicFlag: false, // 공개, 비공개 여부
        showName: '',
        title: '',
        content: '',
        endDate: '',
        // FundignDetail에 출력되는 Data 초기값
        itemLink: '',
        currentAmount: 0,
        dday: '',
        status: false,
        achievementRate: 0,
        ownerFlag: false, // true면 수정 페이지 버튼 보여지게
        modifiedAt: '', // 수정 날짜
        // 후원자 이름 추가
        // 후원자 댓글 추가
    });

  useEffect(() => {
    // API를 호출하여 펀딩 상세 정보를 가져오는 함수 정의
    const fetchData = async () => {
      try {
        if (!id) {
          // 유효한 id가 없으면 데이터를 요청하지 않음
          return;
        }
        // 펀딩 ID를 설정하여 특정 펀딩의 상세 정보 가져오기
        // const fundingid = 1; // 예: 펀딩 ID가 1인 경우
        const data = await fetchFundingDetail(id);
        setDetailData(data); // 가져온 데이터를 상태 변수에 설정
      } catch (error) {
        if (error.response) {
          const statusCode = error.response.status;
          const errorMessage = error.response.data.message;
          if (statusCode === 400) {
            alert(errorMessage);
          }
        }
      }
    };
    // 컴포넌트가 마운트될 때 API 호출 함수 실행
    fetchData();
  }, [id]); // 빈 배열을 전달하여 한 번만 실행하도록 설정

  // 추가된 코드
  const handleLogoutClick = () => {
    dispatch(userLogout()); // 로그아웃 액션 디스패치
    navigate("/");
  };

  return (
    <MainContainer>
      <LeftContainer>
        <Logo>😉 Giftipie</Logo>
        <P pt="25px" fs="16px" fw="800" pb="5px">
          기프티파이에서
        </P>
        <P fs="16px" fw="800" pb="5px">
          정말 원하는 선물을
        </P>
        <P fs="16px" fw="800">
          주고 받아요
        </P>
        <Button
          onClick={() => navigate("/")}
          mt="20px"
          w="180px"
          h="50px"
          fs="16px"
          color="white"
          bc="orange"
        >
          펀딩 시작하기
        </Button>
      </LeftContainer>

      <RightContainer>
        {/* 추가된 코드 */}
        <NavbarDiv>
          <Navbar
            isLoggedIn={isLoggedIn}
            handleLogoutClick={handleLogoutClick}
          />
        </NavbarDiv>

        <Body>
        <NavigateBtn onClick={() => navigate(`/fundingModify/${id}`)} pl="360px" fs="13px" fw="600">
                        🖍 수정하기
                    </NavigateBtn>
          <BannerImg src={detailData.itemImage} alt="image" />
          <FundingDiv>
            <P pt="20px" fs="13px" fw="800">
              {detailData.status}
            </P>
            <P pt="10px" fs="20px" fw="900">
              {detailData.title}
            </P>
            <P pt="10px" fs="15px" fw="900">
              {detailData.itemName}
            </P>
            <BetweenDiv>
              <P pt="10px" fs="15px" fw="800">
                {detailData.dday}
              </P>
              <P pt="10px" fs="15px" fw="800">
                {detailData.endDate}
              </P>
            </BetweenDiv>
            <P pt="10px" fs="15px" fw="800">
              {detailData.showName}
            </P>
            <ProgressBar>
              <Progress width={(65 / 100) * 100} />
            </ProgressBar>
            <BetweenDiv>
              <P pt="8px" fs="15px" fw="800">
                {detailData.achievementRate}%
              </P>
              <P pt="8px" pl="90px" fs="15px" fw="800">
                현재&nbsp;{detailData.currentAmount}원
              </P>
              <P pt="8px" pl="90px" fs="15px" fw="800">
                {detailData.targetAmount}원
              </P>
            </BetweenDiv>
          </FundingDiv>
          <TogetherDiv bc="orange">
            <P pt="30px" pl="30px" fs="14px" fw="800">
              {detailData.content}
            </P>
          </TogetherDiv>

          <FundingDiv>
            <P pt="20px" fs="16px" fw="900">
              후원자
            </P>
            {/* <Sponsor /> */}
            <SponserDiv>
              <SponsorImg src="/imgs/iu.jpg" alt="image" />
              <SponserComment mt="10px">
                <P pl="5px" fs="13px" fw="800">
                  아**
                </P>
                <Button
                  mt="5px"
                  w="300px"
                  h="40px"
                  pr="90px"
                  fs="13px"
                  bc="violet"
                >
                  줄이어폰 그만써~ 생일축하해!!
                </Button>
              </SponserComment>
            </SponserDiv>

            <SponserDiv>
              <SponsorImg src="/imgs/songjoongy.jpg" alt="logo" />
              <SponserComment mt="10px">
                <P pl="5px" fs="13px" fw="800">
                  {detailData.showName}
                </P>
                <Button
                  mt="5px"
                  w="300px"
                  h="40px"
                  pr="90px"
                  fs="13px"
                  bc="violet"
                >
                  {detailData.content}
                </Button>
              </SponserComment>
            </SponserDiv>

            <SponserDiv>
              <SponsorImg src="/imgs/junjihyun.jpg" alt="img" />
              <SponserComment mt="10px">
                <P pl="5px" fs="13px" fw="800">
                  {detailData.showName}
                </P>
                <Button
                  mt="5px"
                  w="300px"
                  h="40px"
                  pr="90px"
                  fs="13px"
                  bc="violet"
                >
                  {detailData.content}
                </Button>
              </SponserComment>
            </SponserDiv>

            <P
              onClick={() => navigate("/fundingsponsordetail")}
              pt="40px"
              pl="160px"
              fs="14px"
              fw="800"
            >
              전체보기 ▶
            </P>
          </FundingDiv>

          <FundingDiv>
            <P pt="10px" fs="16px" fw="900">
              펀딩 참여하기
            </P>

            <Button onClick={() => navigate("/fundingpay")} mt="30px" w="375px" h="60px" bc="orange">
              <BetweenDiv>
                <P pt="2px" pl="20px" fs="15px" fw="800" color="black">
                  커피 한잔 선물하기
                </P>
                <P pt="2px" pr="20px" fs="15px" fw="700" color="black">
                  5,000원
                </P>
              </BetweenDiv>
            </Button>
            <Button onClick={() => navigate("/fundingpay")} mt="10px" w="375px" h="60px" bc="orange">
              <BetweenDiv>
                <P pt="2px" pl="20px" fs="15px" fw="800" color="black">
                  파인트 아이스크림 선물하기
                </P>
                <P pt="2px" pr="20px" fs="15px" fw="700" color="black">
                  10,000원
                </P>
              </BetweenDiv>
            </Button>
            <Button onClick={() => navigate("/fundingpay")}
              mt="10px"
              w="375px"
              h="60px"
              bc="orange"
            >
              <BetweenDiv>
                <P pt="2px" pl="20px" fs="15px" fw="800" color="black">
                  원하는만큼 선물하기
                </P>
                <P pt="2px" pr="20px" fs="15px" fw="700" color="black">
                  직접입력
                </P>
              </BetweenDiv>
            </Button>
            <Button onClick={() => navigate("/fundingpay")} mt="10px" w="375px" h="60px" bc="orange">
              <BetweenDiv>
                <P pt="2px" pl="20px" fs="15px" fw="800" color="black">
                  이 펀딩을 끝내러 왔다
                </P>
                <P pt="2px" pr="20px" fs="15px" fw="700" color="black">
                  {detailData.currentAmount}원
                </P>
              </BetweenDiv>
            </Button>
          </FundingDiv>
          <TogetherDiv bc="violet">
            <P pt="30px" pl="30px" fs="16px" fw="800">
              Giftipie에서 함께 하는 기쁨
            </P>
            <BetweenDiv>
              <P pt="40px" pl="30px" fs="13px" fw="800">
                펀딩에 참여한 사람
              </P>
              <P pt="40px" pr="30px" fs="13px" fw="800">
                11명
              </P>
            </BetweenDiv>
            <BetweenDiv>
              <P pt="20px" pl="30px" fs="13px" fw="800">
                선물을 받은 사람
              </P>
              <P pt="20px" pr="30px" fs="13px" fw="800">
                11명
              </P>
            </BetweenDiv>
            <BetweenDiv>
              <P pt="20px" pl="30px" fs="13px" fw="800">
                모인 펀딩 금액
              </P>
              <P pt="20px" pr="30px" fs="13px" fw="800">
                {detailData.currentAmount}원
              </P>
            </BetweenDiv>
          </TogetherDiv>

          <Button
            onClick={() => navigate("/fundingpay")}
            mt="30px"
            w="442px"
            h="60px"
            color="black"
            fs="19px"
            bc="orange"
          >
            선물하기
          </Button>
        </Body>
      </RightContainer>
    </MainContainer>
  );
};

export default FundingDetail;
import React, { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom'; // React Router에서 네비게이션 기능을 사용하기 위한 hook
import { useParams } from 'react-router-dom'; // React Router에서 URL 매개변수를 가져오기 위한 hook
import Navbar from '../../../components/Navbar'; // 추가된 코드
import { useDispatch, useSelector } from 'react-redux'; // 추가된 코드
import { userLogout } from '../../../redux/authSlice'; // 추가된 코드
import { updateFundingModify } from '../../../api/api'; // 펀딩 수정 API를 호출하기 위한 함수 import
import { deleteFundingModify } from '../../../api/api'; // 펀딩 수정 API를 호출하기 위한 함수 import
import { FundingModifyGet } from '../../../api/api'; // 펀딩 상세 정보를 가져오기 위한 함수 import
import { completeFundingModify } from '../../../api/api'; // 펀딩 상세 정보를 가져오기 위한 함수 import

// import ModifyModal from './ModifyModal'; // 이미지 선택 모달 컴포넌트 import
import {
    MainContainer,
    LeftContainer,
    Logo,
    P,
    Button,
    NavbarDiv,
    RightContainer,
    InputTag,
    Body,
    FundingDiv,
    SponsorDiv,
    RadioInput,
    SponsorComment,
    FundingImg,
    // ImgText,
    TogetherDiv,
} from './FundingModifyStyles'; // 스타일 컴포넌트 import

// 펀딩 수정 페이지 컴포넌트
const FundingModify = () => {
    const navigate = useNavigate(); // React Router의 네비게이션 기능을 사용하기 위한 hook
    const { id } = useParams(); // URL 매개변수(id)를 가져옴
    const isLoggedIn = useSelector((state) => state.auth.isLoggedIn); // 추가된 코드
    const dispatch = useDispatch(); // 추가된 코드

    // 펀딩 데이터 상태와 상태 설정 함수 초기화
    const [fundingData, setFundingData] = useState({
        itemName: '',
        showName: '',
        title: '',
        content: '',
        targetAmount: 0,
        publicFlag: '',
        endDate: '',
        itemImage: '',
    });

    // 추가된 코드
    const handleLogoutClick = () => {
        dispatch(userLogout()); // 로그아웃 액션 디스패치
        navigate('/');
    };
    // const [isFundingModalOpen, setIsFundingModalOpen] = useState(false); // 모달 창의 열림 여부 상태 변수

    // 펀딩 이미지를 클릭하여 모달을 열고 이미지를 설정하는 함수
    // const handleFundingModalClick = (e) => {
    //     setIsFundingModalOpen(true);
    // };

    // 모달을 닫는 함수
    // const closeModal = () => {
    //     setIsFundingModalOpen(false);
    //     // setItemImage(''); // 이미지 상태를 초기화하여 이미지를 숨김
    // };

    // 모달 내에서 이미지를 선택하고 설정하는 함수
    // const handleImageSelection = (itemImage) => {
    //     setFundingData(itemImage);
    //     setIsFundingModalOpen(false); // 이미지 선택 후 모달 닫기
    // };

    useEffect(() => {
        // API를 호출하여 펀딩 상세 정보를 가져오는 함수 정의
        const fetchData = async () => {
            try {
                if (!id) {
                    // 유효한 id가 없으면 데이터를 요청하지 않음
                    return;
                }
                const data = await FundingModifyGet(id); // 펀딩 상세 정보 가져오기
                setFundingData(data); // 가져온 데이터를 상태 변수에 설정
                console.log('펀딩상세 가져오기 성공', data);
            } catch (error) {
                console.error('펀딩상세 가져오기 오류:', error);
            }
        };

        // 컴포넌트가 마운트될 때 API 호출 함수 실행
        fetchData();
    }, [id]); // 빈 배열을 전달하여 한 번만 실행하도록 설정

    // 펀딩 수정 요청 함수
    const handlefundingModifyClick = async () => {
        try {
            if (
                fundingData.publicFlag === '' ||
                fundingData.showName === '' ||
                fundingData.title === '' ||
                fundingData.content === ''
            ) {
                alert('내용을 입력해주세요');
                return;
            }
            const data = await updateFundingModify(id, fundingData); // 펀딩 수정 API 호출
            // setFundingData(fundingData.map((data) => {
            //     if (data.id === id) {
            //         return { ...data, fundingData };
            //     } else {
            //         return data;
            //     }
            // }))
            console.log('펀딩 수정 성공:', data);
            navigate(`/fundingdetail/${data.id}`); // 펀딩 상세 페이지로 이동
        } catch (error) {
            if (error.response) {
                const statusCode = error.response.status;
                const errorMessage = error.response.data.message;
                if (statusCode === 400) {
                    alert('펀딩 수정 실패 :', errorMessage);
                }
            }
        }
    };

    const handledeleteFundingClick = async () => {
        try {
            const confirmDelete = window.confirm('정말 삭제하시겠습니까?');
            if (!confirmDelete) return;

            await deleteFundingModify(id, fundingData);
            console.log('펀딩 삭제 성공:', id);
            navigate(`/`);
            // if (id) {
            //     alert('정말 삭제하시겠습니까?');
            //     return;
            // }
            // const data = await deleteFundingModify(id, fundingData);
            // const data = await deleteFundingModify(id);
            // setFundingData(
            //     fundingData.filter((data) => {
            //         return data.id !== id;
            //     })
            // );
            // console.log('펀딩 삭제 성공:', data);
            // navigate(`/`);
        } catch (error) {
            console.error('펀딩 삭제 실패:', error);
            // 에러 핸들링
        }
    };

    const handlecompleteFundingClick = async () => {
        try {
            if (!id) {
                // 유효한 id가 없으면 데이터를 요청하지 않음
                return;
            }
            const data = await completeFundingModify(id); // 펀딩 상세 정보 가져오기
            setFundingData(data); // 가져온 데이터를 상태 변수에 설정
            console.log('펀딩 종료 성공', data);
            navigate(`/`);
        } catch (error) {
            console.error('펀딩 종료 오류:', error);
        }
    };

    // UI 렌더링
    return (
        <MainContainer>
            {/* 왼쪽 컨테이너 */}
            <LeftContainer>
                {/* 로고 및 간단한 설명 */}
                <Logo>😉 Giftipie</Logo>
                <P pt="25px" fs="16px" fw="800" pb="5px">
                    기프티파이에서
                </P>
                <P fs="16px" fw="800" pb="5px">
                    정말 원하는 선물을
                </P>
                <P fs="16px" fw="800">
                    주고 받아요
                </P>
                {/* 펀딩 시작하기 버튼 */}
                <Button onClick={() => navigate('/')} mt="20px" w="180px" h="50px" fs="16px" color="white" bc="orange">
                    펀딩 시작하기
                </Button>
            </LeftContainer>

            {/* 오른쪽 컨테이너 */}
            <RightContainer>
                {/* 추가된 코드 */}
                <NavbarDiv>
                    <Navbar isLoggedIn={isLoggedIn} handleLogoutClick={handleLogoutClick} />
                </NavbarDiv>
                {/* 펀딩 수정 내용 입력 부분 */}
                <Body>
                    {/* 펀딩 상품 정보 입력 및 이미지 변경 */}
                    <FundingDiv>
                        {/* 펀딩 페이지에 노출되는 상품명 및 이미지 변경 버튼 */}
                        <P pb="10px" fs="16px" fw="900">
                            펀딩 수정페이지
                        </P>
                        <P pb="20px" fs="10px" fw="900">
                            펀딩페이지의 상품명, 가격, 이미지는 변경할 수 없습니다.
                        </P>

                        <SponsorDiv>
                            {/* <SponsorComment pointer="pointer" onClick={handleFundingModalClick}> */}
                            {/* <FundingImg  onClick={handleFundingModalClick} src={fundingData.itemImage} alt="logo"/> */}
                            <FundingImg src={fundingData.itemImage} alt="logo" />
                            {/* <ImgText>이미지 변경</ImgText> */}
                            {/* </SponsorComment> */}
                            <SponsorComment mt="10px">
                                <div>
                                    <InputTag
                                        type="text"
                                        placeholder="상품명을 입력해주세요"
                                        value={fundingData.itemName}
                                        // onChange={(e) => {
                                        //     setFundingData({ ...fundingData, itemName: e.target.value });
                                        // }}
                                        h="40px"
                                        w="92%"
                                        ml="10px"
                                        mb="10px"
                                        pl="10px"
                                    />
                                    <InputTag
                                        type="text"
                                        placeholder="가격을 입력해주세요"
                                        value={fundingData.targetAmount}
                                        // onChange={(e) => {
                                        //     setFundingData({ ...fundingData, targetAmount: e.target.value });
                                        // }}
                                        h="40px"
                                        w="92%"
                                        ml="10px"
                                        pl="10px"
                                    />
                                </div>
                            </SponsorComment>
                            {/* 모달 컴포넌트 표시 여부 확인 후 표시 */}
                            {/* {isFundingModalOpen && (
                                <ModifyModal closeModal={closeModal} handleImageSelection={handleImageSelection} />
                            )} */}
                        </SponsorDiv>
                        {/* 펀딩 내용 및 공개 여부 입력 부분 */}
                        <SponsorDiv>
                            <SponsorComment mt="50px">
                                <P pb="10px" fs="16px" fw="900">
                                    펀딩 내용
                                </P>
                                <P pb="20px" fs="13px" fw="900">
                                    공개 방식
                                </P>
                                <SponsorDiv>
                                    <RadioInput
                                        value="true"
                                        checked={fundingData.publicFlag === "true"}
                                        onChange={(e) => {
                                            setFundingData({ ...fundingData, publicFlag: e.target.value });
                                        }}
                                        type="radio"
                                        mb="21px"
                                    />
                                    <P pb="20px" fs="13px" fw="900" pl="20px">
                                        공개
                                    </P>
                                    <P pb="20px" fs="10px" fw="900" pl="42px">
                                        누구나 볼 수 있어요
                                    </P>
                                </SponsorDiv>

                                <SponsorDiv>
                                    <RadioInput
                                        value="false"
                                        checked={fundingData.publicFlag === "false"}
                                        onChange={(e) => {
                                            setFundingData({ ...fundingData, publicFlag: e.target.value });
                                        }}
                                        type="radio"
                                        mb="21px"
                                    />
                                    <P pb="20px" fs="13px" fw="900" pl="20px">
                                        비공개
                                    </P>
                                    <P pb="20px" fs="10px" fw="900" pl="30px">
                                        링크를 통해서만 방문할 수 있어요
                                    </P>
                                </SponsorDiv>
                            </SponsorComment>
                        </SponsorDiv>
                        <P pt="30px" pb="5px" fs="13px" fw="800">
                            이름
                        </P>
                        <InputTag
                            type="text"
                            placeholder="이름을 입력해주세요"
                            value={fundingData.showName}
                            onChange={(e) => {
                                setFundingData({ ...fundingData, showName: e.target.value });
                            }}
                            h="40px"
                            w="97%"
                            mb="10px"
                            pl="10px"
                        />
                        <P pt="10px" pb="5px" fs="13px" fw="800">
                            제목
                        </P>
                        <InputTag
                            type="text"
                            placeholder="제목을 입력해주세요"
                            value={fundingData.title}
                            onChange={(e) => {
                                setFundingData({ ...fundingData, title: e.target.value });
                            }}
                            h="40px"
                            w="97%"
                            mb="10px"
                            pl="10px"
                        />
                        <P pt="10px" pb="5px" fs="13px" fw="800">
                            본문
                        </P>
                        <InputTag
                            type="text"
                            placeholder="본문을 입력해주세요"
                            value={fundingData.content}
                            onChange={(e) => {
                                setFundingData({ ...fundingData, content: e.target.value });
                            }}
                            h="90px"
                            w="97%"
                            mb="10px"
                            pl="10px"
                            pb="50px"
                        />
                        <P pt="10px" pb="5px" fs="13px" fw="800">
                            마감일 설정
                        </P>
                        <InputTag
                            type="date"
                            value={fundingData.endDate}
                            // onChange={(e) => {
                            //     setFundingData({ ...fundingData, endDate: e.target.value });
                            // }}
                            h="40px"
                            w="97%"
                            pl="10px"
                            pt="10px"
                        />
                    </FundingDiv>
                    {/* 펀딩 안내 문구 */}
                    <TogetherDiv>
                        <P pl="130px" fs="14px" fw="800">
                            펀딩 금액은 계좌로 전달돼요
                        </P>
                        <P pl="95px" fs="14px" fw="800">
                            펀딩에 성공하면 카톡으로 알림이 가요
                        </P>
                    </TogetherDiv>
                    {/* 펀딩 변경하기 및 펀딩 종료하기 버튼 */}
                    <Button
                        onClick={handlefundingModifyClick}
                        w="442px"
                        h="60px"
                        mt="10px"
                        color="white"
                        fs="19px"
                        bc="gray"
                    >
                        펀딩 변경하기
                    </Button>
                    <Button
                        onClick={handlecompleteFundingClick}
                        w="442px"
                        h="60px"
                        mt="10px"
                        color="white"
                        fs="19px"
                        bc="orange"
                    >
                        펀딩 종료하기
                    </Button>
                    <Button
                        onClick={handledeleteFundingClick}
                        w="442px"
                        h="60px"
                        mt="10px"
                        color="white"
                        fs="19px"
                        bc="red"
                    >
                        펀딩 삭제하기
                    </Button>
                </Body>
            </RightContainer>
        </MainContainer>
    );
};

export default FundingModify;
import React from 'react';
import { useNavigate } from 'react-router-dom';
import {
    MainContainer,
    LeftContainer,
    Logo,
    P,
    Button,
    RightContainer,
    SponserMoney,
    InputTag,
    Body,
    FundingDiv,
    SponserDiv,
    SponserComment,
    SponsorImg,
    TogetherDiv,
} from './FundingPayStyles';
import CheckBox from '../FundingPay/CheckBox/CheckBox';
import KakaoPay from './KakaoPay/KakaoPay';

const FundingPay = () => {
    const navigate = useNavigate();

    return (
        <MainContainer>
            <LeftContainer>
                <Logo>😉 Giftipie</Logo>
                <P pt="25px" fs="16px" fw="800" pb="5px">
                    기프티파이에서
                </P>
                <P fs="16px" fw="800" pb="5px">
                    정말 원하는 선물을
                </P>
                <P fs="16px" fw="800">
                    주고 받아요
                </P>
                <Button onClick={() => navigate('/')} mt="20px" w="180px" h="50px" fs="16px" color="white" bc="orange">
                    펀딩 시작하기
                </Button>
            </LeftContainer>

            <RightContainer>
                <Body>
                    <FundingDiv>
                        <SponserMoney>
                            <SponsorImg src="/imgs/junjihyun.jpg" alt="logo" />
                            <P pt="10px" fs="16px" fw="800" pb="5px">
                                윤다인 님에게
                            </P>
                            <P fs="16px" fw="800" pb="5px">
                                5,000원
                            </P>
                            <P fs="16px" fw="800">
                                후원하기
                            </P>
                        </SponserMoney>
                        <P pt="20px" pb="20px" fs="16px" fw="900">
                            후원자
                        </P>

                        <SponserDiv>
                            <SponserComment mt="10px">
                                <P pl="10px" pb="5px" fs="13px" fw="800">
                                    이름
                                </P>
                                <InputTag type="text" placeholder="남길 이름을 입력해주세요" h="40px" />
                                <P pl="10px" fs="10px" fw="800">
                                    주최자에게 이름이 모두 공개되고, 후원자 목록에는 두번째 글자부터 *으로 표시됩니다.
                                    예) 김 * *
                                </P>
                            </SponserComment>
                        </SponserDiv>

                        <P pt="10px" pl="10px" pb="5px" fs="13px" fw="800">
                            후원금
                        </P>
                        <InputTag type="text" placeholder="남길 이름을 입력해주세요" h="40px" />

                        <P pt="10px" pl="10px" pb="5px" fs="13px" fw="800">
                            메시지
                        </P>
                        <InputTag type="text" placeholder="남길 메시지를 입력해주세요" pb="50px" h="100px" />

                        <P pl="10px" fs="10px" fw="800">
                            현재는 테스트 기간으로, 실제 결제가 이루어지지 않습니다. 대신 1명이 참여할 때마다 개설자에게
                            1,000원이 적립됩니다.
                        </P>
                    </FundingDiv>

                    <CheckBox />

                    <TogetherDiv pt="10px" bc="orange">
                        <P pl="140px" fs="14px" fw="800">
                            <br />
                            지금 선물하면 3등이에요!
                            <br />
                        </P>
                    </TogetherDiv>

                    <KakaoPay />
                </Body>
            </RightContainer>
        </MainContainer>
    );
};

export default FundingPay;
import React, { useEffect } from "react"; // React와 useEffect 훅을 React 라이브러리에서 불러옵니다.
import axios from "axios"; // HTTP 요청을 보내기 위해 axios를 가져옵니다.
import { Button, KakaoPayLogo } from "./KakaoPayStyles";

const KakaoPay = () => {
  // KakaoPay라는 함수형 컴포넌트를 정의합니다.
  const sendAmountToServer = async (amount) => {
    // 서버로 금액을 전송하는 비동기 함수를 정의합니다.
    const accessToken = localStorage.getItem("accessToken"); // localStorage에서 accessToken을 가져옵니다.
    try {
      const response = await axios.post(
        "REACT_APP_API_URL",
        {
          // 서버로 POST 요청을 보냅니다.
          point: amount, // 요청 본문에 금액을 담습니다.
        },
        {
          headers: {
            Authorization: accessToken, // 요청 헤더에 accessToken을 포함시킵니다.
          },
        }
      );

      if (response.status === 200) {
        // 요청이 성공했는지 확인합니다.
        alert("서버로 amount 전송 완료"); // 서버로의 전송이 성공한 경우 알림창을 띄웁니다.
      } else {
        alert("서버로 amount 전송 실패"); // 서버로의 전송이 실패한 경우 알림창을 띄웁니다.
      }
    } catch (error) {
      console.error("서버로 amount 전송 중 오류:", error); // 전송 중 오류가 발생한 경우 콘솔에 오류를 기록합니다.
      alert("서버로 amount 전송 중 오류 발생"); // 전송 중 오류가 발생한 경우 알림창을 띄웁니다.
    }
  };

  const requestPay = () => {
    // 결제 요청을 처리하는 함수를 정의합니다.
    const { IMP } = window; // window 객체에서 IMP 객체를 가져옵니다.

    IMP.init("imp82385247"); // IMP 객체를 초기화합니다.

    IMP.request_pay(
      {
        // IMP 객체를 사용하여 결제 요청을 보냅니다.
        pg: "kakaopay.TC0ONETIME", // 결제 수단을 설정합니다.
        pay_method: "card", // 결제 방법을 설정합니다.
        merchant_uid: new Date().getTime(), // 고유한 상점 ID를 생성합니다.
        name: "Giftipie후원금", // 상품 이름을 설정합니다.
        amount: 10000, // 결제 금액을 설정합니다.
        buyer_email: "test@naver.com", // 구매자 이메일을 설정합니다.
        buyer_name: "코드쿡", // 구매자 이름을 설정합니다.
        buyer_tel: "010-1234-5678", // 구매자 전화번호를 설정합니다.
        // buyer_addr: '서울특별시', // 구매자 주소를 설정합니다.
        // buyer_postcode: '123-456', // 구매자 우편번호를 설정합니다.
      },
      async (rsp) => {
        // 결제 요청 후 콜백 함수를 처리합니다.
        try {
          const { data } = await axios.post("REACT_APP_API_URL" + rsp.imp_uid); // 서버에서 결제 검증을 수행합니다.
          if (rsp.paid_amount === data.response.amount) {
            // 결제 금액이 서버 응답과 일치하는지 확인합니다.
            alert("결제 성공"); // 결제가 성공한 경우 알림창을 띄웁니다.
            sendAmountToServer(rsp.paid_amount); // 결제된 금액을 서버로 전송합니다.
          } else {
            alert("결제 실패"); // 결제가 실패한 경우 알림창을 띄웁니다.
          }
        } catch (error) {
          console.error("결제 검증 중 오류:", error); // 결제 검증 중 오류가 발생한 경우 콘솔에 오류를 기록합니다.
          alert("결제 실패"); // 결제 검증 중 오류가 발생한 경우 알림창을 띄웁니다.
        }
      }
    );
  };

  useEffect(() => {
    // 외부 스크립트를 로드하기 위해 useEffect 훅을 사용합니다.
    const jquery = document.createElement("script"); // jQuery 스크립트 엘리먼트를 생성합니다.
    jquery.src = "http://code.jquery.com/jquery-1.12.4.min.js"; // jQuery 스크립트의 소스를 설정합니다.
    const iamport = document.createElement("script"); // Iamport 스크립트 엘리먼트를 생성합니다.
    iamport.src = "http://cdn.iamport.kr/js/iamport.payment-1.1.7.js"; // Iamport 스크립트의 소스를 설정합니다.
    document.head.appendChild(jquery); // jQuery 스크립트를 문서 헤드에 추가합니다.
    document.head.appendChild(iamport); // Iamport 스크립트를 문서 헤드에 추가합니다.
    return () => {
      // 컴포넌트가 언마운트될 때 추가한 스크립트를 제거하기 위한 클린업 함수를 반환합니다.
      document.head.removeChild(jquery); // 문서 헤드에서 jQuery 스크립트를 제거합니다.
      document.head.removeChild(iamport); // 문서 헤드에서 Iamport 스크립트를 제거합니다.
    };
  }, []); // useEffect가 초기 렌더링 후 한 번만 실행되도록 빈 의존성 배열을 전달합니다.

  return (
    <div>
      {/* <button onClick={requestPay}>결제하기</button> */}
      <Button onClick={requestPay}>
        <KakaoPayLogo src="/imgs/kakaopay.png" alt="image" />
      </Button>
    </div>
  );
};

export default KakaoPay; // Payment 컴포넌트를 내보냅니다.