diff --git a/src/api/activityLog.api.ts b/src/api/activityLog.api.ts new file mode 100644 index 00000000..b16adef5 --- /dev/null +++ b/src/api/activityLog.api.ts @@ -0,0 +1,24 @@ +import type { ApiMyComments, ApiMyInquiries } from './../models/activityLog'; +import { httpClient } from './http.api'; + +export const getMyComments = async () => { + try { + const response = await httpClient.get(`user/my-comments`); + + return response.data.data; + } catch (e) { + console.error('내 댓글 에러', e); + throw e; + } +}; + +export const getMyInquiries = async () => { + try { + const response = await httpClient.get(`user/my-inquiries`); + + return response.data.data; + } catch (e) { + console.error('내 문의글 에러 ', e); + throw e; + } +}; diff --git a/src/api/alarm.api.ts b/src/api/alarm.api.ts index 515f5d3c..7105301a 100644 --- a/src/api/alarm.api.ts +++ b/src/api/alarm.api.ts @@ -16,7 +16,8 @@ export const deleteAlarm = async (id: number) => { try { await httpClient.delete(`/user/alarm/${id}`); } catch (e) { - console.log('알림 삭제 에러 ', e); + console.error('알림 삭제 에러 ', e); + throw e; } }; @@ -29,6 +30,7 @@ export const patchAlarm = async (id: number) => { return response.data.data; } catch (e) { - console.log(e); + console.error(e); + throw e; } }; diff --git a/src/api/inquiry.api.ts b/src/api/inquiry.api.ts index 0c96ee99..ead40038 100644 --- a/src/api/inquiry.api.ts +++ b/src/api/inquiry.api.ts @@ -9,6 +9,7 @@ export const postInquiry = async (formData: FormData) => { }); console.log(response); } catch (e) { - console.log('문의하기 에러', e); + console.error('문의하기 에러', e); + throw e; } }; diff --git a/src/api/projectLists.api.ts b/src/api/projectLists.api.ts index 554726d2..d47bead2 100644 --- a/src/api/projectLists.api.ts +++ b/src/api/projectLists.api.ts @@ -11,10 +11,11 @@ export const getProjectLists = async (params: SearchFilters) => { params, paramsSerializer: { indexes: null }, }); - + return response.data.data; } catch (e) { - console.log('getProjectLists', e); + console.error('getProjectLists', e); + throw e; } }; @@ -26,6 +27,7 @@ export const getProjectStatistic = async () => { return response.data.data; } catch (e) { - console.log('getProjectStatistic', e); + console.error('getProjectStatistic', e); + throw e; } }; diff --git a/src/api/projectSearchFiltering.api.ts b/src/api/projectSearchFiltering.api.ts index 348b2d44..f2b0a39f 100644 --- a/src/api/projectSearchFiltering.api.ts +++ b/src/api/projectSearchFiltering.api.ts @@ -7,7 +7,8 @@ export const getSkillTag = async () => { return response.data.data; } catch (e) { - console.log('getSkillTag', e); + console.error('getSkillTag', e); + throw e; } }; @@ -16,7 +17,8 @@ export const getPositionTag = async () => { const response = await httpClient.get('/position-tag'); return response.data.data; } catch (e) { - console.log('getPositionTag', e); + console.error('getPositionTag', e); + throw e; } }; @@ -25,6 +27,7 @@ export const getMethodTag = async () => { const response = await httpClient.get('/method-type'); return response.data.data; } catch (e) { - console.log('getMethodTag', e); + console.error('getMethodTag', e); + throw e; } }; diff --git a/src/components/mypage/activityLog/commentsActivity/CommentsActivity.styled.ts b/src/components/mypage/activityLog/commentsActivity/CommentsActivity.styled.ts index c2b4df2f..a423a17f 100644 --- a/src/components/mypage/activityLog/commentsActivity/CommentsActivity.styled.ts +++ b/src/components/mypage/activityLog/commentsActivity/CommentsActivity.styled.ts @@ -1,6 +1,6 @@ import styled from 'styled-components'; -export const container = styled.div` +export const Container = styled.div` height: 100%; `; @@ -9,3 +9,16 @@ export const WrapperNoContent = styled.div` display: flex; align-items: center; `; + +export const CommentsWrapper = styled.div` + padding: 1.5rem; + display: flex; + flex-direction: column; + gap: 0.5rem; +`; + +export const CommentBorder = styled.div` + width: 100%; + height: 0.5px; + background: ${({ theme }) => theme.color.placeholder}; +`; diff --git a/src/components/mypage/activityLog/commentsActivity/CommentsActivity.tsx b/src/components/mypage/activityLog/commentsActivity/CommentsActivity.tsx index 47e7447e..3f7874bf 100644 --- a/src/components/mypage/activityLog/commentsActivity/CommentsActivity.tsx +++ b/src/components/mypage/activityLog/commentsActivity/CommentsActivity.tsx @@ -1,12 +1,37 @@ +import { Fragment } from 'react/jsx-runtime'; +import { useGetMyComments } from '../../../../hooks/useGetMyComments'; import NoContent from '../../../common/noContent/NoContent'; +import Spinner from '../../Spinner'; +import CommentActivity from './commentActivity/CommentActivity'; import * as S from './CommentsActivity.styled'; export default function CommentsActivity() { - return ( - + const { myCommentsData, isLoading } = useGetMyComments(); + + if (isLoading) { + return ; + } + + if (!myCommentsData || myCommentsData.length === 0) { + return ( - + ); + } + + return ( + + + {myCommentsData.map((list, idx: number) => ( + + + {idx !== myCommentsData.length - 1 && ( + + )} + + ))} + + ); } diff --git a/src/components/mypage/activityLog/commentsActivity/commentActivity/CommentActivity.styled.ts b/src/components/mypage/activityLog/commentsActivity/commentActivity/CommentActivity.styled.ts new file mode 100644 index 00000000..967c93f0 --- /dev/null +++ b/src/components/mypage/activityLog/commentsActivity/commentActivity/CommentActivity.styled.ts @@ -0,0 +1,12 @@ +import styled from 'styled-components'; + +export const CommentContent = styled.div``; + +export const CommentDate = styled.div` + font-size: 0.8rem; + color: ${({ theme }) => theme.color.placeholder}; +`; + +export const CommentProject = styled.div` + font-size: 0.9rem; +`; diff --git a/src/components/mypage/activityLog/commentsActivity/commentActivity/CommentActivity.tsx b/src/components/mypage/activityLog/commentsActivity/commentActivity/CommentActivity.tsx new file mode 100644 index 00000000..add3c693 --- /dev/null +++ b/src/components/mypage/activityLog/commentsActivity/commentActivity/CommentActivity.tsx @@ -0,0 +1,18 @@ +import { Link } from 'react-router-dom'; +import type { MyComments } from '../../../../../models/activityLog'; +import * as S from './CommentActivity.styled'; +import { formatDate } from '../../../../../util/formatDate'; + +interface CommentActivityProps { + list: MyComments; +} + +export default function CommentActivity({ list }: CommentActivityProps) { + return ( + + {list.content} + {formatDate(list.createdAt)} + {list.projectTitle} + + ); +} diff --git a/src/components/mypage/activityLog/inquiries/Inquiries.styled.ts b/src/components/mypage/activityLog/inquiries/Inquiries.styled.ts index 9445124e..c1a3d2c5 100644 --- a/src/components/mypage/activityLog/inquiries/Inquiries.styled.ts +++ b/src/components/mypage/activityLog/inquiries/Inquiries.styled.ts @@ -4,19 +4,41 @@ export const container = styled.div` height: 100%; `; -export const WrapperButton = styled.div` - height: 5%; - display: flex; - justify-content: end; - gap: 1rem; +export const InquiriesContainer = styled.div` + padding: 1rem; + width: 100%; +`; + +export const InquiriesTableHeadWrapper = styled.div` + width: 100%; + display: grid; + grid-template-columns: 8% 18% 62% 12%; + font-size: 1.3rem; + font-weight: 600; + margin-bottom: 1rem; +`; + +export const InquiriesTableHeaderNo = styled.div` + text-align: center; +`; + +export const InquiriesTableHeaderCategory = styled.div` + padding-left: 0.5rem; +`; + +export const InquiriesTableHeaderTitle = styled.div` + text-align: start; + padding-left: 3rem; `; -export const Button = styled.button` - font-size: 1rem; - width: 5rem; - background: ${({ theme }) => theme.color.navy}; - border-radius: ${({ theme }) => theme.borderRadius.primary}; - color: ${({ theme }) => theme.color.white}; +export const InquiriesTableHeaderState = styled.div` + text-align: center; +`; + +export const InquiriesWrapper = styled.div` + display: flex; + flex-direction: column; + gap: 1.5rem; `; export const WrapperNoContent = styled.div` diff --git a/src/components/mypage/activityLog/inquiries/Inquiries.tsx b/src/components/mypage/activityLog/inquiries/Inquiries.tsx index ff07e2d4..d9654ec3 100644 --- a/src/components/mypage/activityLog/inquiries/Inquiries.tsx +++ b/src/components/mypage/activityLog/inquiries/Inquiries.tsx @@ -1,12 +1,42 @@ +import { useGetMyInquiries } from '../../../../hooks/useGetMyInquiries'; import NoContent from '../../../common/noContent/NoContent'; +import Spinner from '../../Spinner'; import * as S from './Inquiries.styled'; +import Inquiry from './inquiry/Inquiry'; export default function Inquiries() { - return ( - + const { myInquiriesData, isLoading } = useGetMyInquiries(); + + if (isLoading) { + return ; + } + + if (!myInquiriesData || myInquiriesData?.length === 0) + return ( + ); + + return ( + + + + No + 구별 + 제목 + 상태 + + + {myInquiriesData.map((list, index) => ( + + ))} + + ); } diff --git a/src/components/mypage/activityLog/inquiries/inquiry/Inquiry.styled.ts b/src/components/mypage/activityLog/inquiries/inquiry/Inquiry.styled.ts new file mode 100644 index 00000000..44647b52 --- /dev/null +++ b/src/components/mypage/activityLog/inquiries/inquiry/Inquiry.styled.ts @@ -0,0 +1,82 @@ +import styled from 'styled-components'; + +export const Container = styled.div` + width: 100%; + font-size: 1.1rem; +`; + +export const InquiryTitleWrapper = styled.div` + display: grid; + grid-template-columns: 8% 18% 62% 12%; + cursor: pointer; +`; + +export const InquiryNumber = styled.div` + text-align: center; +`; + +export const InquiryCategory = styled.div``; + +export const InquiryTitle = styled.div``; + +export const InquiryState = styled.div` + text-align: center; +`; + +export const InquiryContentWrapper = styled.div` + margin: 0.5rem 0; + background: ${({ theme }) => theme.color.white}; + padding: 1rem; +`; + +export const InquiryContent = styled.div``; + +export const InquiryImgWrapper = styled.div` + margin-top: 1rem; + cursor: pointer; +`; + +export const InquiryModalImgWrapper = styled.div` + display: flex; +`; + +export const InquiryImg = styled.img` + width: 5rem; +`; + +export const ModalImgContainer = styled.div` + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: 100vw; + height: 100vh; + z-index: 10; + display: flex; + justify-content: center; + align-items: center; + background: rgba(0, 0, 0, 0.7); +`; + +export const ModalImgWrapper = styled.div` + margin-top: 1rem; + cursor: pointer; + background: ${({ theme }) => theme.color.white}; + border: 1px solid ${({ theme }) => theme.color.navy}; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: fit-content; +`; + +export const ModalImgButtonWrapper = styled.div` + width: 100%; + color: ${({ theme }) => theme.color.white}; + font-size: 0.8rem; + background: ${({ theme }) => theme.color.navy}; + padding: 0.2rem; +`; + +export const ModalImg = styled.img``; diff --git a/src/components/mypage/activityLog/inquiries/inquiry/Inquiry.tsx b/src/components/mypage/activityLog/inquiries/inquiry/Inquiry.tsx new file mode 100644 index 00000000..d150ebf0 --- /dev/null +++ b/src/components/mypage/activityLog/inquiries/inquiry/Inquiry.tsx @@ -0,0 +1,72 @@ +import { useState } from 'react'; +import type { MyInquiries } from '../../../../../models/activityLog'; +import * as S from './Inquiry.styled'; +import { INQUIRY_MESSAGE } from '../../../../../constants/customerService'; + +interface InquiryProps { + list: MyInquiries; + no: number; +} + +interface IsImageOpen { + isImageOpen: boolean; + url: string; +} + +export default function Inquiry({ list, no }: InquiryProps) { + const [isOpen, setIsOpen] = useState(false); + const [isImageOpen, setIsImageOpen] = useState({ + isImageOpen: false, + url: '', + }); + + return ( + + setIsOpen((prev) => !prev)}> + {no} + {`[${list.category}]`} + {list.title} + {list.state ? '답변완료' : '확인중'} + + {isOpen && ( + + {list.content} + {list.imageUrls.length !== 0 && ( + + {list.imageUrls.map((url) => ( + + setIsImageOpen({ + isImageOpen: true, + url, + }) + } + > + + + ))} + + )} + {isImageOpen.isImageOpen && ( + + + setIsImageOpen({ + isImageOpen: false, + url: '', + }) + } + > + + {INQUIRY_MESSAGE.isImageOpenMessage} + + + + + )} + + )} + + ); +} diff --git a/src/components/mypage/notifications/all/All.tsx b/src/components/mypage/notifications/all/All.tsx index 1feea0df..39434831 100644 --- a/src/components/mypage/notifications/all/All.tsx +++ b/src/components/mypage/notifications/all/All.tsx @@ -5,9 +5,10 @@ import * as S from './All.styled'; import { XMarkIcon } from '@heroicons/react/24/outline'; import { useAlarmDelete } from '../../../../hooks/useAlarmDelete'; import { useAlarmPatch } from '../../../../hooks/useAlarmPatch'; +import Spinner from '../../Spinner'; export default function All() { - const { alarmListData } = useAlarmList(); + const { alarmListData, isLoading } = useAlarmList(); const { filterId }: { filterId: number } = useOutletContext(); const { mutate: deleteAlarm } = useAlarmDelete(); const { mutate: patchAlarm } = useAlarmPatch(); @@ -24,7 +25,11 @@ export default function All() { } }; - if (!alarmListData || (alarmListData && alarmListData?.length === 0)) { + if (isLoading) { + return ; + } + + if (!alarmListData || alarmListData.length === 0) { return ( @@ -36,7 +41,7 @@ export default function All() { {alarmListData - ?.filter((list) => { + .filter((list) => { if (filterId === 0) { return true; } else if (list.alarmFilterId === filterId) { diff --git a/src/components/mypage/notifications/appliedProjects/AppliedProjects.tsx b/src/components/mypage/notifications/appliedProjects/AppliedProjects.tsx index 5ed1d63e..67ae7303 100644 --- a/src/components/mypage/notifications/appliedProjects/AppliedProjects.tsx +++ b/src/components/mypage/notifications/appliedProjects/AppliedProjects.tsx @@ -12,19 +12,20 @@ export default function AppliedProjects() { if (isLoading) { return ; } + + if (!myAppliedStatusListData || myAppliedStatusListData.length === 0) { + return ; + } + return ( - {myAppliedStatusListData && myAppliedStatusListData?.length > 0 ? ( - - {myAppliedStatusListData?.map((data) => ( - - - - ))} - - ) : ( - - )} + + {myAppliedStatusListData.map((data) => ( + + + + ))} + ); } diff --git a/src/constants/customerService.ts b/src/constants/customerService.ts index 295003d1..56469f05 100644 --- a/src/constants/customerService.ts +++ b/src/constants/customerService.ts @@ -11,4 +11,5 @@ export const EMPTY_IMAGE = export const INQUIRY_MESSAGE = { categoryDefault: '카테고리', fileDefault: '선택된 파일이 없습니다.', + isImageOpenMessage: '이미지를 클릭하면 사라집니다.', }; diff --git a/src/hooks/queries/keys.ts b/src/hooks/queries/keys.ts index 04e47dfe..d538e460 100644 --- a/src/hooks/queries/keys.ts +++ b/src/hooks/queries/keys.ts @@ -38,3 +38,8 @@ export const ProjectReplyList = { export const ChartDataList = { chartData: ['ChartDataList'], }; + +export const ActivityLog = { + myComments: ['MyComments'], + myInquiries: ['MyInquiries'], +}; diff --git a/src/hooks/useGetMyComments.ts b/src/hooks/useGetMyComments.ts new file mode 100644 index 00000000..4b10c9ee --- /dev/null +++ b/src/hooks/useGetMyComments.ts @@ -0,0 +1,16 @@ +import { useQuery } from '@tanstack/react-query'; +import { getMyComments } from '../api/activityLog.api'; +import useAuthStore from '../store/authStore'; +import { ActivityLog } from './queries/keys'; + +export const useGetMyComments = () => { + const userId = useAuthStore((state) => state.userData?.id); + + const { data: myCommentsData, isLoading } = useQuery({ + queryKey: [ActivityLog.myComments, userId], + queryFn: () => getMyComments(), + enabled: !!userId, + }); + + return { myCommentsData, isLoading }; +}; diff --git a/src/hooks/useGetMyInquiries.ts b/src/hooks/useGetMyInquiries.ts new file mode 100644 index 00000000..d81f01d9 --- /dev/null +++ b/src/hooks/useGetMyInquiries.ts @@ -0,0 +1,15 @@ +import { useQuery } from '@tanstack/react-query'; +import { getMyInquiries } from '../api/activityLog.api'; +import useAuthStore from '../store/authStore'; +import { ActivityLog } from './queries/keys'; + +export const useGetMyInquiries = () => { + const userId = useAuthStore((state) => state.userData?.id); + + const { data: myInquiriesData, isLoading } = useQuery({ + queryKey: [ActivityLog.myInquiries, userId], + queryFn: () => getMyInquiries(), + }); + + return { myInquiriesData, isLoading }; +}; diff --git a/src/models/activityLog.ts b/src/models/activityLog.ts new file mode 100644 index 00000000..1dd69529 --- /dev/null +++ b/src/models/activityLog.ts @@ -0,0 +1,25 @@ +import type { ApiCommonType } from './apiCommon'; + +export interface MyInquiries { + title: string; + content: string; + category: string; + state: boolean; + imageUrls: string[]; +} + +export interface ApiMyInquiries extends ApiCommonType { + data: MyInquiries[]; +} + +export interface MyComments { + id: number; + content: string; + createdAt: string; + projectId: number; + projectTitle: string; +} + +export interface ApiMyComments extends ApiCommonType { + data: MyComments[]; +} diff --git a/src/models/alarm.ts b/src/models/alarm.ts index a44229a5..5f031414 100644 --- a/src/models/alarm.ts +++ b/src/models/alarm.ts @@ -18,7 +18,7 @@ export interface Alarm { id: number; routingId: number; content: string; - AlarmFilterId: number; + alarmFilterId: number; createdAt: string; enabled: boolean; }