+
To claim this feed as your own, you need to verify ownership.
+
+ There are three ways to choose from, you can choose one of them to
+ verify.
+
+
+
+ Content
+ Description
+ RSS Tag
+
+
+
+ Copy the content below and post it to your latest RSS feed.
+
+ {claimMessage?.data.content || ""}
+
+
+
+ Copy the following content and paste it into the
+ {" "}
+ {``}
+ {" "}
+ field of your
+ RSS feed.
+
+
+ {claimMessage?.data.description || ""}
+
+
+
+
+
Copy the code below and paste it into your RSS generator.
+
+ RSS generators generally have two formats to choose from. Please
+ copy the XML and JSON formats below as needed.
+
+
+ XML Format
+
+
{claimMessage?.data.xml || ""}
+
+ JSON Format
+
+
{claimMessage?.data.json || ""}
+
+
+
+
+
+
+ claim()}
+ variant={isSuccess ? "plain" : "primary"}
+ >
+ {isSuccess && }
+ Claim
+
+
+
+ )
+}
+
+const BaseCodeBlock: FC<{
+ children: string
+}> = ({ children }) => (
+ {
+ claimFeed()
+ },
+ },
+ feed.ownerUserId === getUser()?.id && {
+ type: "text",
+ label: "This feed is owned by you",
+ },
+ {
+ type: "separator",
+ },
+
{
type: "text",
label: "Open Feed in Browser",
diff --git a/src/renderer/src/pages/(main)/(layer)/(subview)/profile/index.tsx b/src/renderer/src/pages/(main)/(layer)/(subview)/profile/index.tsx
index 2165e0b684..a58890e9f7 100644
--- a/src/renderer/src/pages/(main)/(layer)/(subview)/profile/index.tsx
+++ b/src/renderer/src/pages/(main)/(layer)/(subview)/profile/index.tsx
@@ -1,3 +1,4 @@
+import { useUser } from "@renderer/atoms/user"
import {
Avatar,
AvatarFallback,
@@ -8,19 +9,18 @@ import { useSignOut } from "@renderer/hooks"
import { views } from "@renderer/lib/constants"
import { cn } from "@renderer/lib/utils"
import { FeedList } from "@renderer/modules/feed-column/list"
-import { useSession } from "@renderer/queries/auth"
export function Component() {
- const { session } = useSession()
+ const user = useUser()
const signOut = useSignOut()
return (
-
- {session?.user?.name?.slice(0, 2)}
+
+ {user?.name?.slice(0, 2)}
-
{session?.user?.name}
+
{user?.name}
-
-
+
+
+ {settingTabs.map((t) => (
+
+
+
+ ))}
+
+
+
+ {APP_NAME}
+
- {settingTabs.map((t) => (
-
-
-
- ))}
diff --git a/src/renderer/src/pages/settings/profile.tsx b/src/renderer/src/pages/settings/profile.tsx
index 0ccc41e433..17947151e7 100644
--- a/src/renderer/src/pages/settings/profile.tsx
+++ b/src/renderer/src/pages/settings/profile.tsx
@@ -1,4 +1,5 @@
import { zodResolver } from "@hookform/resolvers/zod"
+import { useUser } from "@renderer/atoms/user"
import { StyledButton } from "@renderer/components/ui/button"
import {
Form,
@@ -12,7 +13,6 @@ import {
import { Input } from "@renderer/components/ui/input"
import { apiClient } from "@renderer/lib/api-fetch"
import { SettingsTitle } from "@renderer/modules/settings/title"
-import { useSession } from "@renderer/queries/auth"
import { useMutation } from "@tanstack/react-query"
import { useForm } from "react-hook-form"
import { toast } from "sonner"
@@ -25,14 +25,14 @@ const formSchema = z.object({
})
export function Component() {
- const { session } = useSession()
+ const user = useUser()
const form = useForm
>({
resolver: zodResolver(formSchema),
defaultValues: {
- handle: session?.user?.handle || "",
- name: session?.user?.name || "",
- avatar: session?.user?.image || "",
+ handle: user?.handle || "",
+ name: user?.name || "",
+ avatar: user?.image || "",
},
})
diff --git a/src/renderer/src/providers/root-providers.tsx b/src/renderer/src/providers/root-providers.tsx
index 54a5aca8cc..4721571e75 100644
--- a/src/renderer/src/providers/root-providers.tsx
+++ b/src/renderer/src/providers/root-providers.tsx
@@ -11,6 +11,7 @@ import { HelmetProvider } from "react-helmet-async"
import { BizRouterProvider } from "./biz-router-provider"
import { ContextMenuProvider } from "./context-menu-provider"
+import { UserProvider } from "./user-provider"
const loadFeatures = () =>
import("../framer-lazy-feature").then((res) => res.default)
@@ -29,6 +30,7 @@ export const RootProviders: FC = ({ children }) => (
>
+
{children}
diff --git a/src/renderer/src/providers/user-provider.tsx b/src/renderer/src/providers/user-provider.tsx
new file mode 100644
index 0000000000..fd0de95835
--- /dev/null
+++ b/src/renderer/src/providers/user-provider.tsx
@@ -0,0 +1,14 @@
+import { useSetUser } from "@renderer/atoms/user"
+import { useSession } from "@renderer/queries/auth"
+import { useEffect } from "react"
+
+export const UserProvider = () => {
+ const { session } = useSession()
+ const setUser = useSetUser()
+ useEffect(() => {
+ if (!session?.user) return
+ setUser(session.user)
+ }, [session?.user, setUser])
+
+ return null
+}
diff --git a/src/renderer/src/queries/auth.ts b/src/renderer/src/queries/auth.ts
index ea907e3d5e..d2be5db3b5 100644
--- a/src/renderer/src/queries/auth.ts
+++ b/src/renderer/src/queries/auth.ts
@@ -41,7 +41,7 @@ export const useSession = () => {
/**
* Fetch session data, copy and patch code from @hono/auth-js/react
*/
-export async function fetchData(
+async function fetchData(
path: string,
req: any = {},
diff --git a/src/renderer/src/queries/feed.ts b/src/renderer/src/queries/feed.ts
index d9da8c4dd2..92b8b4f37b 100644
--- a/src/renderer/src/queries/feed.ts
+++ b/src/renderer/src/queries/feed.ts
@@ -1,15 +1,13 @@
+import { getUser } from "@renderer/atoms/user"
import { useBizQuery } from "@renderer/hooks"
-import { apiClient } from "@renderer/lib/api-fetch"
+import { apiClient, getFetchErrorMessage } from "@renderer/lib/api-fetch"
import { defineQuery } from "@renderer/lib/defineQuery"
+import { feedActions } from "@renderer/store"
+import { useMutation } from "@tanstack/react-query"
+import { toast } from "sonner"
export const feed = {
- byId: ({
- id,
- url,
- }: {
- id?: string
- url?: string
- }) =>
+ byId: ({ id, url }: { id?: string, url?: string }) =>
defineQuery(
["feed", id, url],
async () => {
@@ -26,18 +24,37 @@ export const feed = {
rootKey: ["feed"],
},
),
+ claimMessage: ({ feedId }: { feedId: string }) =>
+ defineQuery(["feed", "claimMessage", feedId], async () =>
+ apiClient.feeds.claim.message.$get({ query: { feedId } })),
}
-export const useFeed = ({
- id,
- url,
-}: {
- id?: string
- url?: string
-}) =>
- useBizQuery(feed.byId({
- id,
- url,
- }), {
- enabled: !!id || !!url,
- })
+export const useFeed = ({ id, url }: { id?: string, url?: string }) =>
+ useBizQuery(
+ feed.byId({
+ id,
+ url,
+ }),
+ {
+ enabled: !!id || !!url,
+ },
+ )
+
+export const useClaimFeedMutation = (feedId: string) => useMutation({
+ mutationKey: ["claimFeed", feedId],
+ mutationFn: () =>
+ apiClient.feeds.claim.challenge.$post({
+ json: {
+ feedId,
+ },
+ }),
+
+ async onError(err) {
+ toast.error(await getFetchErrorMessage(err))
+ },
+ onSuccess() {
+ feedActions.patch(feedId, {
+ ownerUserId: getUser()?.id,
+ })
+ },
+})
diff --git a/src/renderer/src/store/feed/store.ts b/src/renderer/src/store/feed/store.ts
index 2a0f58e95c..79a40b84e9 100644
--- a/src/renderer/src/store/feed/store.ts
+++ b/src/renderer/src/store/feed/store.ts
@@ -18,7 +18,9 @@ export const useFeedStore = createZustandStore(
set((state) =>
produce(state, (state) => {
for (const feed of feeds) {
- if (feed.id) { state.feeds[feed.id] = feed }
+ if (feed.id) {
+ state.feeds[feed.id] = feed
+ }
}
}),
)
@@ -34,7 +36,19 @@ export const useFeedStore = createZustandStore(
}),
)
},
+
+ patch(feedId, patch) {
+ set((state) =>
+ produce(state, (state) => {
+ const feed = state.feeds[feedId]
+ if (!feed) return
+
+ Object.assign(feed, patch)
+ }),
+ )
+ },
}))
export const feedActions = getStoreActions(useFeedStore)
-export const getFeedById = (feedId: string): Nullable => useFeedStore.getState().feeds[feedId]
+export const getFeedById = (feedId: string): Nullable =>
+ useFeedStore.getState().feeds[feedId]
diff --git a/src/renderer/src/store/feed/types.ts b/src/renderer/src/store/feed/types.ts
index 927666226d..a52c9703aa 100644
--- a/src/renderer/src/store/feed/types.ts
+++ b/src/renderer/src/store/feed/types.ts
@@ -10,4 +10,5 @@ export interface FeedActions {
upsertMany: (feeds: FeedModel[]) => void
optimisticUpdate: (feedId: FeedId, changed: Partial) => void
clear: () => void
+ patch: (feedId: FeedId, patch: Partial) => void
}