feat: use crossbell kit to update character

This commit is contained in:
DIYgod 2023-06-15 00:38:44 +01:00
parent b50fadc2a0
commit 550c27159a
No known key found for this signature in database
8 changed files with 246 additions and 221 deletions

View File

@ -23,20 +23,18 @@ export default function SettingsCSSPage() {
const handleSubmit = (e: any) => {
e.preventDefault()
updateSite.mutate({
site: subdomain,
characterId: site.data?.characterId,
css: css,
})
}
useEffect(() => {
if (updateSite.isSuccess) {
if (updateSite.data?.code === 0) {
toast.success("Saved!")
} else {
toast.error("Failed to update site" + ": " + updateSite.data.message)
}
toast.success("Saved!")
updateSite.reset()
} else if (updateSite.isError) {
toast.error("Failed to update site")
updateSite.reset()
}
}, [updateSite.isSuccess, updateSite.isError])

View File

@ -20,13 +20,14 @@ import { OUR_DOMAIN } from "~/lib/env"
import { getSiteLink } from "~/lib/helpers"
import { useTranslation } from "~/lib/i18n/client"
import { checkDomain } from "~/models/site.model"
import { useGetSite, useUpdateSite } from "~/queries/site"
import { useGetSite, useUpdateHandle, useUpdateSite } from "~/queries/site"
export default function SettingsDomainsPage() {
const params = useParams()
const subdomain = params?.subdomain as string
const updateSite = useUpdateSite()
const updateHandle = useUpdateHandle()
const site = useGetSite(subdomain)
const userRole = useUserRole(subdomain)
const { t } = useTranslation("dashboard")
@ -45,14 +46,18 @@ export default function SettingsDomainsPage() {
})
const handleSubmit = form.handleSubmit((values) => {
updateSite.mutate({
site: subdomain,
...(subdomain !== values.subdomain && { subdomain: values.subdomain }),
...(site.data?.metadata?.content?.custom_domain !==
values.custom_domain && {
if (site.data?.metadata?.content?.custom_domain !== values.custom_domain) {
updateSite.mutate({
characterId: site.data?.characterId,
custom_domain: values.custom_domain,
}),
})
})
}
if (subdomain !== values.subdomain) {
updateHandle.mutate({
characterId: site.data?.characterId,
handle: values.subdomain,
})
}
})
const [customDomain, setCustomDomain] = useState("")
@ -66,26 +71,29 @@ export default function SettingsDomainsPage() {
const customSubdomain = customDomain?.split(".").slice(0, -2).join(".") || ""
useEffect(() => {
if (updateSite.isSuccess) {
if (updateSite.data?.code === 0) {
if (!updateSite.isLoading && !updateHandle.isLoading) {
if (updateSite.isError || updateHandle.isError) {
toast.error("Failed to update site")
} else if (updateSite.isSuccess || updateHandle.isSuccess) {
toast.success("Saved!")
useAccountState
.getState()
.refresh()
.then(() => {
router.replace(
`/dashboard/${
updateSite.variables?.subdomain || updateSite.variables?.site
}/settings/domains`,
)
})
} else {
toast.error("Failed to update site" + ": " + updateSite.data.message)
if (updateHandle.isSuccess) {
useAccountState
.getState()
.refresh()
.then(() => {
router.replace(
`/dashboard/${updateHandle.variables?.handle}/settings/domains`,
)
})
}
}
} else if (updateSite.isError) {
toast.error("Failed to update site")
}
}, [updateSite.isSuccess])
}, [
updateSite.isSuccess,
updateSite.isLoading,
updateHandle.isSuccess,
updateHandle.isLoading,
])
const [domainCheckResult, setDomainCheckResult] = useState<{
isLoading: boolean

View File

@ -49,9 +49,9 @@ export default function SiteSettingsGeneralPage() {
const handleSubmit = form.handleSubmit((values) => {
updateSite.mutate({
characterId: site.data?.characterId,
icon: values.icon,
banner: values.banner,
site: subdomain,
name: values.name,
site_name: values.site_name,
description: values.description,
@ -63,11 +63,7 @@ export default function SiteSettingsGeneralPage() {
useEffect(() => {
if (updateSite.isSuccess) {
if (updateSite.data?.code === 0) {
toast.success("Site updated")
} else {
toast.error("Failed to update site" + ": " + updateSite.data.message)
}
toast.success("Site updated")
} else if (updateSite.isError) {
toast.error("Failed to update site")
}

View File

@ -102,7 +102,7 @@ export default function SiteSettingsNavigationPage() {
e.preventDefault()
if (site.data?.handle) {
updateSite.mutate({
site: site.data?.handle,
characterId: site.data?.characterId,
navigation: items,
})
}
@ -110,11 +110,7 @@ export default function SiteSettingsNavigationPage() {
useEffect(() => {
if (updateSite.isSuccess) {
if (updateSite.data?.code === 0) {
toast.success("Saved")
} else {
toast.error("Failed to save" + ": " + updateSite.data.message)
}
toast.success("Saved")
} else if (updateSite.isError) {
toast.error("Failed to save")
}

View File

@ -116,7 +116,7 @@ export default function SiteSettingsNavigationPage() {
e.preventDefault()
if (site.data?.handle) {
updateSite.mutate({
site: site.data?.handle,
characterId: site.data?.characterId,
connected_accounts: items.map(({ id, ...item }) => item),
})
}
@ -124,11 +124,7 @@ export default function SiteSettingsNavigationPage() {
useEffect(() => {
if (updateSite.isSuccess) {
if (updateSite.data?.code === 0) {
toast.success("Saved")
} else {
toast.error("Failed to save" + ": " + updateSite.data.message)
}
toast.success("Saved")
} else if (updateSite.isError) {
toast.error("Failed to save")
}

View File

@ -1,12 +1,10 @@
import { CharacterOperatorPermission } from "crossbell"
import type Unidata from "unidata.js"
import type { Address } from "viem"
import type { useContract } from "@crossbell/contract"
import { indexer } from "@crossbell/indexer"
import { expandCrossbellCharacter } from "~/lib/expand-unit"
import { SiteNavigationItem } from "~/lib/types"
import { client } from "~/queries/graphql"
type Contract = ReturnType<typeof useContract>
@ -91,124 +89,6 @@ export const getSiteToSubscriptions = async (data: {
})
}
export async function updateSite(
payload: {
site: string
name?: string
site_name?: string
description?: string
icon?: string | null
subdomain?: string
navigation?: SiteNavigationItem[]
css?: string
ga?: string
ua?: string
uh?: string
custom_domain?: string
banner?: {
address: string
mime_type: string
}
connected_accounts?: {
identity: string
platform: string
url?: string | undefined
}[]
},
customUnidata?: Unidata,
newbieToken?: string,
) {
const { default: unidata } = await import("~/queries/unidata.server")
return await (customUnidata || unidata).profiles.set(
{
source: "Crossbell Profile",
identity: payload.site,
platform: "Crossbell",
action: "update",
},
{
...(payload.name && { name: payload.name }),
...(payload.description && { bio: payload.description }),
...(payload.icon && { avatars: [payload.icon] }),
...(payload.banner && { banners: [payload.banner] }),
...(payload.subdomain && { username: payload.subdomain }),
...(payload.connected_accounts && {
connected_accounts: payload.connected_accounts,
}),
...((payload.navigation !== undefined ||
payload.css !== undefined ||
payload.ga !== undefined ||
payload.ua !== undefined ||
payload.uh !== undefined ||
payload.custom_domain !== undefined) && {
attributes: [
...(payload.navigation !== undefined
? [
{
trait_type: "xlog_navigation",
value: JSON.stringify(payload.navigation),
},
]
: []),
...(payload.css !== undefined
? [
{
trait_type: "xlog_css",
value: payload.css,
},
]
: []),
...(payload.ga !== undefined
? [
{
trait_type: "xlog_ga",
value: payload.ga,
},
]
: []),
...(payload.ua !== undefined
? [
{
trait_type: "xlog_ua",
value: payload.ua,
},
]
: []),
...(payload.uh !== undefined
? [
{
trait_type: "xlog_uh",
value: payload.uh,
},
]
: []),
...(payload.custom_domain !== undefined
? [
{
trait_type: "xlog_custom_domain",
value: payload.custom_domain,
},
]
: []),
...(payload.site_name !== undefined &&
payload.site_name !== payload.name
? [
{
trait_type: "xlog_site_name",
value: payload.site_name,
},
]
: []),
],
}),
},
{
newbieToken,
},
)
}
export async function getCommentsBySite(input: {
characterId?: number
cursor?: string

View File

@ -6,8 +6,11 @@ import {
useFollowCharacters,
useTip,
useUnfollowCharacter,
useUpdateCharacterHandle,
useUpdateCharacterMetadata,
} from "@crossbell/connect-kit"
import { useContract } from "@crossbell/contract"
import { useRefCallback } from "@crossbell/util-hooks"
import {
useInfiniteQuery,
useMutation,
@ -15,10 +18,9 @@ import {
useQueryClient,
} from "@tanstack/react-query"
import { SiteNavigationItem } from "~/lib/types"
import * as siteModel from "~/models/site.model"
import { useUnidata } from "./unidata"
export const useGetSite = (input?: string) => {
return useQuery(["getSite", input], async () => {
if (!input) {
@ -86,21 +88,208 @@ export const useGetSiteToSubscriptions = (data: { characterId?: number }) => {
})
}
export function useUpdateSite() {
const newbieToken = useAccountState((s) => s.email?.token)
const unidata = useUnidata()
export function useUpdateHandle() {
const queryClient = useQueryClient()
const mutation = useMutation(
async (payload: Parameters<typeof siteModel.updateSite>[0]) => {
return siteModel.updateSite(payload, unidata, newbieToken)
},
{
onSuccess: (data, variables) => {
queryClient.invalidateQueries(["getSite"])
},
const { mutateAsync: _, ...updateCharacterHandle } =
useUpdateCharacterHandle()
const mutate = useRefCallback(
(input: { characterId?: number; handle?: string }) => {
if (!input.characterId || !input.handle) {
throw new Error("characterId and handle are required")
}
return updateCharacterHandle.mutate(
{
characterId: input.characterId,
handle: input.handle,
},
{
onSuccess: (data, variables) => {
queryClient.invalidateQueries(["getSite"])
},
},
)
},
)
return mutation
return {
...updateCharacterHandle,
mutate,
}
}
export function useUpdateSite() {
const queryClient = useQueryClient()
const { mutateAsync: _, ...updateCharacterMetadata } =
useUpdateCharacterMetadata()
const mutate = useRefCallback(
(input: {
characterId?: number
name?: string
site_name?: string
description?: string
icon?: string
navigation?: SiteNavigationItem[]
css?: string
ga?: string
ua?: string
uh?: string
custom_domain?: string
banner?: {
address: string
mime_type: string
}
connected_accounts?: {
identity: string
platform: string
url?: string | undefined
}[]
}) => {
if (!input.characterId) {
throw new Error("characterId are required")
}
return updateCharacterMetadata.mutate(
{
characterId: input.characterId,
edit(metadataDraft) {
if (input.name !== undefined) {
metadataDraft.name = input.name
}
if (input.description !== undefined) {
metadataDraft.bio = input.description
}
if (input.icon !== undefined) {
metadataDraft.avatars = [input.icon]
}
if (input.banner !== undefined) {
metadataDraft.banners = [input.banner]
}
if (input.connected_accounts !== undefined) {
metadataDraft.connected_accounts = input.connected_accounts.map(
(account) => {
if (account.identity && account.platform) {
return `csb://account:${
account.identity
}@${account.platform.toLowerCase()}`
} else if (typeof account === "string") {
return account
} else {
return ""
}
},
)
}
// attributes
if (input.navigation !== undefined) {
const navigation = metadataDraft.attributes?.find(
(attr) => attr.trait_type === "xlog_navigation",
)
if (navigation) {
navigation.value = JSON.stringify(input.navigation)
} else {
metadataDraft.attributes?.push({
trait_type: "xlog_navigation",
value: JSON.stringify(input.navigation),
})
}
}
if (input.css !== undefined) {
const css = metadataDraft.attributes?.find(
(attr) => attr.trait_type === "xlog_css",
)
if (css) {
css.value = input.css
} else {
metadataDraft.attributes?.push({
trait_type: "xlog_css",
value: input.css,
})
}
}
if (input.ga !== undefined) {
const ga = metadataDraft.attributes?.find(
(attr) => attr.trait_type === "xlog_ga",
)
if (ga) {
ga.value = input.ga
} else {
metadataDraft.attributes?.push({
trait_type: "xlog_ga",
value: input.ga,
})
}
}
if (input.ua !== undefined) {
const ua = metadataDraft.attributes?.find(
(attr) => attr.trait_type === "xlog_ua",
)
if (ua) {
ua.value = input.ua
} else {
metadataDraft.attributes?.push({
trait_type: "xlog_ua",
value: input.ua,
})
}
}
if (input.uh !== undefined) {
const uh = metadataDraft.attributes?.find(
(attr) => attr.trait_type === "xlog_uh",
)
if (uh) {
uh.value = input.uh
} else {
metadataDraft.attributes?.push({
trait_type: "xlog_uh",
value: input.uh,
})
}
}
if (input.custom_domain !== undefined) {
const custom_domain = metadataDraft.attributes?.find(
(attr) => attr.trait_type === "xlog_custom_domain",
)
if (custom_domain) {
custom_domain.value = input.custom_domain
} else {
metadataDraft.attributes?.push({
trait_type: "xlog_custom_domain",
value: input.custom_domain,
})
}
}
if (input.site_name !== undefined) {
const site_name = metadataDraft.attributes?.find(
(attr) => attr.trait_type === "xlog_site_name",
)
if (site_name) {
site_name.value = input.site_name
} else {
metadataDraft.attributes?.push({
trait_type: "xlog_site_name",
value: input.site_name,
})
}
}
},
},
{
onSuccess: (data, variables) => {
queryClient.invalidateQueries(["getSite"])
},
},
)
},
)
return {
...updateCharacterMetadata,
mutate,
}
}
export function useSubscribeToSite() {

View File

@ -1,38 +0,0 @@
"use client"
import { useEffect, useState } from "react"
import type Unidata from "unidata.js"
import { useAccount } from "wagmi"
import { IPFS_GATEWAY } from "../lib/env"
export const useUnidata = () => {
const { connector, isConnected } = useAccount()
const [unidata, setUnidata] = useState<Unidata>()
useEffect(() => {
import("unidata.js").then(({ default: Unidata }) => {
if (isConnected && connector) {
connector?.getProvider().then((provider) => {
setUnidata(
new Unidata({
ethereumProvider: provider,
ipfsGateway: IPFS_GATEWAY,
ipfsRelay: "https://ipfs-relay.crossbell.io/json?gnfd=t",
}),
)
})
} else {
setUnidata(
new Unidata({
ipfsGateway: IPFS_GATEWAY,
ipfsRelay: "https://ipfs-relay.crossbell.io/json?gnfd=t",
}),
)
}
})
}, [isConnected, connector])
return unidata
}