From da9a4dd2f8f31163b69921818cb7edbf60ce21ad Mon Sep 17 00:00:00 2001 From: Stephen Zhou <38493346+hyoban@users.noreply.github.com> Date: Tue, 21 Jan 2025 20:38:06 +0800 Subject: [PATCH 1/2] feat: store to buy subscription limit --- .../src/modules/power/store-section/index.tsx | 82 +++++++++++++++++++ .../(main)/(layer)/(subview)/power/index.tsx | 4 + apps/renderer/src/queries/store.ts | 34 ++++++++ locales/errors/en.json | 4 +- locales/settings/en.json | 9 ++ packages/shared/src/hono.ts | 65 ++++++++++++++- 6 files changed, 195 insertions(+), 3 deletions(-) create mode 100644 apps/renderer/src/modules/power/store-section/index.tsx create mode 100644 apps/renderer/src/queries/store.ts diff --git a/apps/renderer/src/modules/power/store-section/index.tsx b/apps/renderer/src/modules/power/store-section/index.tsx new file mode 100644 index 0000000000..dfe5bd9eaf --- /dev/null +++ b/apps/renderer/src/modules/power/store-section/index.tsx @@ -0,0 +1,82 @@ +import { Button } from "@follow/components/ui/button/index.js" +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@follow/components/ui/table/index.jsx" +import { useTranslation } from "react-i18next" + +import { useTOTPModalWrapper } from "~/modules/profile/hooks" +import { SettingSectionTitle } from "~/modules/settings/section" +import type { Product } from "~/queries/store" +import { useProductList, usePurchaseProduct } from "~/queries/store" +import { useWallet } from "~/queries/wallet" + +export const StoreSection: Component = () => { + const { t } = useTranslation("settings") + + const wallet = useWallet() + const myWallet = wallet.data?.[0] + + if (!myWallet) return null + + return ( +
+ + +
+ ) +} + +const ProductList: Component = () => { + const { t } = useTranslation("settings") + const { data: products } = useProductList() + if (!products) return null + + return ( + + + + {t("wallet.store.product.name")} + {t("wallet.store.product.category")} + {t("wallet.store.product.price")} + {t("wallet.store.product.quantity_per_user")} + {t("wallet.store.product.quantity_purchased")} + {t("wallet.store.product.action")} + + + + {products.map((product) => ( + + {product.name} + {product.category} + {product.price} + {product.quantityPerUser} + {product.quantityPurchased} + + + + + ))} + +
+ ) +} + +const PurchaseButton: Component<{ product: Product }> = ({ product }) => { + const mutation = usePurchaseProduct() + const { t } = useTranslation("settings") + const present = useTOTPModalWrapper(mutation.mutateAsync) + return ( + + ) +} diff --git a/apps/renderer/src/pages/(main)/(layer)/(subview)/power/index.tsx b/apps/renderer/src/pages/(main)/(layer)/(subview)/power/index.tsx index 650ce43460..694b2145c2 100644 --- a/apps/renderer/src/pages/(main)/(layer)/(subview)/power/index.tsx +++ b/apps/renderer/src/pages/(main)/(layer)/(subview)/power/index.tsx @@ -5,6 +5,7 @@ import { useTranslation } from "react-i18next" import { useSubViewTitle } from "~/modules/app-layout/subview/hooks" import { MyWalletSection } from "~/modules/power/my-wallet-section" import { PowerRanking } from "~/modules/power/ranking" +import { StoreSection } from "~/modules/power/store-section" import { TransactionsSection } from "~/modules/power/transaction-section" export function Component() { @@ -28,6 +29,9 @@ export function Component() { + + + diff --git a/apps/renderer/src/queries/store.ts b/apps/renderer/src/queries/store.ts new file mode 100644 index 0000000000..a5021a113e --- /dev/null +++ b/apps/renderer/src/queries/store.ts @@ -0,0 +1,34 @@ +import { useMutation } from "@tanstack/react-query" +import { useTranslation } from "react-i18next" +import { toast } from "sonner" + +import { useAuthQuery } from "~/hooks/common" +import { apiClient } from "~/lib/api-fetch" +import { defineQuery } from "~/lib/defineQuery" + +export const store = { + products: { + get: () => + defineQuery(["store", "products"], async () => { + const { data } = await apiClient.store.products.$get() + return data.products + }), + }, +} +export type Product = Awaited< + ReturnType +>["data"]["products"][number] +export const useProductList = () => useAuthQuery(store.products.get()) + +export const usePurchaseProduct = () => { + const { t } = useTranslation("settings") + return useMutation({ + mutationKey: ["purchaseProduct"], + mutationFn: ({ productId, TOTPCode }: { productId: string } & { TOTPCode?: string }) => + apiClient.store.products.$post({ json: { productId, TOTPCode } }), + onSuccess() { + toast.success(t("wallet.store.product.purchase_success")) + store.products.get().invalidate() + }, + }) +} diff --git a/locales/errors/en.json b/locales/errors/en.json index 9adf4165fd..20b9c91ae4 100644 --- a/locales/errors/en.json +++ b/locales/errors/en.json @@ -60,5 +60,7 @@ "13003": "RSSHub not found", "13004": "RSSHub user limit exceeded", "13005": "RSSHub purchase not found", - "13006": "RSSHub config invalid" + "13006": "RSSHub config invalid", + "14000": "Product not found", + "14001": "Product sold out" } diff --git a/locales/settings/en.json b/locales/settings/en.json index 1c3d65e553..343ab4fce1 100644 --- a/locales/settings/en.json +++ b/locales/settings/en.json @@ -375,6 +375,15 @@ "wallet.rewardDescription.title": "Reward Description", "wallet.rewardDescription.total": "Total Reward Per Day", "wallet.sidebar_title": "Power", + "wallet.store.product.action": "Action", + "wallet.store.product.buy": "Buy", + "wallet.store.product.category": "Category", + "wallet.store.product.name": "Name", + "wallet.store.product.price": "Price", + "wallet.store.product.purchase_success": "Product purchased successfully", + "wallet.store.product.quantity_per_user": "Quantity Per User", + "wallet.store.product.quantity_purchased": "Quantity Purchased", + "wallet.store.title": "Store", "wallet.transactions.amount": "Amount", "wallet.transactions.date": "Date", "wallet.transactions.description": "Certain transactions incur a {{percentage}}% platform fee to support Follow go further. For details, please refer to the blockchain transaction.", diff --git a/packages/shared/src/hono.ts b/packages/shared/src/hono.ts index bcd635b41a..84c7c874df 100644 --- a/packages/shared/src/hono.ts +++ b/packages/shared/src/hono.ts @@ -6455,6 +6455,23 @@ declare const transactions: drizzle_orm_pg_core.PgTableWithColumns<{ identity: undefined; generated: undefined; }, {}, {}>; + toProductId: drizzle_orm_pg_core.PgColumn<{ + name: "to_product_id"; + tableName: "transactions"; + dataType: "string"; + columnType: "PgText"; + data: string; + driverParam: string; + notNull: false; + hasDefault: false; + isPrimaryKey: false; + isAutoincrement: false; + hasRuntimeDefault: false; + enumValues: [string, ...string[]]; + baseColumn: never; + identity: undefined; + generated: undefined; + }, {}, {}>; powerToken: drizzle_orm_pg_core.PgColumn<{ name: "power_token"; tableName: "transactions"; @@ -6535,6 +6552,7 @@ declare const transactionsOpenAPISchema: zod.ZodObject<{ toListId: zod.ZodNullable; toEntryId: zod.ZodNullable; toRSSHubId: zod.ZodNullable; + toProductId: zod.ZodNullable; powerToken: zod.ZodString; tax: zod.ZodString; createdAt: zod.ZodString; @@ -6550,6 +6568,7 @@ declare const transactionsOpenAPISchema: zod.ZodObject<{ toListId: string | null; toEntryId: string | null; toRSSHubId: string | null; + toProductId: string | null; tax: string; comment: string | null; }, { @@ -6563,6 +6582,7 @@ declare const transactionsOpenAPISchema: zod.ZodObject<{ toListId: string | null; toEntryId: string | null; toRSSHubId: string | null; + toProductId: string | null; tax: string; comment: string | null; }>; @@ -15605,6 +15625,7 @@ declare const _routes: hono_hono_base.HonoBase | hono_types.MergeSchemaPath<{ +}, "/boosts"> | hono_types.MergeSchemaPath<{ "/postgresql": { $get: { input: {}; @@ -16729,7 +16750,47 @@ declare const _routes: hono_hono_base.HonoBase, "/">; +}, "/rsshub"> | hono_types.MergeSchemaPath, "/store">, "/">; type AppType = typeof _routes; export { type ActionsModel, type AirdropActivity, type AppType, type AttachmentsModel, type AuthSession, type AuthUser, CommonEntryFields, type ConditionItem, type DetailModel, type EntriesModel, type EntryReadHistoriesModel, type ExtraModel, type FeedModel, type MediaModel, type MessagingData, MessagingType, type SettingsModel, type UrlReadsModel, account, achievements, achievementsOpenAPISchema, actions, actionsItemOpenAPISchema, actionsOpenAPISchema, actionsRelations, activityEnum, airdrops, airdropsOpenAPISchema, attachmentsZodSchema, authPlugins, boosts, collections, collectionsOpenAPISchema, collectionsRelations, detailModelSchema, entries, entriesOpenAPISchema, entriesRelations, entryReadHistories, entryReadHistoriesOpenAPISchema, entryReadHistoriesRelations, extraZodSchema, feedPowerTokens, feedPowerTokensOpenAPISchema, feedPowerTokensRelations, feeds, feedsOpenAPISchema, feedsRelations, inboxHandleSchema, inboxes, inboxesEntries, inboxesEntriesInsertOpenAPISchema, type inboxesEntriesModel, inboxesEntriesOpenAPISchema, inboxesEntriesRelations, inboxesOpenAPISchema, inboxesRelations, invitations, invitationsOpenAPISchema, invitationsRelations, languageSchema, levels, levelsOpenAPISchema, levelsRelations, lists, listsOpenAPISchema, listsRelations, listsSubscriptions, listsSubscriptionsOpenAPISchema, listsSubscriptionsRelations, listsTimeline, listsTimelineOpenAPISchema, listsTimelineRelations, lower, mediaZodSchema, messaging, messagingOpenAPISchema, messagingRelations, rsshub, rsshubOpenAPISchema, rsshubPurchase, rsshubUsage, rsshubUsageOpenAPISchema, rsshubUsageRelations, session, settings, subscriptions, subscriptionsOpenAPISchema, subscriptionsRelations, timeline, timelineOpenAPISchema, timelineRelations, transactionType, transactions, transactionsOpenAPISchema, transactionsRelations, twoFactor, urlReads, urlReadsOpenAPISchema, user, users, usersOpenApiSchema, usersRelations, verification, wallets, walletsOpenAPISchema, walletsRelations }; From f3661d57562039e32026839d21f59e17b64295ad Mon Sep 17 00:00:00 2001 From: Stephen Zhou <38493346+hyoban@users.noreply.github.com> Date: Tue, 21 Jan 2025 20:38:51 +0800 Subject: [PATCH 2/2] chore: update --- locales/settings/en.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/locales/settings/en.json b/locales/settings/en.json index 343ab4fce1..b24e272bdc 100644 --- a/locales/settings/en.json +++ b/locales/settings/en.json @@ -381,8 +381,8 @@ "wallet.store.product.name": "Name", "wallet.store.product.price": "Price", "wallet.store.product.purchase_success": "Product purchased successfully", - "wallet.store.product.quantity_per_user": "Quantity Per User", - "wallet.store.product.quantity_purchased": "Quantity Purchased", + "wallet.store.product.quantity_per_user": "Quantity", + "wallet.store.product.quantity_purchased": "Purchased", "wallet.store.title": "Store", "wallet.transactions.amount": "Amount", "wallet.transactions.date": "Date",