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/#152 해커톤 페이지 구현 #158

Merged
merged 19 commits into from
Aug 25, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
492dea9
feat: 클라이언트 서비스의 페이지네이션 컴포넌트 구현
Aug 13, 2024
dcc23ec
feat: 학생의 마일스톤 획득내역, 실적 목록 페이지네이션 처리
Aug 13, 2024
7d85a78
feat: 나의 마일스톤 획득 내역에 페이지네이션 처리
Aug 13, 2024
8127d7a
fix: 학생의 실적 목록 조회 api의 totalElements가 제대로 불러와지지 않는 문제 해결
Aug 13, 2024
3c4c210
feat: Title 컴포넌트 구현
Aug 14, 2024
9b5c366
Merge branch 'Feature/#150-학생의_마일스톤_획득내역_실적목록_페이지네이션_처리' of https://g…
Aug 14, 2024
107df9d
feat: 해커톤 목록 페이지 구현
Aug 14, 2024
11608ee
refactor: 불필요한 styled comopnent 삭제
Aug 14, 2024
ee540ba
refactor: 파일 다운로드 기능 deprecated
Aug 14, 2024
89625bc
feat: 외부에서 파일 리소스에 직접 접근할 수 있도록 설정
Aug 14, 2024
1747e11
feat: 외부에서 파일 리소스에 직접 접근할 수 있도록 설정
Aug 14, 2024
2a3af0a
Merge branch 'Feature/#155-url로_파일_리소스에_접근할_수_있도록_설정' of https://gith…
Aug 14, 2024
8ebef38
fix: 파일 다운로드 테스트 삭제
Aug 15, 2024
b15dc48
Merge branch 'Feature/#155-url로_파일_리소스에_접근할_수_있도록_설정' of https://gith…
Aug 15, 2024
e54b253
feat: 해커톤 진행 상태를 나타내는 라벨 추가
Aug 25, 2024
c5c8cfd
designed: 해커톤 간 여백 크기 키우기
Aug 25, 2024
a6ee7c5
Merge branch 'main' into Feature/#152-해커톤_페이지_구현
amaran-th Aug 25, 2024
d339775
build: classnames 라이브러리 설치
Aug 25, 2024
a591bdf
Merge branch 'Feature/#152-해커톤_페이지_구현' of https://github.com/SW-CSS/s…
Aug 25, 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
10 changes: 0 additions & 10 deletions backend/src/docs/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,6 @@ endif::[]

== API 목록

== 파일

=== `GET`: 파일 다운로드

.HTTP Request
include::{snippets}/download-file/http-request.adoc[]

.HTTP Response
include::{snippets}/download-file/http-response.adoc[]

== 회원

=== `GET`: 학생 정보 조회
Expand Down
21 changes: 21 additions & 0 deletions backend/src/main/java/sw_css/config/ResourceConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package sw_css.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class ResourceConfig implements WebMvcConfigurer {

private String connectPath = "/files/**";

@Value("${data.file-storage-path}")
private String resourcePath;

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler(connectPath)
.addResourceLocations("file:" + resourcePath);
}
}
8 changes: 7 additions & 1 deletion backend/src/main/java/sw_css/file/api/FileController.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,21 @@
import org.springframework.web.bind.annotation.RestController;
import sw_css.file.application.FileService;

@RequestMapping("/files")
@RequestMapping
@RestController
@RequiredArgsConstructor
public class FileController {
private final FileService fileService;

@Deprecated
@GetMapping("/{fileName}")
public ResponseEntity<byte[]> downloadFile(@PathVariable("fileName") final String fileName) throws IOException {
byte[] downloadFile = fileService.downloadFileFromFileSystem(fileName);
return ResponseEntity.ok(downloadFile);
}

@GetMapping("/favicon.ico")
public ResponseEntity<Void> ignoreFaviconRequest() {
return ResponseEntity.noContent().build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Deprecated
@Service
@RequiredArgsConstructor
@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ public static Page<MilestoneHistoryOfStudentResponse> from(final Page<MilestoneH
milestoneHistory.getActivatedAt(),
milestoneHistory.getCreatedAt()
))
.toList());
.toList(), milestoneHistories.getPageable(), milestoneHistories.getTotalElements());
}
}
1 change: 1 addition & 0 deletions backend/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ spring:
data:
client-url: http://localhost:3000
file-path-prefix: /backend/src/main/resources/static/files
file-storage-path: /절대 경로/
39 changes: 0 additions & 39 deletions backend/src/test/java/sw_css/restdocs/docs/FileApiDocsTest.java

This file was deleted.

3 changes: 3 additions & 0 deletions frontend/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ const nextConfig = {
compiler: {
styledComponents: true,
},
images: {
domains: ['localhost'],
},
};

export default nextConfig;
66 changes: 65 additions & 1 deletion frontend/src/app/(withSidebar)/hackathon/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,67 @@
const Page = () => <div>test</div>;
import Pagination from '@/app/components/Pagination';
import Title from '@/components/Title';
import { getHackathons } from '@/lib/api/server.api';
import { headers } from 'next/headers';
import Image from 'next/image';
import Link from 'next/link';

const Page = async ({ searchParams }: { searchParams?: { [key: string]: string | undefined } }) => {
const headersList = headers();
const pathname = headersList.get('x-pathname') || '';

const page = searchParams?.page ? parseInt(searchParams.page, 10) : 1;

const hackathons = await getHackathons(page, 6);

return (
<div className="flex w-full flex-col gap-4 rounded-sm bg-white p-5">
<Title
title="창의융합SW해커톤"
description="소프트웨어융합교육원에서는 2018년부터 매년 창의융합 SW 해커톤을 개최해오고 있습니다."
/>
<div className="h-0 w-full border border-border" />
{hackathons?.content && hackathons.content.length > 0 ? (
<div className="grid grid-cols-1 gap-4 py-4 sm:grid-cols-2 md:grid-cols-3">
{hackathons.content.map((hackathon) => (
<Link
key={hackathon.id}
href={`/hackathon/${hackathon.id}`}
className="flex w-full min-w-[200px] flex-col rounded-sm border-r border-border shadow-md transition-shadow hover:shadow-xl"
>
<div className="relative h-40 w-full">
<Image
src={process.env.NEXT_PUBLIC_FILE_URL + '/' + hackathon.thumbnailImageName}
alt={'해커톤 섬네일'}
className="rounded-t-sm"
layout="fill"
objectFit="cover"
objectPosition="center"
quality={100}
/>
</div>
<div className="m-2 flex flex-col items-center justify-center gap-2 text-center">
<div className="font-bold">{hackathon.name}</div>
<div className="text-xs text-comment">
<p>
신청 기간: {hackathon.applyStartDate.replaceAll('-', '.')} ~{' '}
{hackathon.applyEndDate.replaceAll('-', '.')}
</p>
<p>
대회 기간: {hackathon.hackathonStartDate.replaceAll('-', '.')} ~{' '}
{hackathon.hackathonEndDate.replaceAll('-', '.')}
</p>
</div>
</div>
</Link>
))}
</div>
) : (
<div className="flex h-40 w-full items-center justify-center text-comment">해커톤 정보가 없습니다.</div>
)}

<Pagination currentPage={page} totalItems={hackathons?.totalElements ?? 0} pathname={pathname} pageSize={6} />
</div>
);
};

export default Page;

This file was deleted.

74 changes: 36 additions & 38 deletions frontend/src/app/(withSidebar)/milestone/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,45 +3,43 @@ import Image from 'next/image';
import * as S from './styled';

const Page = () => (
<S.ContentWrapper>
<S.Content>
<S.ImageWrapper maxWidth="230px" maxHeight="66px">
<Image src="/images/milestone/milestone_img01.png" priority={false} alt="" fill />
</S.ImageWrapper>
<S.Description>
<S.Title>마일스톤이란</S.Title>
마일스톤은 전공자들의 SW역량을 종합적으로 평가하기 위한 역량평가지수입니다.
<S.Content>
<S.ImageWrapper maxWidth="230px" maxHeight="66px">
<Image src="/images/milestone/milestone_img01.png" priority={false} alt="" fill />
</S.ImageWrapper>
<S.Description>
<S.Title>마일스톤이란</S.Title>
마일스톤은 전공자들의 SW역량을 종합적으로 평가하기 위한 역량평가지수입니다.
<br />
학생들은 교내외 여러 활동들을 통하여 실전적 SW역량, 글로벌 역량, 커뮤니케이션 역량을 균형있게 함양하고
SW중심대학사업단에서는 학생들의 적립된 마일스톤 점수에 따라 매년 장학생을 선발하고 있습니다.
</S.Description>
<S.ImageWrapper maxWidth="429px" maxHeight="208px" backgroundImage="/images/milestone/milestone_img02_bg.png">
<Image src="/images/milestone/milestone_img02.png" priority={false} alt="" fill />
</S.ImageWrapper>
<S.InformationList>
<S.Information>
<S.InformationTitle>마일스톤 획득 방법</S.InformationTitle>
각 영역별 활동 수행 시, 책정 기준에 따라 마일스톤을 획득할 수 있습니다.
<br />
학생들은 교내외 여러 활동들을 통하여 실전적 SW역량, 글로벌 역량, 커뮤니케이션 역량을 균형있게 함양하고
SW중심대학사업단에서는 학생들의 적립된 마일스톤 점수에 따라 매년 장학생을 선발하고 있습니다.
</S.Description>
<S.ImageWrapper maxWidth="429px" maxHeight="208px" backgroundImage="/images/milestone/milestone_img02_bg.png">
<Image src="/images/milestone/milestone_img02.png" priority={false} alt="" fill />
</S.ImageWrapper>
<S.InformationList>
<S.Information>
<S.InformationTitle>마일스톤 획득 방법</S.InformationTitle>
각 영역별 활동 수행 시, 책정 기준에 따라 마일스톤을 획득할 수 있습니다.
<br />
상세 내용은 아래 표를 참고해주세요.
</S.Information>
<S.Information>
<S.InformationTitle>마일스톤 평가기간</S.InformationTitle>
전년도 9월부터 당해년도 8월까지의 실적
<br />※ SW 창업, 오픈소스 SW 컨트리뷰션의 경우 당해년도 1월부터 9월까지의 실적만을 반영함.
</S.Information>
<S.Information>
<S.InformationTitle>마일스톤 확인 방법</S.InformationTitle>
SW역량지원시스템에서는 나의 마일스톤 현황을 한 눈에 볼 수 있도록 제공하고 있습니다.
<br />
로그인 후, 메인 페이지와 마이페이지에서 확인하실 수 있습니다.
</S.Information>
</S.InformationList>
<S.ImageWrapper maxWidth="890px" maxHeight="1028px">
<Image src="/images/milestone/milestone_img03.png" priority={false} alt="" fill />
</S.ImageWrapper>
</S.Content>
</S.ContentWrapper>
상세 내용은 아래 표를 참고해주세요.
</S.Information>
<S.Information>
<S.InformationTitle>마일스톤 평가기간</S.InformationTitle>
전년도 9월부터 당해년도 8월까지의 실적
<br />※ SW 창업, 오픈소스 SW 컨트리뷰션의 경우 당해년도 1월부터 9월까지의 실적만을 반영함.
</S.Information>
<S.Information>
<S.InformationTitle>마일스톤 확인 방법</S.InformationTitle>
SW역량지원시스템에서는 나의 마일스톤 현황을 한 눈에 볼 수 있도록 제공하고 있습니다.
<br />
로그인 후, 메인 페이지와 마이페이지에서 확인하실 수 있습니다.
</S.Information>
</S.InformationList>
<S.ImageWrapper maxWidth="890px" maxHeight="1028px">
<Image src="/images/milestone/milestone_img03.png" priority={false} alt="" fill />
</S.ImageWrapper>
</S.Content>
);

export default Page;
4 changes: 0 additions & 4 deletions frontend/src/app/(withSidebar)/milestone/styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@ interface ResponsiveImageProps {
backgroundImage?: string;
}

export const ContentWrapper = styled.div`
background-color: ${COLOR.border};
`;

export const Content = styled.div`
width: 100%;
background-color: white;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
/* eslint-disable jsx-a11y/control-has-associated-label */
/* eslint-disable max-len */
import Pagination from '@/app/components/Pagination';
import MilestoneGroupLabel from '@/components/MilestoneGroupLabel';
import { MilestoneHistoryStatus } from '@/data/milestone';
import { useAppSelector } from '@/lib/hooks/redux';
import { useMilestoneHistoriesOfStudentQuery } from '@/lib/hooks/useApi';
import { Period } from '@/types/common';
import { MilestoneHistorySortCriteria, SortDirection } from '@/types/milestone';
import { usePathname } from 'next/navigation';

interface MilestoneHistoryTableProps {
searchFilterPeriod: Period;
Expand All @@ -14,6 +16,7 @@ interface MilestoneHistoryTableProps {
}

const MilestoneHistoryTable = ({ searchFilterPeriod, pageNumber, pageSize }: MilestoneHistoryTableProps) => {
const pathname = usePathname();
const auth = useAppSelector((state) => state.auth).value;
const { data: milestoneHistoriesOfStudent } = useMilestoneHistoriesOfStudentQuery(
auth.uid,
Expand All @@ -22,36 +25,44 @@ const MilestoneHistoryTable = ({ searchFilterPeriod, pageNumber, pageSize }: Mil
MilestoneHistoryStatus.APPROVED,
MilestoneHistorySortCriteria.ACTIVATED_AT,
SortDirection.DESC,
pageNumber,
pageNumber - 1,
pageSize,
);
return (
<table className="w-full border-collapse">
<thead>
<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-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-xs sm:text-sm">
{milestoneHistoriesOfStudent?.content.map((milestoneHistory) => (
<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-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>
<div className="flex flex-col gap-4">
<table className="w-full border-collapse">
<thead>
<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-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>
))}
</tbody>
</table>
</thead>
<tbody className="border-y-2 border-border text-xs sm:text-sm">
{milestoneHistoriesOfStudent?.content.map((milestoneHistory) => (
<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-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>
</table>
<Pagination
currentPage={pageNumber}
pageSize={pageSize}
totalItems={milestoneHistoriesOfStudent?.totalElements ?? 0}
pathname={pathname}
/>
</div>
);
};

Expand Down
Loading