Skip to content

Commit

Permalink
feat: 빈집거래 상세 페이지 수정/삭제 기능 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
JunJongHun committed Oct 19, 2023
1 parent 1f6eb6e commit 66eab9c
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 52 deletions.
22 changes: 22 additions & 0 deletions src/apis/houses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,25 @@ export const PostHouseAPI = async (form: TradeBoardForm) => {
return err.response?.data;
}
};

export const PutHouseAPI = async (id: number, form: TradeBoardForm) => {
try {
const response = await axios.put<
ApiResponseWithDataType<TradeBoardDetailType>
>(`/houses/${id}`, form);
return response.data;
} catch (error) {
const err = error as AxiosError<ApiResponseType>;
return err.response?.data;
}
};

export const DeleteHouseAPI = async (id: number) => {
try {
const response = await axios.delete<ApiResponseType>(`/houses/${id}`);
return response.data;
} catch (error) {
const err = error as AxiosError<ApiResponseType>;
return err.response?.data;
}
};
57 changes: 50 additions & 7 deletions src/components/Trade/Quill/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { useRef } from 'react';
import ReactQuill from 'react-quill';
import { useNavigate } from 'react-router-dom';
import { TradeBoardForm } from '@/types/Board/tradeType';
import { useLocation, useNavigate } from 'react-router-dom';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { QueryKeys, restFetcher } from '@/queryClient';
import { TradeBoardDetailType, TradeBoardForm } from '@/types/Board/tradeType';
import getImageUrls from '@/utils/Quill/getImageUrls';
import { PostHouseAPI } from '@/apis/houses';
import userStore from '@/store/userStore';
import useQuillModules from '@/hooks/useQuillModules';
import 'react-quill/dist/quill.snow.css';
import { checkBeforeTradePost } from '@/utils/utils';
import styles from './styles.module.scss';
// TODO: 이미지 10개 이상 등록 불가

type TradeQuillProps = {
form: TradeBoardForm;
Expand All @@ -26,11 +27,33 @@ export default function TradeQuill({
}: TradeQuillProps) {
const { user } = userStore();
const navigate = useNavigate();

const { state }: { state: { data: TradeBoardDetailType } } = useLocation();
const QuillRef = useRef<ReactQuill>();
// 이미지를 업로드 하기 위한 함수
const modules = useQuillModules(QuillRef);

const queryClient = useQueryClient();
const { mutate } = useMutation(
(tradeBoardForm: TradeBoardForm) =>
restFetcher({
method: 'PUT',
path: `houses/${state.data.houseId}`,
body: {
...tradeBoardForm,
},
}),
{
onSuccess: () => {
alert('게시글을 수정하였습니다.');
queryClient.refetchQueries([QueryKeys.TRADE_BOARD]);
navigate(`/trade`);
},
onError: () => {
alert('게시글 수정을 실패했습니다.');
},
},
);

const onPost = async () => {
const imageUrls = [thumbnail, ...getImageUrls(form.code)];

Expand All @@ -43,12 +66,25 @@ export default function TradeQuill({

try {
await PostHouseAPI(newForm);
alert('등록되었습니다.');
navigate(`/trade`);
} catch (error) {
console.error(error);
}
};

const onUpdate = async () => {
const imageUrls = [thumbnail, ...getImageUrls(form.code)];

const newForm = {
...form,
imageUrls,
};

if (!checkBeforeTradePost(user!, newForm)) return;

mutate(newForm);
};
return (
<div className={styles.container}>
<section className={styles.sectionWrapper}>
Expand All @@ -72,6 +108,7 @@ export default function TradeQuill({
QuillRef.current = element;
}
}}
value={form.code}
onChange={(value) => setForm((prev) => ({ ...prev, code: value }))}
modules={modules}
placeholder="사진 5장 이상은 필수입니다. 5장 이상(건물 외관, 내부 포함) 업로드 되지 않을 시, 반려됩니다."
Expand All @@ -88,9 +125,15 @@ export default function TradeQuill({
>
임시저장
</button>
<button type="button" onClick={onPost}>
등록하기
</button>
{state ? (
<button type="button" onClick={onUpdate}>
수정하기
</button>
) : (
<button type="button" onClick={onPost}>
등록하기
</button>
)}
</section>
</div>
);
Expand Down
32 changes: 31 additions & 1 deletion src/pages/Trade/Board/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import 'swiper/css';
import 'swiper/css/pagination';
import 'swiper/css/navigation';
import { TradeBoardDetailType } from '@/types/Board/tradeType';
import { DeleteHouseAPI } from '@/apis/houses';
import userStore from '@/store/userStore';
import { getMoveInType, getRentalName, getUserType } from '@/utils/utils';
import { ApiResponseWithDataType } from '@/types/apiResponseType';
Expand All @@ -39,6 +40,19 @@ export default function TradeBoardPage() {
const [modal, setModal] = useState(false);
const ref = useRef<HTMLDivElement>(null);

const handleDeleteButtonClick = async (houseId: number) => {
if (houseId === 0) throw new Error('없는 빈집거래 게시물입니다.');
await DeleteHouseAPI(houseId);
alert('삭제되었습니다.');
navigate('/trade');
};

const handleEditButtonClick = () => {
navigate(`/trade/write`, {
state: { data: data?.data },
});
};

useEffect(() => {
updateState(true);
}, []);
Expand Down Expand Up @@ -86,7 +100,23 @@ export default function TradeBoardPage() {
</p>
{user?.nick_name === data?.data.nickName ? (
<div>
<span>수정</span> | <span>삭제</span>
<button
type="button"
onClick={() => {
handleEditButtonClick();
}}
>
수정
</button>{' '}
|{' '}
<button
type="button"
onClick={() => {
handleDeleteButtonClick(data?.data.houseId || 0);
}}
>
삭제
</button>
</div>
) : null}
</div>
Expand Down
6 changes: 5 additions & 1 deletion src/pages/Trade/Board/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@

& > div {
display: flex;
align-items: center;
gap: 1rem;
font-size: 1.25rem;
font-weight: 400;
Expand All @@ -70,8 +71,11 @@
font-weight: 200;
}

& > div > span {
& > div > button {
cursor: pointer;
background: inherit;
border: none;
color: var(--darkgray-color);
&:hover {
color: var(--main-color);
}
Expand Down
62 changes: 38 additions & 24 deletions src/pages/Trade/Write/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { useRef, useState } from 'react';
import { Navigate } from 'react-router-dom';
import { Navigate, useLocation } from 'react-router-dom';
import { FiSearch } from 'react-icons/fi';
import { MdUploadFile } from 'react-icons/md';
import { AxiosError } from 'axios';
import { motion } from 'framer-motion';
import AddressModal from '@/components/Trade/AddressModal';
import TradeQuill from '@/components/Trade/Quill';
import { RentalType, TradeBoardForm } from '@/types/Board/tradeType';
import {
RentalType,
TradeBoardDetailType,
TradeBoardForm,
} from '@/types/Board/tradeType';
import { uploadFile } from '@/apis/uploadS3';
import userStore from '@/store/userStore';
import { getRentalPriceType } from '@/utils/utils';
Expand All @@ -20,43 +24,45 @@ const { VITE_S3_DOMAIN, VITE_CLOUD_FRONT_DOMAIN } = import.meta.env;
export default function TradeWritePage() {
const { user } = userStore();

const { state }: { state: { data: TradeBoardDetailType } } = useLocation();

const [form, setForm] = useState<TradeBoardForm>({
rentalType: 'SALE',
city: '',
zipCode: '',
size: '',
purpose: '',
floorNum: 0,
contact: '',
createdDate: '',
price: 0,
monthlyPrice: 0,
agentName: '',
title: '',
code: '',
imageUrls: [],
tmpYn: false,
recommendedTag: [],
rentalType: state?.data.rentalType || 'SALE',
city: state?.data.city || '',
zipCode: state?.data.zipCode || '',
size: state?.data.size || '',
purpose: state?.data.purpose || '',
floorNum: state?.data.floorNum || 0,
contact: state?.data.contact || '',
createdDate: state?.data.createdDate || '',
price: state?.data.price || 0,
monthlyPrice: state?.data.monthlyPrice || 0,
agentName: state?.data.agentName || '',
title: state?.data.title || '',
code: state?.data.code || '',
imageUrls: state?.data.imageUrls || [],
tmpYn: state?.data.tmpYn || false,
recommendedTag: state?.data.recommendedTag || [],
});

const [thumbnail, setThumbnail] = useState('');
const [thumbnailTitle, setThumbnailTitle] = useState('');
const [thumbnail, setThumbnail] = useState(state.data.imageUrls[0] || '');
const [thumbnailTitle, setThumbnailTitle] = useState(
state.data.imageUrls[0].split('/')[3] || '',
);
const thumbnailRef = useRef<HTMLInputElement>(null);
// 매물특징
// const appendSpecialCategory = (category: string) => {};
const [isPostcodeOpen, setIsPostcodeOpen] = useState(false);

const postCodeCallback = (fullAddress: string, zipCode?: string) => {
const postCodeCallback = (fullAddress: string, zipCodePost?: string) => {
setForm((prev: TradeBoardForm) => ({
...prev,
city: fullAddress,
zipCode: zipCode ?? '',
zipCode: zipCodePost ?? '',
}));
};

const onChangeForm = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;

setForm((prev) => ({ ...prev, [name]: value }));
};

Expand Down Expand Up @@ -212,6 +218,7 @@ export default function TradeWritePage() {
type="number"
placeholder="만원으로 표기"
name="price"
value={form.price}
onChange={onChangeForm}
/>
</div>
Expand All @@ -226,6 +233,7 @@ export default function TradeWritePage() {
type="number"
placeholder="만원으로 표기"
name="monthlyPrice"
value={form.monthlyPrice}
onChange={onChangeForm}
/>
</div>
Expand All @@ -236,6 +244,7 @@ export default function TradeWritePage() {
type="text"
placeholder="01000000000 표기(매물 관련 연락 가능한 연락처)"
name="contact"
value={form.contact}
onChange={onChangeForm}
/>
</div>
Expand All @@ -247,6 +256,7 @@ export default function TradeWritePage() {
type="text"
placeholder="부동산명 표기"
name="agentName"
value={form.agentName}
onChange={onChangeForm}
/>
</div>
Expand All @@ -266,6 +276,7 @@ export default function TradeWritePage() {
type="text"
placeholder="m2로 표기"
name="size"
value={form.size}
onChange={onChangeForm}
/>
</div>
Expand All @@ -278,6 +289,7 @@ export default function TradeWritePage() {
type="text"
placeholder="년도로 표기"
name="createdDate"
value={form.createdDate}
onChange={onChangeForm}
/>
</div>
Expand All @@ -290,6 +302,7 @@ export default function TradeWritePage() {
type="text"
placeholder="용도 및 방 개수, 화장실 개수 포함"
name="purpose"
value={form.purpose}
onChange={onChangeForm}
/>
</div>
Expand All @@ -300,6 +313,7 @@ export default function TradeWritePage() {
type="number"
placeholder="아파트, 빌라와 같은 다가구 주택만 작성"
name="floorNum"
value={form.floorNum}
onChange={onChangeForm}
/>
</div>
Expand Down
Loading

0 comments on commit 66eab9c

Please sign in to comment.