Skip to content

Commit

Permalink
✨ Feat: ProjectRetro 그룹 삭제 기능 구현 (#318)
Browse files Browse the repository at this point in the history
* ✨ Feat: ProjectRetro 개별 그룹 조회 api 연결

* 🐛 Fix: 렌더링 오류

* 💄 Design: ProjectRetro 그룹 삭제 모달창 퍼블리싱

* ✨ Feat: ProjectRetro 그룹 삭제 api 연결
  • Loading branch information
yeneua authored Jul 13, 2024
1 parent fa0fba2 commit e281182
Show file tree
Hide file tree
Showing 14 changed files with 273 additions and 37 deletions.
23 changes: 22 additions & 1 deletion src/api/@types/Groups.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// get
// get all groups
export interface GetRetrospectiveGroupsNodes {
id: number;
title: string;
Expand Down Expand Up @@ -81,3 +81,24 @@ export interface PutRetrospectivesGroupNodes {
description: string;
updatedDate: Date | string;
}

// get a group
export interface GetRetrospectiveGroupRequest {
retrospectiveGroupId: number;
}

export interface GetRetrospectiveGroupResponse {
code: number;
message: string;
data: Array<GetRetrospectiveGroupNodes>;
}

export interface GetRetrospectiveGroupNodes {
title: string;
userId: number;
userName: string;
description: string;
thumnail: string | null;
status: string;
id: number;
}
11 changes: 11 additions & 0 deletions src/api/retroGroupsApi/deleteGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { DeleteRetrospectiveRequest } from '@/api/@types/Groups';
import axiosInstance from '@/api/axiosConfig';

export const DeleteGroup = async ({ retrospectiveGroupId }: DeleteRetrospectiveRequest): Promise<void> => {
try {
const response = await axiosInstance.delete(`/retrospectiveGroups/${retrospectiveGroupId}`);
return response.data;
} catch (error) {
throw new Error(error as string);
}
};
19 changes: 19 additions & 0 deletions src/api/retroGroupsApi/getGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { GetRetrospectiveGroupRequest, GetRetrospectiveGroupResponse } from '@/api/@types/Groups';
import axiosInstance from '@/api/axiosConfig';

export const GetRetrospectiveGroup = async ({
retrospectiveGroupId,
...request
}: GetRetrospectiveGroupRequest): Promise<GetRetrospectiveGroupResponse> => {
try {
const response = await axiosInstance.get<GetRetrospectiveGroupResponse>(
`/retrospectiveGroups/${retrospectiveGroupId}`,
request,
);
return response.data;
} catch (error) {
throw new Error('단일 그룹 조회 실패');
}
};

export default GetRetrospectiveGroup;
Empty file.
1 change: 1 addition & 0 deletions src/components/createRetro/modal/CreateModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ const CreateModal: React.FC<CreateModalProps> = ({ isOpen, onClose, templateId,
setRequestData({ ...requestData, thumbnail: imageUUID });
setImage(file);
}}
text="PC에서 이미지 선택"
/>
</S.LeftColumn>
<S.RightColumn>
Expand Down
5 changes: 3 additions & 2 deletions src/components/createRetro/modal/ImageUpload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import { v4 as uuidv4 } from 'uuid';

interface ImageUploadProps {
onChange: (file: File | null, uuid: string) => void; // 파일 객체, uuid 함께 전달
text: string;
}

const ImageUpload: React.FC<ImageUploadProps> = ({ onChange }) => {
const ImageUpload: React.FC<ImageUploadProps> = ({ onChange, text }) => {
const [imagePreview, setImagePreview] = useState<string | null>(null);
const [_, setImageUUID] = useState<string | null>(null); // 상태를 활용할 수 있도록 수정

Expand Down Expand Up @@ -41,7 +42,7 @@ const ImageUpload: React.FC<ImageUploadProps> = ({ onChange }) => {
<Center>
<label htmlFor="image-upload">
<Button as="span" mt={4} variant="outline" borderColor="gray.700" size="md" width="15rem" id="cr_loadpc">
PC에서 이미지 선택
{text}
</Button>
</label>
</Center>
Expand Down
55 changes: 55 additions & 0 deletions src/components/projectRetro/DeleteModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { IoMdClose } from 'react-icons/io';
import { RiFolder6Fill } from 'react-icons/ri';
import { DeleteGroup } from '@/api/retroGroupsApi/deleteGroup';
import { useCustomToast } from '@/hooks/useCustomToast';
import * as S from '@/styles/projectRetro/DeleteModal.styles';

interface DeleteModalProps {
isClose: () => void;
modalClose: () => void;
groupId: number;
}

const DeleteModal: React.FC<DeleteModalProps> = ({ isClose, modalClose, groupId }) => {
const toast = useCustomToast();
const handleDeleteGroup = async () => {
try {
await DeleteGroup({ retrospectiveGroupId: groupId });
setTimeout(() => {
isClose();
modalClose();
toast.info('그룹이 삭제되었습니다.');
}, 1000);
} catch (e) {
toast.error('그룹 삭제에 실패했습니다.');
}
};

return (
<S.Background>
<S.Container>
<S.Modal>
<S.Top>
<S.Title>회고 프로젝트 삭제</S.Title>
<IoMdClose
onClick={isClose}
size={20}
style={{ color: '#6c6c6c', marginLeft: 'auto', cursor: 'pointer' }}
/>
</S.Top>
<hr />
<S.Bottom>
<div style={{ display: 'flex', alignItems: 'center' }}>
<RiFolder6Fill size={25} style={{ color: '#FFE500', padding: 0 }} />
<S.ProjectName>프로젝트1</S.ProjectName> {/* 프로젝트 이름 */}
<S.Text>를 삭제하시겠습니까?</S.Text>
</div>
<S.Button onClick={handleDeleteGroup}>Delete</S.Button>
</S.Bottom>
</S.Modal>
</S.Container>
</S.Background>
);
};

export default DeleteModal;
8 changes: 3 additions & 5 deletions src/components/projectRetro/DescriptionInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@ import * as S from '@/styles/projectRetro/Modal.styles';

interface DescriptionInputProps {
onChange: (description: string) => void;
placeholder: string;
}

const DescriptionInput: React.FC<DescriptionInputProps> = ({ onChange }) => {
const DescriptionInput: React.FC<DescriptionInputProps> = ({ onChange, placeholder }) => {
return (
<>
<S.DescriptionInput
placeholder="프로젝트에 대한 설명을 입력해 주세요."
onChange={e => onChange(e.target.value)}
></S.DescriptionInput>
<S.DescriptionInput placeholder={placeholder} onChange={e => onChange(e.target.value)}></S.DescriptionInput>
</>
);
};
Expand Down
2 changes: 1 addition & 1 deletion src/components/projectRetro/GroupList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const GroupList: React.FC<GroupListProps> = ({ groups }) => {

return (
<>
{isModalOpen && <Modal isClose={() => setIsModalOpen(false)} type="edit" groupId={6} />}
<S.Container>
{groups.map(group => (
<div key={group.id}>
Expand All @@ -31,7 +32,6 @@ const GroupList: React.FC<GroupListProps> = ({ groups }) => {
))}
<MdOutlineMoreHoriz onClick={handleModal} style={{ cursor: 'pointer' }} />
</S.Container>
{isModalOpen && <Modal isClose={() => setIsModalOpen(false)} type="edit" />}
</>
);
};
Expand Down
88 changes: 69 additions & 19 deletions src/components/projectRetro/Modal.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import { useState } from 'react';
import { useEffect, useState } from 'react';
import { CgTimelapse } from 'react-icons/cg'; // ing
import { FaRegCircleCheck } from 'react-icons/fa6'; // done
import { IoMdClose } from 'react-icons/io';
import { IoIosArrowDown } from 'react-icons/io';
import axios from 'axios';
import { PostRetrospectivesGroupRequest } from '@/api/@types/Groups';
import {
PostRetrospectivesGroupRequest,
GetRetrospectiveGroupRequest,
GetRetrospectiveGroupResponse,
} from '@/api/@types/Groups';
import postImageToS3 from '@/api/imageApi/postImageToS3';
import { GetRetrospectiveGroup } from '@/api/retroGroupsApi/getGroup';
import postGroup from '@/api/retroGroupsApi/postGroup';
import ImageUpload from '@/components/createRetro/modal/ImageUpload';
import DeleteModal from '@/components/projectRetro/DeleteModal';
import DescriptionInput from '@/components/projectRetro/DescriptionInput';
import TitleInput from '@/components/projectRetro/TitleInput';
import { useCustomToast } from '@/hooks/useCustomToast';
Expand All @@ -16,15 +22,21 @@ import * as S from '@/styles/projectRetro/Modal.styles';
interface ModalProps {
isClose: () => void;
type: string;
groupId?: number;
}

const Modal: React.FC<ModalProps> = ({ isClose, type }) => {
const Modal: React.FC<ModalProps> = ({ isClose, type, groupId }) => {
const toast = useCustomToast();
const [isOpen, setIsOpen] = useState<boolean>(false);
const [statusOption, setStatusOption] = useState<string>('ING');
const statusList = ['ING', 'DONE'];
const statusObj: { [key: string]: string } = { ING: 'IN_PROGRESS', DONE: 'COMPLETED' };
const availableOption = statusList.filter(statusList => statusList !== statusOption);
const [deleteModal, setDeleteModal] = useState<boolean>(false);

const handleDeleteModal = () => {
setDeleteModal(true);
};

const [requestData, setRequestData] = useState<PostRetrospectivesGroupRequest>({
title: '',
Expand Down Expand Up @@ -79,7 +91,28 @@ const Modal: React.FC<ModalProps> = ({ isClose, type }) => {
}
};

// const handleEdit = async () => {};
const [groupData, setGroupData] = useState<GetRetrospectiveGroupResponse['data']>([]);

// 단일 그룹 조회
useEffect(() => {
if (type === 'edit' && groupId !== undefined) {
const fetchGroup = async () => {
try {
const requestData: GetRetrospectiveGroupRequest = {
retrospectiveGroupId: groupId,
};
const responseData = await GetRetrospectiveGroup(requestData);
setGroupData(responseData.data);
console.log('단일 그룹 불러오기', responseData);
} catch (error) {
toast.error('그룹 불러오기에 실패했습니다');
}
};
fetchGroup();
}
}, []);

const handleEditGroup = async () => {};

const handleToggle = () => {
setIsOpen(!isOpen);
Expand Down Expand Up @@ -110,22 +143,34 @@ const Modal: React.FC<ModalProps> = ({ isClose, type }) => {
setRequestData({ ...requestData, thumbnail: imageUUID });
setImage(file);
}}
text="PC에서 이미지 선택"
/>
)}
{type === 'edit' &&
// <ImageUpload
// onChange={(file, imageUUID) => {
// setRequestData({ ...requestData, thumbnail: imageUUID });
// setImage(file);
// }}
// text="PC에서 이미지 선택"
// />
'변경하기'}
{type === 'edit' && (
<>
{!requestData.thumbnail && <S.ImageText>변경 전 사진이 없으면 보이지 않습니다.</S.ImageText>}
<ImageUpload
onChange={(file, imageUUID) => {
setRequestData({ ...requestData, thumbnail: imageUUID });
setImage(file);
}}
text="변경하기"
/>
</>
)}
</S.ImageBox>
<TitleInput onChange={title => setRequestData({ ...requestData, title })} />
<TitleInput
placeholder={groupData.length > 0 ? `${groupData[0].title}` : 'Project Name *'}
onChange={title => setRequestData({ ...requestData, title })}
/>
<S.DescriptionBox>
<S.Text>프로젝트 설명</S.Text>
<DescriptionInput onChange={description => setRequestData({ ...requestData, description })} />
<DescriptionInput
placeholder={
groupData.length > 0 ? `${groupData[0].description}` : '프로젝트에 대한 설명을 입력해 주세요.'
}
onChange={description => setRequestData({ ...requestData, description })}
/>
</S.DescriptionBox>
<S.StatusBox>
<S.Text>프로젝트 상태</S.Text>
Expand Down Expand Up @@ -160,12 +205,17 @@ const Modal: React.FC<ModalProps> = ({ isClose, type }) => {
</div>
)}
</S.StatusBox>
<S.SubmitButton onClick={handleCreateGroup}>
{type === 'create' && 'Create'}
{type === 'edit' && 'Edit'}
</S.SubmitButton>
<S.ButtonContainer>
<S.SubmitButton onClick={type === 'create' ? handleCreateGroup : handleEditGroup}>
{type === 'create' && 'Create'}
{type === 'edit' && 'Edit'}
</S.SubmitButton>
{type === 'edit' && <S.DeleteButton onClick={handleDeleteModal}>Delete</S.DeleteButton>}
</S.ButtonContainer>
</S.Modal>
</S.Container>
{deleteModal && <DeleteModal groupId={9} isClose={() => setDeleteModal(false)} modalClose={isClose} />}{' '}
{/* groupId 받아오기 */}
</S.Background>
);
};
Expand Down
5 changes: 3 additions & 2 deletions src/components/projectRetro/TitleInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import * as S from '@/styles/projectRetro/Modal.styles';

interface TitleInputProps {
onChange: (title: string) => void;
placeholder: string;
}

const TitleInput: React.FC<TitleInputProps> = ({ onChange }) => {
const TitleInput: React.FC<TitleInputProps> = ({ onChange, placeholder }) => {
return (
<>
<S.NameInput placeholder="Project Name *" onChange={e => onChange(e.target.value)}></S.NameInput>
<S.NameInput placeholder={placeholder} onChange={e => onChange(e.target.value)}></S.NameInput>
</>
);
};
Expand Down
10 changes: 4 additions & 6 deletions src/pages/ProjectRetroPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,10 @@ const ProjectRetro = () => {
<S.DescriptionText>사용법</S.DescriptionText>
</S.DescriptionBox>
<StatusFilter onSelectedFilter={handleStatusFilter} />
<div>
<S.CreateBox>
<FiPlusCircle size={40} style={{ color: '#a9a9a9', cursor: 'pointer' }} onClick={handleModal} />
</S.CreateBox>
<GroupList groups={filteredGroups} />
</div>
<S.CreateBox>
<FiPlusCircle size={40} style={{ color: '#a9a9a9', cursor: 'pointer' }} onClick={handleModal} />
</S.CreateBox>
<GroupList groups={filteredGroups} />
{isDescriptionOpen ? <DescriptionModal isClose={() => setIsDescriptionOpen(false)} /> : null}
{isModalOpen && <Modal isClose={() => setIsModalOpen(false)} type="create" />}
</>
Expand Down
Loading

0 comments on commit e281182

Please sign in to comment.