Skip to content

Commit

Permalink
refactor(member): 활동 3차 QA 피드백 반영 (#242)
Browse files Browse the repository at this point in the history
* fix(member): 업로드 파일 이미지 조회 문제 해결

* refactor(member): 선택 멤버 승인 예외처리 추가, 지원자 없는 경우엔 버튼 표시 X

* refactor(member): 글자수 제한 추가, 활동 카테고리 한글로 표시

* refactor(member): 제출물 조회에서 지난 제출 시간 표시되도록 수정

* refactor(member): 종료된 활동 상세 페이지 접근 제한

* refactor(member): 페이지네이션 오류 수정

* style(member): 버튼마다 모달창 message 다르게 적용, 활동 상세 페이지 레이아웃 변경

* fix(member): endpoint 오타 수정, 공지사항 추가 후 파일 input 초기화

* style(member): safari 브라우저에서 이미지 깨지는 현상 보완

* refactor(member): mode에 따른 페이지네이션 초기화, 확인 모달창 문구 수정

* style(member): 선택된 이미지 명확하게 확인할 수 있도록 변경

* refactor(member): 활동 쿼리키 수정

* fix(member): 변경된 modal 구조 적용

* Create modern-panthers-eat.md

* refactor(member): 관리자 페이지 UI 개선

* refactor(member): 불필요한 쿼리키 삭제 및 코드 개선

---------

Co-authored-by: Gwansik Kim <[email protected]>
  • Loading branch information
Jeong-Ag and gwansikk authored Sep 21, 2024
1 parent 9c41efb commit 475690f
Show file tree
Hide file tree
Showing 27 changed files with 288 additions and 131 deletions.
5 changes: 5 additions & 0 deletions .changeset/modern-panthers-eat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@clab-platforms/member": patch
---

refactor(member): 활동 3차 QA 피드백 반영
11 changes: 10 additions & 1 deletion apps/member/src/components/common/Image/Image.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { SyntheticEvent, useCallback, useState } from 'react';

import { cn } from '@clab-platforms/utils';
import { cn, createURL } from '@clab-platforms/utils';

import { SERVER_BASE_URL } from '@constants/api';
import { NOT_FOUND_IMG } from '@constants/path';

interface ImageProps extends React.ImgHTMLAttributes<HTMLImageElement> {
width?: string;
height?: string;
overflow?: boolean;
isFile?: boolean;
}

type Status = 'loading' | 'error' | 'loaded';
Expand All @@ -19,13 +21,20 @@ const Image = ({
overflow,
className,
onClick,
isFile,
...rest
}: ImageProps) => {
const [status, setStatus] = useState<Status>('loading');

const _width = width ?? 'w-full';
const _height = height ?? 'h-full';

if (isFile) {
if (!src?.startsWith(SERVER_BASE_URL)) {
src = createURL(SERVER_BASE_URL, src);
}
}

const handleLoad = useCallback(() => {
setStatus('loaded');
}, []);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,18 @@ import { useRef, useState } from 'react';
import { Button, Grid, Input } from '@clab-platforms/design-system';

import { Section } from '@components/common/Section';
import TextCounting from '@components/common/TextCounting/TextCounting';
import Textarea from '@components/common/Textarea/Textarea';

import { FORM_DATA_KEY } from '@constants/api';
import { ACTIVITY_BOARD_CATEGORY_STATE } from '@constants/state';
import {
ACTIVITY_BOARD_CATEGORY_STATE,
ACTIVITY_GROUP_CONTENT_MAX_LENGTH,
} from '@constants/state';
import useToast from '@hooks/common/useToast';
import { useActivityGroupBoardMutation, useMyProfile } from '@hooks/queries';
import { isDateValid, toKoreaISOString } from '@utils/date';
import dayjs from 'dayjs';

interface Props {
parentId: number;
Expand Down Expand Up @@ -42,11 +48,25 @@ const ActivityAssignmentEditor = ({ parentId, activityGroupId }: Props) => {
const formData = new FormData();
const files = uploaderRef.current?.files;

if (!board.title || !board.content || !board.dueDateTime)
if (!board.title || !board.content || !board.dueDateTime) {
return toast({
state: 'error',
message: '제목, 내용, 종료 일시는 필수 입력 요소입니다.',
});
} else if (board.content.length > ACTIVITY_GROUP_CONTENT_MAX_LENGTH) {
return toast({
state: 'error',
message: `내용은 ${ACTIVITY_GROUP_CONTENT_MAX_LENGTH}자 이내로 작성해주세요.`,
});
}

if (isDateValid(board.dueDateTime, toKoreaISOString(String(dayjs())))) {
return toast({
state: 'error',
message: '종료 일시는 현재 일시 이후로 선택해주세요.',
});
}

if (files) {
Array.from(files).forEach((file) => {
formData.append(FORM_DATA_KEY, file);
Expand Down Expand Up @@ -87,10 +107,13 @@ const ActivityAssignmentEditor = ({ parentId, activityGroupId }: Props) => {
label="내용"
placeholder="내용을 입력해주세요."
className="w-full"
maxLength={200}
value={board.content}
onChange={handlePostChange}
/>
<TextCounting
maxLength={ACTIVITY_GROUP_CONTENT_MAX_LENGTH}
text={board.content}
/>
<Grid col="2" gap="md" className="items-center">
<Input
label="종료 일시"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const ActivityDetailSection = ({ data }: ActivityDetailSectionProps) => {
alt={data.name}
className="rounded-lg border object-cover"
/>
<Section className="flex h-[160px] flex-col justify-between overflow-scroll">
<Section className="flex min-h-[120px] flex-col justify-between">
<h1 className="text-xl font-bold">{data.name}</h1>
<p className="my-1 whitespace-pre-line text-sm ">{data.content}</p>
<div className="flex items-center gap-1 text-sm text-gray-500">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,14 @@ const ActivityNoticeEditor = ({ groupId, data }: ActivityNoticeEditorProps) => {
body: notice,
files: files?.length ? formData : undefined,
},
{ onSuccess: () => setNotice(defaultNotice) },
{
onSuccess: () => {
setNotice(defaultNotice);
if (uploaderRef.current) {
uploaderRef.current.value = '';
}
},
},
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const ActivityNoticeModal = ({
alt={file.originalFileName}
height="w-[300px]"
className="object-cover"
isFile
/>
) : (
<File
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { GROUP_MESSAGE } from '@constants/message';
import { ACTIVITY_MEMBER_ROLE, ACTIVITY_MEMBER_STATE } from '@constants/state';
import { useModal } from '@hooks/common/useModal';
import { usePagination } from '@hooks/common/usePagination';
import useToast from '@hooks/common/useToast';
import {
useActivityGroupApplication,
useActivityGroupApplicationMutation,
Expand Down Expand Up @@ -62,6 +63,7 @@ function getRoleColor(state: ActivityMemberRoleType): BadgeColorVariant {
const ActivityParticipantEditor = ({
groupId,
}: ActivityParticipantEditorProps) => {
const toast = useToast();
const [mode, setMode] = useState(false);
const { page, size, handlePageChange } = usePagination({ defaultSize: 10 });
const { open, close } = useModal();
Expand Down Expand Up @@ -132,11 +134,16 @@ const ActivityParticipantEditor = ({
const changeList = selectedMember
.filter((member) => member.status === true)
.map((member) => member.memberId);

if (!changeList.length) {
return toast({
state: 'error',
message: '선택된 멤버가 없어요',
});
}
open({
content: (
<CheckConfirmModal
message="변경하시겠습니까?"
message="승인하시겠습니까?"
handleConfirmButton={() => {
activityGroupApplicationMutate({
activityGroupId: groupId,
Expand All @@ -153,11 +160,16 @@ const ActivityParticipantEditor = ({
return (
<Section>
<Section.Header title="참여자 관리">
<Menubar>
<Menubar.Item selected={mode} onClick={() => setMode(!mode)}>
선택
</Menubar.Item>
</Menubar>
{!(applyMemberList.items.length === 1) && (
<Menubar>
<Menubar.Item
selected={mode}
onClick={() => setMode((prev) => !prev)}
>
선택
</Menubar.Item>
</Menubar>
)}
</Section.Header>
<Section.Body>
{applyMemberList.items.length === 1 ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ import { Button, Input } from '@clab-platforms/design-system';

import Hr from '@components/common/Hr/Hr';
import Section from '@components/common/Section/Section';
import TextCounting from '@components/common/TextCounting/TextCounting';
import Textarea from '@components/common/Textarea/Textarea';
import { ActivityBoardEditModal } from '@components/modal';

import { FORM_DATA_KEY } from '@constants/api.ts';
import { ACTIVITY_BOARD_CATEGORY_STATE } from '@constants/state.ts';
import { useModal } from '@hooks/common/useModal';
import {
ACTIVITY_BOARD_CATEGORY_STATE,
ACTIVITY_GROUP_CONTENT_MAX_LENGTH,
} from '@constants/state.ts';
import { useModal } from '@hooks/common/useModal.ts';
import useToast from '@hooks/common/useToast';
import {
useActivityGroupBoardDeleteMutation,
Expand Down Expand Up @@ -47,17 +51,17 @@ const ActivityPostEditor = ({
);
const uploaderRef = useRef<HTMLInputElement>(null);

useEffect(() => {
setEditAssignment(Array.from({ length: activities.length }, () => false));
}, [activities]);

const { data: myProfile } = useMyProfile();

const { activityGroupBoardMutate, activityGroupBoardIsPending } =
useActivityGroupBoardMutation();
const { activityGroupBoardDeleteMutate } =
useActivityGroupBoardDeleteMutation();

useEffect(() => {
setEditAssignment(Array.from({ length: activities.length }, () => false));
}, [activities]);

const handlePostChange = (
e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => {
Expand All @@ -73,7 +77,13 @@ const ActivityPostEditor = ({
state: 'error',
message: '제목, 내용은 필수 입력 요소입니다.',
});
} else if (post.content.length > ACTIVITY_GROUP_CONTENT_MAX_LENGTH) {
return toast({
state: 'error',
message: `내용은 ${ACTIVITY_GROUP_CONTENT_MAX_LENGTH}자 이내로 작성해주세요.`,
});
}

if (files?.length) {
Array.from(files).forEach((file) => {
formData.append(FORM_DATA_KEY, file);
Expand Down Expand Up @@ -128,10 +138,13 @@ const ActivityPostEditor = ({
label="내용"
placeholder="내용을 입력해주세요."
className="w-full"
maxLength={200}
value={post.content}
onChange={handlePostChange}
/>
<TextCounting
maxLength={ACTIVITY_GROUP_CONTENT_MAX_LENGTH}
text={post.content}
/>
<div className="flex flex-col">
<label htmlFor="fileUpload" className="mb-1 ml-1 text-xs">
첨부 파일
Expand Down Expand Up @@ -167,7 +180,7 @@ const ActivityPostEditor = ({
color="orange"
onClick={() => handleAssignmentEditClick(index)}
>
{editAssignment[index] ? '과제 닫기' : '과제 열기'}
{editAssignment[index] ? '과제 관리 닫기' : '과제 관리 하기'}
</Button>
<Button
size="sm"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useParams } from 'react-router-dom';

import { Button, Table } from '@clab-platforms/design-system';
import { cn } from '@clab-platforms/utils';

import File from '@components/common/File/File';
import { Section } from '@components/common/Section';
Expand All @@ -13,16 +14,24 @@ import {
useActivityGroupBoardByParent,
useActivityGroupMemberList,
} from '@hooks/queries';
import { formattedDate, toKoreaISOString } from '@utils/date';
import {
calOverDate,
formattedDate,
isDateValid,
toKoreaISOString,
} from '@utils/date';

import type { ActivityBoardType } from '@type/activity';

import AssignmentFeedbackModal from './AssignmentFeedbackModal';

const AssignmentListSection = () => {
interface AssignmentListSectionProps {
dueDate: string;
}

const AssignmentListSection = ({ dueDate }: AssignmentListSectionProps) => {
const { id, assignmentId } = useParams();
const { open } = useModal();

if (!assignmentId || !id) {
throw new Error(GROUP_MESSAGE.NO_ACTIVITY);
}
Expand Down Expand Up @@ -72,9 +81,17 @@ const AssignmentListSection = () => {
<Table.Row key={item.id}>
<Table.Cell>{item.memberId}</Table.Cell>
<Table.Cell>{item.memberName}</Table.Cell>
<Table.Cell>
{item.files
? formattedDate(toKoreaISOString(item.updatedAt))
<Table.Cell
className={cn(
isDateValid(dueDate, toKoreaISOString(item.updatedAt))
? 'text-red-500'
: '',
)}
>
{item.updatedAt
? isDateValid(dueDate, toKoreaISOString(item.updatedAt))
? calOverDate(dueDate, toKoreaISOString(item.updatedAt))
: formattedDate(toKoreaISOString(item.updatedAt))
: '-'}
</Table.Cell>
<Table.Cell className="hover:underline">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,16 +122,10 @@ const AssignmentUploadSection = ({
<Table.Cell>종료 일시</Table.Cell>
<Table.Cell
className={cn({
'text-red-500': isDateValid(
dueDateTime,
toKoreaISOString(dayjs().format('YYYY.MM.DD')),
),
'text-red-500': isDateValid(dueDateTime, String(dayjs())),
})}
>
{isDateValid(
dueDateTime,
toKoreaISOString(dayjs().format('YYYY.MM.DD')),
)
{isDateValid(dueDateTime, String(dayjs()))
? '제출 기한이 지났습니다'
: formattedDate(dueDateTime)}
</Table.Cell>
Expand Down
1 change: 0 additions & 1 deletion apps/member/src/components/group/GroupCard/GroupCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ const GroupCard = ({
<Image
src={createImageUrl(imageUrl)}
alt={name}
height="min-h-fit h-full"
className="overflow-hidden rounded-l-lg border-r object-cover"
/>
<div className="col-span-2 flex flex-col gap-2 divide-y p-4 ">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,8 @@ const GroupCreateSection = () => {
className={cn(
'rounded-md object-cover transition duration-300 ease-in-out hover:scale-110 hover:cursor-pointer hover:opacity-50',
{
'opacity-50': inputs.imageUrl === photoItem.urls['full'],
'border-4 border-red-500':
inputs.imageUrl === photoItem.urls['full'],
},
)}
/>
Expand Down
Loading

0 comments on commit 475690f

Please sign in to comment.