Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions src/api/command.api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { CommandType } from '../models/command';
import { httpClient } from './http.api';

export const postCommand = async (id: number, content: string) => {
try {
const response = await httpClient.post(`/project/${id}/comment`, {
content: content,
});
if (response.status !== 200) {
throw new Error(`${response.status}`);
}
return response.status;
} catch (error) {
console.error(error);
throw error;
}
};

export const getCommand = async (id: number): Promise<CommandType[]> => {
try {
const response = await httpClient.get(`/project/${id}/comment`);
return response.data.data;
} catch (error) {
console.error(error);
throw ErrorEvent;
}
};

export const deleteCommand = async (id: number, commandId: number) => {
try {
const response = await httpClient.delete(
`/project/${id}/comment/${commandId}`
);
return response;
} catch (error) {
console.error(error);
throw ErrorEvent;
}
};

export const patchCommand = async (
id: number,
commandId: number,
content: string
) => {
try {
const response = await httpClient.patch(
`/project/${id}/comment/${commandId}?content=${content}`
);
return response.status;
} catch (error) {
console.error(error);
throw ErrorEvent;
}
};
2 changes: 1 addition & 1 deletion src/api/http.api.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import axios, { AxiosRequestConfig } from 'axios';
import useAuthStore, { getTokens } from '../store/authStore';

const BASE_URL = `${import.meta.env.VITE_APP_API_BASE_URL}`;
export const BASE_URL = `${import.meta.env.VITE_APP_API_BASE_URL}`;
const DEFAULT_TIMEOUT = 15000;

export const createClient = (config?: AxiosRequestConfig) => {
Expand Down
6 changes: 5 additions & 1 deletion src/components/command/CommandLayout.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ export const CommandCountsContainer = styled.div`
margin-bottom: 20px;
`;

export const Count = styled.span``;
export const Count = styled.span`
font-size: 20px;
font-weight: bold;
margin-top: 10px;
`;

export const CommandContainer = styled.div``;

Expand Down
57 changes: 45 additions & 12 deletions src/components/command/CommandLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,38 +5,71 @@ import { IoIosArrowDown } from 'react-icons/io';
import { IoIosArrowUp } from 'react-icons/io';

import CommandInput from './commandInput/CommandInput';
import useGetCommand from '../../hooks/CommandHooks/useGetCommand';
import LoadingSpinner from '../common/loadingSpinner/LoadingSpinner';

const CommandLayout = () => {
interface CommandLayoutProps {
projectId: number;
createrId: number;
loginUserId: number | undefined;
}

const CommandLayout = ({
projectId,
createrId,
loginUserId,
}: CommandLayoutProps) => {
const [isShowReply, setIsShowReply] = useState<boolean>(false);

const { getCommandList, isLoading, isFetching, isError } =
useGetCommand(projectId);

const handleClick = () => {
setIsShowReply(!isShowReply);
};

if (isLoading || isFetching) {
return <LoadingSpinner />;
}

if (isError) {
console.error(isError);
}

return (
<S.Container>
<S.CommandCountsContainer>
<S.Count>댓글 {2}개</S.Count>
<S.Count>댓글 {getCommandList?.length}개</S.Count>
</S.CommandCountsContainer>

<S.CommandInput>
<CommandInput />
<CommandInput projectId={projectId} commandId={0} />
</S.CommandInput>

<S.CommandContainer>
<CommandComponent data={[]} />
<CommandComponent
getCommandList={getCommandList}
projectId={projectId}
createrId={createrId}
loginUserId={loginUserId}
/>
<S.ShowReply onClick={handleClick}>
<S.ShowReplyButton>
<S.Icon>
{isShowReply ? <IoIosArrowUp /> : <IoIosArrowDown />}
</S.Icon>
<S.Content>답글 확인하기</S.Content>
</S.ShowReplyButton>
</S.ShowReply>
</S.CommandContainer>

<S.ShowReply onClick={handleClick}>
<S.ShowReplyButton>
<S.Icon>{isShowReply ? <IoIosArrowUp /> : <IoIosArrowDown />}</S.Icon>
<S.Content>답글 확인하기</S.Content>
</S.ShowReplyButton>
</S.ShowReply>

{isShowReply && (
<S.ReplyContainer>
<CommandComponent data={[]} reply={true} />
<CommandComponent
getCommandList={getCommandList}
reply={true}
projectId={projectId}
/>
</S.ReplyContainer>
)}
</S.Container>
Expand Down
12 changes: 12 additions & 0 deletions src/components/command/commandComponent/CommandComponent.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const Container = styled.div`
display: flex;
justify-content: space-between;
width: 100%;
margin-bottom: 20px;
`;

export const Wrapper = styled.div`
Expand Down Expand Up @@ -52,4 +53,15 @@ export const CommandInput = styled.div`
export const ReplyInput = styled.div`
width: 100%;
padding-left: 15px;
margin-bottom: 10px;
`;

export const ErrorMessage = styled.div`
padding-left: 15px;
margin-bottom: 10px;
`;

export const Message = styled.p`
color: ${({ theme }) => theme.color.red};
font-size: 10px;
`;
134 changes: 84 additions & 50 deletions src/components/command/commandComponent/CommandComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,72 +7,106 @@ import CommandInput from '../commandInput/CommandInput';
import { CiMenuKebab } from 'react-icons/ci';
import DropDown from '../../common/dropDown/DropDown';
import DropDownItem from '../../common/dropDown/DropDownItem';
import useDropDownItem from '../../../hooks/useDropDownItem';
import { CommandType } from '../../../models/command';

interface CommandLayoutProps {
data: [];
projectId: number;
getCommandList: CommandType[] | undefined;
reply?: boolean;
createrId?: number;
loginUserId?: number | undefined;
}

const command = '안녕하세요';

const CommandComponent = ({ data, reply }: CommandLayoutProps) => {
const [showReplyInput, setShowReplyInput] = useState<boolean>(false);
const CommandComponent = ({
projectId,
getCommandList,
reply,
createrId,
loginUserId,
}: CommandLayoutProps) => {
const [activeReplyId, setActiveReplyId] = useState<number | null>(null);
const [activateEditMode, setActivateEditMode] = useState<number | null>(null);
const [showMenu, setShowMenu] = useState<boolean>(false);
const [onReplyMessage, setOnReplyMessage] = useState<boolean>(false);

const { onReport, onEdit, onDelete, isEditMode } = useDropDownItem();
const handleClick = (commandId: number) => {
setActiveReplyId((prev) => (prev === commandId ? null : commandId));

const handleClick = () => {
setShowReplyInput(!showReplyInput);
if (createrId !== loginUserId) {
setOnReplyMessage(true);
setTimeout(() => {
setOnReplyMessage(false);
}, 2000);
}
};

console.log(isEditMode);

const onClick = () => {
setShowMenu(!showMenu);
};

const onEdit = (commandId: number) => {
setActivateEditMode((prev) => (prev === commandId ? null : commandId));
};

return (
<S.Container>
{/* 전체를 map으로 감싸 하기 */}
<S.Wrapper>
<Avatar size={reply ? '55px' : '75px'} image={DefaultImg} />
<S.CommandWrapper>
<S.NickName>SeungYeon</S.NickName>
{isEditMode ? (
<CommandInput
isEditMode={isEditMode}
onEdit={onEdit}
command={command}
<>
{getCommandList?.map((item, index) => (
<S.Container>
<S.Wrapper key={index}>
<Avatar size={reply ? '45px' : '55px'} image={DefaultImg} />
<S.CommandWrapper>
<S.NickName>{item.user.nickname}</S.NickName>
{activateEditMode === item.id ? (
<CommandInput
activateEditMode={activateEditMode}
command={item.content}
projectId={projectId}
commandId={item.id}
setActivateEditMode={setActivateEditMode}
/>
) : (
<S.Command>{item.content}</S.Command>
)}
{!reply && (
<S.ReplyButton onClick={() => handleClick(item.id)}>
<S.Icon>
<IoChatbubbleEllipsesOutline />
</S.Icon>
<S.ReplyContent>댓글 달기</S.ReplyContent>
</S.ReplyButton>
)}

{activeReplyId === item.id && onReplyMessage && (
<S.ErrorMessage>
<S.Message>
프로젝트 생성자만 답글을 달 수 있습니다.
</S.Message>
</S.ErrorMessage>
)}
{activeReplyId === item.id && createrId === loginUserId && (
<S.ReplyInput>
<CommandInput
reply={true}
projectId={projectId}
commandId={item.id}
/>
</S.ReplyInput>
)}
</S.CommandWrapper>
</S.Wrapper>
<DropDown toggleButton={<CiMenuKebab size='20' onClick={onClick} />}>
<DropDownItem
projectId={projectId}
commandId={item.id}
onEdit={() => onEdit(item.id)}
loginUserId={loginUserId}
commandUserId={item.user.id}
activateEditMode={activateEditMode}
/>
) : (
<S.Command>{command}</S.Command>
)}
{!reply && (
<S.ReplyButton onClick={handleClick}>
<S.Icon>
<IoChatbubbleEllipsesOutline />
</S.Icon>
<S.ReplyContent>댓글 달기</S.ReplyContent>
</S.ReplyButton>
)}
{showReplyInput && (
<S.ReplyInput>
<CommandInput reply={true} />
</S.ReplyInput>
)}
</S.CommandWrapper>
</S.Wrapper>
<DropDown toggleButton={<CiMenuKebab size='20' onClick={onClick} />}>
<DropDownItem
commandId={4}
onReport={onReport}
onEdit={onEdit}
onDelete={onDelete}
isEditMode={isEditMode}
/>
</DropDown>
</S.Container>
</DropDown>
</S.Container>
))}
</>
);
};

Expand Down
3 changes: 2 additions & 1 deletion src/components/command/commandInput/CommandInput.styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import Button from '../../common/Button/Button';

export const InputContainer = styled.div`
display: flex;
margin-left: 8px;
`;

export const Input = styled.input`
width: 100%;
margin-left: 10px;
`;

export const InputWrapper = styled.div`
Expand All @@ -24,6 +24,7 @@ export const ButtonWrapper = styled.div`
export const Line = styled.hr<{ $isFocused: boolean }>`
opacity: ${({ $isFocused }) => ($isFocused ? 1.0 : 0.2)};
border: ${({ $isFocused }) => ($isFocused ? 2 : 1)};
margin-left: 10px;
`;

export const ButtonCancel = styled(Button)``;
Expand Down
Loading