2022. 08 ~ 2023. 02
git clone https://github.com/KSWA-SWEEP/jaksim31-front.git
cd jaksim31-front
npm install
프로젝트 루트 경로에 환경 변수 파일 설정
⇒ 기본적으로 env 파일 만들어서 설정해주면 되며, .env.local
등 환경에 맞는 파일 추가하여 환경에 따른 변수 설정 가능
📋 .env
NEXT_PUBLIC_UNSPLASH_ACCESSKEY=${Unsplash API Access Key}
NEXT_PUBLIC_BASE_URL=${Backend url - local일 경우 http://localhost:8080}
NEXT_PUBLIC_API_URL=${Frontend url - local일 경우 http://localhost:3000}
# Kakao 로그인을 위한 변수
NEXT_PUBLIC_KAKAO_CLIENT_ID=${Kakao Client ID}
NEXT_PUBLIC_KAKAO_REDIRECT_URL=${Kakao 로그인 후 이동할 redirect url}
# KiC Object Storage
NEXT_PUBLIC_KAKAO_API_AUTH_URL=https://iam.kakaoi.io/identity/v3/auth/tokens
NEXT_PUBLIC_KAKAO_API_AUTH_ACCESSKEY=${Kakao i Cloud API Access Key}
NEXT_PUBLIC_KAKAO_API_AUTH_SECRET=${Kakao i Cloud Auth Secret}
NEXT_PUBLIC_KAKAO_FILE_UPLOAD_URL=${이미지 업로드 경로}
NEXT_PUBLIC_KAKAO_FILE_VIEW_URL=${이미지 조회 경로}
NEXT_PUBLIC_DEFAULT_PROFILE=${default 프로필 이미지 url}
# Google Analytics
NEXT_PUBLIC_GA_TRACKING_ID=${Google Analytics Tracking ID}
- API Key 및 기타 설정 참고
-
Unsplash API Unsplash Image API | Free HD Photo API
-
Kakao 로그인 Kakao Developers
-
Object Storage Object Storage
-
# development 환경 실행 시
npm run dev
# production 환경 실행 시
npm run build
npm start
- JavaScript
- CSS
📋 package.json
...
"dependencies": {
// Next.js - 13 버전 사용
"next": "13.1.1",
// React - 18 버전 사용
"react": "18.2.0",]
"react-dom": "18.2.0",
// 📄 UI
// Tailwind Component Library - modal, popup 등 사용
"daisyui": "^2.46.1",
"@headlessui/react": "^1.7.7",
// SVG icon Library
"@heroicons/react": "^2.0.13",
// 일기 작성을 위한 Editor Library
"@ckeditor/ckeditor5-react": "^5.0.5",
"ckeditor5-custom-build": "file:ckeditor5",
// nextjs 13의 next/font
"@next/font": "^13.1.1",
// Positioning Library - 툴팁 및 팝오버 요소가 컴포넌트 영역 밖에서 잘리는 현상 해결
"@popperjs/core": "^2.11.6",
// SVG 이미지를 사용하기 위한 Library
"@svgr/webpack": "^6.5.1",
// 대시보드의 차트들을 그리기 위한 Library
"chart.js": "^2.9.4",
// Animation Library
"framer-motion": "^8.2.4",
"react-transition-group": "^4.4.5",
// 스크롤바 숨기기 Library
"tailwind-scrollbar-hide": "^1.1.7"
// 📄 기타 기능
// Classname joining library - 케이스에 따라 클래스명 변경하거나 조건 추가할 경우 사용
"classnames": "^2.3.2",
// 쿠키 값을 읽거나 변경하기 위한 Library
"cookies-next": "^2.1.1",
// 환경변수 설정(.env 파일)을 위한 Library
"dotenv": "^16.0.3",
"dotenv-webpack": "^8.0.1",
// 이메일 인증 Library - 회원 가입 시 이메일 인증 사용
"emailjs-com": "^3.2.0",
// 날짜 Library
"moment": "^2.29.4",
// SEO - sitemap 자동 생성 Library
"next-sitemap": "^3.1.50",
// Calendar Library - custom 디자인 해서 사용
"react-calendar": "^4.0.0",
// Datepicker Library
"react-datepicker": "^4.8.0",
// Pagination Library -
"react-js-pagination": "^3.0.3",
// Data Fetching Library
"react-query": "^3.39.2",
// Image Optimization Library
"sharp": "^0.31.3",
// 📄 Test
// E2E Test
"@cypress/react18": "^2.0.0",
// Mocking Library
"intersection-observer": "^0.12.2",
// Type check Library
"prop-types": "^15.8.1",
}
...
📙 jaksim31-front
├─ 📁 app
│ ├─ common
│ │ ├─ Drawer.jsx
│ │ ├─ header
│ │ │ ├─ Header.jsx
│ │ │ ├─ loading.js
│ │ │ ├─ Login.js
│ │ │ └─ Profile.js
│ │ ├─ LazyShow.js
│ │ └─ Tutorial.js
│ ├─ home
│ │ ├─ landing
│ │ │ ├─ ExampleScreen.js
│ │ │ └─ page.jsx
│ │ ├─ page.jsx
│ │ └─ tutorial
│ │ └─ page.jsx
│ ├─ diary
│ │ ├─ common
│ │ │ ├─ backButton.js
│ │ │ ├─ diaryInputFormat.js
│ │ │ ├─ Editor.js
│ │ │ └─ loading.js
│ │ ├─ create
│ │ │ └─ [date]
│ │ │ ├─ createDiary.js
│ │ │ └─ page.jsx
│ │ ├─ dashboard
│ │ │ ├─ BarChartCard.js
│ │ │ ├─ DonutChartCard.js
│ │ │ ├─ layout.jsx
│ │ │ ├─ page.jsx
│ │ │ ├─ ProfileCard.js
│ │ │ └─ RecentDiaryCard.js
│ │ ├─ list
│ │ │ ├─ calendar
│ │ │ │ ├─ Calendar.css
│ │ │ │ ├─ calendarList.js
│ │ │ │ ├─ loading.js
│ │ │ │ └─ page.jsx
│ │ │ ├─ DateRangePicker.js
│ │ │ ├─ grid
│ │ │ │ ├─ error.js
│ │ │ │ ├─ gridList.js
│ │ │ │ ├─ loading.js
│ │ │ │ ├─ page.jsx
│ │ │ │ └─ Pagination.css
│ │ │ ├─ layout.jsx
│ │ │ ├─ ListBox.js
│ │ │ ├─ page.jsx
│ │ │ └─ ViewTypeTab.js
│ │ ├─ page.jsx
│ │ └─ [diaryId]
│ │ ├─ diaryContents.js
│ │ ├─ loading.js
│ │ ├─ modify
│ │ │ ├─ date.js
│ │ │ ├─ loading.js
│ │ │ └─ page.jsx
│ │ └─ page.jsx
│ ├─ globals.css
│ ├─ head.jsx
│ ├─ layout.jsx
│ ├─ loading.js
│ ├─ page.module.css
│ ├─ page.jsx
│ ├─ api
│ │ ├─ addDiary.js
│ │ ├─ analyzeDiary.js
│ │ ├─ checkIsMember.js
│ │ ├─ checkPassword.js
│ │ ├─ deleteDiary.js
│ │ ├─ getDiary.js
│ │ ├─ getDiaryList.js
│ │ ├─ getEmotionCount.js
│ │ ├─ getKakaoApiAccessKey.js
│ │ ├─ getUserInfo.js
│ │ ├─ login.js
│ │ ├─ logout.js
│ │ ├─ modifyDiary.js
│ │ ├─ signUp.js
│ │ ├─ updatePassword.js
│ │ ├─ updateUserInfo.js
│ │ └─ uploadImg.js
│ ├─ hooks
│ │ ├─ mutations
│ │ │ ├─ useDiaryDelete.js
│ │ │ ├─ useDiarySave.js
│ │ │ ├─ useLogin.js
│ │ │ ├─ useLogout.js
│ │ │ └─ useUserInfoUpdate.js
│ │ └─ queries
│ │ ├─ useDiaryListPageQuery.js
│ │ ├─ useDiaryListQuery.js
│ │ ├─ useDiaryQuery.js
│ │ ├─ useEmotionCountQuery.js
│ │ └─ useUserInfoQuery.js
│ └─ ReactQueryWrapper.jsx
│
├─ 😺 .github
│ └─ workflows
│ └─ github-action.yml
│
├─ 🧪 cypress
│ ├─ downloads
│ ├─ e2e
│ │ ├─ diary
│ │ │ ├─ diaryEdit.cy.js
│ │ │ ├─ diaryList.cy.js
│ │ │ └─ diarySave.cy.js
│ │ └─ member
│ │ ├─ userInfo.cy.js
│ │ └─ userLogin.cy.js
│ ├─ fixtures
│ │ └─ example.json
│ └─ support
│ ├─ commands.js
│ └─ e2e.js
│
├─ 📦 public
│ ├─ jaksim31.ico
│ ├─ images
│ │ ├─ emotion
│ │ │ ├─ bad-small.png
│ │ │ ├─ bad.png
│ │ │ ├─ bored-small.png
│ │ │ ├─ bored.png
│ │ │ ├─ embarrassed-small.png
│ │ │ ├─ embarrassed.png
│ │ │ ├─ good-small.png
│ │ │ ├─ good.png
│ │ │ ├─ nothing-small.png
│ │ │ ├─ nothing.png
│ │ │ ├─ sad-small.png
│ │ │ ├─ sad.png
│ │ │ ├─ scared-small.png
│ │ │ ├─ scared.png
│ │ │ ├─ surprised-small.png
│ │ │ ├─ surprised.png
│ │ │ ├─ unsure-small.png
│ │ │ └─ unsure.png
│ │ ├─ gradient.jpg
│ │ ├─ kakaoLogin.png
│ │ ├─ landing-example.webp
│ │ ├─ paperTexture.jpg
│ │ └─ tutorial
│ │ ├─ calendar.webp
│ │ ├─ create.webp
│ │ ├─ drawer.webp
│ │ ├─ dashboard.webp
│ │ ├─ grid.webp
│ │ ├─ login.webp
│ │ └─ signUp.webp
│ ├─ next.svg
│ ├─ svgs
│ │ └─ spinner.svg
│ ├─ thirteen.svg
│ └─ vercel.svg
│
├─ 📖 README.md
├─ 🐳 Dockerfile
├─ package.json
├─ next.config.js
├─ cypress.config.js
├─ postcss.config.js
└─ tailwind.config.js
작심삼일은 반응형 웹으로 구현되었기에, React Native를 통해 앱으로도 구현 및 출시가 진행되었습니다.
Google Play Sotre에서 다운로드 할 수 있으며, 웹앱으로 구현되어 웹사이트에서 사용할 수 있는 모든 기능들을 동일하게 사용할 수 있습니다.
Google Play - Jaksim31 링크
- 키워드 Custom 기능 - 추출된 키워드에 대해 수정 및 추가하는 기능
- 일기 공유 및 공개 게시 기능 - 작성한 일기를 공유하거나 공개 게시하는 등의 기능
- 친구 & 댓글, 좋아요 기능 - 사용자간 친구를 맺어 서로의 일기를 조회하고 댓글, 좋아요 등을 남길 수 있는 기능
-
썸네일 이미지 생성
- 사용자들에게 다양한 썸네일 이미지를 제공하기 위해 Unsplash 의 Search photos by keyword API를 사용하여 이미지 가져옴
-
일기 작성 ( CKEditor )
- 사용자들이 일기에 다양한 글씨 크기, 색상, 폰트 등을 설정할 수 있도록 JavaScript 기반의 에디터인 CKEditor를 적용함 (버전 5)
-
CKEditor Customize 필요 기능들을 넣어 CKEditor Customize하여 사용
CKEditor5 Online Builder 링크 -
사용 📋
Editor.js
-
- 사용자들이 일기에 다양한 글씨 크기, 색상, 폰트 등을 설정할 수 있도록 JavaScript 기반의 에디터인 CKEditor를 적용함 (버전 5)
-
Responsive & Dark Mode
-
Server State 관리
- 서버로부터 data fetching을 통해 가져오는 Server state에 대한 전역 상태 관리를 위해 Data fetching 라이브러리인 React Query를 적용하여 Server State 관리
-
적용 📋
app/layout.jsx
루트 경로의 layout(📄
app/layout.jsx
)에서 하위 컴포넌트들에 대해 자체적으로 만든 React Query 컴포넌트인 **<ReactQueryWrapper>
**로 감싸주어 모든 페이지에 대해 하나의 query client를 갖는 상태 적용📋
app/ReactQueryWrapper.js
**
QueryClientProvider
**를 통해 queryClient default 설정을 해주고, 개발 시 편리를 위해 **ReactQueryDevtools
**를 설정하였으며, queryClient 설정 시 query client에 대한 기본 설정- React Query hooks
📁
app/hooks
경로 내에 React Query hook들에 대한 함수를 만들어두어 해당 hook이 필요한 컴포넌트들 내에서 간단하게 가져다 쓸 수 있도록 함
📋
useDiaryListQuery.js
api fetch 한 이후 만약 response를 제대로 받아오지 못한 경우(= 에러 발생의 경우 = response data에 errorCode가 포함된 경우) error throw
📋
calendarList.js
useDiaryListQuery 선언 시 error 메세지를 받아올 error와 error 상태에 대한 isError 값 선언
- React Query hooks
-
- 서버로부터 data fetching을 통해 가져오는 Server state에 대한 전역 상태 관리를 위해 Data fetching 라이브러리인 React Query를 적용하여 Server State 관리
-
이미지 Object Stroage 저장
-
SEO
-
Google Analytics
- 방문자의 유입 출처를 확인하거나, 사용자 행동을 파악하는 등 유용한 정보를 수집하고 저장하여 분석하고자 구글에서 무료로 제공하는 웹 로그분석 툴인 Google Analytics 적용
-
적용
📋
layout.jsx
export default function RootLayout({ children }) { return ( <html> <head /> <body> ... **{/* Google Analytics */} <script strategy="afterInteractive" src={`https://www.googletagmanager.com/gtag/js?id=${process.env.NEXT_PUBLIC_GA_TRACKING_ID}`} /> <script id="gtag-init" strategy="afterInteractive" dangerouslySetInnerHTML={{ __html: ` window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', '${process.env.NEXT_PUBLIC_GA_TRACKING_ID}', { page_path: window.location.pathname, }); ` }} />** ... </body> </html> ) }
-
- 방문자의 유입 출처를 확인하거나, 사용자 행동을 파악하는 등 유용한 정보를 수집하고 저장하여 분석하고자 구글에서 무료로 제공하는 웹 로그분석 툴인 Google Analytics 적용