Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion src/components/calendar/Calendar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export default function Calendar({
{!isCourseCalendarLoadingArr?.includes(true) &&
sideViewEvents &&
((sideViewEvents as FullCalendarEvent[]).length !== 0 ? (
<ul className="flex w-full flex-col justify-center gap-4 px-2 pt-2">
<ul className="flex w-full flex-col justify-center gap-2 px-2 pt-2">
{(sideViewEvents as FullCalendarEvent[]).map(
({ id, start, end, title }) => (
<SmallCalendarBottomEvent
Expand Down
2 changes: 1 addition & 1 deletion src/components/calendar/SmallCalendarBottomEvent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default function SmallCalendarBottomEvent({
time,
}: SmallCalendarBottomEventProps) {
return (
<li className="line-clamp-1 flex w-full items-center">
<li className="line-clamp-1 flex w-full items-center py-1">
<div className="min-w-[154px]">
<span className="inline-block w-[50px] text-justify text-mainGray-active">
{date}
Expand Down
4 changes: 2 additions & 2 deletions src/components/common/input/SearchInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>(
className={`flex h-12 w-[422px] items-center justify-between bg-white hover:text-black hover:outline hover:outline-1 hover:outline-gray-300 ${inputStyle === 'rounded' ? 'rounded-full' : 'rounded-xl'} px-4 ${!isFocus && 'text-gray-400'} ${className}`}
htmlFor={name}
>
{!isFocus && <FaMagnifyingGlass />}
{!isFocus && <FaMagnifyingGlass className="mr-2" />}
<TextInput
ref={ref}
name={name}
Expand All @@ -59,7 +59,7 @@ const SearchInput = forwardRef<HTMLInputElement, SearchInputProps>(
onChange={onChange}
toggleFocus={onToggleFocus}
onEnter={handlePressEnter}
className="ml-2 border-none px-0"
className="border-none px-0"
/>
{value && value !== '' && (
<button type="button" onClick={resetChange}>
Expand Down
37 changes: 27 additions & 10 deletions src/components/common/table/TableBody.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,49 @@
import { ReactNode } from 'react';
import { Fragment } from 'react/jsx-runtime';

import { UserComment, UserPost } from '@/types';

import LoopLoading from '@/components/common/LoopLoading';

interface TableBodyProps<T> {
paginationList: T[];
children: (item: T) => ReactNode;
colLength: number;
isLoading: boolean;
}

export default function TableBody<T extends { createdAt: string }>({
export default function TableBody<T extends UserPost | UserComment>({
paginationList,
children,
colLength,
isLoading,
}: TableBodyProps<T>) {
return (
<tbody>
{paginationList.length !== 0 ? (
paginationList.map(pageItem => (
<Fragment key={pageItem.createdAt}>{children(pageItem)}</Fragment>
))
) : (
{isLoading && (
<tr>
<td colSpan={colLength}>
<span className="flex justify-center py-14 text-mainGray">
아직 정보가 없어요
</span>
<td colSpan={5} className="mx-auto">
<div className="flex justify-center py-3">
<LoopLoading size={115} />
</div>
</td>
</tr>
)}

{!isLoading &&
(paginationList.length !== 0 ? (
paginationList.map(pageItem => (
<Fragment key={pageItem.createdAt}>{children(pageItem)}</Fragment>
))
) : (
<tr>
<td colSpan={colLength}>
<span className="flex justify-center py-14 text-mainGray">
아직 정보가 없어요
</span>
</td>
</tr>
))}
</tbody>
);
}
6 changes: 4 additions & 2 deletions src/components/lounge/form/LoungeForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,10 @@ export default function LoungeForm() {
const { data: projectsDetail } = useGetPostDetail<LoungeDto.GetProjectDetail>(
Number(modifyProjectId || 0),
);
const { mutateAsync: postProject } =
const { mutateAsync: postProject, isPending: isPostProjectPending } =
usePostMyPost<LoungeDto.PostProjectParams>();

const { mutateAsync: putProject } =
const { mutateAsync: putProject, isPending: isEditProjectPending } =
usePutMyPost<LoungeDto.PostProjectParams>();

const { techStackList } = useTechStackList();
Expand Down Expand Up @@ -114,6 +114,8 @@ export default function LoungeForm() {
const { handleImagesInHtmlContent } = useHandleImage();

const onSubmit: SubmitHandler<FormValues> = async data => {
if (isPostProjectPending || isEditProjectPending) return;

const descriptionWithHandledImage = await handleImagesInHtmlContent(
data.projectDescription,
modifyProjectId ? projectsDetail?.description : undefined,
Expand Down
109 changes: 54 additions & 55 deletions src/components/mypage/MyCollection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default function MyCollection() {
const initialFilter: MyPostDto.GetPostListParams = {
page: 1,
size: 3,
// order: 'latest',
// order: 'latest', NOTE: 최신순 정렬 적용 필요
};

const {
Expand Down Expand Up @@ -72,10 +72,10 @@ export default function MyCollection() {
currPostList,
page: { totalPage },
postCheckbox: {
checkedPostIdList,
currCheckedIdList,
isCheckBoxChecked,
onCheckBoxClick,
onPostCheckboxChange,
onHeaderCheckBoxClick,
onTableItemCheckboxChange,
initializePostCheckedBoxList,
},
deletePost: {
Expand Down Expand Up @@ -133,60 +133,61 @@ export default function MyCollection() {
currCollection={currCollection}
onTabClick={(collection: Collection) => {
initializePostCheckedBoxList();
handleChangeFilter({ postTypes: [] });
handleChangeFilter({ postTypes: [], page: 1 });
setCurrCollection(collection);
}}
/>

{currCollection !== '내가 찜한 글' && (
<>
<div className="mb-8 flex min-h-[230px] flex-col rounded-[20px] bg-white p-6">
{!isMyPostListLoading && !isMyCommentListLoading && (
<TableContainer colWidthList={[3, 10, 12, 64, 6]}>
<TableHeader
headerCellList={headerCellList}
currCollection={currCollection}
isCheckBoxChecked={isCheckBoxChecked}
disabledCheckBox={false}
onCheckboxClick={onCheckBoxClick}
onChangeOrder={onChangeOrder}
categoryOptionList={contentList.categoryOptionList}
checkedCategoryOptionList={checkedCategoryOptionList}
onChangeCategory={onChangeCategory}
disabledDelete={disabledDelete}
onDeleteConfirmClick={() =>
onDeleteConfirmClick(currCollection, checkedPostIdList)
}
/>
<TableBody<UserPost | UserComment>
paginationList={currPostList?.content || []}
colLength={5}
>
{post => (
<PostTableRow
headerCellList={headerCellList}
post={post}
handleShowDialog={handleShowDialog}
checkedPostIdList={checkedPostIdList}
onPostCheckboxChange={onPostCheckboxChange}
onDeleteConfirmClick={(postId: number) =>
onDeleteConfirmClick(currCollection, [postId])
}
/>
)}
</TableBody>
</TableContainer>
)}
<div className="mb-8 flex min-h-[220px] flex-col rounded-[20px] bg-white px-6 pb-4 pt-6">
<TableContainer colWidthList={[3, 10, 12, 64, 6]}>
<TableHeader
headerCellList={headerCellList}
currCollection={currCollection}
isCheckBoxChecked={isCheckBoxChecked}
disabledCheckBox={false}
onCheckboxClick={onHeaderCheckBoxClick}
onChangeOrder={onChangeOrder}
categoryOptionList={contentList.categoryOptionList}
checkedCategoryOptionList={checkedCategoryOptionList}
onChangeCategory={onChangeCategory}
disabledDelete={disabledDelete}
onDeleteConfirmClick={() =>
onDeleteConfirmClick(currCollection, currCheckedIdList)
}
/>
<TableBody<UserPost | UserComment>
paginationList={currPostList?.content || []}
colLength={5}
isLoading={isMyCommentListLoading || isMyPostListLoading}
>
{post => (
<PostTableRow
headerCellList={headerCellList}
post={post}
handleShowDialog={handleShowDialog}
checkedIdList={currCheckedIdList}
onCheckboxChange={onTableItemCheckboxChange}
onDeleteConfirmClick={(postId: number) =>
onDeleteConfirmClick(currCollection, [postId])
}
/>
)}
</TableBody>
</TableContainer>
</div>

<Pagination
totalPages={totalPage || 1}
currentPage={tableFilter.page}
onPageChange={(page: number) => {
handleChangeFilter({ page, size: 3 });
initializePostCheckedBoxList();
}}
/>
{totalPage && (
<Pagination
totalPages={totalPage}
currentPage={tableFilter.page}
onPageChange={(page: number) => {
handleChangeFilter({ page, size: 3 });
initializePostCheckedBoxList();
}}
/>
)}
</>
)}

Expand All @@ -195,11 +196,9 @@ export default function MyCollection() {
{!isScrapedPostListLoading &&
(scrapedPostList?.content.length !== 0 ? (
<ul className="grid min-h-[230px] grid-cols-3 gap-5">
{scrapedPostList?.content
?.slice(0, 3)
?.map(card => (
<ScrapedPostCard key={card.postId} card={card} />
))}
{scrapedPostList?.content?.map(card => (
<ScrapedPostCard key={card.postId} card={card} />
))}
</ul>
) : (
<div className="flex h-[230px] items-center justify-center rounded-[20px] border bg-white p-3">
Expand Down
17 changes: 11 additions & 6 deletions src/components/notice/NoticePostCard.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback } from 'react';

import { Link } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';

import { useNoticeIncrementViewCount } from '@/services/post/noticeMutations';

Expand Down Expand Up @@ -33,15 +33,20 @@ export default function NoticePostCard({ notice }: NoticePostCardProps) {

const { mutateAsync: postViewCount } = useNoticeIncrementViewCount();

const navigate = useNavigate();

const onViewCount = useCallback(async () => {
await postViewCount({ noticeId: notice.noticeId });
}, [notice.noticeId, postViewCount]);
navigate(`/notice/post/${notice.postId}`);
}, [navigate, notice.noticeId, notice.postId, postViewCount]);

return (
<Link
to={`/notice/post/${notice.postId}`}
className="flex w-full flex-col rounded-2xl bg-white p-4 px-6 py-4"
<div
role="button"
tabIndex={0}
className="flex w-full cursor-pointer flex-col rounded-2xl bg-white p-4 px-6 py-4"
onClick={onViewCount}
onKeyDown={e => e.key === 'Enter' && onViewCount()}
>
<div className="flex w-full items-center justify-between">
<Tag
Expand Down Expand Up @@ -85,6 +90,6 @@ export default function NoticePostCard({ notice }: NoticePostCardProps) {
{formatDate(notice.createdDateTime)}
</div>
</div>
</Link>
</div>
);
}
26 changes: 7 additions & 19 deletions src/components/notice/layout/NoticeDisplayList.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import {
useGetCloseSoonNoticeList,
useGetInfiniteNoticeList,
useGetThisWeekNoticeList,
} from '@/services/post/noticeQueries';

import { HasAdminRole, NoticeDisplay } from '@/types';

import TitleLinkWithRoleTag from '@/components/common/TitleLinkWithRoleTag';

type NoticeTitle = '공지사항' | 'NEW' | '마감임박';
type NoticeTitle = 'NEW' | '마감임박';

interface NoticeInfoListProps {
title: NoticeTitle;
Expand All @@ -19,40 +18,29 @@ export default function NoticeDisplayList({
title,
className = '',
}: NoticeInfoListProps) {
const {
data: thisWeekNoticeList = [],
isLoading: isInfiniteNoticListLoading,
} = useGetThisWeekNoticeList();

const {
data = {
pages: [{ notices: [] }],
},
isLoading: isInfiniteNoticeListLoading,
} = useGetInfiniteNoticeList({ page: 1, size: 4 });

const {
data: closeSoonNoticeList = [],
isLoading: isCloseSoonNoticeList, //
} = useGetCloseSoonNoticeList({ size: 4, days: 7 });

const isLoading =
isCloseSoonNoticeList ||
isInfiniteNoticeListLoading ||
isInfiniteNoticListLoading;
const {
data: thisWeekNoticeList = [],
isLoading: isInfiniteNoticListLoading,
} = useGetThisWeekNoticeList();

const noticeObj: {
[key in NoticeTitle]: (NoticeDisplay & {
manager?: { role: keyof HasAdminRole };
})[];
} = {
공지사항: data.pages[0].notices,
마감임박: closeSoonNoticeList,
NEW: thisWeekNoticeList,
};

const noticeDisplayList = noticeObj[title];

const isLoading = isCloseSoonNoticeList || isInfiniteNoticListLoading;

return (
!isLoading &&
(noticeDisplayList?.length !== 0 ? (
Expand Down
Loading
Loading