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

Feature/#105 클라이언트 마이페이지 반응형 처리 #140

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
5d1a5c0
feat: 마일스톤 실적 목록 페이지 UI 구현
Jul 23, 2024
20a2f38
feat: 누락된 응답 DTO 스니펫 추
Jul 24, 2024
c7ff651
feat: 마일스톤 실적 검색을 위한 동적쿼리 작성 및 전체 데이터 수가 잘못 출력되던 문제 수
Jul 24, 2024
bdeb8e4
feat: 실패하는 테스트 해
Jul 24, 2024
23b6ac9
feat: 마일스톤 실적 승인/반려 취소 api 구
Jul 24, 2024
04fe2a3
feat: 마일스톤 실적 단건 조회 API 구현
Jul 24, 2024
e183a11
feat: MilestoneGroupLabel을 공통컴포넌트로 구현
Jul 24, 2024
8efa07a
fix: 마일스톤 조회 API의 명세 변경으로 인한 데이터 처리 작업 수정
Jul 24, 2024
87ee96c
feat: 마일스톤 실적 단건 조회 페이지 UI 구현
Jul 24, 2024
f5d510e
feat: 파일 다운로드 API 구현
Aug 8, 2024
9e3ab25
feat: 증빙자료 미리보기 기능 구현
Aug 8, 2024
53bfe07
feat: 마일스톤 실적 내역 상태 변경 기능 구현
Aug 8, 2024
774fc76
feat: 참고 자료 파일 업로드
Aug 9, 2024
f20a11b
feat: 마일스톤 실적 일괄등록 페이지 구현
Aug 9, 2024
73f5e23
design: 마이페이지 반응형 처리
Aug 9, 2024
32c7e4b
design: 실적 등록 페이지 반응형 처리
Aug 9, 2024
607986f
design: 마일스톤 획득 내역 페이지 반응형 처리
Aug 9, 2024
f4c2981
Merge branch 'main' of https://github.com/SW-CSS/sw-css into Feature/…
Aug 9, 2024
c4de3ec
fix: controller의 pathParameter를 명시적으로 수정
Aug 9, 2024
971595b
fix: prettier, lint 에러 해결
Aug 9, 2024
49e0af0
style: tailwindcss 정렬 관련 설정 변경
Aug 9, 2024
6e8e3bd
feat: window.alert를 toast로 변경
Aug 10, 2024
e697229
Merge branch 'Feature/#104-마일스톤_실적_일괄등록_페이지_구현' of https://github.com…
Aug 10, 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
4 changes: 2 additions & 2 deletions backend/src/main/java/sw_css/file/api/FileController.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
public class FileController {
private final FileService fileService;

@GetMapping
public ResponseEntity<byte[]> downloadFile(@PathVariable final String fileName) throws IOException {
@GetMapping("/{fileName}")
public ResponseEntity<byte[]> downloadFile(@PathVariable("fileName") final String fileName) throws IOException {
byte[] downloadFile = fileService.downloadFileFromFileSystem(fileName);
return ResponseEntity.ok(downloadFile);
}
Expand Down
Binary file not shown.
Binary file not shown.
17 changes: 12 additions & 5 deletions backend/src/test/java/sw_css/restdocs/docs/FileApiDocsTest.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
package sw_css.restdocs.docs;

import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders;
import org.springframework.restdocs.request.PathParametersSnippet;
import sw_css.file.api.FileController;
import sw_css.restdocs.RestDocsTest;

Expand All @@ -20,13 +23,17 @@ public class FileApiDocsTest extends RestDocsTest {
public void downloadFile() throws Exception {
// given
final byte[] response = new byte[]{};
final PathParametersSnippet pathParameters = pathParameters(
parameterWithName("fileName").description("조회하고자 하는 파일의 이름")
);

// when
when(fileService.downloadFileFromFileSystem(anyString())).thenReturn(response);
when(fileService.downloadFileFromFileSystem(any())).thenReturn(response);

// then
mockMvc.perform(get("/files/dd71ceeb-a721-462f-9ea1-411415f57607_Eg7BBFlUcAAQMzI.jpeg"))
final String fileName = "test-file.jpeg";
mockMvc.perform(RestDocumentationRequestBuilders.get("/files/{fileName}", fileName))
.andExpect(status().isOk())
.andDo(document("download-file"));
.andDo(document("download-file", pathParameters));
}
}
2 changes: 1 addition & 1 deletion frontend/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"parser": "@typescript-eslint/parser",
"plugins": ["@typescript-eslint"],
"plugins": ["@typescript-eslint", "react", "tailwindcss"],
"extends": [
"next/core-web-vitals",
"plugin:@typescript-eslint/recommended",
Expand Down
11 changes: 11 additions & 0 deletions frontend/public/images/admin/pdf_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const MilestoneHistorySection = async () => {
);

return (
<div className="w-[280px] rounded-sm bg-white p-5">
<div className="w-full min-w-[260px] flex-1 rounded-sm bg-white p-5 lg:max-w-[280px]">
<SubTitle title="실적 등록" urlText="등록하기" url="/my-page/milestone/register" />
<div className="mt-4">
{milestoneHistoriesOfStudent?.content.map((milestoneHistory) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,17 @@ const MilestoneSection = () => {
);

return (
<div className="w-[630px] rounded-sm bg-white p-5">
<div className="w-full flex-1 rounded-sm bg-white p-5 sm:min-w-[630px] lg:max-w-[630px]">
<SubTitle title="내 마일스톤 상세" urlText="전체보기" url="/my-page/milestone" />
<div className="my-5 flex items-center justify-end gap-2">
<div className="my-5 flex items-center justify-center gap-2 sm:justify-end">
<span className="rounded-lg bg-border px-4 py-1">{searchFilterPeriod.startDate}</span>~
<span className="rounded-lg bg-border px-4 py-1">{searchFilterPeriod.endDate}</span>
</div>
<div className="flex">
<div className="flex flex-wrap">
{milestoneInfoTypes.map((type) => (
<button
type="button"
className={`h-[30px] flex-grow border-0 bg-white ${selectedInfoType === type.id ? 'border-b-2 text-black' : 'text-comment'} border-black hover:border-b-2 hover:text-black`}
className={`h-[30px] min-w-[6em] flex-grow border-0 bg-white ${selectedInfoType === type.id ? 'border-b-2 text-black' : 'text-comment'} border-black hover:border-b-2 hover:text-black`}
key={type.id}
onClick={() => setSelectedInfoType(type.id)}
>
Expand All @@ -68,7 +68,7 @@ const MilestoneSection = () => {
</div>
<div className="p-4">
{selectedInfoType === MilestoneInfoType.TOTAL && (
<div className="flex py-10">
<div className="flex flex-wrap gap-y-5 py-1 sm:py-10">
<MilestoneChart chartSize={180} fontSize="lg" milestoneOverviewScore={milestoneOverviewScore} />
<MilestoneTable milestoneOverviewScore={milestoneOverviewScore} />
</div>
Expand All @@ -85,7 +85,7 @@ const MilestoneSection = () => {
/>
)}
{selectedInfoType === MilestoneInfoType.HISTORY && (
<MilestoneHistoryTable searchFilterPeriod={searchFilterPeriod} page={0} size={5} />
<MilestoneHistoryTable searchFilterPeriod={searchFilterPeriod} pageNumber={0} pageSize={5} />
)}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ interface StudentInfoLabelProps {
}

const StudentInfoLabel = ({ label, value }: StudentInfoLabelProps) => (
<p className="flex flex-grow">
<p className="flex sm:min-w-80 sm:flex-1">
<span className="mr-4 w-[4em]">{label}</span>
<b>{value}</b>
</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ const StudentInfoSection = () => {
<SubTitle title="내 정보" urlText="수정" url="/my-page/edit" />
{member && (
<div className="my-5">
<div className="mb-5 flex items-end gap-4">
<div className="mb-5 flex flex-wrap items-end gap-4">
<p className="text-xl font-bold">{member.name}</p>
<p className="text-lg text-comment">{member.email}</p>
</div>
<div className="grid grid-cols-2 gap-4 text-sm">
<div className="col-span-2 flex justify-between gap-4">
<StudentInfoLabel label="주전공" value={member.major} />
{member.minor && <StudentInfoLabel label="부전공" value={member.minor} />}
{member.doubleMajor && <StudentInfoLabel label="복수전공" value={member.doubleMajor} />}
</div>
<div className="mb-4 flex w-full justify-between gap-4">
<StudentInfoLabel label="주전공" value={member.major} />
{member.minor && <StudentInfoLabel label="부전공" value={member.minor} />}
{member.doubleMajor && <StudentInfoLabel label="복수전공" value={member.doubleMajor} />}
</div>
<div className="flex flex-wrap gap-y-4">
<StudentInfoLabel label="전화번호" value={appendDashPhoneNumber(member.phoneNumber)} />
<StudentInfoLabel
label="진로 계획"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
import { useState } from 'react';

import { MilestoneGroup, milestoneGroups } from '@/data/milestone';
import { useAppSelector } from '@/lib/hooks/redux';
import { useMilestoneScoresOfStudentQuery } from '@/lib/hooks/useApi';
import { compareByIdAsc } from '@/lib/utils/utils';
import { Period } from '@/types/common';

import { GroupButton } from './styled';
import MilestoneRowBarTable from '../../../components/MilestoneRowBarTable';
import { useAppSelector } from '@/lib/hooks/redux';

const MilestoneDetail = ({ startDate, endDate }: Period) => {
const auth = useAppSelector((state) => state.auth).value;
Expand All @@ -18,7 +18,7 @@ const MilestoneDetail = ({ startDate, endDate }: Period) => {

return (
<div style={{ display: 'flex', flexGrow: '1', flexDirection: 'column' }}>
<div style={{ display: 'flex' }}>
<div className="flex flex-wrap">
{milestoneGroups.map((group) => (
<GroupButton
key={group.id}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
/* eslint-disable jsx-a11y/control-has-associated-label */
/* eslint-disable max-len */
import MilestoneGroupLabel from '@/components/MilestoneGroupLabel';
import { MilestoneGroup, MilestoneHistoryStatus } from '@/data/milestone';
import { MilestoneHistoryStatus } from '@/data/milestone';
import { useAppSelector } from '@/lib/hooks/redux';
import { useMilestoneHistoriesOfStudentQuery } from '@/lib/hooks/useApi';
import { convertMilestoneGroup } from '@/lib/utils/utils';
import { Period } from '@/types/common';
import { MilestoneHistorySortCriteria, SortDirection } from '@/types/milestone';

Expand All @@ -29,22 +28,26 @@ const MilestoneHistoryTable = ({ searchFilterPeriod, pageNumber, pageSize }: Mil
return (
<table className="w-full border-collapse">
<thead>
<tr className="flex border-b border-border text-center">
<tr className="flex items-center border-b border-border text-center text-sm sm:text-base">
<th className="flex-grow p-[10px]">활동명</th>
<th className="w-20 p-[10px]">역량 구분</th>
<th className="w-20 p-[10px]">획득 점수</th>
<th className="w-[112px] p-[10px]">활동일</th>
<th className="w-16 p-1 sm:w-20 sm:p-[10px]">구분</th>
<th className="w-16 p-1 sm:p-[10px]">점수</th>
<th className="hidden w-[80px] p-1 sm:table-cell sm:w-[100px] sm:p-[10px]">활동일</th>
</tr>
</thead>
<tbody className="border-y-2 border-border text-sm">
<tbody className="border-y-2 border-border text-xs sm:text-sm">
{milestoneHistoriesOfStudent?.content.map((milestoneHistory) => (
<tr key={milestoneHistory.id} className="flex border-b border-border text-center">
<td className="max-w-[calc(100%-273px)] flex-grow p-[10px] text-left">{milestoneHistory.description}</td>
<td className="w-20 p-[10px]">
<tr key={milestoneHistory.id} className="flex items-center border-b border-border text-center">
<td className="max-w-[calc(100%-128px)] flex-grow p-[10px] text-left sm:max-w-[calc(100%-244px)]">
{milestoneHistory.description}
</td>
<td className="w-16 p-1 sm:w-20 sm:p-[10px]">
<MilestoneGroupLabel group={milestoneHistory.milestone.categoryGroup} />
</td>
<td className="w-20 p-[10px]">{milestoneHistory.milestone.score * milestoneHistory.count}</td>
<td className="w-[112px] p-[10px]">{milestoneHistory.activatedAt.slice(0, 10)}</td>
<td className="w-16 p-1 sm:p-[10px]">{milestoneHistory.milestone.score * milestoneHistory.count}</td>
<td className="hidden w-[100px] p-[10px] sm:table-cell">
{milestoneHistory.activatedAt.slice(0, 10).replaceAll('-', '.')}
</td>
</tr>
))}
</tbody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import { useMemo } from 'react';
import MilestoneChart from '@/components/MilestoneChart';
import MilestoneTable from '@/components/MilestoneTable';
import { initialMilestoneOverview } from '@/data/milestone';
import { useAppSelector } from '@/lib/hooks/redux';
import { useMilestoneScoresOfStudentQuery } from '@/lib/hooks/useApi';
import { Period } from '@/types/common';
import { MilestoneOverviewScore } from '@/types/milestone';

import { MilestoneWrapper } from './styled';
import MilestoneDetail from '../MilestoneDetail';
import { useAppSelector } from '@/lib/hooks/redux';

interface MilestoneOverviewProps {
searchFilterPeriod: Period;
Expand All @@ -37,7 +37,7 @@ const MilestoneOverview = ({ searchFilterPeriod }: MilestoneOverviewProps) => {
[milestoneScoresOfStudent],
);
return (
<div style={{ display: 'flex', gap: '16px' }}>
<div className="flex flex-wrap justify-center gap-4">
<MilestoneWrapper>
<MilestoneChart chartSize={180} fontSize="lg" milestoneOverviewScore={milestoneOverviewScore} />
<MilestoneTable milestoneOverviewScore={milestoneOverviewScore} />
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/app/(withSidebar)/my-page/milestone/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Period } from '@/types/common';

import MilestoneHistoryTable from './components/MilestoneHistoryTable';
import MilestoneOverview from './components/MilestoneOverview';
import { Content, SubTitle, Title } from './styled';
import { Content, SubTitle } from './styled';
import MilestonePeriodSearchForm from '../../../../components/MilestonePeriodSearchForm';

const Page = () => {
Expand All @@ -20,8 +20,8 @@ const Page = () => {

return (
<Content>
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '25px' }}>
<Title>마일스톤 획득 내역</Title>
<div className="mb-6 flex flex-wrap justify-between gap-4">
<p className="min-w-[10em] text-xl font-bold">마일스톤 획득 내역</p>
<MilestonePeriodSearchForm
setFilterPeriod={setFilterPeriod}
filterPeriod={filterPeriod}
Expand All @@ -33,7 +33,7 @@ const Page = () => {
<div style={{ borderBottom: `1px dotted ${COLOR.border}`, margin: '30px 0px' }} />
<SubTitle>획득 내역</SubTitle>
{/* TODO 제대로 페이지네이션 처리 하기 */}
<MilestoneHistoryTable searchFilterPeriod={searchFilterPeriod} page={0} size={10} />
<MilestoneHistoryTable searchFilterPeriod={searchFilterPeriod} pageNumber={0} pageSize={10} />
</Content>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { useRouter } from 'next/navigation';

import { toast } from 'react-toastify';
import { useMilestoneHistoryDeleteMutation } from '@/lib/hooks/useApi';

interface MilestoneHistoryDeleteButtonProps {
Expand All @@ -19,7 +20,7 @@ const MilestoneHistoryDeleteButton = ({ historyId }: MilestoneHistoryDeleteButto
if (router) router.refresh();
},
onError: () => {
window.alert('삭제에 실패하였습니다.');
toast.error('삭제에 실패하였습니다.');
},
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/* eslint-disable jsx-a11y/control-has-associated-label */
/* eslint-disable max-len */
/* eslint-disable no-alert */

import MilestoneHistoryStatusLabel from '@/app/(withSidebar)/my-page/components/MilestoneHistoryStatusLabel';
import { getMilestoneHistoriesOfStudent } from '@/lib/api/server.api';
Expand All @@ -25,29 +24,44 @@ const MilestoneHistoryTable = async () => {
<thead className="font-bold">
<tr className="text-center">
<td className="min-w-[2em] p-2">No</td>
<td className="w-full p-2">제목</td>
<td className="hidden w-full p-2 sm:table-cell">제목</td>
<td className="min-w-[3em] p-2">점수</td>
<td className="min-w-[10em] p-2">활동일</td>
<td className="min-w-[10em] p-2">등록일</td>
<td className="min-w-[6em] p-2">진행 상황</td>
<td className="min-w-[6em] p-2">처리</td>
<td className="hidden min-w-[8em] p-2 sm:table-cell">활동일</td>
<td className="hidden min-w-[8em] p-2 sm:table-cell">등록일</td>
<td className="hidden min-w-[6em] p-2 sm:table-cell">진행 상황</td>
<td className="hidden min-w-[6em] p-2 sm:table-cell">처리</td>
<td className="table-cell min-w-[6em] p-2 sm:hidden">실적 내역</td>
</tr>
</thead>
<tbody className="border-y text-center">
{milestoneHistories?.content.map((milestoneHistory, index) => (
<tr className="border-b border-border p-2">
<td className="p-2">{index + 1} </td>
<td className="p-2 text-left">{milestoneHistory.description}</td>
<td className="hidden p-2 text-left sm:table-cell">{milestoneHistory.description}</td>
<td className="p-2">{milestoneHistory.milestone.score * milestoneHistory.count}</td>
<td className="p-2">{milestoneHistory.activatedAt}</td>
<td className="p-2">{milestoneHistory.createdAt.slice(0, 10)}</td>
<td className="p-2" align="center">
<td className="hidden p-2 sm:table-cell">{milestoneHistory.activatedAt.replaceAll('-', '.')}</td>
<td className="hidden p-2 sm:table-cell">{milestoneHistory.createdAt.slice(0, 10).replaceAll('-', '.')}</td>
<td className="hidden p-2 sm:table-cell" align="center">
<MilestoneHistoryStatusLabel
status={milestoneHistory.status}
rejectReason={milestoneHistory.rejectReason}
/>
</td>
<td className="p-2">
<td className="hidden p-2 sm:table-cell">
<MilestoneHistoryDeleteButton historyId={milestoneHistory.id} />
</td>
<td className="flex flex-col gap-1 p-2 sm:hidden">
<div className="flex items-center justify-start gap-1">
<MilestoneHistoryStatusLabel
status={milestoneHistory.status}
rejectReason={milestoneHistory.rejectReason}
/>
<div className="flex-grow text-left font-bold">{milestoneHistory.description}</div>
</div>
<div className="flex justify-between text-xs text-comment">
<div>활동: {milestoneHistory.activatedAt.replaceAll('-', '.')}</div>
<div>등록: {milestoneHistory.createdAt.slice(0, 10).replaceAll('-', '.')}</div>
</div>
<MilestoneHistoryDeleteButton historyId={milestoneHistory.id} />
</td>
</tr>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ const MilestoneDropdown = ({ ...props }: MilestoneDropdownProps) => {
}, [milestoneId, milestoneOptions, setSelectedMilestone]);

return (
<div className="flex gap-x-4">
<div className="w-[540px]">
<div className="flex flex-col flex-wrap gap-4 sm:flex-row">
<div className="flex-grow sm:min-w-[540px] lg:w-[540px]">
<Dropdown
name={categoryName}
label="활동"
Expand All @@ -80,7 +80,7 @@ const MilestoneDropdown = ({ ...props }: MilestoneDropdownProps) => {
errorText={dropdownProps.errorText ? '' : undefined}
/>
</div>
<div className="flex-grow">
<div className="flex-grow sm:min-w-[330px]">
<Dropdown
name={milestoneName}
label="구분"
Expand Down
Loading