Skip to content

Commit

Permalink
Merge pull request #34 from HappyScrolls/feature/#30_commonSchedule
Browse files Browse the repository at this point in the history
Feature/#30 common schedule
  • Loading branch information
mnbvcxzyj authored Oct 8, 2024
2 parents a185f68 + 03ab15e commit 5a47444
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 8 deletions.
17 changes: 17 additions & 0 deletions src/api/schedule/scheduleAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,20 @@ export const updateScheduleStatus = async ({
throw new Error(`일정 상태 업데이트 실패: ${error}`);
}
};

// 공통 일정으로 변경
export const changeCommonSchedule = async (scheduleNo: number) => {
try {
const response = await scheduleAxiosInstance.put(
`/schedule/${scheduleNo}/common-schedule`,
{}
);
return response.data;
} catch (error) {
console.error("공통일정으로 변경 중 오류 발생:", error);
if (axios.isAxiosError(error) && error.response) {
console.warn(`에러 상태 코드: ${error.response.status}`);
}
throw new Error(`공통일정으로 변경 업데이트 실패: ${error}`);
}
};
101 changes: 101 additions & 0 deletions src/components/modal/OneBtnModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React from "react";
import { ISModalProps } from "../../types/ISModalProps";
import { styled } from "styled-components";

const OneBtnModal: React.FC<ISModalProps> = ({
title,
description,
imageSrc,
confirmText = "확인",
onConfirm,
}) => {
return (
<>
{console.log("모달 열림")}
<ModalOverlay>
<ModalContent>
{imageSrc && <ModalImage src={imageSrc} alt="modal image" />}
<ModalTitle>{title}</ModalTitle>
{description && <ModalDescription>{description}</ModalDescription>}
<ModalButtonWrapper>
<ModalButton onClick={onConfirm}>{confirmText}</ModalButton>
</ModalButtonWrapper>
</ModalContent>
</ModalOverlay>
</>
);
};

export default OneBtnModal;

const ModalOverlay = styled.div`
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 10;
`;

const ModalContent = styled.div`
padding: 20px;
border-radius: 20px;
background: #fff;
display: flex;
flex-direction: column;
align-items: center;
`;

const ModalTitle = styled.h2`
color: var(--Black, #3b3634);
text-align: center;
font-family: SUIT;
font-size: 10px;
font-style: normal;
font-weight: 400;
line-height: normal;
`;

const ModalDescription = styled.div`
margin-top: 5px;
color: var(--Primary, #f14040);
font-family: SUIT;
font-size: 8px;
font-style: normal;
font-weight: 400;
line-height: normal;
`;

const ModalImage = styled.img`
width: 100px;
height: 100px;
`;

const ModalButtonWrapper = styled.div`
display: flex;
margin-top: 10px;
gap: 20px;
`;

const ModalButton = styled.button`
border-radius: 10px;
width: 90px;
padding: 9px 0px 8px 0px;
border-radius: 10px;
background: #f25454;
box-shadow: 0px 0px 4px 1px rgba(0, 0, 0, 0.25);
color: #fff;
text-align: center;
font-family: SUIT;
font-size: 10px;
font-style: normal;
font-weight: 400;
line-height: normal;
`;
26 changes: 26 additions & 0 deletions src/hooks/useChangeCoupleSchedule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useMutation } from "@tanstack/react-query";
import { changeCommonSchedule } from "../api/schedule/scheduleAPI";
import { AxiosError } from "axios";

export const useChangeCommonSchedule = () => {
return useMutation({
mutationFn: (scheduleNo: number) => changeCommonSchedule(scheduleNo),
onError: (error: unknown) => {
if (error instanceof AxiosError) {
if (error.response) {
console.error(
"서버 에러:",
error.response.status,
error.response.data
);
} else if (error.request) {
console.error("Request failed 실패:", error.request);
} else {
console.error("Error message 에러:", error.message);
}
} else {
console.error("Unknown error:", error);
}
},
});
};
54 changes: 50 additions & 4 deletions src/pages/calendar/components/TimeTableView.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useRef, useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import styled, { keyframes } from "styled-components";

import { getBusyBackgroundColor, getBusyColor } from "../../../utils/colors";
import { useNavigate } from "react-router-dom";
import { useLocation, useNavigate } from "react-router-dom";
import {
useFetchCommonScheduleList,
useFetchMyScheduleList,
Expand All @@ -15,6 +15,9 @@ import { useDeleteSchedule } from "../../../hooks/useDeleteSchedule";
import tearEmoji from "../../../images/emoji/이모지_눈물.png";
import { scheduleModalButtons } from "../../../utils/scheduleModalBtn";
import ScheduleDetailModal from "./ScheduleDetailModal";
import coupleEmoji from "../../../images/emoji/이모지_커플.png";
import { useChangeCommonSchedule } from "../../../hooks/useChangeCoupleSchedule";
import OneBtnModal from "../../../components/modal/OneBtnModal";

// (1시간 = 26px)
const timeToPosition = (dateTime: string): number => {
Expand Down Expand Up @@ -51,21 +54,33 @@ interface ScheduleItemProps {
type ModalType = "empty" | "schedule" | null;

const TimeTableView: React.FC<{ date: string }> = ({ date }) => {
const { data: myScheduleList } = useFetchMyScheduleList(date);
const { data: myScheduleList, refetch: refetchMyScheduleList } =
useFetchMyScheduleList(date);
const { data: partnerScheduleList } = useFetchPartnerScheduleList(date);
const { data: commonScheduleList } = useFetchCommonScheduleList(date);
const { mutate: deleteSchedule } = useDeleteSchedule();
const { mutate: changeCommonSchedule } = useChangeCommonSchedule();

const navigate = useNavigate();
const [activeModal, setActiveModal] = useState<ModalType>(null);
const [isClosing, setIsClosing] = useState(false);
const [touchStartY, setTouchStartY] = useState(0);
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [isChangeCommonModalOpen, setIsChangeCommonModalOpen] = useState(false);

const [selectedSchedule, setSelectedSchedule] = useState<ScheduleData | null>(
null
);

const location = useLocation();
useEffect(() => {
if (location.state?.refetch) {
refetchMyScheduleList();

navigate(location.pathname, { replace: true, state: {} });
}
}, [location, refetchMyScheduleList]);

const modalRef = useRef<HTMLDivElement>(null);

const openModal = (type: ModalType) => {
Expand All @@ -87,6 +102,8 @@ const TimeTableView: React.FC<{ date: string }> = ({ date }) => {
deleteSchedule(selectedSchedule.scheduleNo, {
onSuccess: () => {
setIsDeleteModalOpen(false);
closeModal();
refetchMyScheduleList();
console.log("일정이 성공적으로 삭제되었습니다.");
},
onError: (error) => {
Expand All @@ -97,6 +114,22 @@ const TimeTableView: React.FC<{ date: string }> = ({ date }) => {
}
};

const handleChangeCommonSchedule = () => {
if (selectedSchedule?.scheduleNo) {
changeCommonSchedule(selectedSchedule.scheduleNo, {
onSuccess: () => {
setIsChangeCommonModalOpen(false);
closeModal();
console.log("공통일정으로 변경되었습니다.");
},
onError: (error) => {
console.log("변경 오류 : ", error);
alert("공통일정 변경 중 오류가 발생했습니다:");
},
});
}
};

const handleOutsideClick = (e: React.MouseEvent) => {
if (modalRef.current && !modalRef.current.contains(e.target as Node)) {
closeModal();
Expand Down Expand Up @@ -257,6 +290,17 @@ const TimeTableView: React.FC<{ date: string }> = ({ date }) => {
/>
)}

{/* 공통 일정 변경 모달 */}
{isChangeCommonModalOpen && (
<OneBtnModal
title="공통 일정으로 변경되었습니다."
description=""
imageSrc={coupleEmoji}
confirmText="확인"
onConfirm={handleChangeCommonSchedule}
/>
)}

{/* 일정 상세 모달 */}
{activeModal === "schedule" && selectedSchedule && (
<Overlay onClick={handleOutsideClick} onTouchEnd={handleTouchEnd}>
Expand All @@ -270,7 +314,9 @@ const TimeTableView: React.FC<{ date: string }> = ({ date }) => {
isCommonSchedule: commonScheduleList?.includes(selectedSchedule),
onDelete: () => setIsDeleteModalOpen(true),
onEdit: () => console.log("일정 수정"),
onCommon: () => console.log("공통 일정으로 변경"),
onCommon: () => {
setIsChangeCommonModalOpen(true);
},
onEmoji: () => console.log("이모지 남기기"),
onEditRequest: () => console.log("일정 수정 요청"),
})}
Expand Down
8 changes: 6 additions & 2 deletions src/pages/main/components/ScheduleList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,14 @@ const ScheduleList = () => {
navigate(`/calendar/${formattedDate}`);
};

const myName = coupleInfo ? coupleInfo.nickNameA : myInfo?.name;

const partnerName = coupleInfo
? coupleInfo.nickNameB
: "커플로 등록해주세요!";

console.log(coupleInfo);

return (
<ScheduleBox>
<DayWrapper>
Expand Down Expand Up @@ -85,7 +89,7 @@ const ScheduleList = () => {
/>
</ProfileImage>
<TextWrapper>
<NameText>{myInfo.name}의 일정</NameText>
<NameText>{myName}의 일정</NameText>
<Wrapper>
<Status color={getBusyColor(currentMySchedule.busyLevel)} />
<ScheduleTitle>
Expand Down Expand Up @@ -113,7 +117,7 @@ const ScheduleList = () => {
/>
</ProfileImage>
<TextWrapper>
<NameText>{myInfo?.name}의 일정</NameText>
<NameText>{myName}의 일정</NameText>
<NoText>현재 등록된 일정이 없습니다.</NoText>
</TextWrapper>
</ScheduleInfo>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/schedule/AddMySchedulePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const AddMySchedulePage = () => {
console.log("서버에 전송하려는 데이터 :", formData);
saveSchedule(formData, {
onSuccess: () => {
navigate(`/calendar/${date}`);
navigate(`/calendar/${date}`, { state: { refetch: true } });
},
});
};
Expand Down
2 changes: 1 addition & 1 deletion src/types/ISModalProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ export interface ISModalProps {
confirmText?: string;
cancelText?: string;
onConfirm: () => void;
onCancel: () => void;
onCancel?: () => void;
}

0 comments on commit 5a47444

Please sign in to comment.