diff --git a/next-i18next.config.js b/next-i18next.config.js deleted file mode 100644 index 5e1ff69..0000000 --- a/next-i18next.config.js +++ /dev/null @@ -1,11 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-require-imports -const path = require('path'); - -module.exports = { - i18n: { - locales: ['ko', 'en'], - defaultLocale: 'ko', - }, - reloadOnPrerender: true, - localePath: path.resolve('./public/locales'), // 절대 경로 사용 -}; diff --git a/next-i18next.config.ts b/next-i18next.config.ts new file mode 100644 index 0000000..7f29f16 --- /dev/null +++ b/next-i18next.config.ts @@ -0,0 +1,14 @@ +import path from 'path'; +import type { UserConfig } from 'next-i18next'; + +const nextI18NextConfig: UserConfig = { + i18n: { + locales: ['ko', 'en'], + defaultLocale: 'ko', + localeDetection: false, // 리터럴 false + }, + reloadOnPrerender: process.env.NODE_ENV === 'development', + localePath: path.resolve('./public/locales'), +}; + +export default nextI18NextConfig; // ← 반드시 export default diff --git a/next.config.ts b/next.config.ts index f852557..7b5e3d2 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,5 +1,4 @@ import type { NextConfig } from 'next'; -import { i18n } from './next-i18next.config.js'; const nextConfig: NextConfig = { webpack: (config) => { @@ -10,7 +9,6 @@ const nextConfig: NextConfig = { return config; }, reactStrictMode: true, - i18n, images: { remotePatterns: [ { diff --git a/public/locales/en/feed.json b/public/locales/en/feed.json new file mode 100644 index 0000000..7e96a05 --- /dev/null +++ b/public/locales/en/feed.json @@ -0,0 +1,6 @@ +{ + "feed": "Feed", + "more_icon": "more icon", + "loading": "loading...", + "more": "More Epigrams" +} diff --git a/public/locales/ko/feed.json b/public/locales/ko/feed.json new file mode 100644 index 0000000..7050523 --- /dev/null +++ b/public/locales/ko/feed.json @@ -0,0 +1,6 @@ +{ + "feed": "피드", + "more_icon": "더보기 아이콘", + "loading": "불러오는 중...", + "more": "에피그램 더보기" +} diff --git a/src/components/Feed/index.tsx b/src/components/Feed/index.tsx index e5a10eb..d5dd88b 100644 --- a/src/components/Feed/index.tsx +++ b/src/components/Feed/index.tsx @@ -4,14 +4,15 @@ import Link from 'next/link'; type feedProps = { feed: Epigram; + className?: string; }; -const Feed = ({ feed }: feedProps) => { +const Feed = ({ feed, className }: feedProps) => { return ( - -
+ +

{feed?.content}

diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 4c19ae8..9f19e3f 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -5,7 +5,7 @@ import { AnimatePresence, motion } from 'framer-motion'; import { HydrationBoundary, QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import { appWithTranslation } from 'next-i18next'; -import nextI18NextConfig from '../../next-i18next.config.js'; +import nextI18NextConfig from '../../next-i18next.config'; import GlobalNavagationBar from '@/components/GNB/index'; import ModalRoot from '@/components/Modal/ModalRoot'; import { useState } from 'react'; diff --git a/src/pages/feed.tsx b/src/pages/feed.tsx new file mode 100644 index 0000000..6888f4f --- /dev/null +++ b/src/pages/feed.tsx @@ -0,0 +1,91 @@ +import Image from 'next/image'; + +import more from '@/assets/icon/more-icon.svg'; + +import FeedSkeleton from '@/components/Feed/FeedSkeleton'; +import { QUERY_KEYS } from '@/lib/QUERY_KEYS'; +import { listEpigrams } from '@/services/epigrams'; +import { dehydrate, QueryClient } from '@tanstack/react-query'; +import { GetStaticProps } from 'next'; +import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; +import { useTranslation } from 'next-i18next'; +import { useInfiniteEpigrams } from '@/hooks/useEpigrams'; +import Feed from '@/components/Feed'; +import nextI18NextConfig from '../../next-i18next.config'; + +export const getStaticProps: GetStaticProps = async ({ locale }) => { + const qc = new QueryClient(); + + await qc.prefetchInfiniteQuery({ + queryKey: QUERY_KEYS.epigrams(6), + queryFn: ({ pageParam }) => + listEpigrams({ cursor: pageParam === null ? undefined : (pageParam as number), limit: 6 }), + initialPageParam: null, + }); + + return { + props: { + dehydratedState: dehydrate(qc), + ...(await serverSideTranslations(locale ?? 'ko', ['feed'], nextI18NextConfig)), + }, + revalidate: 60, + }; +}; + +const FeedPage = () => { + const { t } = useTranslation('feed'); + + const { + list: latestFeeds, + hasNextPage: hasMoreEpigrams, + fetchNextPage: fetchEpigramNextPage, + isFetchingNextPage: isFetchingEpigramNextPage, + reachedEnd: noMoreEpigrams, + isLoading: isEpigramsLoading, + } = useInfiniteEpigrams(6); + + return ( +
+
+

{t('feed')}

+
+ {isEpigramsLoading + ? [1, 2, 3, 4, 5, 6].map((index) => ( +
+ +
+ )) + : latestFeeds.map((f) => ( +
+ +
+ ))} + + {isFetchingEpigramNextPage && + [1, 2, 3, 4, 5, 6].map((index) => ( +
+ +
+ ))} +
+ +
+ {hasMoreEpigrams && !noMoreEpigrams && ( + + )} +
+
+
+ ); +}; + +export default FeedPage; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index f3a8dee..4553d90 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -19,10 +19,11 @@ import landing3 from '@/assets/images/img_Desktop_landing03.svg'; import landing4 from '@/assets/images/img_Desktop_landing04.svg'; import Button from '@/components/Button'; import Link from 'next/link'; +import nextI18NextConfig from '../../next-i18next.config'; export const getStaticProps: GetStaticProps = async ({ locale }) => ({ props: { - ...(await serverSideTranslations(locale ?? 'ko', ['home'])), + ...(await serverSideTranslations(locale ?? 'ko', ['home'], nextI18NextConfig)), }, }); diff --git a/src/pages/login.tsx b/src/pages/login.tsx index 6b36f84..63fce56 100644 --- a/src/pages/login.tsx +++ b/src/pages/login.tsx @@ -9,6 +9,7 @@ import Button from '@/components/Button'; import Input from '@/components/Input'; import logo from '@/assets/images/logo-lg.svg'; import Link from 'next/link'; +import nextI18NextConfig from '../../next-i18next.config'; type LoginForm = { email: string; @@ -17,7 +18,7 @@ type LoginForm = { export const getStaticProps: GetStaticProps = async ({ locale }) => ({ props: { - ...(await serverSideTranslations(locale ?? 'ko', ['login'])), + ...(await serverSideTranslations(locale ?? 'ko', ['login'], nextI18NextConfig)), }, }); diff --git a/src/pages/main.tsx b/src/pages/main.tsx index 910a5c3..3380cd8 100644 --- a/src/pages/main.tsx +++ b/src/pages/main.tsx @@ -9,7 +9,6 @@ import topArrow from '@/assets/icon/top-arrow-icon.svg'; import { GetServerSideProps } from 'next'; import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; -import nextI18NextConfig from '../../next-i18next.config.js'; import { useTranslation } from 'next-i18next'; import { useTodayEpigram } from '@/hooks/useTodayEpigram'; import { useInfiniteEpigrams } from '@/hooks/useEpigrams'; @@ -22,6 +21,7 @@ import { QUERY_KEYS } from '@/lib/QUERY_KEYS'; import { dehydrate, QueryClient } from '@tanstack/react-query'; import { listEpigrams } from '@/services/epigrams'; import { listComments } from '@/services/comments'; +import nextI18NextConfig from '../../next-i18next.config'; export const getServerSideProps: GetServerSideProps = async ({ locale }) => { const qc = new QueryClient(); @@ -42,10 +42,11 @@ export const getServerSideProps: GetServerSideProps = async ({ locale }) => { return { props: { - ...(await serverSideTranslations(locale ?? 'ko', ['emotion', 'main', 'comment'], { - ...nextI18NextConfig, - reloadOnPrerender: true, - })), + ...(await serverSideTranslations( + locale ?? 'ko', + ['emotion', 'main', 'comment'], + nextI18NextConfig, + )), dehydratedState: dehydrate(qc), }, }; diff --git a/src/pages/signup.tsx b/src/pages/signup.tsx index 6217ac3..956c79e 100644 --- a/src/pages/signup.tsx +++ b/src/pages/signup.tsx @@ -11,6 +11,7 @@ import { GetStaticProps } from 'next'; import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; import { useTranslation } from 'next-i18next'; import { useLogin } from '@/hooks/useLogin'; +import nextI18NextConfig from '../../next-i18next.config'; type SignupForm = { email: string; @@ -21,7 +22,7 @@ type SignupForm = { export const getStaticProps: GetStaticProps = async ({ locale }) => ({ props: { - ...(await serverSideTranslations(locale ?? 'ko', ['join'])), + ...(await serverSideTranslations(locale ?? 'ko', ['join'], nextI18NextConfig)), }, });