Skip to content

Commit

Permalink
Merge pull request #309 from boostcampwm2023/feature/backlogPage
Browse files Browse the repository at this point in the history
feat: 스토리 수정, 삭제 기능 구현, 에픽 기능 피드백 반영
  • Loading branch information
surinkwon authored Jul 15, 2024
2 parents 3b8dd13 + 2a38f47 commit 19c76f2
Show file tree
Hide file tree
Showing 13 changed files with 347 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const BacklogStatusDropdown = ({
const statusList: BacklogStatusType[] = ["시작전", "진행중", "완료"];

return (
<div className="rounded-md w-fit shadow-box">
<div className="absolute top-0 bg-white rounded-md w-fit shadow-box">
<ul>
{...statusList.map((status) => (
<li
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/backlog/CategoryChip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ interface CategoryChipProps {

const CategoryChip = ({ content, bgColor }: CategoryChipProps) => (
<div
className={`w-fit max-w-[4.5rem] rounded-md ${CATEGORY_COLOR[bgColor]} px-2 py-[2px]`}
title={content}
className={`w-fit max-w-[4.5rem] rounded-md ${CATEGORY_COLOR[bgColor]} px-2 py-[2px] overflow-hidden text-ellipsis whitespace-nowrap`}
>
{content}
</div>
Expand Down
32 changes: 26 additions & 6 deletions frontend/src/components/backlog/EpicDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,24 @@ import { CATEGORY_COLOR } from "../../constants/backlog";
import getRandomNumber from "../../utils/getRandomNumber";
import { BacklogCategoryColor } from "../../types/common/backlog";
import EpicDropdownOption from "./EpicDropdownOption";
import EpicUpdateBox from "./EpicUpdateBox";
import useDropdownState from "../../hooks/common/dropdown/useDropdownState";

interface EpicDropdownProps {
selectedEpic?: EpicCategoryDTO;
epicList: EpicCategoryDTO[];
onEpicSelect: (epicId: number) => void;
onEpicChange: (epicId: number | undefined) => void;
}

const EpicDropdown = ({
selectedEpic,
epicList,
onEpicSelect,
onEpicChange,
}: EpicDropdownProps) => {
const { socket }: { socket: Socket } = useOutletContext();
const { emitEpicCreateEvent } = useEpicEmitEvent(socket);
const [value, setValue] = useState("");
const { open, handleOpen, handleClose } = useDropdownState();

const handleInputChange = ({ target }: ChangeEvent<HTMLInputElement>) => {
const { value } = target;
Expand All @@ -36,6 +39,11 @@ const EpicDropdown = ({
}

if (event.key === "Enter" && value) {
if (value.length > 10) {
alert("에픽 이름은 10자 이하여야 합니다.");
return;
}

setValue("");
const colors = Object.keys(CATEGORY_COLOR);
const color = colors[
Expand All @@ -45,8 +53,8 @@ const EpicDropdown = ({
}
};

const handleEpicSelect = (epicId: number) => {
onEpicSelect(epicId);
const handleEpicChange = (epicId: number | undefined) => {
onEpicChange(epicId);
};

return (
Expand All @@ -71,8 +79,20 @@ const EpicDropdown = ({
</div>
<ul className="pt-1">
{...epicList.map((epic) => (
<li key={epic.id} onClick={() => handleEpicSelect(epic.id)}>
<EpicDropdownOption key={epic.id} epic={epic} />
<li
key={epic.id}
onClick={() => {
handleEpicChange(epic.id);
}}
>
<EpicDropdownOption key={epic.id} epic={epic} onOpen={handleOpen} />
{open && (
<EpicUpdateBox
epic={epic}
onBoxClose={handleClose}
onEpicChange={handleEpicChange}
/>
)}
</li>
))}
</ul>
Expand Down
43 changes: 15 additions & 28 deletions frontend/src/components/backlog/EpicDropdownOption.tsx
Original file line number Diff line number Diff line change
@@ -1,44 +1,31 @@
import CategoryChip from "./CategoryChip";
import MenuKebab from "../../assets/icons/menu-kebab.svg?react";
import { EpicCategoryDTO } from "../../types/DTO/backlogDTO";
import useDropdownState from "../../hooks/common/dropdown/useDropdownState";
import EpicUpdateBox from "./EpicUpdateBox";
import { MouseEvent, useRef } from "react";

import { MouseEvent } from "react";

interface EpicDropdownOptionProps {
epic: EpicCategoryDTO;
onOpen: () => void;
}

const EpicDropdownOption = ({ epic }: EpicDropdownOptionProps) => {
const { open, handleOpen, handleClose } = useDropdownState();
const buttonRef = useRef<HTMLButtonElement | null>(null);

const EpicDropdownOption = ({ epic, onOpen }: EpicDropdownOptionProps) => {
const handleMenuButtonClick = (event: MouseEvent) => {
event.stopPropagation();
handleOpen();
onOpen();
};

return (
<>
<div className="flex justify-between px-1 py-1 rounded-md group hover:cursor-pointer hover:bg-gray-100">
<CategoryChip content={epic.name} bgColor={epic.color} />
<button
className="invisible px-1 rounded-md group-hover:visible hover:bg-gray-300"
type="button"
onClick={handleMenuButtonClick}
ref={buttonRef}
>
<MenuKebab width={20} height={20} stroke="#696969" />
</button>
</div>
{open && (
<EpicUpdateBox
epic={epic}
onBoxClose={handleClose}
buttonRef={buttonRef}
/>
)}
</>
<div className="flex justify-between px-1 py-1 rounded-md group hover:cursor-pointer hover:bg-gray-100">
<CategoryChip content={epic.name} bgColor={epic.color} />
<button
className="invisible px-1 rounded-md group-hover:visible hover:bg-gray-300"
type="button"
onClick={handleMenuButtonClick}
>
<MenuKebab width={20} height={20} stroke="#696969" />
</button>
</div>
);
};

Expand Down
29 changes: 20 additions & 9 deletions frontend/src/components/backlog/EpicUpdateBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,31 @@ import { BacklogCategoryColor } from "../../types/common/backlog";
interface EpicUpdateBoxProps {
epic: EpicCategoryDTO;
onBoxClose: () => void;
buttonRef: React.MutableRefObject<HTMLButtonElement | null>;
onEpicChange: (epicId: number | undefined) => void;
}

const EpicUpdateBox = ({ epic, onBoxClose, buttonRef }: EpicUpdateBoxProps) => {
const EpicUpdateBox = ({
epic,
onBoxClose,
onEpicChange,
}: EpicUpdateBoxProps) => {
const { open, close } = useModal();
const { socket }: { socket: Socket } = useOutletContext();
const { emitEpicDeleteEvent, emitEpicUpdateEvent } = useEpicEmitEvent(socket);
const boxRef = useRef<HTMLDivElement | null>(null);
const inputRef = useRef<HTMLInputElement | null>(null);
const colorList = Object.entries(CATEGORY_COLOR);

const handleConfirmButtonClick = () => {
const handleConfirmButtonClick = (event?: React.MouseEvent) => {
event?.stopPropagation();
onEpicChange(undefined);
emitEpicDeleteEvent({ id: epic.id });
onBoxClose();
close();
};

const handleDeleteButtonClick = () => {
const handleDeleteButtonClick = (event: React.MouseEvent) => {
event.stopPropagation();
open(
<ConfirmModal
title="에픽을 삭제하시겠습니까?"
Expand All @@ -54,7 +62,11 @@ const EpicUpdateBox = ({ epic, onBoxClose, buttonRef }: EpicUpdateBoxProps) => {
}
};

const handleColorUpdate = (color: BacklogCategoryColor) => {
const handleColorUpdate = (
event: React.MouseEvent,
color: BacklogCategoryColor
) => {
event.stopPropagation();
if (epic.color === color) {
return;
}
Expand All @@ -63,9 +75,6 @@ const EpicUpdateBox = ({ epic, onBoxClose, buttonRef }: EpicUpdateBoxProps) => {
};

const handleOutsideClick = ({ target }: MouseEvent) => {
if (buttonRef.current && buttonRef.current.contains(target as Node)) {
return;
}
if (boxRef.current && !boxRef.current.contains(target as Node)) {
onBoxClose();
}
Expand Down Expand Up @@ -100,7 +109,9 @@ const EpicUpdateBox = ({ epic, onBoxClose, buttonRef }: EpicUpdateBoxProps) => {
<li
key={color}
className="flex items-center gap-2 pl-1 pr-2 mb-1 rounded-md hover:cursor-pointer hover:bg-gray-100"
onClick={() => handleColorUpdate(name as BacklogCategoryColor)}
onClick={(event) =>
handleColorUpdate(event, name as BacklogCategoryColor)
}
>
<div className={`w-5 h-5 rounded-md ${color}`}></div>
<span>{name}</span>
Expand Down
Loading

0 comments on commit 19c76f2

Please sign in to comment.