Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(member): 활동 3차 QA 피드백 반영 #242

Merged
merged 18 commits into from
Sep 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
2625cae
fix(member): 업로드 파일 이미지 조회 문제 해결
Jeong-Ag Sep 20, 2024
13fb751
refactor(member): 선택 멤버 승인 예외처리 추가, 지원자 없는 경우엔 버튼 표시 X
Jeong-Ag Sep 20, 2024
c965520
refactor(member): 글자수 제한 추가, 활동 카테고리 한글로 표시
Jeong-Ag Sep 20, 2024
6471a8a
refactor(member): 제출물 조회에서 지난 제출 시간 표시되도록 수정
Jeong-Ag Sep 20, 2024
97c010e
refactor(member): 종료된 활동 상세 페이지 접근 제한
Jeong-Ag Sep 20, 2024
8258343
refactor(member): 페이지네이션 오류 수정
Jeong-Ag Sep 20, 2024
017ebad
style(member): 버튼마다 모달창 message 다르게 적용, 활동 상세 페이지 레이아웃 변경
Jeong-Ag Sep 20, 2024
845ded9
fix(member): endpoint 오타 수정, 공지사항 추가 후 파일 input 초기화
Jeong-Ag Sep 20, 2024
34b3595
style(member): safari 브라우저에서 이미지 깨지는 현상 보완
Jeong-Ag Sep 21, 2024
ff9e2c6
refactor(member): mode에 따른 페이지네이션 초기화, 확인 모달창 문구 수정
Jeong-Ag Sep 21, 2024
6e721b9
style(member): 선택된 이미지 명확하게 확인할 수 있도록 변경
Jeong-Ag Sep 21, 2024
fb86fdc
refactor(member): 활동 쿼리키 수정
Jeong-Ag Sep 21, 2024
eb9e0b4
Merge branch 'main' into refactor/236
Jeong-Ag Sep 21, 2024
965d42f
fix(member): 변경된 modal 구조 적용
Jeong-Ag Sep 21, 2024
3e9adf3
Create modern-panthers-eat.md
gwansikk Sep 21, 2024
3a90611
Merge branch 'main' into refactor/236
gwansikk Sep 21, 2024
c973857
refactor(member): 관리자 페이지 UI 개선
gwansikk Sep 21, 2024
54c22ff
refactor(member): 불필요한 쿼리키 삭제 및 코드 개선
Jeong-Ag Sep 21, 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
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
Loading