Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
2907ba3
πŸ›  fix(#82): ν›… μ΅œμƒμœ„μ—μ„œλ§Œ 쓰도둝 λ³€κ²½
un0211 Jul 5, 2024
3f5ee1d
πŸ›  fix(#168): κ³΅μœ κ³„μ •μœΌλ‘œ ν•˜λŠ” μš”μ²­ μ œν•œ
un0211 Jul 5, 2024
7625cb2
πŸ›  fix(#168): μƒμ„±μžκ°€ μ•„λ‹Œ 경우 λŒ€μ‹œλ³΄λ“œ 관리 νŽ˜μ΄μ§€ μ ‘κ·Όμ‹œ λ¦¬λ‹€μ΄λ ‰νŠΈ
un0211 Jul 5, 2024
b427566
🎨 design(#168): λŒ€μ‹œλ³΄λ“œ κ΄€λ¦¬νŽ˜μ΄μ§€ μ—λŸ¬λ¬Έκ΅¬ κ°œμ„ 
un0211 Jul 5, 2024
c82b2a6
πŸ›  fix(#168): λŒ€μ‹œλ³΄λ“œ κ΄€λ¦¬νŽ˜μ΄μ§€ μ ‘κ·Ό μ™„μ „ μ œμ–΄, λ¦¬λ‹€μ΄λ ‰νŠΈ ν›… ν˜•μ‹ λ³€κ²½
un0211 Jul 5, 2024
4f1ac10
πŸ›  fix(#168): λŒ€μ‹œλ³΄λ“œ μ ‘κ·Ό μ œμ–΄
un0211 Jul 5, 2024
a8ed44a
🎨 design(#168, #41): 곡유 λŒ€μ‹œλ³΄λ“œ λΉ„λ‘œκ·ΈμΈ μƒνƒœμΌλ•Œ λ ˆμ΄μ•„μ›ƒ 꽉 차게
un0211 Jul 5, 2024
4e3d79b
πŸ›  fix(#168): κ³΅μœ κ³„μ •μ—μ„œ λͺ¨λ“  μˆ˜μ • κΈ°λŠ₯ λΉ„ν™œμ„±ν™”
un0211 Jul 5, 2024
4f0fe33
πŸ›  fix(#4, #21): 변경사항 없을 μ‹œ λ²„νŠΌ λΉ„ν™œμ„±ν™” (λŒ“κΈ€μˆ˜μ •, 컬럼 μˆ˜μ •
un0211 Jul 5, 2024
37fc272
πŸ›  fix(#168): λ¦¬λ‹€μ΄λ ‰νŠΈ μˆ˜μ • (λžœλ”©, 404)
un0211 Jul 5, 2024
d6f2901
Merge branch 'develop' into feature/fix-redirect
un0211 Jul 6, 2024
3f6b993
πŸ›  fix(#168): 멀버가 μ•„λ‹Œ 둜그인 ν•œ μ‚¬λžŒλ„ μˆ˜μ • λ²„νŠΌ λΉ„ν™œμ„±ν™”
un0211 Jul 7, 2024
f2896fa
Merge branch 'develop' into feature/fix-redirect
un0211 Jul 7, 2024
b179824
Merge branch 'develop' into feature/fix-redirect
un0211 Jul 7, 2024
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
6 changes: 5 additions & 1 deletion src/components/Modal/ModifyColumnModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,11 @@ export default function ModifyColumnModal({ columnId, columnTitle = '', columns
<ModalCancelButton type='button' onClick={closeModal}>
μ·¨μ†Œ
</ModalCancelButton>
<ModalActionButton type='button' onClick={handleModifyClick} disabled={!!errorMessage}>
<ModalActionButton
type='button'
onClick={handleModifyClick}
disabled={!!errorMessage || columnTitle === title}
>
λ³€κ²½
</ModalActionButton>
</div>
Expand Down
3 changes: 2 additions & 1 deletion src/components/Modal/TodoCardModal/Comment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ export default function Comment({ comment }: CommentProps) {
μ·¨μ†Œ
</button>
<button
className='text-black-33 transition-all duration-100 hover:text-violet hover:underline dark:text-dark-10 dark:hover:text-violet-light-hover'
className='text-black-33 transition-all duration-100 hover:text-violet hover:underline disabled:text-gray-9f dark:text-dark-10 dark:hover:text-violet-light-hover dark:disabled:text-gray-9f'
disabled={editedComment === comment.content}
onClick={handleSaveEdit}
>
μ €μž₯
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { TodoCardModalProps } from '@/types/Modal.interface';
import { CommentsResponse, CommentForm } from '@/types/post/CommentForm.interface';
import formatDate from '@/utils/formatDate';

export default function TodoCardModal({ card, column, onClick }: TodoCardModalProps) {
export default function TodoCardModal({ card, column, isMember, onClick }: TodoCardModalProps) {
const { data, refetch } = useFetchData<CommentsResponse>(['comments', card.id], () => getComments(card.id));
const [newComment, setNewComment] = useState('');
const [isCommentEmpty, setIsCommentEmpty] = useState(true);
Expand Down Expand Up @@ -68,9 +68,11 @@ export default function TodoCardModal({ card, column, onClick }: TodoCardModalPr
{card.title}
</div>
<div className='flex'>
<div className='relative'>
<EditDropdown card={card} column={column} />
</div>
{isMember && (
<div className='relative'>
<EditDropdown card={card} column={column} />
</div>
)}
<button onClick={handleModalClose} className='transition-all duration-200 hover:opacity-50'>
<Image src='/icons/x.svg' alt='X μ•„μ΄μ½˜' width={32} height={32} className='dark:hidden' />
<Image src='/icons/x-white.svg' alt='X μ•„μ΄μ½˜' width={32} height={32} className='hidden dark:block' />
Expand Down Expand Up @@ -112,12 +114,13 @@ export default function TodoCardModal({ card, column, onClick }: TodoCardModalPr
value={newComment}
onChange={(e) => setNewComment(e.target.value)}
placeholder='λŒ“κΈ€μ„ μž…λ ₯ν•˜μ„Έμš”.'
disabled={!isMember}
/>

<button
className='btn-violet-light dark:btn-white absolute right-1 h-[28px] w-[60px] rounded-[4px] text-[12px] text-violet md:h-[32px] md:w-[78px] lg:w-[84px] dark:rounded-[4px]'
type='submit'
disabled={isCommentEmpty}
disabled={isCommentEmpty || !isMember}
>
μž…λ ₯
</button>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import ModifyColumnModal from './ModifyColumnModal';
import NewColumnModal from './NewColumnModal';
import NewDashboardModal from './NewDashboardModal';
import NotificationModal from './NotificationModal';
import TodoCardModal from './TodoCardModal/TodoCardModal';
import TodoCardModal from './TodoCardModal';

import useModal from '@/hooks/useModal';
import { modalSelector } from '@/store/reducers/modalSlice';
Expand Down
29 changes: 23 additions & 6 deletions src/components/Redirect/index.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,40 @@
import { useRouter } from 'next/router';
import { useSelector } from 'react-redux';

import useRedirectIfAuthenticated from '@/hooks/useRedirectIfAuthenticated';
import useRedirectIfAuth from '@/hooks/useRedirectIfAuth';
import useRedirectIfNotAuth from '@/hooks/useRedirectIfNotAuth';
import { RootState } from '@/store/store';

export default function Redirect({ children }: { children: React.ReactNode }) {
const router = useRouter();
const currentPath = router.asPath;
const { user } = useSelector((state: RootState) => state.user);
const currentPath = router.pathname;

if (['/', '/signup', '/signin'].includes(currentPath)) {
const isRedirecting = useRedirectIfAuthenticated();
const redirectIfAuth = useRedirectIfAuth();
const redirectIfNotAuth = useRedirectIfNotAuth();

if (currentPath === '/' && user) {
router.replace('/mydashboard');
}

if (currentPath === '/404') {
const nextPath = user ? '/mydashboard' : '/';
setTimeout(() => router.push(nextPath), 3000);
}

if (['/signup', '/signin'].includes(currentPath)) {
const isRedirecting = redirectIfAuth();
if (isRedirecting) {
return <></>;
}
}
if (['/mypage', '/mydashboard'].includes(currentPath) || currentPath.startsWith('/dashboard')) {
const isRedirecting = useRedirectIfNotAuth();

if (['/mypage', '/mydashboard'].includes(currentPath)) {
const isRedirecting = redirectIfNotAuth();
if (isRedirecting) {
return <></>;
}
}

return children;
}
23 changes: 13 additions & 10 deletions src/containers/dashboard/Column.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ interface ColumnProps {
column: ColumnType;
columns: ColumnType[];
index: number;
isMember: boolean;
}

function Column({ column, index, columns }: ColumnProps) {
function Column({ column, columns, isMember }: ColumnProps) {
const { openModifyColumnModal, openEditCardModal, openTodoCardModal } = useModal();
const { data: cardsData, isLoading } = useFetchData<{ cards: CardType[] }>(['cards', column.id], () =>
getCardsList(column.id),
Expand All @@ -41,7 +42,8 @@ function Column({ column, index, columns }: ColumnProps) {

{/* Column Edit Button */}
<button
className='transition duration-300 ease-in-out hover:rotate-90'
className='transition duration-300 ease-in-out hover:rotate-90 disabled:rotate-0'
disabled={!isMember}
onClick={() => {
openModifyColumnModal({ columns, columnId: column.id, columnTitle: column.title });
}}
Expand All @@ -53,6 +55,7 @@ function Column({ column, index, columns }: ColumnProps) {
{/* Add Card Button */}
<button
className='btn-violet-light dark:btn-violet-dark mb-[16px] h-[40px] rounded-[6px] border'
disabled={!isMember}
onClick={() => {
openEditCardModal({ column: column, isEdit: false });
}}
Expand All @@ -63,26 +66,26 @@ function Column({ column, index, columns }: ColumnProps) {

{/* Card List Section */}
<div className='scrollbar-hide lg:h-[700px] lg:overflow-y-auto'>
<Droppable droppableId={`column-${column.id}`} key={`column-${column.id}`}>
<Droppable droppableId={`column-${column.id}`} key={`column-${column.id}`} isDropDisabled={!isMember}>
{(provided) => (
<div
ref={provided.innerRef}
{...provided.droppableProps}
style={{ minHeight: '100px' }} // μ΅œμ†Œ 높이
>
{cards.map((card, index) => (
<Draggable key={`card-${card.id}`} draggableId={`card-${card.id}`} index={index}>
<Draggable
key={`card-${card.id}`}
draggableId={`card-${card.id}`}
index={index}
isDragDisabled={!isMember}
>
{(provided) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
onClick={() => {
openTodoCardModal({
card,
column,
});
}}
onClick={() => openTodoCardModal({ card, column, isMember })}
>
<Card key={`card-${card.id}`} card={card} />
</div>
Expand Down
57 changes: 53 additions & 4 deletions src/containers/dashboard/ColumnsSection.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import { useQueryClient } from '@tanstack/react-query';
import Image from 'next/image';
import { useState, useEffect } from 'react';
import { DragDropContext, Droppable, DropResult } from 'react-beautiful-dnd';
import { useSelector } from 'react-redux';

import Column from './Column';
import ColumnSkeleton from './ColumnSkeleton';

import useFetchData from '@/hooks/useFetchData';
import useModal from '@/hooks/useModal';
import { getColumnsList } from '@/services/getService';
import useRedirectIfNotMember from '@/hooks/useRedirectIfNotMember';
import instance from '@/services/axios';
import { getColumnsList, getDashboard } from '@/services/getService';
import { moveToOtherColumn } from '@/services/putService';
import { RootState } from '@/store/store';
import { ColumnsResponse } from '@/types/Column.interface';
import { checkPublic } from '@/utils/shareAccount';

interface ColumnsSectionProps {
dashboardId: string;
Expand All @@ -18,6 +24,11 @@ interface ColumnsSectionProps {
export default function ColumnsSection({ dashboardId }: ColumnsSectionProps) {
const queryClient = useQueryClient();
const { openNewColumnModal, openNotificationModal } = useModal();
const redirectIfNotMember = useRedirectIfNotMember();
const { user } = useSelector((state: RootState) => state.user);
const [isMember, setIsMember] = useState(true);
const [isPublic, setIsPublic] = useState(false);

const {
data: columns,
isLoading,
Expand All @@ -26,6 +37,35 @@ export default function ColumnsSection({ dashboardId }: ColumnsSectionProps) {

const columnList = columns?.data || [];

useEffect(() => {
const handleRedirect = async () => {
try {
const newIsPublic = await checkPublic(Number(dashboardId));
setIsPublic(newIsPublic);
if (!newIsPublic && dashboardId) {
await getDashboard(String(dashboardId));
}
} catch {
redirectIfNotMember();
}
};

const handleCheckMember = async () => {
if (dashboardId) {
try {
await instance.get(`/dashboards/${dashboardId}`, {
headers: { memberTest: true },
});
} catch {
setIsMember(false);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

멀버인지 일일이 ν™•μΈν•˜κΈ° 번거둜울 것 κ°™μ•„, λ©€λ²„λ§Œ ν•  수 μžˆλŠ” 일을 ν•΄μ„œ μ—λŸ¬κ°€ λ‚˜λ©΄ 멀버가 μ•„λ‹Œ κ²ƒμœΌλ‘œ νŒλ‹¨ν–ˆμŠ΅λ‹ˆλ‹€

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

λ„΅ 멀버가 μ•„λ‹ˆλ©΄ λ°”λ‘œ 잘 λ¦¬λ‹€μ΄λ ‰νŠΈ λ˜λ„€μš”!! ν™•μΈν–ˆμŠ΅λ‹ˆλ‹€! πŸ‘

2024-07-07.5.06.53.mov

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

μš”κ±°λŠ” λ¦¬λ‹€μ΄λ ‰νŠΈ μ•„λ‹ˆλΌ 곡유 λŒ€μ‹œλ³΄λ“œμ—μ„œ 멀버가 μ•„λ‹κ²½μš° λ²„νŠΌ λΉ„ν™œμ„±ν™” ν•˜λ €κ³  멀버인지 ν™•μΈν•˜λŠ” λΆ€λΆ„μ΄μ—μš”!
이거 λ°”λ‘œ μœ„μ—κ°€ λ¦¬λ‹€μ΄λ ‰νŠΈ λΆ€λΆ„μž…λ‹ˆλ‹€ (ν†΅ν•©ν•΄μ„œ μ‚¬μš©ν•  수 μžˆκ² λ„€μš”)
μ½”λ“œλŠ” μ˜μƒ λ‹€ λ§Œλ“€κ³  λ¦¬νŒ©ν† λ§ ν•΄λ³Όκ²Œμš” γ… γ…  확인 κ°μ‚¬ν•©λ‹ˆλ‹€!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

μ•— κ·Έλ ‡λ„€μš” λ²„νŠΌ λΉ„ν™œμ„±ν™”!!! 잘λͺ»λ΄€μŠ΅λ‹ˆλ‹€ γ…‹γ…‹ γ… γ… 
λ‹€μ‹œ ν™•μΈν•΄λ³΄λ‹ˆ 잘 λ©λ‹ˆλ‹€!! κ³ μƒν•˜μ…¨μ–΄μš”!

image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이것도 μ•„λ‹ˆκ³ , 곡유 λŒ€μ‹œλ³΄λ“œμ—μ„œ 멀버가 μ•„λ‹Œ 둜그인 ν•œ μ‚¬λžŒμ˜ 경우 μˆ˜μ •μ΄ λΆˆκ°€λŠ₯ν•˜κ²Œ λΉ„ν™œμ„±ν™”ν•œ μ½”λ“œμž…λ‹ˆλ‹€ γ… γ… 
λ‚˜μ€‘μ— 주석도 μΆ”κ°€ν•˜κ³  μ½”λ“œλ„ 쀑볡 μ—†κ²Œ κ°œμ„ ν• κ²Œμš”!! ν…ŒμŠ€νŠΈν•˜κ³  μ½”λ©˜νŠΈ λ‚¨κ²¨μ£Όμ…”μ„œ κ°μ‚¬ν•©λ‹ˆλ‹€!!
image

}
};

handleRedirect();
handleCheckMember();
}, [dashboardId, user]);

const handleNewColumnClick = () => {
if (columnList.length >= 10) {
openNotificationModal({ text: 'μ»¬λŸΌμ€ μ΅œλŒ€ 10κ°œκΉŒμ§€ 생성할 수 μžˆμŠ΅λ‹ˆλ‹€.' });
Expand Down Expand Up @@ -62,13 +102,21 @@ export default function ColumnsSection({ dashboardId }: ColumnsSectionProps) {
<ColumnSkeleton />
) : (
<DragDropContext onDragEnd={onDragEnd}>
<section className='block h-full overflow-x-auto lg:flex lg:w-[calc(100dvw-300px)]'>
<section
className={`block h-full overflow-x-auto lg:flex ${isPublic && !user ? 'lg:w-screen' : 'lg:w-[calc(100dvw-300px)]'}`}
>
<ul className='block lg:flex'>
{columnList.map((column, index) => (
<Droppable droppableId={`column-${column.id}`} key={`column-${column.id}`}>
<Droppable droppableId={`column-${column.id}`} key={`column-${column.id}`} isDropDisabled={!isMember}>
{(provided) => (
<li id={`column-${column.id}`} ref={provided.innerRef} {...provided.droppableProps}>
<Column key={`column-${column.id}`} column={column} columns={columnList} index={index} />
<Column
key={`column-${column.id}`}
column={column}
columns={columnList}
index={index}
isMember={isMember}
/>
{provided.placeholder}
</li>
)}
Expand All @@ -79,6 +127,7 @@ export default function ColumnsSection({ dashboardId }: ColumnsSectionProps) {
<button
className='btn-violet-light dark:btn-violet-dark mb-4 h-[70px] w-full rounded-[6px] py-[24px] lg:mb-0 lg:w-[354px]'
onClick={handleNewColumnClick}
disabled={!isMember}
>
<div className='mr-[12px] text-lg font-bold text-black-33 dark:text-dark-10'>μƒˆλ‘œμš΄ 컬럼 μΆ”κ°€ν•˜κΈ°</div>
<Image src='/icons/plus-filled.svg' width={22} height={22} alt='μΉ΄λ“œ μΆ”κ°€ μ•„μ΄μ½˜' className='dark:hidden' />
Expand Down
24 changes: 16 additions & 8 deletions src/containers/dashboard/edit/InvitedMembersSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default function InvitedMembersSection() {
const { mutate } = useDeleteData<CancelInvitationInput>({ mutationFn: deleteInvitation, handleSuccess });
const queryClient = useQueryClient();

const { data, error } = useFetchData<DashboardInvitationsResponse>(['invitations', id, currentChunk], () =>
const { data, isLoading, error } = useFetchData<DashboardInvitationsResponse>(['invitations', id, currentChunk], () =>
getDashboardInvitations(Number(id), currentChunk, 5),
);
const totalPage = data ? Math.max(1, Math.ceil(data.totalCount / 5)) : 1;
Expand All @@ -55,6 +55,20 @@ export default function InvitedMembersSection() {
handleDelete();
};

if (isLoading) {
return <section className='section align-center h-[395px] animate-pulse bg-gray-f5 md:h-[477px]'></section>;
}

if (error || !data) {
return (
<section className='section align-center h-[395px] md:h-[477px]'>
<p role='alert' className='text-[22px] font-bold text-black-33'>
μ΄ˆλŒ€λ‚΄μ—­ 정보가 μ—†μŠ΅λ‹ˆλ‹€!
</p>
</section>
);
}

return (
<section className='section h-[395px] pb-4 transition-colors md:h-[477px] md:pb-5 dark:bg-dark'>
<header className='mb-4 mt-6 flex items-center justify-between md:my-7'>
Expand All @@ -80,13 +94,7 @@ export default function InvitedMembersSection() {
</header>
<main className='text-sm md:text-base'>
<h3 className='mb-[29px] text-gray-9f md:mb-6'>이메일</h3>
{data ? (
<InvitedMemberList invitations={data.invitations} onCancelClick={handleCancelInvitation} />
) : error ? (
<p>{`μ—λŸ¬κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. \n${error.message}`}</p>
) : (
<p>λ‘œλ”©μ€‘...</p>
)}
<InvitedMemberList invitations={data.invitations} onCancelClick={handleCancelInvitation} />
</main>
</section>
);
Expand Down
24 changes: 16 additions & 8 deletions src/containers/dashboard/edit/MembersSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default function MembersSection({ onDeleteMember }: MemberSectionProps) {
const { id } = router.query;
const [currentChunk, setCurrentChunk] = useState(1);

const { data, error } = useFetchData<MembersResponse>(['members', id, currentChunk], () =>
const { data, isLoading, error } = useFetchData<MembersResponse>(['members', id, currentChunk], () =>
getMembersList(Number(id), currentChunk, 4),
);
const totalPage = data ? Math.max(1, Math.ceil(data.totalCount / 4)) : 1;
Expand Down Expand Up @@ -59,6 +59,20 @@ export default function MembersSection({ onDeleteMember }: MemberSectionProps) {
openConfirmModal({ text: '정말 ꡬ성원을 μ‚­μ œν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ?', onActionClick: handleDelete });
};

if (isLoading) {
return <section className='section align-center h-[341px] animate-pulse bg-gray-f5 md:h-[408px]'></section>;
}

if (error || !data) {
return (
<section className='section align-center h-[341px] md:h-[408px]'>
<p role='alert' className='text-[22px] font-bold text-black-33'>
ꡬ성원 정보가 μ—†μŠ΅λ‹ˆλ‹€!
</p>
</section>
);
}

return (
<section className='section h-[341px] pb-4 transition-colors md:h-[408px] md:pb-5 dark:bg-dark'>
<header className='mb-[18px] mt-[22px] flex items-center justify-between md:mb-[27px] md:mt-[26px]'>
Expand All @@ -72,13 +86,7 @@ export default function MembersSection({ onDeleteMember }: MemberSectionProps) {
</header>
<main className='text-sm md:text-base'>
<h3 className='mb-5 h-[17px] text-gray-9f md:mb-6 md:h-[19px]'>이름</h3>
{data ? (
<MemberList members={data.members} onDeleteClick={handleDeleteMember} />
) : error ? (
<p>{`μ—λŸ¬κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. \n${error.message}`}</p>
) : (
<p>λ‘œλ”©μ€‘...</p>
)}
<MemberList members={data.members} onDeleteClick={handleDeleteMember} />
</main>
</section>
);
Expand Down
Loading