chore: remove list power pricing ui

This commit is contained in:
DIYgod 2025-12-15 12:58:39 +08:00
parent 899eb7309f
commit 45568d010f
No known key found for this signature in database
13 changed files with 34 additions and 210 deletions

View File

@ -24,7 +24,6 @@ import { useTranslation } from "react-i18next"
import { useSearchParams } from "react-router"
import { z } from "zod"
import { useIsInMASReview } from "~/atoms/server-configs"
import { useModalStack } from "~/components/ui/modal/stacked/hooks"
import { useRequireLogin } from "~/hooks/common/useRequireLogin"
import { followClient } from "~/lib/api-client"
@ -127,19 +126,15 @@ export function DiscoverForm({ type = "search" }: { type?: string }) {
const target = watch("target")
const atomKey = keywordFromSearch + target
const { t } = useTranslation()
const isInMASReview = useIsInMASReview()
const { ensureLogin } = useRequireLogin()
const jotaiStore = useStore()
const mutation = useMutation({
mutationFn: async ({ keyword, target }: { keyword: string; target: "feeds" | "lists" }) => {
let { data } = await followClient.api.discover.discover({
const { data } = await followClient.api.discover.discover({
keyword: keyword.trim(),
target,
})
if (isInMASReview) {
data = data.filter((item) => !item.list?.fee)
}
jotaiStore.set(discoverSearchDataAtom, (prev) => ({
...prev,

View File

@ -256,15 +256,7 @@ const ListInnerForm = ({
return (
<div className="flex flex-1 flex-col gap-y-4">
<FeedSummary
isLoading={isLoading}
feed={{
...list,
fee: list.fee || 0,
}}
analytics={analytics}
showAnalytics
/>
<FeedSummary isLoading={isLoading} feed={list} analytics={analytics} showAnalytics />
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-1 flex-col gap-y-4">
<FormField
@ -343,18 +335,6 @@ const ListInnerForm = ({
</FormItem>
)}
/>
{!!list.fee && !isSubscribed && (
<div>
<FormLabel className="flex items-center gap-1">
{t("feed_form.fee")}{" "}
<div className="ml-2 flex scale-[0.85] items-center gap-1">
{list.fee}
<i className="i-mgc-power size-4 text-folo" />
</div>
</FormLabel>
<FormDescription className="mt-0.5">{t("feed_form.fee_description")}</FormDescription>
</div>
)}
<div className="flex flex-1 items-center justify-end gap-4">
{isSubscribed && (
<Button
@ -369,13 +349,7 @@ const ListInnerForm = ({
</Button>
)}
<Button ref={buttonRef} type="submit" isLoading={followMutation.isPending}>
{isSubscribed
? t("feed_form.update")
: list.fee
? t("feed_form.follow_with_fee", {
fee: list.fee,
})
: t("feed_form.follow")}
{isSubscribed ? t("feed_form.update") : t("feed_form.follow")}
</Button>
</div>
</form>

View File

@ -24,7 +24,6 @@ import { useTranslation } from "react-i18next"
import { useSearchParams } from "react-router"
import { z } from "zod"
import { useIsInMASReview } from "~/atoms/server-configs"
import { useModalStack } from "~/components/ui/modal/stacked/hooks"
import { useRequireLogin } from "~/hooks/common/useRequireLogin"
import { followClient } from "~/lib/api-client"
@ -96,7 +95,6 @@ export function UnifiedDiscoverForm() {
const [searchParams, setSearchParams] = useSearchParams()
const keywordFromSearch = searchParams.get("keyword") || ""
const { t } = useTranslation()
const isInMASReview = useIsInMASReview()
const { ensureLogin } = useRequireLogin()
const { present, dismissAll } = useModalStack()
const isMobile = useMobile()
@ -163,13 +161,10 @@ export function UnifiedDiscoverForm() {
}
// For search, perform discovery
let { data } = await followClient.api.discover.discover({
const { data } = await followClient.api.discover.discover({
keyword: keyword.trim(),
target,
})
if (isInMASReview) {
data = data.filter((item) => !item.list?.fee)
}
setDiscoverSearchData((prev) => ({
...prev,

View File

@ -98,27 +98,18 @@ const ListCard = memo(({ list }: { list: ListWithStats }) => {
</div>
{/* Stats Footer */}
{(typeof list.subscriptionCount === "number" ||
(typeof list.fee === "number" && list.fee > 0)) && (
{typeof list.subscriptionCount === "number" && (
<div className="border-t border-fill-secondary px-4 py-2.5">
<div className="flex items-center justify-between text-xs">
{typeof list.subscriptionCount === "number" && (
<div className="flex items-center gap-1.5 text-text-secondary">
<i className="i-mingcute-group-2-line size-3" />
<span>
{list.subscriptionCount}
<span className="ml-1 hidden sm:inline">
{list.subscriptionCount > 1 ? "subscribers" : "subscriber"}
</span>
<div className="flex items-center gap-1.5 text-text-secondary">
<i className="i-mingcute-group-2-line size-3" />
<span>
{list.subscriptionCount}
<span className="ml-1 hidden sm:inline">
{list.subscriptionCount > 1 ? "subscribers" : "subscriber"}
</span>
</div>
)}
{typeof list.fee === "number" && list.fee > 0 && (
<div className="flex items-center gap-1.5">
<i className="i-mgc-power size-3 text-folo" />
<span className="font-medium">{list.fee}</span>
</div>
)}
</span>
</div>
</div>
</div>
)}

View File

@ -28,7 +28,6 @@ import { toast } from "sonner"
import { useCurrentModal, useModalStack } from "~/components/ui/modal/stacked/hooks"
import { useI18n } from "~/hooks/common"
import { UrlBuilder } from "~/lib/url-builder"
import { Balance } from "~/modules/wallet/balance"
import { ListCreationModalContent, ListFeedsModalContent } from "./modals"
@ -75,7 +74,6 @@ export const SettingLists = () => {
acc[curr.id] = {
id: curr.id,
subscriptionCount: curr.subscriptionCount,
purchaseAmount: Number(curr.purchaseAmount || 0),
}
return acc
},
@ -84,7 +82,6 @@ export const SettingLists = () => {
{
id: string
subscriptionCount: number | null | undefined
purchaseAmount: number | null | undefined
}
>,
)
@ -126,9 +123,7 @@ export const SettingLists = () => {
<TableRow className="[&_*]:!font-semibold">
<TableHead size="sm">{t.settings("lists.title")}</TableHead>
<TableHead size="sm">{t.settings("lists.view")}</TableHead>
<TableHead size="sm">{t.settings("lists.fee.label")}</TableHead>
<TableHead size="sm">{t.settings("lists.subscriptions")}</TableHead>
<TableHead size="sm">{t.settings("lists.earnings")}</TableHead>
<TableHead size="sm" className="center">
{t.common("words.actions")}
</TableHead>
@ -172,18 +167,9 @@ export const SettingLists = () => {
</TooltipPortal>
</Tooltip>
</TableCell>
<TableCell size="sm">
<div className="flex items-center gap-1 tabular-nums">
{row.fee}
<i className="i-mgc-power shrink-0 text-lg text-folo" />
</div>
</TableCell>
<TableCell size="sm" className="tabular-nums">
{formatNumber(listDataMap[row.id]?.subscriptionCount || 0)}
</TableCell>
<TableCell size="sm" className="tabular-nums">
<Balance>{BigInt(listDataMap[row.id]?.purchaseAmount || 0n)}</Balance>
</TableCell>
<TableCell size="sm" className="center">
<Tooltip>
<TooltipTrigger asChild>

View File

@ -4,7 +4,6 @@ import { Divider } from "@follow/components/ui/divider/index.js"
import {
Form,
FormControl,
FormDescription,
FormField,
FormItem,
FormLabel,
@ -50,7 +49,6 @@ const formSchema = z.object({
title: z.string().min(1),
description: z.string().optional(),
image: z.string().optional(),
fee: z.number().min(0),
})
export const ListCreationModalContent = ({ id }: { id?: string }) => {
@ -63,7 +61,6 @@ export const ListCreationModalContent = ({ id }: { id?: string }) => {
resolver: zodResolver(formSchema),
defaultValues: {
view: list?.view.toString() || FeedViewType.Articles.toString(),
fee: list?.fee || 0,
title: list?.title || "",
description: list?.description || "",
image: list?.image || "",
@ -172,32 +169,6 @@ export const ListCreationModalContent = ({ id }: { id?: string }) => {
</FormItem>
)}
/>
<FormField
control={form.control}
name="fee"
render={({ field }) => (
<FormItem>
<div>
<FormLabel>{t("lists.fee.label")}</FormLabel>
<FormDescription>{t("lists.fee.description")}</FormDescription>
</div>
<FormControl>
<div className="flex items-center">
<Input
{...field}
type="number"
inputMode="numeric"
pattern="[0-9]*"
min={0}
onChange={(value) => field.onChange(value.target.valueAsNumber)}
/>
<i className="i-mgc-power ml-4 shrink-0 text-xl text-folo" />
</div>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div className="flex justify-end">
<Button type="submit" isLoading={createMutation.isPending}>
{id ? t("common:words.update") : t("common:words.create")}

View File

@ -8,7 +8,7 @@ import { useQuery } from "@tanstack/react-query"
import { useEffect } from "react"
import { Controller, useForm } from "react-hook-form"
import { useTranslation } from "react-i18next"
import { Alert, StyleSheet, View } from "react-native"
import { StyleSheet, View } from "react-native"
import { z } from "zod"
import { HeaderSubmitTextButton } from "@/src/components/layouts/header/HeaderElements"
@ -24,11 +24,9 @@ import { GroupedInsetListCard } from "@/src/components/ui/grouped/GroupedList"
import { IconWithFallback } from "@/src/components/ui/icon/fallback-icon"
import { PlatformActivityIndicator } from "@/src/components/ui/loading/PlatformActivityIndicator"
import { Text } from "@/src/components/ui/typography/Text"
import { PowerIcon } from "@/src/icons/power"
import { useNavigation, useScreenIsInSheetModal } from "@/src/lib/navigation/hooks"
import { useSetModalScreenOptions } from "@/src/lib/navigation/ScreenOptionsContext"
import { toast } from "@/src/lib/toast"
import { accentColor } from "@/src/theme/colors"
import { FeedViewSelector } from "../feed/view-selector"
@ -106,27 +104,7 @@ const Impl = (props: { id: string }) => {
}
toast.success(isSubscribed ? "List updated" : "List followed")
}
if (list.fee && !isSubscribed) {
Alert.alert(
`Follow List - ${list.title}`,
`To follow this list, you must pay a fee to the list creator. Press OK to pay ${list.fee} power to follow this list.`,
[
{
text: "Cancel",
style: "cancel",
},
{
text: "OK",
onPress: () => {
subscribeOrUpdate()
},
isPreferred: true,
},
],
)
} else {
subscribeOrUpdate()
}
subscribeOrUpdate()
}
const isLoading = false
const setModalOptions = useSetModalScreenOptions()
@ -230,21 +208,6 @@ const Impl = (props: { id: string }) => {
)}
/>
</View>
{!!list.fee && (
<View className="ml-1">
<View className="flex-row">
<FormLabel label="Follow fee" optional />
<View className="ml-1 flex-row items-center gap-x-0.5">
<PowerIcon height={14} width={14} color={accentColor} />
<Text className="text-sm font-semibold text-label">{list.fee}</Text>
</View>
</View>
<Text className="text-sm text-secondary-label">
To follow this list, you must pay a fee to the list creator.
</Text>
</View>
)}
</FormProvider>
</GroupedInsetListCard>
</SafeNavigationScrollView>

View File

@ -7,7 +7,6 @@ import { Image, StyleSheet, View } from "react-native"
import Animated, { LinearTransition } from "react-native-reanimated"
import { useColor, useColors } from "react-native-uikit-colors"
import { Balance } from "@/src/components/common/Balance"
import { UINavigationHeaderActionButton } from "@/src/components/layouts/header/NavigationHeader"
import {
NavigationBlurEffectHeaderView,
@ -23,10 +22,8 @@ import { ItemPressable } from "@/src/components/ui/pressable/ItemPressable"
import { Text } from "@/src/components/ui/typography/Text"
import { views } from "@/src/constants/views"
import { AddCuteReIcon } from "@/src/icons/add_cute_re"
import { PowerIcon } from "@/src/icons/power"
import { RadaCuteFiIcon } from "@/src/icons/rada_cute_fi"
import { UserAdd2CuteFiIcon } from "@/src/icons/user_add_2_cute_fi"
import { Wallet2CuteFiIcon } from "@/src/icons/wallet_2_cute_fi"
import { useNavigation } from "@/src/lib/navigation/hooks"
import { ListScreen } from "@/src/screens/(modal)/ListScreen"
import { accentColor } from "@/src/theme/colors"
@ -141,6 +138,7 @@ const ListItemCellImpl: ListRenderItem<ListModel> = ({ item: list }) => {
const listData = use(ListContext)[list.id]
const navigation = useNavigation()
const colors = useColors()
const subscriptionCount = listData?.subscriptionCount ?? list.subscriptionCount ?? 0
return (
<SwipeableItem
swipeRightToCallAction
@ -211,34 +209,11 @@ const ListItemCellImpl: ListRenderItem<ListModel> = ({ item: list }) => {
{t(views.find((v) => v.view === list.view)!.name)}
</Text>
)}
</View>
</View>
<View
className="mx-4 h-full bg-opaque-separator"
style={{
width: StyleSheet.hairlineWidth,
}}
/>
<View className="w-16 gap-1">
<View className="flex-row items-center gap-1">
<PowerIcon height={16} width={16} color={accentColor} />
<Text className="text-sm text-secondary-label">{list.fee}</Text>
</View>
<View className="flex-row items-center gap-1">
<UserAdd2CuteFiIcon height={16} width={16} color={accentColor} />
<Text className="text-sm text-secondary-label">{listData?.subscriptionCount || 0}</Text>
</View>
{!!listData?.purchaseAmount && (
<View className="flex-row items-center gap-1">
<Wallet2CuteFiIcon height={16} width={16} color={accentColor} />
<Balance className="text-sm text-secondary-label">
{BigInt(listData.purchaseAmount)}
</Balance>
<View className="ml-1 flex-row items-center gap-1">
<UserAdd2CuteFiIcon height={16} width={16} color={accentColor} />
<Text className="text-sm text-secondary-label">{subscriptionCount}</Text>
</View>
)}
</View>
</View>
</ItemPressable>
</SwipeableItem>

View File

@ -3,7 +3,7 @@ import { FeedViewType } from "@follow/constants"
import { getListById } from "@follow/store/list/getters"
import { useListById } from "@follow/store/list/hooks"
import { listSyncServices } from "@follow/store/list/store"
import type { CreateListModel, ListModel } from "@follow/store/list/types"
import type { CreateListModel } from "@follow/store/list/types"
import { zodResolver } from "@hookform/resolvers/zod"
import { memo, useEffect, useState } from "react"
import { Controller, useForm } from "react-hook-form"
@ -18,19 +18,17 @@ import {
} from "@/src/components/layouts/views/SafeNavigationScrollView"
import { FormProvider, useFormContext } from "@/src/components/ui/form/FormProvider"
import { FormLabel } from "@/src/components/ui/form/Label"
import { NumberField, TextField } from "@/src/components/ui/form/TextField"
import { TextField } from "@/src/components/ui/form/TextField"
import {
GroupedInsetButtonCell,
GroupedInsetListCard,
} from "@/src/components/ui/grouped/GroupedList"
import { PowerIcon } from "@/src/icons/power"
import { useNavigation } from "@/src/lib/navigation/hooks"
import { useSetModalScreenOptions } from "@/src/lib/navigation/ScreenOptionsContext"
import type { NavigationControllerView } from "@/src/lib/navigation/types"
import { getBizFetchErrorMessage } from "@/src/lib/parse-api-error"
import { toast } from "@/src/lib/toast"
import { FeedViewSelector } from "@/src/modules/feed/view-selector"
import { accentColor } from "@/src/theme/colors"
const listSchema = z.object({
title: z.string().min(1),
@ -41,8 +39,6 @@ const listSchema = z.object({
.nullable()
.optional()
.transform((val) => (val === "" ? null : val)),
fee: z.number().min(0).nullable().optional(),
view: z.number().int(),
})
@ -50,16 +46,22 @@ const defaultValues = {
title: "",
description: null,
image: null,
fee: 0,
view: FeedViewType.Articles,
} as ListModel
} satisfies z.infer<typeof listSchema>
export const ListScreen: NavigationControllerView<{
listId?: string
}> = ({ listId }) => {
const { t } = useTranslation("settings")
const list = useListById(listId || "")
const form = useForm({
defaultValues: list || defaultValues,
const form = useForm<z.infer<typeof listSchema>>({
defaultValues: list
? {
title: list.title ?? "",
description: list.description ?? null,
image: list.image ?? null,
view: list.view ?? FeedViewType.Articles,
}
: defaultValues,
resolver: zodResolver(listSchema),
mode: "all",
})
@ -144,26 +146,6 @@ export const ListScreen: NavigationControllerView<{
)}
/>
</View>
<View className="mt-4">
<Controller
name="fee"
control={form.control}
render={({ field: { onChange, onBlur, ref, value } }) => (
<NumberField
label={t("lists.fee.label")}
wrapperClassName="mt-2"
placeholder="0"
onBlur={onBlur}
onChangeNumber={onChange}
defaultValue={list?.fee ?? 0}
value={value ?? 0}
inputPostfixElement={<PowerIcon color={accentColor} />}
ref={ref}
/>
)}
/>
</View>
</GroupedInsetListCard>
{isEditing && (

View File

@ -217,12 +217,6 @@ const Lists = ({ userId }: { userId: string }) => {
</span>
</div>
)}
{typeof list.fee === "number" && list.fee > 0 && (
<div className="flex items-center space-x-1">
<i className="i-mingcute-copper-coin-line" />
<span>{list.fee}</span>
</div>
)}
</div>
</div>
<div className="absolute bottom-4 right-4">

View File

@ -99,7 +99,6 @@ class ListSyncServices {
description: params.list.description,
image: params.list.image,
view: params.list.view,
fee: params.list.fee || 0,
})
await listActions.upsertMany([apiMorph.toList(res.data)])
await subscriptionActions.upsertMany([
@ -126,7 +125,6 @@ class ListSyncServices {
description: params.list.description,
image: params.list.image,
view: params.list.view,
fee: params.list.fee || 0,
listId: params.listId,
}

View File

@ -1,6 +1,6 @@
import type { ListSchema } from "@follow/database/schemas/types"
export type CreateListModel = Pick<ListModel, "description" | "image" | "view" | "fee"> & {
export type CreateListModel = Pick<ListModel, "description" | "image" | "view"> & {
title: string
}

View File

@ -151,7 +151,7 @@ class APIMorph {
image: list.image!,
ownerUserId: list.owner.id,
feedIds: list.feedIds!,
fee: list.fee!,
fee: list.fee ?? 0,
subscriptionCount: null,
purchaseAmount: null,
type: "list",