From 3a5e2e8ce928c2bd93183a40e6bfb223e9eb35b9 Mon Sep 17 00:00:00 2001 From: amirhouieh Date: Mon, 8 May 2023 15:48:18 +0200 Subject: [PATCH] add getarticlepost --- src/containers/ArticleContainer.tsx | 30 +++--- src/lib/unbody/unbody-content.types.ts | 141 ++++++++++++++++++++++--- src/lib/unbody/unbody.types.ts | 4 +- src/lib/unbody/unbody.utils.ts | 16 ++- src/pages/article/[remoteId].tsx | 59 +++++++++++ src/pages/article/[slug].tsx | 67 ------------ src/queries/getPost.ts | 7 +- src/queries/getPosts.ts | 7 +- src/queries/getPostsSlugs.ts | 9 ++ src/queries/index.ts | 10 +- src/services/unbody.service.ts | 32 +++++- src/types/data.types.ts | 6 ++ 12 files changed, 273 insertions(+), 115 deletions(-) create mode 100644 src/pages/article/[remoteId].tsx delete mode 100644 src/pages/article/[slug].tsx create mode 100644 src/queries/getPostsSlugs.ts create mode 100644 src/types/data.types.ts diff --git a/src/containers/ArticleContainer.tsx b/src/containers/ArticleContainer.tsx index ecfdc05..1ecfed1 100644 --- a/src/containers/ArticleContainer.tsx +++ b/src/containers/ArticleContainer.tsx @@ -1,30 +1,28 @@ import { Article } from '@/components/Article' import { TableOfContents } from '@/components/TableOfContents' -import { ArticleProps } from '@/pages/article/[slug]' import styled from '@emotion/styled' import { useState } from 'react' import { uiConfigs } from '@/configs/ui.configs' import { ArticleContainerContext } from '@/containers/ArticleContainer.Context' +import { UnbodyGoogleDoc } from '@/lib/unbody/unbody.types' -const ArticleContainer = (props: ArticleProps) => { - const { post } = props +interface Props { + data: UnbodyGoogleDoc +} + +const ArticleContainer = (props: Props) => { + const { data } = props const [tocIndex, setTocIndex] = useState(0) return ( - {typeof post !== 'undefined' ? ( - - -
- - - ) : ( -
-

Loading

-
- )} + + + {/*
*/} + + ) } diff --git a/src/lib/unbody/unbody-content.types.ts b/src/lib/unbody/unbody-content.types.ts index 56b71ea..5facaa9 100644 --- a/src/lib/unbody/unbody-content.types.ts +++ b/src/lib/unbody/unbody-content.types.ts @@ -11,6 +11,7 @@ export namespace UnbodyGraphQl { result: string startPosition: number } + interface AdditionalnumbererpretationSource { concept: string occurrence: number @@ -22,7 +23,7 @@ export namespace UnbodyGraphQl { } interface AdditionalFeatureProjection { - vector: [number] + vector: number[] } interface AdditionalNearestNeighborsNeighbor { @@ -43,11 +44,11 @@ export namespace UnbodyGraphQl { } interface AdditionalClassification { - basedOn: [string] - classifiedFields: [string] + basedOn: string[] + classifiedFields: string[] completed: string id: string - scope: [string] + scope: string[] } export interface AdditionalProps { @@ -58,7 +59,7 @@ export namespace UnbodyGraphQl { id: string lastUpdateTimeUnix: string score: string - vector: [number] + vector: number[] interpretation: Additionalnumbererpretation nearestNeighbors: AdditionalNearestNeighbors @@ -83,6 +84,7 @@ export namespace UnbodyGraphQl { export namespace Fragments { export interface TocItem {} + export interface FootnoteItem {} } @@ -163,7 +165,7 @@ export namespace UnbodyGraphQl { organizerEmail: string organizerId: string organizerSelf: boolean - recurrence: [string] + recurrence: string[] remoteId: string sequence: number sourceId: string @@ -176,8 +178,8 @@ export namespace UnbodyGraphQl { attachments: Array } - export namespace Explore { - interface ExploreNearObjectInpObj { + export namespace Filters { + interface NearObjectInpObj { beacon?: string certainty?: number distance?: number @@ -206,7 +208,7 @@ export namespace UnbodyGraphQl { force?: number } - interface Txt2VecC11yExploreNearTextInpObj { + interface Txt2VecC11yNearTextInpObj { moveTo?: Txt2VecC11yExploreMoveTo certainty?: number distance?: number @@ -214,24 +216,133 @@ export namespace UnbodyGraphQl { concepts?: string[] } - interface ExploreNearVectorInpObj { + interface NearVectorInpObj { distance?: number vector?: number[] certainty?: number } - interface QnATransformersExploreAskInpObj { + interface QnATransformersAskInpObj { question: string properties?: string[] } export interface ExploreArgs { - nearObject?: ExploreNearObjectInpObj - nearText?: Txt2VecC11yExploreNearTextInpObj - ask?: QnATransformersExploreAskInpObj + nearObject?: NearObjectInpObj + nearText?: Txt2VecC11yNearTextInpObj + ask?: QnATransformersAskInpObj offset?: number limit?: number - nearVector?: ExploreNearVectorInpObj + nearVector?: NearVectorInpObj + } + + enum GroupInpObjTypeEnum { + closest = 'closest', + merge = 'merge', + } + + export interface GroupInpObj { + force: number + type: GroupInpObjTypeEnum + } + + export interface HybridInpObj { + query: string + alpha: number + vector: number[] + } + + interface WhereGeoRangeGeoCoordinatesInpObj { + latitude: number + longitude: number + } + + interface WhereGeoRangeDistanceInpObj { + max: number + } + + export interface WhereGeoRangeInpObj { + geoCoordinates: WhereGeoRangeGeoCoordinatesInpObj + distance: WhereGeoRangeDistanceInpObj + } + + export enum WhereOperatorEnum { + GreaterThanEqual = 'GreaterThanEqual', + WithinGeoRange = 'WithinGeoRange', + IsNull = 'IsNull', + And = 'And', + Like = 'Like', + Not = 'Not', + NotEqual = 'NotEqual', + GreaterThan = 'GreaterThan', + LessThan = 'LessThan', + LessThanEqual = 'LessThanEqual', + Or = 'Or', + Equal = 'Equal', + } + + export interface WhereOperandsInpObj { + operator?: WhereOperatorEnum + path: [String] + operands?: [WhereOperandsInpObj] + valueGeoRange?: WhereGeoRangeInpObj + valueNumber?: number + valueBoolean?: boolean + valueString?: string + valueText?: string + valueDate?: string + valueInt?: number + } + + export enum ObjTypeEnum { + asc = 'asc', + desc = 'desc', + } + + export interface Bm25InpObj { + properties?: string[] + query: string + } + + export interface AskInpObj { + question: string + properties?: string[] + } + + export interface SortInpObj { + path: string[] + order: string + } + + export interface WhereInpObj { + path: string[] + valueInt?: number + valueNumber?: number + valueGeoRange?: WhereGeoRangeInpObj + operator?: WhereOperatorEnum + operands?: WhereOperandsInpObj[] + valueBoolean?: boolean + valuestring?: string + valueDate?: string + valueText?: string + valueString?: string + } + + export interface GetDocsArgs { + where?: WhereInpObj + bm25?: Bm25InpObj + ask?: AskInpObj + sort?: ObjTypeEnum[] + + nearText?: Txt2VecC11yNearTextInpObj + nearVector?: NearVectorInpObj + nearObject?: NearObjectInpObj + + offset?: number + limit?: number + + group?: GroupInpObj + hybrid?: HybridInpObj } } } diff --git a/src/lib/unbody/unbody.types.ts b/src/lib/unbody/unbody.types.ts index a741596..bfd1c8a 100644 --- a/src/lib/unbody/unbody.types.ts +++ b/src/lib/unbody/unbody.types.ts @@ -5,7 +5,9 @@ export type UnbodyGoogleCalendarEvent = UnbodyGraphQl.GoogleCalendarEvent export type UnbodyTextBlock = UnbodyGraphQl.TextBlock export type UnbodyImageBlock = UnbodyGraphQl.ImageBlock export type UnbodyAudio = UnbodyGraphQl.AudioFile -export type UnbodyExploreArgs = UnbodyGraphQl.Explore.ExploreArgs +export type UnbodyGetFilters = UnbodyGraphQl.Filters.GetDocsArgs + +export * as UnbodyGraphQl from './unbody-content.types' export type UnbodyGraphQlResponse = { data: { diff --git a/src/lib/unbody/unbody.utils.ts b/src/lib/unbody/unbody.utils.ts index 9a7ef71..d578c93 100644 --- a/src/lib/unbody/unbody.utils.ts +++ b/src/lib/unbody/unbody.utils.ts @@ -1,11 +1,23 @@ -import { UnbodyExploreArgs } from './unbody.types' +import { UnbodyGetFilters } from './unbody.types' +import { UnbodyGraphQl } from './unbody-content.types' -export const pareseExploreArgs = (args: UnbodyExploreArgs = {}): string => { +const operators = Object.values(UnbodyGraphQl.Filters.WhereOperatorEnum) + +export const parseFilterArgs = (args: UnbodyGetFilters = {}): string => { const parse = (obj: any): string | number => { if (typeof obj === 'number') { return obj } + if ( + typeof obj === 'string' && + operators.includes(obj as UnbodyGraphQl.Filters.WhereOperatorEnum) + ) { + return obj + } + + //TODO needs to be improved in order to support more complex queries + if (Array.isArray(obj)) { const props = obj.map((value) => `${parse(value)}`).join(',') return `[${props}]` diff --git a/src/pages/article/[remoteId].tsx b/src/pages/article/[remoteId].tsx new file mode 100644 index 0000000..1191c43 --- /dev/null +++ b/src/pages/article/[remoteId].tsx @@ -0,0 +1,59 @@ +import { GetStaticPropsContext } from 'next' +import { ArticleLayout } from '@/layouts/ArticleLayout' +import { ReactNode } from 'react' +import ArticleContainer from '@/containers/ArticleContainer' +import { UnbodyGoogleDoc, UnbodyImageBlock } from '@/lib/unbody/unbody.types' +import { + getAllArticlePostSlugs, + getArticlePost, +} from '@/services/unbody.service' +import { ArticlePostData } from '@/types/data.types' + +type ArticleProps = { + data: ArticlePostData | null + error: string | null +} + +export const getStaticProps = async ({ params }: GetStaticPropsContext) => { + const { remoteId } = params! + if (!remoteId) { + return { + notFound: true, + } + } + + const article = await getArticlePost(remoteId as string) + + return { + props: { + data: article, + error: !!article, + }, + } +} + +// @jinho lets handle the error directly in thew page component +const ArticlePage = (props: ArticleProps) => { + if (!props.data) return
Opps...
+ + return ( +
{props.data.title}
+ // + ) +} + +export async function getStaticPaths() { + const posts = await getAllArticlePostSlugs() + return { + paths: posts.map((post) => ({ params: { remoteId: `${post.remoteId}` } })), + fallback: true, + } +} + +ArticlePage.getLayout = function getLayout(page: ReactNode) { + return {page} +} + +export default ArticlePage diff --git a/src/pages/article/[slug].tsx b/src/pages/article/[slug].tsx deleted file mode 100644 index 1fb1a50..0000000 --- a/src/pages/article/[slug].tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { GetStaticPropsContext } from 'next' -import { ArticleLayout } from '@/layouts/ArticleLayout' -import { ReactNode } from 'react' -import ArticleContainer from '@/containers/ArticleContainer' -import { UnbodyGoogleDoc, UnbodyImageBlock } from '@/lib/unbody/unbody.types' -import { getArticlePost } from '@/services/unbody.service' -import { PostDataProps } from '@/components/Post/Post' - -export type ArticleProps = { - post: PostDataProps - error: string | null -} - -export const getStaticProps = async ({ params }: GetStaticPropsContext) => { - const slug = params?.slug - console.log('slug', slug) // TODO : fetch data based on slug - let post: Partial = {} - let error = null - - try { - const posts = await getArticlePost() - post = posts[0] - } catch (e) { - error = JSON.stringify(e) - } - - return { - props: { - post: { - date: post.modifiedAt, - title: post.title, - summary: post.summary, - //@ts-ignore - blocks: post.blocks - ?.map((block) => `${block.html}\n`) - .slice(2) - .join(''), // temporary solution for HTML/CSS work - author: 'Cameron Williamson', - authorEmail: 'leo@acid.info', - tags: ['Tools', 'Cyber Punk', 'Docs'], - //@ts-ignore - toc: JSON.parse(post?.toc), - ...(post.blocks && post.blocks!.length > 0 - ? { coverImage: post.blocks![0] as UnbodyImageBlock } - : {}), - }, - error, - }, - } -} - -const ArticlePage = (props: ArticleProps) => { - return -} - -export async function getStaticPaths() { - return { - paths: [{ params: { slug: 'sth' } }], - fallback: true, - } -} - -ArticlePage.getLayout = function getLayout(page: ReactNode) { - return {page} -} - -export default ArticlePage diff --git a/src/queries/getPost.ts b/src/queries/getPost.ts index 2ccec39..993bf0e 100644 --- a/src/queries/getPost.ts +++ b/src/queries/getPost.ts @@ -1,12 +1,11 @@ import { GetGoogleDocQuery } from '.' -import { UnbodyExploreArgs } from '@/lib/unbody/unbody.types' +import { UnbodyGetFilters } from '@/lib/unbody/unbody.types' -const defaultArgs: UnbodyExploreArgs = { +const defaultArgs: UnbodyGetFilters = { limit: 1, - nearText: { concepts: ['home'] }, } -export const getArticlePostQuery = (args: UnbodyExploreArgs = defaultArgs) => +export const getArticlePostQuery = (args: UnbodyGetFilters = defaultArgs) => GetGoogleDocQuery(args)(` sourceId remoteId diff --git a/src/queries/getPosts.ts b/src/queries/getPosts.ts index 33cc161..ea9afac 100644 --- a/src/queries/getPosts.ts +++ b/src/queries/getPosts.ts @@ -1,15 +1,14 @@ import { gql } from 'graphql-request' import { GetGoogleDocQuery, GetQuery } from '.' -import { pareseExploreArgs } from '@/lib/unbody/unbody.utils' -import { UnbodyExploreArgs } from '@/lib/unbody/unbody.types' +import { UnbodyGetFilters } from '@/lib/unbody/unbody.types' -const defaultArgs: UnbodyExploreArgs = { +const defaultArgs: UnbodyGetFilters = { limit: 10, nearText: { concepts: ['home'] }, } -export const getHomePagePostsQuery = (args: UnbodyExploreArgs = defaultArgs) => +export const getHomePagePostsQuery = (args: UnbodyGetFilters = defaultArgs) => GetGoogleDocQuery(args)(` title summary diff --git a/src/queries/getPostsSlugs.ts b/src/queries/getPostsSlugs.ts new file mode 100644 index 0000000..df2a987 --- /dev/null +++ b/src/queries/getPostsSlugs.ts @@ -0,0 +1,9 @@ +import { GetGoogleDocQuery } from '.' +import { UnbodyGetFilters } from '@/lib/unbody/unbody.types' + +const defaultArgs: UnbodyGetFilters = {} + +export const getAllPostsSlugQuery = (args: UnbodyGetFilters = defaultArgs) => + GetGoogleDocQuery(args)(` + remoteId + `) diff --git a/src/queries/index.ts b/src/queries/index.ts index bd22e31..bffed32 100644 --- a/src/queries/index.ts +++ b/src/queries/index.ts @@ -1,7 +1,9 @@ -import { UnbodyExploreArgs } from '@/lib/unbody/unbody.types' -import { pareseExploreArgs } from '@/lib/unbody/unbody.utils' +import { UnbodyGetFilters } from '@/lib/unbody/unbody.types' +import { parseFilterArgs } from '@/lib/unbody/unbody.utils' export const GetQuery = (q: string) => `query { Get{ ${q} } }` -export const GetGoogleDocQuery = (args: UnbodyExploreArgs) => (q: string) => - GetQuery(`GoogleDoc(${pareseExploreArgs(args)}){ ${q} }`) +export const GetGoogleDocQuery = (args: UnbodyGetFilters) => (q: string) => { + if (Object.keys(args).length === 0) return GetQuery(`GoogleDoc{ ${q} }`) + return GetQuery(`GoogleDoc(${parseFilterArgs(args)}){ ${q} }`) +} diff --git a/src/services/unbody.service.ts b/src/services/unbody.service.ts index 567e324..29f183f 100644 --- a/src/services/unbody.service.ts +++ b/src/services/unbody.service.ts @@ -2,9 +2,14 @@ import { UnbodyClient } from '@/lib/unbody/client.class' import { UnbodyGoogleDoc, UnbodyGraphQlResponseGoogleDoc, + UnbodyGetFilters, } from '@/lib/unbody/unbody.types' + +import { UnbodyGraphQl } from '@/lib/unbody/unbody-content.types' + import { getArticlePostQuery } from '@/queries/getPost' import { getHomePagePostsQuery } from '@/queries/getPosts' +import { getAllPostsSlugQuery } from '@/queries/getPostsSlugs' const { UNBODY_API_KEY, UNBODY_LPE_PROJECT_ID } = process.env @@ -24,10 +29,33 @@ export const getHomepagePosts = (): Promise => { .then(({ data }) => data.Get.GoogleDoc) } -export const getArticlePost = (): Promise => { +export const getAllArticlePostSlugs = (): Promise<{ remoteId: string }[]> => { + console.log(getAllPostsSlugQuery()) return unbody - .request(getArticlePostQuery()) + .request(getAllPostsSlugQuery()) .then(({ data }) => data.Get.GoogleDoc) } +export const getArticlePost = (id: string): Promise => { + const query = getArticlePostQuery({ + where: { + path: ['remoteId'], + operator: UnbodyGraphQl.Filters.WhereOperatorEnum.Equal, + valueString: id, + }, + }) + + return unbody + .request(getArticlePostQuery()) + .then(({ data }) => { + const article = data.Get.GoogleDoc[0] + return { + ...article, + toc: JSON.parse( + article.toc as string, + ) as Array, + } + }) +} + export default unbody diff --git a/src/types/data.types.ts b/src/types/data.types.ts new file mode 100644 index 0000000..63a33cb --- /dev/null +++ b/src/types/data.types.ts @@ -0,0 +1,6 @@ +import { UnbodyGoogleDoc } from '@/lib/unbody/unbody.types' +import { UnbodyGraphQl } from '@/lib/unbody/unbody-content.types' + +export interface ArticlePostData extends UnbodyGoogleDoc { + toc: Array +}