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
-
λ€μν λλ°μ΄μ€ νκ²½ λ° λͺ¨λμμ μ μ°ν μλμ ν μ μλλ‘ UI νλ μμν¬μΈ Tailwindcssλ₯Ό ν΅ν΄ λ°μν λ° λ€ν¬λͺ¨λ λμ
-
Responsice web
-
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 κ° μ μΈ
isError μΌ κ²½μ° error λ©μΈμ§λ₯Ό 보μ¬μ£Όλ UI ꡬμ±
- React Query hooks
π
-
- μλ²λ‘λΆν° data fetchingμ ν΅ν΄ κ°μ Έμ€λ Server stateμ λν μ μ μν κ΄λ¦¬λ₯Ό μν΄ Data fetching λΌμ΄λΈλ¬λ¦¬μΈ React Queryλ₯Ό μ μ©νμ¬ Server State κ΄λ¦¬
-
μ΄λ―Έμ§ Object Stroage μ μ₯
- μ¬μ©μκ° μΌκΈ°λ₯Ό μ μ₯ν κ²½μ° μμ±λλ μΈλ€μΌ μ΄λ―Έμ§μ μ¬μ©μμ νλ‘ν μ΄λ―Έμ§λ₯Ό KiC Object Storage μ μ₯νμ¬ μ¬μ©
-
μ μ©
π
uploadImg.js
KiC API μμ²μ νμ©λ°κΈ° μν Access key λ°κΈ μ΄ν, ν΄λΉ keyλ₯Ό μ¬μ©νμ¬ Object Storageμ μ΄λ―Έμ§ upload μμ²- UI
μ μ₯μ μκ°μ΄ μ’ κ±Έλ¦¬κΈ° λλ¬Έμ μΌκΈ° μ μ₯ λͺ¨λ¬μμ μ μ₯ μ (μΈλ€μΌ μ ν) / μ μ₯μ€ / μ μ₯ μλ£ μνμ λ°λΌ UI λ° μ μ₯ λ²νΌ λΉνμ±νλ₯Ό λ€λ₯΄κ² νμ¬ μ¬μ©μκ° μΌκΈ° μ΅μ’
μ μ₯μ κ³Όμ μμ κΈ°λ€λ¦¬κ² λλ μκ°μ μ€μ! (μ¬μ©μ κ²½ν ν₯μβ)
- μΈλ€μΌ μ μ₯ κ³Όμ
- UI
μ μ₯μ μκ°μ΄ μ’ κ±Έλ¦¬κΈ° λλ¬Έμ μΌκΈ° μ μ₯ λͺ¨λ¬μμ μ μ₯ μ (μΈλ€μΌ μ ν) / μ μ₯μ€ / μ μ₯ μλ£ μνμ λ°λΌ UI λ° μ μ₯ λ²νΌ λΉνμ±νλ₯Ό λ€λ₯΄κ² νμ¬ μ¬μ©μκ° μΌκΈ° μ΅μ’
μ μ₯μ κ³Όμ μμ κΈ°λ€λ¦¬κ² λλ μκ°μ μ€μ! (μ¬μ©μ κ²½ν ν₯μβ)
-
- μ¬μ©μκ° μΌκΈ°λ₯Ό μ μ₯ν κ²½μ° μμ±λλ μΈλ€μΌ μ΄λ―Έμ§μ μ¬μ©μμ νλ‘ν μ΄λ―Έμ§λ₯Ό KiC Object Storage μ μ₯νμ¬ μ¬μ©
-
SEO
- μΉμ¬μ΄νΈκ° κ²μ μμ§μμ μ½κ² λ
ΈμΆλ μ μλλ‘ κ²μ μμ§ μ΅μ ν μ μ©
- μ μ©
-
NAVER
π
DefaultTags.jsx
header.js νμΌμ 곡ν΅μ μΌλ‘ λ€μ΄κ°λ
DefaultTags.jsx
νμΌμ naverμμ μ 곡νλ meta tag μΆκ° -
Google
λλ©μΈ ꡬμ ν μ¬μ΄νΈμμ μ 곡νλ txt λ μ½λ μΆκ°νμ¬ μΈμ¦
-
OpenGraph
-
robots.txt & sitemap.xml
- μΉμ¬μ΄νΈμμ ν¬λ‘€λ§νλ©° μ 보λ₯Ό μμ§νλ κ²μμμ§ ν¬λ‘€λ¬κ° μΉνμ΄μ§λ₯Ό μμ§ν μ μλλ‘ νλ
**robots.txt**
νμΌκ³Ό**sitemap.xml**
νμΌμ μ€μ ν¨
π
robots.txt
π
sitemap.xml
βnext-sitemap
λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νμ¬ νλ‘μ νΈ λΉλ μ μλ μμ±λλλ‘ μ€μ - μΉμ¬μ΄νΈμμ ν¬λ‘€λ§νλ©° μ 보λ₯Ό μμ§νλ κ²μμμ§ ν¬λ‘€λ¬κ° μΉνμ΄μ§λ₯Ό μμ§ν μ μλλ‘ νλ
-
- μ μ©
- μΉμ¬μ΄νΈκ° κ²μ μμ§μμ μ½κ² λ
ΈμΆλ μ μλλ‘ κ²μ μμ§ μ΅μ ν μ μ©
-
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 μ μ©