From 6bd13bb45ff31a4fed2efa3085a19e6b68c45d59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9B=90=EB=8D=94?= Date: Thu, 4 Feb 2021 21:36:36 +0900 Subject: [PATCH] feat: added category route close: https://github.com/koreanbots/v2-testing/issues/16 --- pages/categories/[category].tsx | 63 +++++++++++++++++++++++++++++++++ utils/Query.ts | 7 ++++ utils/Yup.ts | 23 ++++++++++-- 3 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 pages/categories/[category].tsx diff --git a/pages/categories/[category].tsx b/pages/categories/[category].tsx new file mode 100644 index 0000000..e49b87d --- /dev/null +++ b/pages/categories/[category].tsx @@ -0,0 +1,63 @@ +import { NextPage, NextPageContext } from 'next' +import dynamic from 'next/dynamic' +import { ParsedUrlQuery } from 'querystring' + +import { get } from '@utils/Query' +import { BotList } from '@types' +import { botCategoryListArgumentSchema } from '@utils/Yup' +import NotFound from 'pages/404' + +const Hero = dynamic(() => import('@components/Hero')) +const Advertisement = dynamic(() => import('@components/Advertisement')) +const SEO = dynamic(() => import('@components/SEO')) +const BotCard = dynamic(() => import('@components/BotCard')) +const Container = dynamic(() => import('@components/Container')) +const Paginator = dynamic(() => import('@components/Paginator')) + +const Category: NextPage = ({ data, query }) => { + if(!data || data.data.length === 0 || data.totalPage < Number(query.page)) return + return <> + + + + + +
+ { + data.data.map(bot => ) + } +
+ +
+ +} + +export const getServerSideProps = async (ctx: Context) => { + let data: BotList + if(!ctx.query.page) ctx.query.page = '1' + const validate = await botCategoryListArgumentSchema.validate(ctx.query).then(el => el).catch(() => null) + if(!validate || isNaN(Number(ctx.query.page))) data = null + else data = await get.list.category.load(JSON.stringify({ page: Number(ctx.query.page), category: ctx.query.category })) + return { + props: { + data, + query: ctx.query + } + } +} + +interface CategoryProps { + data: BotList + query: URLQuery +} + +interface Context extends NextPageContext { + query: URLQuery +} + +interface URLQuery extends ParsedUrlQuery { + category: string + page: string +} + +export default Category \ No newline at end of file diff --git a/utils/Query.ts b/utils/Query.ts index e33bd01..b1204d9 100644 --- a/utils/Query.ts +++ b/utils/Query.ts @@ -259,6 +259,13 @@ export const get = { (await Promise.all(ids.map(async (el: string) => await getUser(el, false)))).map(row => ({ ...row })) , { cacheMap: new TLRU({ maxStoreSize: 50, maxAgeMs: 60000 }) }), list: { + category: new DataLoader( + async (key: string[]) => + (await Promise.all(key.map(async (k: string) => { + const json = JSON.parse(k) + return await getBotList('CATEGORY', json.page, json.category) + }))).map(row => ({ ...row })) + , { cacheMap: new TLRU({ maxStoreSize: 50, maxAgeMs: 3000000 }) }), votes: new DataLoader( async (pages: number[]) => (await Promise.all(pages.map(async (page: number) => await getBotList('VOTE', page)))).map(row => ({ ...row })) diff --git a/utils/Yup.ts b/utils/Yup.ts index 27c3646..9d4c86e 100644 --- a/utils/Yup.ts +++ b/utils/Yup.ts @@ -6,8 +6,8 @@ import { HTTPProtocol, ID, Prefix, Url, Vanity } from './Regex' Yup.setLocale(YupKorean) -export const botListArgumentSchema = Yup.object({ - type: Yup.string().oneOf(['VOTE', 'TRUSTED', 'NEW', 'PARTNERED', 'CATEGORY', 'SEARCH']).required(), +export const botListArgumentSchema: Yup.SchemaOf = Yup.object({ + type: Yup.mixed().oneOf(['VOTE', 'TRUSTED', 'NEW', 'PARTNERED', 'CATEGORY', 'SEARCH']).required(), page: Yup.number().positive().integer().notRequired().default(1), query: Yup.string().notRequired() }) @@ -33,16 +33,33 @@ interface ImageOptions { type ext = 'webp' | 'png' | 'gif' type ImageSize = '128' | '256' | '512' -export const PageCount = Yup.number().integer().positive() +export const PageCount = Yup.number().integer().positive().required() export const OauthCallbackSchema: Yup.SchemaOf = Yup.object({ code: Yup.string().required() }) +export const botCategoryListArgumentSchema: Yup.SchemaOf = Yup.object({ + page: PageCount, + category: Yup.mixed().oneOf(categories).required() +}) + +interface botCategoryListArgument { + page: number + category: string +} interface OauthCallback { code: string } +export const SearchQuerySchema: Yup.SchemaOf = Yup.object({ + q: Yup.string().min(2, '최소 2글자 이상 입력해주세요.').required() +}) + +interface SearchQuery { + q: string +} + export const AddBotSubmitSchema = Yup.object({ agree: Yup.boolean().oneOf([true], '상단의 체크박스를 클릭해주세요.').required('상단의 체크박스를 클릭해주세요.'), id: Yup.string().matches(ID, '올바른 봇 ID를 입력해주세요.').required('봇 ID는 필수 항목입니다.'),