Skip to content

Commit

Permalink
Feature/#105 클라이언트 마이페이지 반응형 처리 (#140)
Browse files Browse the repository at this point in the history
* feat: 마일스톤 실적 목록 페이지 UI 구현

- 마일스톤 실적 목록 조회 API 연결
- 검색 및 페이지네이션 처리

#102

* feat: 누락된 응답 DTO 스니펫 추

#102

* feat: 마일스톤 실적 검색을 위한 동적쿼리 작성 및 전체 데이터 수가 잘못 출력되던 문제 수

#102

* feat: 실패하는 테스트 해

#102

* feat: 마일스톤 실적 승인/반려 취소 api 구

#102

* feat: 마일스톤 실적 단건 조회 API 구현

#102

* feat: MilestoneGroupLabel을 공통컴포넌트로 구현

* fix: 마일스톤 조회 API의 명세 변경으로 인한 데이터 처리 작업 수정

#102

* feat: 마일스톤 실적 단건 조회 페이지 UI 구현

#102

* feat: 파일 다운로드 API 구현

#102

* feat: 증빙자료 미리보기 기능 구현

#102

* feat: 마일스톤 실적 내역 상태 변경 기능 구현

#102

* feat: 참고 자료 파일 업로드

#104

* feat: 마일스톤 실적 일괄등록 페이지 구현

#104

* design: 마이페이지 반응형 처리

#105

* design: 실적 등록 페이지 반응형 처리

#105

* design: 마일스톤 획득 내역 페이지 반응형 처리

#105

* fix: controller의 pathParameter를 명시적으로 수정

#104

* fix: prettier, lint 에러 해결

#104

* style: tailwindcss 정렬 관련 설정 변경

#104

* feat: window.alert를 toast로 변경

#104

---------

Co-authored-by: amaran-th <[email protected]>
  • Loading branch information
amaran-th and amaran-th authored Aug 12, 2024
1 parent 55347d8 commit 90e71ab
Show file tree
Hide file tree
Showing 16 changed files with 106 additions and 80 deletions.
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 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 @@ -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
Expand Up @@ -28,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 @@ -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
6 changes: 3 additions & 3 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 Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,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
Original file line number Diff line number Diff line change
Expand Up @@ -92,36 +92,44 @@ const Page = () => {
setSelectedMilestone={setSelectedMilestone}
errorText={touched.milestoneId && errors.milestoneId ? errors.milestoneId : undefined}
/>
<div className="flex gap-4">
<TextInput
name="unitScore"
label="건당 점수"
type="text"
defaultValue={0}
value={selectedMilestone?.score || 0}
disabled
/>
<span className="mt-6">x</span>
<TextInput
name="count"
label="횟수(건)"
type="number"
value={values.count}
onChange={handleChange}
onBlur={handleBlur}
errorText={touched.count && errors.count ? errors.count : undefined}
/>
<span className="mt-6">=</span>
<TextInput
name="totalScore"
label="총 점수"
type="text"
defaultValue={0}
value={(selectedMilestone?.score ?? 0) * values.count}
disabled
/>
<div className="flex flex-wrap gap-4">
<div className="min-w-[4em] flex-grow">
<TextInput
name="unitScore"
label="건당 점수"
type="text"
defaultValue={0}
value={selectedMilestone?.score || 0}
disabled
/>
</div>
<div className="flex flex-grow gap-4">
<span className="mt-6">x</span>
<TextInput
name="count"
label="횟수(건)"
type="number"
value={values.count}
onChange={handleChange}
onBlur={handleBlur}
errorText={touched.count && errors.count ? errors.count : undefined}
/>
</div>
<div className="flex flex-grow gap-4">
<span className="mt-6">=</span>
<div className="min-w-[4em] flex-grow">
<TextInput
name="totalScore"
label="총 점수"
type="text"
defaultValue={0}
value={(selectedMilestone?.score ?? 0) * values.count}
disabled
/>
</div>
</div>
</div>
<div className="flex gap-4">
<div className="flex flex-wrap gap-4">
<TextInput
name="description"
label="등록 상세 제목"
Expand Down
5 changes: 0 additions & 5 deletions frontend/src/app/(withSidebar)/my-page/milestone/styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@ export const Content = styled.div`
border-radius: ${BORDER_RADIUS.sm};
`;

export const Title = styled.div`
color: ${COLOR.black_text};
font: ${FONT_STYLE.xl.bold};
`;

export const SubTitle = styled.div`
color: ${COLOR.black_text};
font: ${FONT_STYLE.lg.bold};
Expand Down
1 change: 1 addition & 0 deletions frontend/src/app/(withSidebar)/styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@ export const Content = styled.div`
@media screen and (max-width: ${RESPONSIVE_WIDTH.desktop}) {
padding: 20px;
width: 100%;
}
`;
2 changes: 1 addition & 1 deletion frontend/src/app/components/Formik/TextInput/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export const TextInput = ({ isRequired = false, ...props }: TextInputProps) => {
{label} {isRequired && <span className="text-sm font-semibold text-red-400">*</span>}
</label>
<input
{...inputProps}
onKeyDown={(e) => {
if (e.key === 'Enter') {
onKeyDownEnter?.();
Expand All @@ -33,6 +32,7 @@ export const TextInput = ({ isRequired = false, ...props }: TextInputProps) => {
onChangeText?.(e.target.value);
}}
className={`m-0 rounded-sm border-[1px] border-border p-3 text-base ${hasError && 'border-red-400'}`}
{...inputProps}
/>
{errorText && <span className="pl-1 text-xs text-red-400">{errorText}</span>}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const MilestonePeriodSearchForm = ({
};

return (
<div style={{ display: 'flex', alignItems: 'center' }}>
<div className="flex flex-grow flex-col items-center justify-center gap-x-4 sm:flex-row">
<PeriodInput
type="date"
value={filterPeriod.startDate}
Expand Down
7 changes: 5 additions & 2 deletions frontend/src/components/MilestonePeriodSearchForm/styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

import styled from 'styled-components';

import { BORDER_RADIUS, COLOR } from '@/constants';
import { BORDER_RADIUS, COLOR, RESPONSIVE_WIDTH } from '@/constants';

export const PeriodInput = styled.input`
text-align: center;
padding: 8px;
margin: 0 8px;
border-radius: ${BORDER_RADIUS.md};
border: none;
background-color: ${COLOR.border};
Expand All @@ -22,4 +21,8 @@ export const SearchButton = styled.button`
color: white;
padding: 4px 16px;
border-radius: ${BORDER_RADIUS.sm};
@media screen and (max-width: ${RESPONSIVE_WIDTH.mobile}) {
margin-top: 16px;
}
`;

0 comments on commit 90e71ab

Please sign in to comment.