diff --git a/backend/src/main/resources/config b/backend/src/main/resources/config index 8858300d..f8b6ccd0 160000 --- a/backend/src/main/resources/config +++ b/backend/src/main/resources/config @@ -1 +1 @@ -Subproject commit 8858300d99fe63edca63b26f837adea13e71b950 +Subproject commit f8b6ccd0232837bbda578eb6f953ec27ef55d8fb diff --git a/backend/src/main/resources/test-data.sql b/backend/src/main/resources/test-data.sql index 03a7a557..a2dcc63d 100644 --- a/backend/src/main/resources/test-data.sql +++ b/backend/src/main/resources/test-data.sql @@ -7,7 +7,7 @@ insert into student_member (id, member_id, major_id, minor_id, double_major_id, values (202055558, 1, 1, null, null, 'EMPLOYMENT_COMPANY', 'IT 기업 개발자'); insert into member (email, name, password, phone_number, is_deleted) -values ( 'iddang@pusan.ac.kr', '이다은', '$2a$10$YyiOL/E5WjKrZPkB6eQSK.PwZtAO.z3JimFbq/Ky3u3rFf3XTGrWK', '010-0000-0000' +values ( 'ddang@pusan.ac.kr', '이다은', '$2a$10$YyiOL/E5WjKrZPkB6eQSK.PwZtAO.z3JimFbq/Ky3u3rFf3XTGrWK', '010-0000-0000' , false); insert into student_member (id, member_id, major_id, minor_id, double_major_id, career, career_detail) @@ -32,7 +32,7 @@ INSERT INTO sw_css.milestone_history (id, milestone_id, student_id, description, VALUES (3, 5, 202055558, 'TOPCIT 수준 2', null, 'APPROVED', null, 1, '2024-06-03', 0, '2024-07-01 18:35:47.563444'); INSERT INTO sw_css.milestone_history (id, milestone_id, student_id, description, file_url, status, reject_reason, count, activated_at, is_deleted, created_at) -VALUES (4, 6, 202000000, 'PCC lv3', null, 'APPROVED', null, 1, '2024-06-04', 0, '2024-07-01 18:35:47.566673'); +VALUES (4, 6, 202055555, 'PCC lv3', null, 'APPROVED', null, 1, '2024-06-04', 0, '2024-07-01 18:35:47.566673'); INSERT INTO sw_css.milestone_history (id, milestone_id, student_id, description, file_url, status, reject_reason, count, activated_at, is_deleted, created_at) VALUES (5, 7, 202055558, 'PCC lv2', null, 'APPROVED', null, 1, '2024-06-05', 0, '2024-07-01 18:35:47.569843'); @@ -50,12 +50,12 @@ INSERT INTO sw_css.milestone_history (id, milestone_id, student_id, description, VALUES (9, 15, 202055558, '글로벌 행사 참여', null, 'PENDING', null, 1, '2024-06-08', 0, '2024-07-01 18:35:47.580376'); INSERT INTO sw_css.milestone_history (id, milestone_id, student_id, description, file_url, status, reject_reason, count, activated_at, is_deleted, created_at) -VALUES (10, 7, 202000000, 'PCC lv2', null, 'PENDING', null, 1, '2024-06-11', 0, '2024-07-01 18:35:47.580376'); +VALUES (10, 7, 202055555, 'PCC lv2', null, 'PENDING', null, 1, '2024-06-11', 0, '2024-07-01 18:35:47.580376'); INSERT INTO sw_css.milestone_history (id, milestone_id, student_id, description, file_url, status, reject_reason, count, activated_at, is_deleted, created_at) -VALUES (11, 15, 202000000, '글로벌 행사 참여', null, 'APPROVED', null, 1, '2024-06-08', 0, '2024-07-01 18:35:47.580376'); +VALUES (11, 15, 202055555, '글로벌 행사 참여', null, 'APPROVED', null, 1, '2024-06-08', 0, '2024-07-01 18:35:47.580376'); INSERT INTO sw_css.milestone_history (id, milestone_id, student_id, description, file_url, status, reject_reason, count, activated_at, is_deleted, created_at) -VALUES (12, 3, 202000000, '비교과 SW 관련 창업', null, 'APPROVED', null, 2, '2024-06-08', 0, '2024-07-01 18:35:47.580376'); +VALUES (12, 3, 202055555, '비교과 SW 관련 창업', null, 'APPROVED', null, 2, '2024-06-08', 0, '2024-07-01 18:35:47.580376'); diff --git a/frontend/src/app/(withSidebar)/hackathon/page.tsx b/frontend/src/app/(withSidebar)/hackathon/page.tsx index 03c8acd4..298aa125 100644 --- a/frontend/src/app/(withSidebar)/hackathon/page.tsx +++ b/frontend/src/app/(withSidebar)/hackathon/page.tsx @@ -13,7 +13,12 @@ const Page = async ({ searchParams }: { searchParams?: { [key: string]: string | const page = searchParams?.page ? parseInt(searchParams.page, 10) : 1; - const hackathons = await getHackathons(page, 6); + let hackathons; + try { + hackathons = await getHackathons(page, 6); + } catch (err) { + // TODO: server api error handling + } const getHackathonState = (startDate: string, endDate: string) => { const now = Date.now(); @@ -44,7 +49,10 @@ const Page = async ({ searchParams }: { searchParams?: { [key: string]: string | description="소프트웨어융합교육원에서는 2018년부터 매년 창의융합 SW 해커톤을 개최해오고 있습니다." />
- {hackathons?.content && hackathons.content.length > 0 ? ( + +
개발 중인 기능입니다.
+ + {/* {hackathons?.content && hackathons.content.length > 0 ? (
{hackathons.content.map((hackathon) => ( 해커톤 정보가 없습니다.
)} - + */}
); }; diff --git a/frontend/src/app/(withSidebar)/hackathon/sw-contest/page.tsx b/frontend/src/app/(withSidebar)/hackathon/sw-contest/page.tsx index 905905f6..3db07350 100644 --- a/frontend/src/app/(withSidebar)/hackathon/sw-contest/page.tsx +++ b/frontend/src/app/(withSidebar)/hackathon/sw-contest/page.tsx @@ -1,3 +1,14 @@ -const Page = () =>
test
; +import Title from '@/components/Title'; + +const Page = () => { + return ( +
+ + <div className="h-0 w-full border border-border" /> + + <div className="flex h-40 w-full items-center justify-center text-comment">개발 중인 기능입니다.</div> + </div> + ); +}; export default Page; diff --git a/frontend/src/app/(withSidebar)/team-building/page.tsx b/frontend/src/app/(withSidebar)/team-building/page.tsx new file mode 100644 index 00000000..ba587ac6 --- /dev/null +++ b/frontend/src/app/(withSidebar)/team-building/page.tsx @@ -0,0 +1,13 @@ +import Title from '@/components/Title'; + +const Page = () => { + return ( + <div className="flex w-full flex-col gap-4 rounded-sm bg-white p-5"> + <Title title="팀 빌딩" /> + + <div className="flex h-40 w-full items-center justify-center text-comment">개발 중인 기능입니다.</div> + </div> + ); +}; + +export default Page; diff --git a/frontend/src/app/components/Milestone/index.tsx b/frontend/src/app/components/Milestone/index.tsx index e7eff076..f30025f2 100644 --- a/frontend/src/app/components/Milestone/index.tsx +++ b/frontend/src/app/components/Milestone/index.tsx @@ -1,17 +1,48 @@ import MilestoneChart from '@/components/MilestoneChart'; import MilestoneTable from '@/components/MilestoneTable'; import { getAuthFromCookie } from '@/lib/utils/auth'; -import { milestoneSummaryInfo } from '@/mocks/milestone'; import { AuthSliceState } from '@/store/auth.slice'; import { MilestoneChartWrapper } from './styled'; import GoPageIcon from '../GoPageIcon'; import SignIn from '../SignIn'; import { Description, Title, TitleContent, TitleWrapper } from '../styled'; +import { getMyMilestoneHistory } from '@/lib/api/server.api'; +import { DateTime } from 'luxon'; +import { MilestoneOverviewScore } from '@/types/milestone'; +import { initialMilestoneOverview } from '@/data/milestone'; -const Milestone = () => { +const getMilestoneScores = async (studentId: number) => { + const startDate = DateTime.now().minus({ years: 1 }).toFormat('yyyy-MM-dd'); + const endDate = DateTime.now().toFormat('yyyy-MM-dd'); + try { + const milestoneScores = await getMyMilestoneHistory(studentId, startDate, endDate); + return milestoneScores; + } catch (err) { + // TODO: server api error handling + } + return null; +}; + +const getMilestoneOverviewScore = async (studentId: number) => { + const milestoneScores = await getMilestoneScores(studentId); + const milestoneOverviewScore = milestoneScores?.reduce<MilestoneOverviewScore>( + (acc, cur) => { + const key = `${cur.group.toLowerCase()}Score` as keyof MilestoneOverviewScore; + acc[key] += cur.score; + acc.totalScore += cur.score; + return acc; + }, + { ...initialMilestoneOverview }, + ); + return milestoneOverviewScore || initialMilestoneOverview; +}; + +const Milestone = async () => { const auth: AuthSliceState = getAuthFromCookie(); + const milestoneOverviewScore = await getMilestoneOverviewScore(auth.id); + return ( <div style={{ display: 'flex', flexDirection: 'column' }}> <TitleWrapper style={{ justifyContent: 'space-between' }}> @@ -19,13 +50,12 @@ const Milestone = () => { <Title>나의 마일스톤 나의 마일스톤 내역을 확인할 수 있어요. - {/* TODO: url 자신의 마일스톤으로 이동하도록 수정하기 */} - {auth.isAuth && } + {auth.isAuth && } {auth.isAuth && ( - - + + )} {!auth.isAuth && } diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx index 1e84cd2e..a94e7084 100644 --- a/frontend/src/app/layout.tsx +++ b/frontend/src/app/layout.tsx @@ -18,6 +18,7 @@ export const metadata: Metadata = { const RootLayout = ({ children }: Readonly<{ children: React.ReactNode }>) => ( + diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx index 8a968f5c..f4d3cee3 100644 --- a/frontend/src/app/page.tsx +++ b/frontend/src/app/page.tsx @@ -18,9 +18,10 @@ const Page = () => ( + {/* TODO: 팀빌딩 구현 완료 되면 주석 풀기 - - + + */} diff --git a/frontend/src/components/Header/index.tsx b/frontend/src/components/Header/index.tsx index ba0bf5f7..61fbdbcd 100644 --- a/frontend/src/components/Header/index.tsx +++ b/frontend/src/components/Header/index.tsx @@ -3,6 +3,7 @@ 'use client'; +import { VscSettingsGear } from '@react-icons/all-files/vsc/VscSettingsGear'; import { VscAccount } from '@react-icons/all-files/vsc/VscAccount'; import { VscSignIn } from '@react-icons/all-files/vsc/VscSignIn'; import { VscSignOut } from '@react-icons/all-files/vsc/VscSignOut'; @@ -49,12 +50,19 @@ const Header = () => { ), )}
- {auth.isAuth ? ( + {auth.isAuth && auth.isModerator && ( + <> + } title="관리" size="sm" link="/admin" /> + } title="로그아웃" size="sm" link="/sign-out" /> + + )} + {auth.isAuth && !auth.isModerator && ( <> } title="마이페이지" size="sm" link="/my-page" /> } title="로그아웃" size="sm" link="/sign-out" /> - ) : ( + )} + {!auth.isAuth && ( 로그인 /회원가입 @@ -66,6 +74,7 @@ const Header = () => { style={{ display: `${isSidebarOpen ? 'block' : 'none'}` }} onClick={() => setIsSideBarOpen(false)} /> + { />
- {auth.isAuth ? ( + {auth.isAuth && auth.isModerator && ( + <> + } title="관리" size="sm" link="/admin" /> + } title="로그아웃" size="sm" link="/sign-out" /> + + )} + {auth.isAuth && !auth.isModerator && ( <> } title="마이페이지" size="sm" link="/my-page" /> } title="로그아웃" size="sm" link="/sign-out" /> - ) : ( - } title="로그인" size="sm" link="/sign-in" /> )} + {!auth.isAuth && } title="로그인" size="sm" link="/sign-in" />}
diff --git a/frontend/src/components/Title/index.tsx b/frontend/src/components/Title/index.tsx index 6437b3d6..1c77647f 100644 --- a/frontend/src/components/Title/index.tsx +++ b/frontend/src/components/Title/index.tsx @@ -1,22 +1,11 @@ -import Link from 'next/link'; - export interface TitleProps { title: string; description?: string; - urlText?: string; - url?: string; } -const Title = ({ title, description, urlText, url }: TitleProps) => ( -
-
-

{title}

- {urlText && url && ( - - {urlText} - - )} -
+const Title = ({ title, description }: TitleProps) => ( +
+

{title}

{description &&
{description}
}
); diff --git a/frontend/src/data/externalLink.ts b/frontend/src/data/externalLink.ts index 7aac8760..00e8e2f8 100644 --- a/frontend/src/data/externalLink.ts +++ b/frontend/src/data/externalLink.ts @@ -10,8 +10,8 @@ export const externalLinkInfos: { title: string; url: string; img: string }[] = img: '/images/main/external_link_2_plato.png', }, { - title: '온라인강좌
(edwith)', - url: 'http://edwith.org/ptnr/pnuswedu', + title: '온라인강좌
(Inflearn)', + url: 'https://www.inflearn.com/users/1370319', img: '/images/main/external_link_3_edwith.png', }, { title: 'TOPCIT', url: 'http://topcit.or.kr/', img: '/images/main/external_link_4_topcit.png' }, @@ -20,7 +20,7 @@ export const externalLinkInfos: { title: string; url: string; img: string }[] = url: 'http://bd.pusan.ac.kr/', img: '/images/main/external_link_5_pnu_achieve.png', }, - { title: 'PNU
Online Judge', url: 'http://oj.pusan.ac.kr/', img: '/images/main/external_link_6_pnu_oj.png' }, + { title: 'PNU
Code Place', url: 'http://code.pusan.ac.kr/', img: '/images/main/external_link_6_pnu_oj.png' }, ]; export const pnuLinkInfos: { title: string; url: string; img: string }[] = [ diff --git a/frontend/src/lib/api/server.api.ts b/frontend/src/lib/api/server.api.ts index 2799fa4f..c11d309a 100644 --- a/frontend/src/lib/api/server.api.ts +++ b/frontend/src/lib/api/server.api.ts @@ -7,6 +7,7 @@ import { MilestoneHistoryDto, MilestoneHistoryOfStudentPageableDto, MilestoneHistoryPageableDto, + MilestoneScoreDto, } from '@/types/common.dto'; import { MilestoneHistorySortCriteria, SortDirection } from '@/types/milestone'; @@ -23,7 +24,7 @@ export async function getMilestoneHistoriesOfStudent( page: number = 0, size: number = 10, ) { - const response = await server + return await server .get(`/milestones/histories/members/${memberId}`, { params: removeEmptyField({ start_date: startDate, @@ -37,11 +38,10 @@ export async function getMilestoneHistoriesOfStudent( }) .then((res) => res.data) .catch((err) => Promise.reject(err)); - return response; } export async function getMilestoneHistories(field?: number, keyword?: string, page: number = 0, size: number = 10) { - const response = await server + return await server .get('/admin/milestones/histories', { params: removeEmptyField({ field, @@ -52,28 +52,36 @@ export async function getMilestoneHistories(field?: number, keyword?: string, pa }) .then((res) => res.data) .catch((err) => Promise.reject(err)); - return response; } export async function getMilestoneHistory(historyId: number) { - const response = await server + return await server .get(`/admin/milestones/histories/${historyId}`) .then((res) => res.data) .catch((err) => Promise.reject(err)); - return response; } export async function getValidationStudentId(studentId: string) { - const response = await server + return await server .get(`/sign-up/exists/student-id`, { params: removeEmptyField({ student_id: studentId, }), }) .then((res) => res.data) - .catch((err) => { - return Promise.reject(err); - }); + .catch((err) => Promise.reject(err)); +} + +export async function getMyMilestoneHistory(studentId: number, startDate: string, endDate: string) { + const response = await server + .get(`/milestones/histories/scores/members/${studentId}`, { + params: removeEmptyField({ + start_date: startDate, + end_date: endDate, + }), + }) + .then((res) => res.data) + .catch((err) => Promise.reject(err)); return response; } diff --git a/frontend/src/mocks/milestone.ts b/frontend/src/mocks/milestone.ts deleted file mode 100644 index 141614dd..00000000 --- a/frontend/src/mocks/milestone.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { MilestoneOverviewScore } from '@/types/milestone'; - -export const milestoneSummaryInfo: MilestoneOverviewScore = { - activityScore: 20, - globalScore: 40, - communityScore: 60, - totalScore: 120, -};