feat: unified editor data converter

This commit is contained in:
DIYgod 2023-08-26 00:39:43 +01:00
parent 215bd8fbc0
commit 3bf8c1d3ba
No known key found for this signature in database
20 changed files with 285 additions and 265 deletions

View File

@ -17,20 +17,17 @@ import EditorExternalUrl from "~/components/dashboard/editor-properties/EditorEx
import EditorPublishAt from "~/components/dashboard/editor-properties/EditorPublishAt"
import EditorTitle from "~/components/dashboard/editor-properties/EditorTitle"
import { useModalStack } from "~/components/ui/ModalStack"
import {
Values,
initialEditorState,
useEditorState,
} from "~/hooks/useEditorState"
import { initialEditorState, useEditorState } from "~/hooks/useEditorState"
import { useGetState } from "~/hooks/useGetState"
import { useBeforeMounted } from "~/hooks/useSyncOnce"
import { showConfetti } from "~/lib/confetti"
import { crossbell2Editor } from "~/lib/editor-converter"
import { CSB_SCAN } from "~/lib/env"
import { getTwitterShareUrl } from "~/lib/helpers"
import { useTranslation } from "~/lib/i18n/client"
import { getPageVisibility } from "~/lib/page-helpers"
import { delStorage, setStorage } from "~/lib/storage"
import { PageVisibilityEnum } from "~/lib/types"
import { EditorValues, PageVisibilityEnum } from "~/lib/types"
import { cn } from "~/lib/utils"
import {
useCreatePage,
@ -107,7 +104,7 @@ export default function PortfolioEditor() {
const getValues = useGetState(values)
const updateValue = useCallback(
(val: Partial<Values>) => {
(val: Partial<EditorValues>) => {
if (visibility !== PageVisibilityEnum.Draft) {
setVisibility(PageVisibilityEnum.Modified)
}
@ -232,19 +229,7 @@ export default function PortfolioEditor() {
// Init
useEffect(() => {
if (!page.data?.metadata || !draftKey) return
useEditorState.setState({
published: !!page.data.noteId,
title: page.data.metadata?.content?.title || "",
publishedAt: page.data.metadata?.content?.date_published,
excerpt: page.data.metadata?.content?.summary || "",
cover: page.data.metadata?.content?.attachments?.find(
(attachment) => attachment.name === "cover",
) || {
address: "",
mime_type: "",
},
externalUrl: page.data.metadata?.content?.external_urls?.[0] || "",
})
useEditorState.setState(crossbell2Editor(page.data))
}, [page.data, subdomain, draftKey, site.data?.characterId])
// Reset
@ -315,7 +300,7 @@ export default function PortfolioEditor() {
}
const EditorExtraProperties = memo(
({ updateValue }: { updateValue: (val: Partial<Values>) => void }) => {
({ updateValue }: { updateValue: (val: Partial<EditorValues>) => void }) => {
const { t } = useTranslation("dashboard")
return (

View File

@ -22,23 +22,24 @@ import EditorSlug from "~/components/dashboard/editor-properties/EditorSlug"
import EditorTags from "~/components/dashboard/editor-properties/EditorTags"
import { Button } from "~/components/ui/Button"
import { useModalStack } from "~/components/ui/ModalStack"
import {
Values,
initialEditorState,
useEditorState,
} from "~/hooks/useEditorState"
import { initialEditorState, useEditorState } from "~/hooks/useEditorState"
import { useGetState } from "~/hooks/useGetState"
import { useIsMobileLayout } from "~/hooks/useMobileLayout"
import { useBeforeMounted } from "~/hooks/useSyncOnce"
import { showConfetti } from "~/lib/confetti"
import { RESERVED_TAGS } from "~/lib/constants"
import { getDefaultSlug } from "~/lib/default-slug"
import { crossbell2Editor } from "~/lib/editor-converter"
import { CSB_SCAN } from "~/lib/env"
import { getSiteLink, getTwitterShareUrl } from "~/lib/helpers"
import { useTranslation } from "~/lib/i18n/client"
import { getPageVisibility } from "~/lib/page-helpers"
import { delStorage, setStorage } from "~/lib/storage"
import { ExpandedNote, NoteType, PageVisibilityEnum } from "~/lib/types"
import {
EditorValues,
ExpandedNote,
NoteType,
PageVisibilityEnum,
} from "~/lib/types"
import { cn } from "~/lib/utils"
import { checkPageSlug } from "~/models/page.model"
import {
@ -132,7 +133,7 @@ export default function PostEditor() {
const getDraftKey = useGetState(draftKey)
const updateValue = useCallback(
(val: Partial<Values>) => {
(val: Partial<EditorValues>) => {
if (visibility !== PageVisibilityEnum.Draft) {
setVisibility(PageVisibilityEnum.Modified)
}
@ -318,25 +319,7 @@ export default function PostEditor() {
useEffect(() => {
if (!page.data?.metadata?.content || !draftKey) return
setInitialContent(page.data.metadata?.content?.content || "")
useEditorState.setState({
title: page.data.metadata?.content?.title || "",
publishedAt: page.data.metadata?.content?.date_published,
published: !!page.data.noteId,
excerpt: page.data.metadata?.content?.summary || "",
slug: page.data.metadata?.content?.slug || "",
tags:
page.data.metadata?.content?.tags
?.filter((tag) => !RESERVED_TAGS.includes(tag))
?.join(", ") || "",
content: page.data.metadata?.content?.content || "",
cover: page.data.metadata?.content?.attachments?.find(
(attachment) => attachment.name === "cover",
) || {
address: "",
mime_type: "",
},
disableAISummary: page.data.metadata?.content?.disableAISummary,
})
useEditorState.setState(crossbell2Editor(page.data))
setDefaultSlug(
getDefaultSlug(
page.data.metadata?.content?.title || "",
@ -533,7 +516,7 @@ const EditorExtraProperties = memo(
characterId,
siteLink,
}: {
updateValue: (val: Partial<Values>) => void
updateValue: (val: Partial<EditorValues>) => void
type: NoteType
defaultSlug: string
characterId?: number

View File

@ -15,20 +15,17 @@ import EditorImages from "~/components/dashboard/editor-properties/EditorImages"
import EditorPublishAt from "~/components/dashboard/editor-properties/EditorPublishAt"
import EditorTitle from "~/components/dashboard/editor-properties/EditorTitle"
import { useModalStack } from "~/components/ui/ModalStack"
import {
Values,
initialEditorState,
useEditorState,
} from "~/hooks/useEditorState"
import { initialEditorState, useEditorState } from "~/hooks/useEditorState"
import { useGetState } from "~/hooks/useGetState"
import { useBeforeMounted } from "~/hooks/useSyncOnce"
import { showConfetti } from "~/lib/confetti"
import { crossbell2Editor } from "~/lib/editor-converter"
import { CSB_SCAN } from "~/lib/env"
import { getTwitterShareUrl } from "~/lib/helpers"
import { useTranslation } from "~/lib/i18n/client"
import { getPageVisibility } from "~/lib/page-helpers"
import { delStorage, setStorage } from "~/lib/storage"
import { PageVisibilityEnum } from "~/lib/types"
import { EditorValues, PageVisibilityEnum } from "~/lib/types"
import { cn } from "~/lib/utils"
import {
useCreatePage,
@ -105,7 +102,7 @@ export default function ShortEditor() {
const getValues = useGetState(values)
const updateValue = useCallback(
(val: Partial<Values>) => {
(val: Partial<EditorValues>) => {
if (visibility !== PageVisibilityEnum.Draft) {
setVisibility(PageVisibilityEnum.Modified)
}
@ -230,16 +227,7 @@ export default function ShortEditor() {
// Init
useEffect(() => {
if (!page.data?.metadata || !draftKey) return
useEditorState.setState({
published: !!page.data.noteId,
title: page.data.metadata?.content?.title || "",
publishedAt: page.data.metadata?.content?.date_published,
content: page.data.metadata?.content?.content || "",
images:
page.data.metadata?.content?.attachments?.filter(
(attachment) => attachment.name === "image",
) || [],
})
useEditorState.setState(crossbell2Editor(page.data))
}, [page.data, subdomain, draftKey, site.data?.characterId])
// Reset
@ -310,7 +298,7 @@ export default function ShortEditor() {
}
const EditorExtraProperties = memo(
({ updateValue }: { updateValue: (val: Partial<Values>) => void }) => {
({ updateValue }: { updateValue: (val: Partial<EditorValues>) => void }) => {
const { t } = useTranslation("dashboard")
return (

View File

@ -1,13 +1,14 @@
import { useState } from "react"
import { Button } from "~/components/ui/Button"
import { Values, useEditorState } from "~/hooks/useEditorState"
import { useEditorState } from "~/hooks/useEditorState"
import { useTranslation } from "~/lib/i18n/client"
import { EditorValues } from "~/lib/types"
export default function EditorAutofill({
updateValue,
}: {
updateValue: (val: Partial<Values>) => void
updateValue: (val: Partial<EditorValues>) => void
}) {
const { t } = useTranslation("dashboard")
const externalUrl = useEditorState((state) => state.externalUrl)

View File

@ -1,14 +1,15 @@
import { ChangeEvent } from "react"
import { Input } from "~/components/ui/Input"
import { Values, useEditorState } from "~/hooks/useEditorState"
import { useEditorState } from "~/hooks/useEditorState"
import { useTranslation } from "~/lib/i18n/client"
import { EditorValues } from "~/lib/types"
export default function EditorContent({
updateValue,
prompt,
}: {
updateValue: (val: Partial<Values>) => void
updateValue: (val: Partial<EditorValues>) => void
prompt?: string
}) {
const { t } = useTranslation("dashboard")

View File

@ -1,13 +1,14 @@
import { FieldLabel } from "~/components/ui/FieldLabel"
import { ImageUploader } from "~/components/ui/ImageUploader"
import { Values, useEditorState } from "~/hooks/useEditorState"
import { useEditorState } from "~/hooks/useEditorState"
import { useTranslation } from "~/lib/i18n/client"
import { EditorValues } from "~/lib/types"
export default function EditorCover({
updateValue,
prompt,
}: {
updateValue: (val: Partial<Values>) => void
updateValue: (val: Partial<EditorValues>) => void
prompt?: string
}) {
const { t } = useTranslation("dashboard")

View File

@ -1,11 +1,12 @@
import { Switch } from "~/components/ui/Switch"
import { Values, useEditorState } from "~/hooks/useEditorState"
import { useEditorState } from "~/hooks/useEditorState"
import { useTranslation } from "~/lib/i18n/client"
import { EditorValues } from "~/lib/types"
export default function EditorDisableAISummary({
updateValue,
}: {
updateValue: (val: Partial<Values>) => void
updateValue: (val: Partial<EditorValues>) => void
}) {
const { t } = useTranslation("dashboard")
const value = useEditorState((state) => state.disableAISummary)

View File

@ -1,14 +1,15 @@
import { ChangeEvent } from "react"
import { Input } from "~/components/ui/Input"
import { Values, useEditorState } from "~/hooks/useEditorState"
import { useEditorState } from "~/hooks/useEditorState"
import { useTranslation } from "~/lib/i18n/client"
import { EditorValues } from "~/lib/types"
export default function EditorExcerpt({
updateValue,
prompt,
}: {
updateValue: (val: Partial<Values>) => void
updateValue: (val: Partial<EditorValues>) => void
prompt?: string
}) {
const { t } = useTranslation("dashboard")

View File

@ -1,13 +1,14 @@
import { ChangeEvent } from "react"
import { Input } from "~/components/ui/Input"
import { Values, useEditorState } from "~/hooks/useEditorState"
import { useEditorState } from "~/hooks/useEditorState"
import { useTranslation } from "~/lib/i18n/client"
import { EditorValues } from "~/lib/types"
export default function EditorExternalUrl({
updateValue,
}: {
updateValue: (val: Partial<Values>) => void
updateValue: (val: Partial<EditorValues>) => void
}) {
const { t } = useTranslation("dashboard")
const value = useEditorState((state) => state.externalUrl)

View File

@ -2,14 +2,15 @@ import { useState } from "react"
import { FieldLabel } from "~/components/ui/FieldLabel"
import { ImageUploader } from "~/components/ui/ImageUploader"
import { Values, useEditorState } from "~/hooks/useEditorState"
import { useEditorState } from "~/hooks/useEditorState"
import { useTranslation } from "~/lib/i18n/client"
import { EditorValues } from "~/lib/types"
export default function EditorImages({
updateValue,
prompt,
}: {
updateValue: (val: Partial<Values>) => void
updateValue: (val: Partial<EditorValues>) => void
prompt?: string
}) {
const { t } = useTranslation("dashboard")

View File

@ -1,13 +1,14 @@
import { DateInput } from "@mantine/dates"
import { Values, useEditorState } from "~/hooks/useEditorState"
import { useEditorState } from "~/hooks/useEditorState"
import { useTranslation } from "~/lib/i18n/client"
import { EditorValues } from "~/lib/types"
export default function EditorPublishAt({
updateValue,
prompt,
}: {
updateValue: (val: Partial<Values>) => void
updateValue: (val: Partial<EditorValues>) => void
prompt?: string
}) {
const { t } = useTranslation("dashboard")

View File

@ -2,8 +2,9 @@ import { ChangeEvent } from "react"
import { Input } from "~/components/ui/Input"
import { UniLink } from "~/components/ui/UniLink"
import { Values, useEditorState } from "~/hooks/useEditorState"
import { useEditorState } from "~/hooks/useEditorState"
import { useTranslation } from "~/lib/i18n/client"
import { EditorValues } from "~/lib/types"
export default function EditorSlug({
updateValue,
@ -11,7 +12,7 @@ export default function EditorSlug({
type,
siteLink,
}: {
updateValue: (val: Partial<Values>) => void
updateValue: (val: Partial<EditorValues>) => void
defaultValue?: string
type: string
siteLink?: string

View File

@ -1,14 +1,15 @@
import { Input } from "~/components/ui/Input"
import { TagInput } from "~/components/ui/TagInput"
import { Values, useEditorState } from "~/hooks/useEditorState"
import { useEditorState } from "~/hooks/useEditorState"
import { useTranslation } from "~/lib/i18n/client"
import { EditorValues } from "~/lib/types"
import { useGetDistinctNoteTagsOfCharacter } from "~/queries/page"
export default function EditorTags({
updateValue,
characterId,
}: {
updateValue: (val: Partial<Values>) => void
updateValue: (val: Partial<EditorValues>) => void
characterId?: number
}) {
const { t } = useTranslation("dashboard")

View File

@ -1,13 +1,14 @@
import { ChangeEvent } from "react"
import { Input } from "~/components/ui/Input"
import { Values, useEditorState } from "~/hooks/useEditorState"
import { useEditorState } from "~/hooks/useEditorState"
import { useTranslation } from "~/lib/i18n/client"
import { EditorValues } from "~/lib/types"
export default function EditorTitle({
updateValue,
}: {
updateValue: (val: Partial<Values>) => void
updateValue: (val: Partial<EditorValues>) => void
}) {
const { t } = useTranslation("dashboard")
const value = useEditorState((state) => state.title)

View File

@ -1,5 +1,7 @@
import { create } from "zustand"
import { EditorValues } from "~/lib/types"
export const initialEditorState = {
title: "",
publishedAt: "",
@ -17,28 +19,8 @@ export const initialEditorState = {
images: [],
}
export type Values = {
title: string
publishedAt: string
published: boolean
excerpt: string
slug: string
tags: string
content: string
cover: {
address?: string
mime_type?: string
}
disableAISummary: boolean
externalUrl: string
images: {
address?: string
mime_type?: string
}[]
}
export const useEditorState = create<
Values & {
EditorValues & {
setValues: (values: Partial<typeof initialEditorState>) => void
}
>((set) => ({

133
src/lib/editor-converter.ts Normal file
View File

@ -0,0 +1,133 @@
import { NoteEntity } from "crossbell"
import { nanoid } from "nanoid"
import { zeroAddress } from "viem"
import { EditorValues, ExpandedNote } from "~/lib/types"
import { RESERVED_TAGS } from "./constants"
export const editor2Crossbell = ({
values,
type,
autofill,
}: {
values: EditorValues
type: string
autofill?: boolean
}): NoteEntity & {
metadata: {
content: {
summary?: string
}
}
} => {
return {
characterId: 0,
noteId: 0,
linkItemType: null,
linkKey: "",
toCharacterId: null,
toAddress: null,
toNoteId: null,
toHeadCharacterId: null,
toHeadNoteId: null,
toContractAddress: null,
toTokenId: null,
toLinklistId: null,
toUri: null,
deleted: false,
locked: false,
contractAddress: null,
uri: null,
operator: zeroAddress,
owner: zeroAddress,
createdAt: "",
publishedAt: "",
updatedAt: "",
deletedAt: null,
transactionHash: zeroAddress,
blockNumber: 0,
logIndex: 0,
updatedTransactionHash: zeroAddress,
updatedBlockNumber: 0,
updatedLogIndex: 0,
metadata: {
content: {
title: values?.title,
content: values?.content,
date_published:
values?.publishedAt ||
(autofill ? new Date().toISOString() : undefined),
summary: values?.excerpt,
tags: [
type,
...(values?.tags
?.split(",")
.map((tag: string) => tag.trim())
.filter((tag: string) => tag) || []),
],
sources: ["xlog"],
attributes: [
{
trait_type: "xlog_slug",
value: values.slug || (autofill ? nanoid() : ""),
},
...(values.disableAISummary
? [
{
trait_type: "xlog_disable_ai_summary",
value: values.disableAISummary,
},
]
: []),
],
external_urls: values?.externalUrl ? [values?.externalUrl] : undefined,
attachments: [
...(values.cover?.address
? [
{
name: "cover",
address: values.cover.address,
mime_type: values.cover.mime_type,
},
]
: []),
...(values.images?.length
? values.images?.map((image) => ({
name: "image",
address: image.address,
mime_type: image.mime_type,
}))
: []),
],
},
},
}
}
export const crossbell2Editor = (note: ExpandedNote): EditorValues => {
return {
title: note?.metadata?.content?.title || "",
publishedAt: note?.metadata?.content?.date_published || "",
published: !!note?.noteId,
excerpt: note?.metadata?.content?.summary || "",
slug: note?.metadata?.content?.slug || "",
tags:
note?.metadata?.content?.tags
?.filter((tag) => !RESERVED_TAGS.includes(tag))
?.join(", ") || "",
content: note?.metadata?.content?.content || "",
cover: note?.metadata?.content?.attachments?.find(
(attachment) => attachment.name === "cover",
) || {
address: "",
mime_type: "",
},
disableAISummary: note?.metadata?.content?.disableAISummary || false,
externalUrl: note?.metadata?.content?.external_urls?.[0] || "",
images:
note.metadata?.content?.attachments?.filter(
(attachment) => attachment.name === "image",
) || [],
}
}

View File

@ -15,12 +15,20 @@ export const expandCrossbellNote = async ({
useScore,
keyword,
useHTML,
disableAutofill,
}: {
note: NoteEntity
note: NoteEntity & {
metadata?: {
content?: {
summary?: string
} | null
} | null
}
useStat?: boolean
useScore?: boolean
keyword?: string
useHTML?: boolean
disableAutofill?: boolean
}) => {
const expandedNote: ExpandedNote = Object.assign(
{
@ -45,7 +53,7 @@ export const expandCrossbellNote = async ({
position + 100,
)}`
} else {
if (!expandedNote.metadata.content.summary) {
if (!expandedNote.metadata.content.summary && !disableAutofill) {
expandedNote.metadata.content.summary = rendered.excerpt
}
}
@ -60,7 +68,7 @@ export const expandCrossbellNote = async ({
expandedNote.metadata.content.cover =
expandedNote.metadata?.content?.attachments?.find(
(attachment) => attachment.name === "cover",
)?.address || rendered?.cover
)?.address || (disableAutofill ? "" : rendered?.cover)
expandedNote.metadata.content.images = []
@ -86,8 +94,14 @@ export const expandCrossbellNote = async ({
...new Set(expandedNote.metadata.content.images),
]
expandedNote.metadata.content.slug = getNoteSlug(expandedNote)
if (!expandedNote.metadata.content.date_published && expandedNote.noteId) {
if (!disableAutofill) {
expandedNote.metadata.content.slug = getNoteSlug(expandedNote)
}
if (
!expandedNote.metadata.content.date_published &&
expandedNote.noteId &&
!disableAutofill
) {
expandedNote.metadata.content.date_published = expandedNote.createdAt
}

View File

@ -125,3 +125,23 @@ export type ExpandedCharacter = CharacterEntity & {
export type ColorScheme = "dark" | "light"
export type NoteType = "post" | "page" | "portfolio" | "short"
export type EditorValues = {
title: string
publishedAt: string
published: boolean
excerpt: string
slug: string
tags: string
content: string
cover: {
address?: string
mime_type?: string
}
disableAISummary: boolean
externalUrl: string
images: {
address?: string
mime_type?: string
}[]
}

View File

@ -6,7 +6,7 @@ import type {
NoteEntity,
NoteMetadata,
} from "crossbell"
import type { Address } from "viem"
import { type Address } from "viem"
import { GeneralAccount } from "@crossbell/connect-kit"
import { indexer } from "@crossbell/indexer"
@ -14,6 +14,7 @@ import { extractCharacterAttribute } from "@crossbell/util-metadata"
import { gql } from "@urql/core"
import { RESERVED_TAGS } from "~/lib/constants"
import { editor2Crossbell } from "~/lib/editor-converter"
import { expandCrossbellNote } from "~/lib/expand-unit"
import { filterCommentCharacter } from "~/lib/filter-character"
import { getNoteSlug } from "~/lib/helpers"
@ -64,102 +65,47 @@ export async function postNotes(
})
}
const getLocalPages = (input: {
const getLocalPages = async (input: {
characterId: number
isPost?: boolean // In order to be compatible with old drafts
type?: NoteType[]
handle?: string
}) => {
const pages: ExpandedNote[] = []
getKeys([`draft-${input.characterId}-`, `draft-${input.handle}-`]).forEach(
(key) => {
const page = getStorage(key)
if (
page.isPost === input.isPost ||
input.type?.includes(page.type) ||
input.type === undefined
) {
const note: ExpandedNote = {
characterId: input.characterId,
noteId: 0,
draftKey: key
.replace(`draft-${input.characterId}-`, "")
.replace(`draft-${input.handle}-${input.characterId}-`, ""), // In order to be compatible with old drafts
linkItemType: null,
linkKey: "",
toCharacterId: null,
toAddress: null,
toNoteId: null,
toHeadCharacterId: null,
toHeadNoteId: null,
toContractAddress: null,
toTokenId: null,
toLinklistId: null,
toUri: null,
deleted: false,
locked: false,
contractAddress: null,
uri: null,
operator: "" as Address, // TODO: check usage and replace it with viem's `zeroAddress`.
owner: "" as Address, // TODO: check usage and replace it with viem's `zeroAddress`.
createdAt: new Date(page.date).toISOString(),
publishedAt: new Date(page.date).toISOString(),
updatedAt: new Date(page.date).toISOString(),
deletedAt: null,
transactionHash: "" as Address, // TODO: check usage and replace it with viem's `zeroAddress`.
blockNumber: 0,
logIndex: 0,
updatedTransactionHash: "" as Address, // TODO: check usage and replace it with viem's `zeroAddress`.
updatedBlockNumber: 0,
updatedLogIndex: 0,
metadata: {
content: {
title: page.values?.title,
content: page.values?.content,
date_published: page.values?.publishedAt,
summary: page.values?.excerpt,
tags: [
page.type,
...(page.values?.tags
?.split(",")
.map((tag: string) => tag.trim())
.filter((tag: string) => tag) || []),
],
slug: page.values?.slug,
sources: ["xlog"],
disableAISummary: page.values?.disableAISummary,
external_urls: page.values?.externalUrl
? [page.values?.externalUrl]
: undefined,
cover: page.values?.cover?.address,
images: [page.values?.cover?.address],
attachments: [
...(page.values?.cover?.address
? [
{
name: "cover",
address: page.values?.cover.address,
mime_type: page.values?.cover.mime_type,
},
]
: []),
...(page.values.images?.length
? page.values.images?.map((image: any) => ({
name: "image",
address: image?.address,
mime_type: image?.mime_type,
}))
: []),
],
},
},
local: true,
}
pages.push(note)
}
},
)
return pages
return (
await Promise.all(
getKeys([`draft-${input.characterId}-`, `draft-${input.handle}-`]).map(
async (key) => {
const page = getStorage(key)
if (
page.isPost === input.isPost ||
input.type?.includes(page.type) ||
input.type === undefined
) {
const note: ExpandedNote = Object.assign(
await expandCrossbellNote({
note: editor2Crossbell({
values: page.values,
type: page.type,
}),
disableAutofill: true,
}),
{
draftKey: key
.replace(`draft-${input.characterId}-`, "")
.replace(`draft-${input.handle}-${input.characterId}-`, ""), // In order to be compatible with old drafts
local: true,
characterId: input.characterId,
createdAt: new Date(page.date).toISOString(),
publishedAt: new Date(page.date).toISOString(),
updatedAt: new Date(page.date).toISOString(),
},
)
return note
}
},
),
)
).filter((item): item is ExpandedNote => !!item)
}
export async function getPagesBySite(input: {
@ -349,7 +295,7 @@ export async function getPagesBySite(input: {
),
}
const local = getLocalPages({
const local = await getLocalPages({
characterId: input.characterId,
isPost: input.type[0] === "post", // In order to be compatible with old drafts
type: input.type,
@ -363,7 +309,10 @@ export async function getPagesBySite(input: {
if (index !== -1) {
if (
new Date(localPage.updatedAt) >
new Date(expandedNotes.list[index].updatedAt)
new Date(
expandedNotes.list[index].updatedAt ||
expandedNotes.list[index].createdAt,
)
) {
expandedNotes.list[index] = {
...expandedNotes.list[index],
@ -591,7 +540,7 @@ export async function getPage<TRender extends boolean = false>(input: {
}
// local page
const local = getLocalPages({
const local = await getLocalPages({
characterId: input.characterId,
handle: input.handle,
})

View File

@ -1,7 +1,6 @@
"use client"
import type { NoteEntity, NoteMetadata } from "crossbell"
import { nanoid } from "nanoid"
import type { NoteEntity } from "crossbell"
import {
useAccountState,
@ -25,9 +24,9 @@ import {
useQueryClient,
} from "@tanstack/react-query"
import { type Values } from "~/hooks/useEditorState"
import { editor2Crossbell } from "~/lib/editor-converter"
import createSearchParams from "~/lib/search-params"
import { NoteType } from "~/lib/types"
import { EditorValues, NoteType } from "~/lib/types"
import * as pageModel from "~/models/page.model"
export const useGetPagesBySiteLite = (
@ -219,7 +218,7 @@ export function useCreatePage() {
input: {
characterId?: number
type?: NoteType
} & Values,
} & EditorValues,
) => {
if (!input.characterId) {
throw new Error("characterId is required")
@ -228,55 +227,11 @@ export function useCreatePage() {
return postNote.mutate(
{
characterId: input.characterId,
metadata: {
title: input.title,
content: input.content,
date_published: input.publishedAt || new Date().toISOString(),
summary: input.excerpt,
tags: [
input.type,
...(input.tags
?.split(",")
.map((tag) => tag.trim())
.filter((tag) => tag) || []),
],
sources: ["xlog"],
attributes: [
{
trait_type: "xlog_slug",
value: input.slug || nanoid(),
},
...(input.disableAISummary
? [
{
trait_type: "xlog_disable_ai_summary",
value: input.disableAISummary,
},
]
: []),
],
attachments: [
...(input.cover?.address
? [
{
name: "cover",
address: input.cover.address,
mime_type: input.cover.mime_type,
},
]
: []),
...(input.images?.length
? input.images?.map((image) => ({
name: "image",
address: image.address,
mime_type: image.mime_type,
}))
: []),
],
external_urls: [input.externalUrl],
} as NoteMetadata & {
summary?: string
},
metadata: editor2Crossbell({
values: input,
autofill: true,
type: input.type || "post",
}).metadata.content,
},
{
onSuccess: (data, variables) => {
@ -304,7 +259,7 @@ export function useUpdatePage() {
noteId?: number
characterId?: number
type?: NoteType
} & Values,
} & EditorValues,
) => {
if (!input.characterId || !input.noteId) {
throw new Error("characterId and noteId are required")