Frontend Spec
- Language : TypeScript
- Framework : Next.js
- Library : Axios, Moment.js, react-paginate, react-quill, next/Image, react-slick
- CSS : Sass
- IDE : Visual Studio Code
- Git Hooks : Husky, Prettier, ESLint
이론 관련 문서화 내용들
JavaScript에서 화살표 함수와 function 함수의 차이점
https://time-map-installer.tistory.com/233
고도화 주제 탐색 중 SEO 향상 방법에 관한 탐색 진행
https://time-map-installer.tistory.com/225
서비스가 복잡해짐에 따라 상태관리의 필요성을 느껴 알아본 관련 상태관리 툴들
https://time-map-installer.tistory.com/224
일관된 코드 템플릿 적용을 위한 코드 품질 및 일관성 유지 도구 탐색
https://time-map-installer.tistory.com/211
Type 관련 네이밍 통일을 위한 type과 interface의 차이점 탐색
https://time-map-installer.tistory.com/197
유지보수를 위한 폴더구조 설정 중 Hooks, Utils의 차이점 인식을 위한 탐색
https://time-map-installer.tistory.com/196
담당 주 작업 페이지 : MainPage
총 5개의 구역으로 이루어져 있으며 아래와 같이 나뉩니다.
1번 구역 - Calendar Section
Calendar 컴포넌트가 들어가있는 곳
- Moment.js 를 활용하여 날짜 관련된 작업 수행
- 현재 달에 해당하는 날 뿐만아니라 이전, 다음달에 해당하는 일부 일을 가지고 오는 작업 수행(사진 참고)
- 개인 일정이 있는 날에는 하단에 붉은 점을, 배너를 통해 가져온 일정이 있으면 하단에 주황 점을 나타내도록 함
- 특정 날짜 클릭 시 현재 선택된 날짜를 클릭된 날짜로 변경
- 회색으로 되어있는 다른 달의 날을 클릭할 경우 현재 위치해있는 월을 해당 월로 변경
- (사진에서 7월 7일 누를 시 7월로 테이블 변경 이벤트 발생)
// CalendarTable(날짜를 나타내는 부분 일부 코드 발췌)
let result: JSX.Element[] = [];
let week = firstWeek;
for (week; week <= lastWeek || result.length < 6; week++) {
result = result.concat(
<tr key={week}>
{Array(7)
.fill(0)
.map((data, index) => {
let days = today
.clone()
.startOf('year')
.week(week)
.startOf('week')
.add(index, 'day');
const buttonColor =
moment().format('YYYYMMDD') === days.format('YYYYMMDD')
? 'yellow'
: recentlyClickedDay?.format('YYYYMMDD') ===
days.format('YYYYMMDD')
? 'green'
: days.format('MM') !== today.format('MM')
? 'lightgray'
: 'inherit';
return (
<td key={index}>
<button
onClick={() => handleClick(days)}
style={{ backgroundColor: buttonColor }}
>
<span>{days.format('D')}</span>
<br />
<span
style={{
color: hasEvent(days, tasks) ? 'red' : 'transparent',
}}
>
•
</span>
<span
style={{
color: hasBannerEvent(days, bannerTasks)
? 'orange'
: 'transparent',
}}
>
•
</span>
</button>
</td>
);
})}
</tr>,
);
}
2번 구역 - Routine Section
Routine 컴포넌트가 들어가있는 곳, 관련 CRUD가 진행되는 위치
개인 일정 추가할 때 위 위치에서 폼이 생성됨 - 컴포넌트 간 소통 작업 진행
- React의 디자인 패턴 중 Lift up state 패턴을 사용하여 컴포넌트간 상호작용 구현
// CalendarProps, 여기서 onAddTaskClick을 통해 폼 생성 요청 보냄
interface CalendarProps {
onTasksChange: (tasks: TaskInfoType[]) => void;
onBannerTasksChange: (tasks: BannerTaskInfoType[]) => void;
onAddTaskClick: () => void;
}
const Calendar: React.FC<CalendarProps> = ({
onAddTaskClick,
onTasksChange,
onBannerTasksChange,
}) => {
...
return(
<button onClick={onAddTaskClick}>+ 일정 추가하기</button>
);
...
}
// MainPage, 여길 통해 Routine Component로 인자 전달
const [showForm, setShowForm] = useState(false);
const handleShowForm = () => {
setShowForm(!showForm);
};
...
return(
...
{/* 달력 컴포넌트 */}
<Calendar
onTasksChange={setSelectedTasks}
onBannerTasksChange={setSelectedBannerTasks}
onAddTaskClick={handleShowForm}
// onBannerTasksChange={handleBannerTasksChange}
/>
{/* Routine 컴포넌트 */}
<RoutineMain
selectedTasks={selectedTasks}
selectedBannerTasks={selectedBannerTasks}
setSelectedTasks={setSelectedTasks}
showForm={showForm}
setShowForm={setShowForm}
onUpdateSelectedBannerTask={updateBannerSelectedTask}
onUpdateSelectedTask={updateSelectedTask}
/>
...
)
// Routine 컴포넌트, MainPage를 통해 받아온 상태값을 전달
const RoutineMain: React.FC<RoutineMainProps> = ({
selectedTasks,
selectedBannerTasks,
showForm,
setShowForm,
onUpdateSelectedTask,
setSelectedTasks,
onUpdateSelectedBannerTask,
}) => {
3번 구역 - UserInfo Section
간단한 Info를 보여주는 위치
사용자의 정보를 불러와서 보여준다
4번 구역 - SpecialRoutine Section
Special Routine 관련 컴포넌트가 들어가있는 공간
현재 바로 다음에 어떤 일정이 올 지 가져오는 기능이 구현되어 있음
status를 추가하여 현재 일정 진행중인지, 시작 전인 지 여부 구현
현재 시간과 지정된 시간 사이의 차이를 일정 시간마다 다시 확인해서 업데이트
// 관련 코드 중 일부
const [routineStatus, setRoutineStatus] = useState<string>('');
const [nextRoutineData, setNextRoutineData] = useState<
TaskInfoType | undefined
>(undefined);
useEffect(() => {
const fetchData = async () => {
const data = await getSingleRoutine(1);
// console.log(data);
if (data) {
setNextRoutineData(data);
const interval = setInterval(() => {
const currentTime = new Date().getTime();
const startAtTime = new Date(data.startAt).getTime();
const endAtTime = new Date(data.endAt).getTime();
const timeDiff = endAtTime - currentTime;
const days = Math.floor(timeDiff / (1000 * 60 * 60 * 24));
const hours = Math.floor(
(timeDiff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60),
);
const minutes = Math.floor(
(timeDiff % (1000 * 60 * 60)) / (1000 * 60),
);
setTimeLeft({ days, hours, minutes });
if (currentTime < startAtTime && !data.isFinished) {
setRoutineStatus('시작 전');
} else if (
currentTime >= startAtTime &&
currentTime < endAtTime &&
!data.isFinished
) {
setRoutineStatus('진행 중');
} else {
setRoutineStatus('종료');
clearInterval(interval);
}
}, 1000);
return () => {
clearInterval(interval);
};
}
};
fetchData();
}, []);
5번 구역 - Banner Slider Section
다른 사용자들이 추가한 Banner을 불러오는 기능 구현
직접 이미지를 넘길수도 있지만 일정 시간마다 다음 이미지로 넘어가게 두어 여러 프로모션 배너를 사용자들이 볼 수 있도록 함
const settings = {
dots: false,
infinite: true,
autoplay: true,
autoplaySpeed: 3000,
slidesToShow: 2,
slidesToScroll: 1,
};
return(
<Slider {...settings}>
{/*여기에 Slider 구현*/}
</Slider>
);
관련 정보를 수정하고 가독성 향상과 유지보수를 위해 분리, next/Image 라이브러리를 이용하여 이미지 로드
react-slick 라이브러리를 활용하여 슬라이더 기능 구현
+ Frontend Part 진행상황
+ Backend Part 진행상황
End
'활동내역.zip > Techeer' 카테고리의 다른 글
[2nd Good Night Hackathon] 해커톤 프레임워크 어떤걸로 할까? Svelte Go? (0) | 2023.08.28 |
---|---|
[실리콘밸리 해커톤] 방방고(iOS) (0) | 2023.06.20 |
[Project : HQRoutine] 테커인의 낮, 즐거웠던 POC 중간발표의 날 (0) | 2023.05.11 |
[Project : HQRoutine] 7~8차 스프린트 패치노트 (0) | 2023.04.28 |
[Project : HQRoutine] 6차 스프린트 회고 (0) | 2023.04.16 |