Skip to content

Commit

Permalink
♻️ 세미나 페이지 리팩토링 (#49)
Browse files Browse the repository at this point in the history
* 세미나 페이지 리팩토링

* 리뷰 반영

* 리뷰 반영
  • Loading branch information
whwoohw authored Aug 23, 2023
1 parent db23fba commit 6cad046
Show file tree
Hide file tree
Showing 6 changed files with 152 additions and 128 deletions.
32 changes: 19 additions & 13 deletions apis/seminar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,41 +19,48 @@ export const getMockSeminarPosts: typeof getSeminarPosts = async (
const startDate = new Date('2023-01-10');
const endDate = new Date('2022-12-25');

const seminarList = Array.from({ length: 16 }, (_, index) => {
const searchList = Array.from({ length: 16 }, (_, index) => {
const currentDate = new Date(startDate);
currentDate.setDate(startDate.getDate() - index);
const isLast = index === 0 || index === 10;

return {
id: index + 1,
title: `세미나 ${index + 1}`,
host: `박순일 (Souneil Park)`,
company: `Telefonica Research, Barcelona`,
date: currentDate.toISOString(),
name: `박순일 (Souneil Park)`,
affiliation: `Telefonica Research, Barcelona`,
startDate: currentDate.toISOString(),
location: `302동 209호`,
imageURL:
'https://cse.snu.ac.kr/sites/default/files/styles/medium-small-focus/public/node--seminar/%EB%B0%95%EC%88%9C%EC%9D%BC%20%EB%B0%95%EC%82%AC%20%EC%82%AC%EC%A7%84.jpg?itok=n-iHZlh9',
isLast: isLast,
isYearLast: isLast,
};
});

return {
total: 50,
seminarList,
searchList,
};
};

export const getMockSeminarPost: typeof getSeminarPost = async (id: number) => {
return {
id: id,
title: `${id}번째 세미나`,
host: '박순일 (Souneil Park)',
company: 'Telefonica Research, Barcelona',
professor: '이영기 교수',
date: '2023년 7월 24일 월요일 AM 10:30 - 2023년 7월 24일 월요일 AM 11:30',
name: '박순일 (Souneil Park)',
category: '',
speakerUrl: 'https://dial.skku.edu/members/jongwuk_lee',
speakerTitle: '부교수',
affiliation: 'Telefonica Research, Barcelona',
affiliationUrl: 'https://cs.skku.edu/ko/people/faculty_main',
host: '이영기 교수',
startDate: '2023년 7월 24일 월요일',
startTime: 'AM 10:30',
endDate: '2023년 7월 24일 월요일',
endTime: 'AM 11:30',
location: '302동 209호',
description: `In this talk, I will present my works on diversity exposure and social inclusion. Across the globe, rising inequality and political polarization is dismantling common spaces where people from different backgrounds come together. As market mechanisms deeply permeate our society, people make diverging choices about where to live, work, or attend school, even where to shop, socialize, or which hospitals to visit. This societal fragmentation is also mirrored in online spaces, in the choices of news, political contents, social network, and online communities. People increasingly lose common ground and opportunities to build social empathy and collective problem solving skills, which ultimately threatens the democracy and resilience of the society. In the first half, I will present my early works that develop AI and interactive systems that empower people to compare and contrast different ideological viewpoints and practice media literacy in their daily news browsing sessions. The next part will cover my recent works that approach the problem from the dimension of geography and urbanism, and explore social polarization and isolation of activity spaces through data-driven methods.`,
hostDescription: `Souneil Park is currently at Telefonica Research in Barcelona, and he leads innovation initiatives in mobility at Telefónica. With a background in computational social science, his recent works focus on studying social dynamics in urban spaces by examining large-scale mobility. The results have been published in top-tier venues across both computer science and social sciences. Additionally, he currently serves as the co-PI of the H2020 EU project "SPATIAL - Security and Privacy Accountable Technology Innovations, Algorithms, and machine Learning", which has been awarded €5 million in funding. Before joining Telefónica, he worked on technologies to mitigate media bias and contributed to the field of computational journalism through pioneering works. He holds a PhD in computer science from KAIST and completed a postdoctoral research position under Paul Resnick at the University of Michigan.`,
introduction: `Souneil Park is currently at Telefonica Research in Barcelona, and he leads innovation initiatives in mobility at Telefónica. With a background in computational social science, his recent works focus on studying social dynamics in urban spaces by examining large-scale mobility. The results have been published in top-tier venues across both computer science and social sciences. Additionally, he currently serves as the co-PI of the H2020 EU project "SPATIAL - Security and Privacy Accountable Technology Innovations, Algorithms, and machine Learning", which has been awarded €5 million in funding. Before joining Telefónica, he worked on technologies to mitigate media bias and contributed to the field of computational journalism through pioneering works. He holds a PhD in computer science from KAIST and completed a postdoctoral research position under Paul Resnick at the University of Michigan.`,
imageURL:
'https://cse.snu.ac.kr/sites/default/files/styles/medium-small-focus/public/node--seminar/%EB%B0%95%EC%88%9C%EC%9D%BC%20%EB%B0%95%EC%82%AC%20%EC%82%AC%EC%A7%84.jpg?itok=n-iHZlh9',
prevId: id - 1,
Expand All @@ -64,7 +71,6 @@ export const getMockSeminarPost: typeof getSeminarPost = async (id: number) => {
modifiedAt: new Date().toISOString(),
isPublic: true,
isSlide: true,
isLast: false,
attachment: '',
additionalNote: '',
};
};
53 changes: 31 additions & 22 deletions app/community/seminar/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
'use client';

import Image from 'next/image';
import { useParams } from 'next/navigation';
import { useCallback, useEffect, useState } from 'react';
import Link from 'next/link';

import { getMockSeminarPost } from '@/apis/seminar';

Expand All @@ -21,26 +20,13 @@ import { getPath } from '@/utils/page';
const seminarPath = getPath(seminar);

export default function SeminarPostPage() {
let { currPost, nextPostPreview, prevPostPreview, listPathWithQuery } =
const { currPost, nextPostPreview, prevPostPreview, listPathWithQuery } =
usePosts<SeminarPostResponse>(seminarPath, getMockSeminarPost);

const id = parseInt(useParams().id);
const [mockdata, setMockdata] = useState<SeminarPostResponse>();
const fetchSeminarPost = useCallback(async () => {
const res = await getMockSeminarPost(id);
setMockdata(res);
}, [id]);

useEffect(() => {
fetchSeminarPost();
}, [fetchSeminarPost]);

currPost ||= mockdata;

return (
currPost && (
<PageLayout title={currPost.title} titleType="small" titleMargin="mb-5">
<div className="mb-9 text-sm font-yoon text-neutral-700 leading-[1.63rem] flow-root break-all">
<div className="mb-9 text-sm font-noto text-neutral-700 leading-[1.63rem] flow-root break-all">
<Attachment />
<div className="relative float-right ml-7 mt-4 mb-7 w-60 h-60">
<Image
Expand All @@ -52,17 +38,40 @@ export default function SeminarPostPage() {
sizes="240px"
/>
</div>
<div>이름: {currPost.host}</div>
<div>소속: {currPost.company}</div>
<div>
이름:{' '}
{currPost.speakerUrl ? (
<Link className="text-link hover:underline" href={currPost.speakerUrl}>
{currPost.name}
</Link>
) : (
<p>{currPost.name}</p>
)}
</div>

<div className="mt-12">주최: {currPost.professor}</div>
<div>일시: {currPost.date}</div>
{currPost.speakerTitle && <p>직함: {currPost.speakerTitle}</p>}

<div>
소속:{' '}
{currPost.affiliationUrl ? (
<Link className="text-link hover:underline" href={currPost.affiliationUrl}>
{currPost.affiliation}
</Link>
) : (
<p>{currPost.affiliation}</p>
)}
</div>

<div className="mt-10">주최: {currPost.host}</div>
<div>
일시: {currPost.startDate} {currPost.startTime} - {currPost.endDate} {currPost.endTime}
</div>
<div>장소: {currPost.location}</div>

<div className="font-bold mt-12">요약</div>
<div>{currPost.description}</div>
<div className="font-bold mt-12">연사 소개</div>
<div>{currPost.hostDescription}</div>
<div>{currPost.introduction}</div>
</div>
<StraightNode />
<AdjPostNav
Expand Down
115 changes: 40 additions & 75 deletions app/community/seminar/page.tsx
Original file line number Diff line number Diff line change
@@ -1,99 +1,64 @@
'use client';

import { useCallback, useEffect, useState } from 'react';
import useSWR from 'swr';

import { getMockSeminarPosts } from '@/apis/seminar';

import Pagination from '@/components/common/Pagination';
import PageLayout from '@/components/layout/pageLayout/PageLayout';
import SeminarSearchBar from '@/components/seminar/SearchBar';
import SeminarRow from '@/components/seminar/SeminarRow';
import SeminarYear from '@/components/seminar/SeminarYear';

import { useCustomSearchParams } from '@/hooks/useCustomSearchParams';

import { seminar } from '@/types/page';
import { GETSeminarPostsResponse, SimpleSeminarPost } from '@/types/post';

const postsCountPerPage = 10;

interface SeminarListWithYear extends SimpleSeminarPost {
year?: number;
}

export default function SeminarPage() {
const { page, keyword, setSearchParams } = useCustomSearchParams();
const [totalPostsCount, setTotalPostsCount] = useState(0);
const [posts, setPosts] = useState<SeminarListWithYear[]>([]);

const setCurrentPage = (pageNum: number) => {
setSearchParams({ purpose: 'navigation', page: pageNum });
};

const fetchPost = useCallback(async () => {
const res = await getMockSeminarPosts({
keyword: keyword === null ? undefined : keyword,
page: page,
});

const postsWithYear: SeminarListWithYear[] = [];

res.seminarList.forEach((post) => {
const postYear = new Date(post.date).getFullYear();

if (post.isLast) {
postsWithYear.push({
...post,
year: postYear,
});
} else {
postsWithYear.push({
...post,
});
}
});

setTotalPostsCount(res.total);
setPosts(postsWithYear);
}, [keyword, page]);

useEffect(() => {
fetchPost();
}, [fetchPost]);
const { data, isLoading, error } = useSWR(
{ url: '/seminar', params: { keyword, page } },
getMockSeminarPosts,
);

return (
<PageLayout titleType="big" titleMargin="mb-6">
<div className="flex flex-row items-center gap-6">
<h3 className="text-neutral-700 font-yoon text-md font-bold w-7 text-center leading-[1.2rem]">
검색
</h3>
<SeminarSearchBar setSearchParams={setSearchParams} />
</div>
<div className="flex flex-col mt-10 mb-8">
{posts.map((post, i) => (
<div key={post.year}>
{post.isLast && (
<div className={`border-b-[1px] border-neutral-500 ${i !== 0 ? 'mt-12' : null}`}>
<h3 className="text-neutral-700 font-noto text-[1.25rem] font-bold pb-[.69rem] w-[4.5rem] text-center leading-7">
{post.year}
</h3>
</div>
)}
<SeminarRow
title={post.title}
host={post.host}
company={post.company}
date={new Date(post.date)}
location={post.location}
imageURL={post.imageURL}
/>
</div>
))}
</div>
<Pagination
totalPostsCount={totalPostsCount}
postsCountPerPage={postsCountPerPage}
currentPage={page}
setCurrentPage={setCurrentPage}
/>
</PageLayout>
data && (
<PageLayout titleType="big" titleMargin="mb-6">
<div className="flex flex-row items-center gap-6">
<h3 className="text-neutral-700 font-yoon text-md font-bold w-7 text-center leading-[1.2rem]">
검색
</h3>
<SeminarSearchBar setSearchParams={setSearchParams} />
</div>
<div className="flex flex-col mt-10 mb-8 border-neutral-200 border-b-[1px]">
{data.searchList.map((post, index) => (
<div key={post.id}>
{post.isYearLast && <SeminarYear index={index} startDate={post.startDate} />}
<SeminarRow
id={post.id}
title={post.title}
host={post.name}
company={post.affiliation}
date={new Date(post.startDate)}
location={post.location}
imageURL={post.imageURL}
isYearLast={post.isYearLast}
/>
</div>
))}
</div>
<Pagination
totalPostsCount={data.total}
postsCountPerPage={postsCountPerPage}
currentPage={page}
setCurrentPage={setCurrentPage}
/>
</PageLayout>
)
);
}
35 changes: 27 additions & 8 deletions components/seminar/SeminarRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,45 @@ import Link from 'next/link';

import SnuLogo from '@/public/image/SNU_Logo.svg';

import { useQueryString } from '@/hooks/useQueryString';

import { seminar } from '@/types/page';

import { formatDateWithDays } from '@/utils/formatting';
import { getPath } from '@/utils/page';

export interface SeminarRowProps {
id: number;
title: string;
host: string;
company: string;
date: Date;
location: string;
imageURL?: string;
isYearLast: boolean;
}

const seminarPath = getPath(seminar);

export default function SeminarRow({
id,
title,
host,
company,
date,
location,
imageURL,
isYearLast,
}: SeminarRowProps) {
const queryString = useQueryString();
return (
<article className="text-neutral-700 font-noto flex py-[1.2rem] border-b-[1px] border-neutral-200 ">
<article
className={`text-neutral-700 font-noto flex py-[1.2rem] border-neutral-200 ${
!isYearLast ? 'border-t-[1px]' : null
}`}
>
<Link
href=""
href={`${seminarPath}/${id}${queryString}`}
className={`flex items-center justify-center h-[6.25rem] w-[6.25rem] relative ${
!imageURL && 'bg-neutral-100'
}`}
Expand All @@ -37,11 +53,14 @@ export default function SeminarRow({
)}
</Link>
<div className="flex flex-col items-start pl-5 break-all">
<Link href="" className="hover:underline">
<Link href={`${seminarPath}/${id}${queryString}`} className="hover:underline">
<h3 className="text-md font-bold mb-[.63rem] leading-5">{title}</h3>
</Link>

<Link href="" className="hover:cursor-pointer flex flex-row leading-[1.63rem] items-center">
<Link
href={`${seminarPath}/${id}${queryString}`}
className="hover:cursor-pointer flex flex-row leading-[1.63rem] items-center"
>
<span className="material-symbols-rounded font-light text-[1.25rem] cursor-default text-neutral-400">
person
</span>
Expand All @@ -50,17 +69,17 @@ export default function SeminarRow({
<p className="text-xs font-normal ">{company}</p>
</Link>
<Link
href=""
className="hover:cursor-pointer flex flex-row leading-[1.63rem] items-center gap-x-1"
href={`${seminarPath}/${id}${queryString}`}
className="hover:cursor-pointer flex flex-row leading-[1.63rem] items-center"
>
<span className="material-symbols-rounded font-light text-lg cursor-default text-neutral-400">
calendar_month
</span>
<p className="text-xs font-normal ">{formatDateWithDays(date)}</p>
<p className="text-xs font-normal mx-1">{formatDateWithDays(date)}</p>
<span className="material-symbols-rounded font-light text-lg cursor-default text-neutral-400">
distance
</span>
<p className="text-xs font-normal ">{location}</p>
<p className="text-xs font-normal ml-[1.5px]">{location}</p>
</Link>
</div>
</article>
Expand Down
15 changes: 15 additions & 0 deletions components/seminar/SeminarYear.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export interface SeminarYearProps {
index: number;
startDate: string;
}

export default function SeminarYear({ index, startDate }: SeminarYearProps) {
const seminarYear = new Date(startDate).getFullYear();
return (
<div className={`border-b-[1px] border-neutral-500 ${index !== 0 ? 'mt-12' : null}`}>
<h3 className="text-neutral-700 font-noto text-[1.25rem] font-bold pb-[.69rem] w-[4.5rem] text-center leading-7">
{seminarYear}
</h3>
</div>
);
}
Loading

0 comments on commit 6cad046

Please sign in to comment.