Skip to content

Commit e1daec3

Browse files
committed
feat(power): restrict power usage to wallet
1 parent 88ad11a commit e1daec3

25 files changed

Lines changed: 78 additions & 189 deletions

File tree

apps/desktop/layer/renderer/src/modules/discover/FeedForm.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ export const FeedForm: Component<{
117117
isError: feedQuery.isError,
118118
})
119119
}
120-
}, [feedQuery.isLoading])
120+
}, [feedQuery.data?.feed.url, feedQuery.isError, feedQuery.isLoading, id, url])
121121

122122
return (
123123
<div
@@ -250,7 +250,7 @@ const FeedInnerForm = ({
250250

251251
useEffect(() => {
252252
setClickOutSideToDismiss(!form.formState.isDirty)
253-
}, [form.formState.isDirty])
253+
}, [form.formState.isDirty, setClickOutSideToDismiss])
254254

255255
useEffect(() => {
256256
if (subscription) {
@@ -262,7 +262,7 @@ const FeedInnerForm = ({
262262
form.setValue("hideFromTimeline", subscription.hideFromTimeline)
263263
subscription?.title && form.setValue("title", subscription.title)
264264
}
265-
}, [subscription])
265+
}, [form, subscription])
266266

267267
useEffect(() => {
268268
if (
@@ -272,7 +272,7 @@ const FeedInnerForm = ({
272272
) {
273273
form.setValue("view", `${analytics.view}`)
274274
}
275-
}, [analytics, subscription, defaultValues?.view])
275+
}, [analytics, defaultValues?.view, form, subscription])
276276

277277
const followMutation = useMutation({
278278
mutationFn: async (values: z.infer<typeof formSchema>) => {

apps/desktop/layer/renderer/src/modules/power/my-wallet-section/withdraw.tsx

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ import { useTOTPModalWrapper } from "~/modules/profile/hooks"
3131
import { Balance } from "~/modules/wallet/balance"
3232
import { useWallet, wallet as walletActions } from "~/queries/wallet"
3333

34+
const RSS3_CONVERSION_RATE = 0.043
35+
3436
export const WithdrawButton = () => {
3537
const { t } = useTranslation("settings")
3638
const { present } = useModalStack()
@@ -54,18 +56,22 @@ const WithdrawModalContent = ({ dismiss }: { dismiss: () => void }) => {
5456
const wallet = useWallet()
5557
const cashablePowerTokenBigInt = [BigInt(wallet.data?.[0]!.cashablePowerToken || 0n), 18] as const
5658
const cashablePowerTokenNumber = toNumber(cashablePowerTokenBigInt)
59+
const walletAddress = wallet.data?.[0]?.address ?? "-"
5760

5861
const formSchema = z.object({
5962
address: z.string().startsWith("0x").length(42),
6063
amount: z.number().positive().max(cashablePowerTokenNumber),
61-
toRss3: z.boolean().optional(),
64+
toRss3: z.boolean(),
6265
})
6366

6467
const form = useForm<z.infer<typeof formSchema>>({
6568
resolver: zodResolver(formSchema),
69+
defaultValues: {
70+
toRss3: true,
71+
},
6672
})
67-
68-
const rss3ConversionRate: number | null = null
73+
const withdrawAmount = form.watch("amount")
74+
const receiveAmount = Number.isFinite(withdrawAmount) ? withdrawAmount * RSS3_CONVERSION_RATE : 0
6975

7076
const mutation = useMutation({
7177
mutationFn: async ({
@@ -91,7 +97,7 @@ const WithdrawModalContent = ({ dismiss }: { dismiss: () => void }) => {
9197
const present = useTOTPModalWrapper(mutation.mutateAsync, { force: true })
9298

9399
const onSubmit = (values: z.infer<typeof formSchema>) => {
94-
present(values)
100+
present({ ...values, toRss3: true })
95101
}
96102

97103
useEffect(() => {
@@ -126,6 +132,9 @@ const WithdrawModalContent = ({ dismiss }: { dismiss: () => void }) => {
126132
</div>
127133
<Form {...form}>
128134
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4 lg:w-96">
135+
<div className="rounded-md border border-orange/20 bg-orange/10 p-3 text-xs leading-relaxed text-text-secondary">
136+
{t("wallet.withdraw.gasFeeNotice", { address: walletAddress })}
137+
</div>
129138
<FormField
130139
control={form.control}
131140
name="address"
@@ -161,7 +170,7 @@ const WithdrawModalContent = ({ dismiss }: { dismiss: () => void }) => {
161170
<FormField
162171
control={form.control}
163172
name="toRss3"
164-
render={({ field }) => (
173+
render={() => (
165174
<FormItem>
166175
<div className="flex items-center gap-2">
167176
<FormLabel className="flex items-center gap-1">
@@ -173,25 +182,23 @@ const WithdrawModalContent = ({ dismiss }: { dismiss: () => void }) => {
173182
<TooltipPortal>
174183
<TooltipContent>
175184
<span className="text-xs text-gray-500">
176-
<span>1 POWER = {rss3ConversionRate ?? "-"} RSS3</span>
185+
<span>1 POWER = {RSS3_CONVERSION_RATE} RSS3</span>
177186
</span>
178187
</TooltipContent>
179188
</TooltipPortal>
180189
</Tooltip>
181190
</FormLabel>
182191
<FormControl className="!mt-0">
183192
<span className="inline-flex">
184-
<Switch checked={field.value} onCheckedChange={field.onChange} />
193+
<Switch checked={true} disabled />
185194
</span>
186195
</FormControl>
187196
</div>
188-
{field.value && rss3ConversionRate !== null && (
189-
<span className="text-xs text-gray-500">
190-
{t("wallet.withdraw.receiveRSS3", {
191-
amount: ((form.watch("amount") || 0) * rss3ConversionRate).toFixed(4),
192-
})}
193-
</span>
194-
)}
197+
<span className="text-xs text-gray-500">
198+
{t("wallet.withdraw.receiveRSS3", {
199+
amount: receiveAmount.toFixed(4),
200+
})}
201+
</span>
195202
<FormMessage />
196203
</FormItem>
197204
)}

apps/desktop/layer/renderer/src/modules/rsshub/add-modal-content.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export function AddModalContent({
5555
if (addRSSHubMutation.isSuccess) {
5656
dismiss()
5757
}
58-
}, [addRSSHubMutation.isSuccess])
58+
}, [addRSSHubMutation.isSuccess, dismiss])
5959

6060
useEffect(() => {
6161
if (details.data?.instance.baseUrl) {
@@ -64,12 +64,11 @@ export function AddModalContent({
6464
accessKey: details.data.instance.accessKey || undefined,
6565
})
6666
}
67-
}, [details.data])
67+
}, [details.data, form])
6868

6969
const codes = [
7070
`FOLLOW_OWNER_USER_ID=${me?.handle || me?.id} # User id or handle of your follow account`,
7171
`FOLLOW_DESCRIPTION=${instance?.description || `${me?.name}'s instance`} # The description of your instance`,
72-
`FOLLOW_PRICE=${instance?.price || 100} # The monthly price of your instance, set to 0 means free.`,
7372
`FOLLOW_USER_LIMIT=${instance?.userLimit || 1000} # The user limit of your instance, set it to 0 or 1 can make your instance private, leaving it empty means no restriction`,
7473
]
7574

Lines changed: 11 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,10 @@
11
import { Button } from "@follow/components/ui/button/index.js"
22
import { Card, CardContent } from "@follow/components/ui/card/index.js"
3-
import {
4-
Form,
5-
FormControl,
6-
FormField,
7-
FormItem,
8-
FormLabel,
9-
FormMessage,
10-
} from "@follow/components/ui/form/index.jsx"
11-
import { Input } from "@follow/components/ui/input/Input.js"
12-
import { whoami } from "@follow/store/user/getters"
133
import type { RSSHubListItem } from "@follow-app/client-sdk"
14-
import { zodResolver } from "@hookform/resolvers/zod"
154
import { useEffect } from "react"
16-
import { useForm } from "react-hook-form"
17-
import { Trans, useTranslation } from "react-i18next"
18-
import { z } from "zod"
5+
import { useTranslation } from "react-i18next"
196

20-
import { useAuthQuery } from "~/hooks/common"
217
import { UserAvatar } from "~/modules/user/UserAvatar"
22-
import { Queries } from "~/queries"
238
import { useSetRSSHubMutation } from "~/queries/rsshub"
249

2510
import { useTOTPModalWrapper } from "../profile/hooks"
@@ -34,35 +19,12 @@ export function SetModalContent({
3419
const { t } = useTranslation("settings")
3520
const setRSSHubMutation = useSetRSSHubMutation()
3621
const preset = useTOTPModalWrapper(setRSSHubMutation.mutateAsync)
37-
const details = useAuthQuery(Queries.rsshub.get({ id: instance.id }))
38-
const hasPurchase = !!details.data?.purchase
39-
const price = instance.ownerUserId === whoami()?.id ? 0 : instance.price
40-
41-
const formSchema = z.object({
42-
months: z.coerce
43-
.number()
44-
.min(hasPurchase ? 0 : 1)
45-
.max(12),
46-
})
47-
48-
const form = useForm<z.infer<typeof formSchema>>({
49-
resolver: zodResolver(formSchema),
50-
defaultValues: {
51-
months: hasPurchase ? 0 : 1,
52-
},
53-
})
54-
55-
const months = form.watch("months")
56-
57-
const onSubmit = (data: z.infer<typeof formSchema>) => {
58-
preset({ id: instance.id, durationInMonths: data.months })
59-
}
6022

6123
useEffect(() => {
6224
if (setRSSHubMutation.isSuccess) {
6325
dismiss()
6426
}
65-
}, [setRSSHubMutation.isSuccess])
27+
}, [setRSSHubMutation.isSuccess, dismiss])
6628

6729
return (
6830
<div className="max-w-[550px] space-y-4 lg:min-w-[550px]">
@@ -85,12 +47,6 @@ export function SetModalContent({
8547
<td className="text-sm text-text-secondary">{t("rsshub.table.description")}</td>
8648
<td className="line-clamp-2">{instance.description}</td>
8749
</tr>
88-
<tr>
89-
<td className="text-sm text-text-secondary">{t("rsshub.table.price")}</td>
90-
<td className="flex items-center gap-1">
91-
{instance.price} <i className="i-mgc-power text-folo" />
92-
</td>
93-
</tr>
9450
<tr>
9551
<td className="text-sm text-text-secondary">{t("rsshub.table.userCount")}</td>
9652
<td>{instance.userCount}</td>
@@ -103,64 +59,15 @@ export function SetModalContent({
10359
</table>
10460
</CardContent>
10561
</Card>
106-
{details.data?.purchase && (
107-
<div>
108-
<div className="text-sm text-text-secondary">
109-
{t("rsshub.useModal.purchase_expires_at")}
110-
</div>
111-
<div className="line-clamp-2">
112-
{new Date(details.data.purchase.expiresAt).toLocaleString()}
113-
</div>
114-
</div>
115-
)}
116-
<Form {...form}>
117-
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
118-
{price > 0 && (
119-
<FormField
120-
control={form.control}
121-
name="months"
122-
render={({ field }) => (
123-
<FormItem className="flex flex-row items-center gap-4">
124-
<FormLabel>{t("rsshub.useModal.months_label")}</FormLabel>
125-
<FormControl className="!mt-0">
126-
<div className="flex items-center gap-10">
127-
<div className="space-x-2">
128-
<Input
129-
className="w-24"
130-
type="number"
131-
inputMode="numeric"
132-
pattern="[0-9]*"
133-
max={12}
134-
min={hasPurchase ? 0 : 1}
135-
{...field}
136-
/>
137-
<span className="text-sm text-text-secondary">
138-
{t("rsshub.useModal.month")}
139-
</span>
140-
</div>
141-
</div>
142-
</FormControl>
143-
<FormMessage />
144-
</FormItem>
145-
)}
146-
/>
147-
)}
148-
<div className="flex items-center justify-end">
149-
<Button type="submit" isLoading={setRSSHubMutation.isPending}>
150-
{price ? (
151-
<Trans
152-
ns="settings"
153-
i18nKey={"rsshub.useModal.useWith"}
154-
components={{ Power: <i className="i-mgc-power ml-1 text-white" /> }}
155-
values={{ amount: price * months }}
156-
/>
157-
) : (
158-
t("rsshub.table.use")
159-
)}
160-
</Button>
161-
</div>
162-
</form>
163-
</Form>
62+
<div className="flex items-center justify-end">
63+
<Button
64+
type="button"
65+
isLoading={setRSSHubMutation.isPending}
66+
onClick={() => preset({ id: instance.id })}
67+
>
68+
{t("rsshub.table.use")}
69+
</Button>
70+
</div>
16471
</div>
16572
)
16673
}

apps/desktop/layer/renderer/src/modules/settings/control.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,12 @@ export const PaidBadge: Component<{
4747
</TooltipTrigger>
4848
<TooltipPortal>
4949
<TooltipContent>
50-
{paidLevel === SettingPaidLevels.FreeLimited && t("control.paid_badge.free_limited")}
51-
{paidLevel === SettingPaidLevels.Basic && t("control.paid_badge.basic_or_higher")}
50+
{paidLevel === SettingPaidLevels.FreeLimited && (
51+
<span>{t("control.paid_badge.free_limited")}</span>
52+
)}
53+
{paidLevel === SettingPaidLevels.Basic && (
54+
<span>{t("control.paid_badge.basic_or_higher")}</span>
55+
)}
5256
</TooltipContent>
5357
</TooltipPortal>
5458
</Tooltip>

apps/desktop/layer/renderer/src/modules/user/ProfileButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ export const ProfileButton: FC<ProfileButtonProps> = memo((props) => {
139139
}}
140140
icon={<i className="i-mgc-power-outline" />}
141141
>
142-
{t("user_button.power")}
142+
{t("user_button.wallet")}
143143
</DropdownMenuItem>
144144
)}
145145
<DropdownMenuItem

apps/desktop/layer/renderer/src/pages/(main)/(layer)/(subview)/rsshub/index.tsx

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Logo } from "@follow/components/icons/logo.jsx"
22
import { Button } from "@follow/components/ui/button/index.js"
33
import { RSSHubLogo } from "@follow/components/ui/platform-icon/icons.js"
44
import { whoami } from "@follow/store/user/getters"
5-
import { cn, formatNumber } from "@follow/utils/utils"
5+
import { cn } from "@follow/utils/utils"
66
import type { RSSHubListItem } from "@follow-app/client-sdk"
77
import { memo, useCallback, useEffect } from "react"
88
import { useTranslation } from "react-i18next"
@@ -110,7 +110,6 @@ const InstanceCard = memo(({ item }: { item: InstanceItem }) => {
110110
)
111111

112112
const title = isOfficial ? "Folo Official" : ""
113-
const price = isOfficial ? 0 : instance.price
114113
const description = isOfficial ? "Folo Built-in RSSHub" : instance.description
115114

116115
const usersStat = isOfficial ? "*" : instance.userCount || 0
@@ -166,11 +165,6 @@ const InstanceCard = memo(({ item }: { item: InstanceItem }) => {
166165
<div className="flex items-center gap-1">{tags}</div>
167166
</div>
168167
</div>
169-
<div className="text-right">
170-
<div className="flex items-center gap-1 text-sm font-medium">
171-
{formatNumber(price ?? 0)} <i className="i-mgc-power size-3 text-folo" />
172-
</div>
173-
</div>
174168
</div>
175169

176170
<p className="mb-3 line-clamp-1 text-xs text-text-secondary">{description}</p>
@@ -276,7 +270,7 @@ function List({ data }: { data?: RSSHubListItem[] }) {
276270

277271
// full load last
278272
if (loadA === 1 && loadB === 1) {
279-
return a.price - b.price
273+
return 0
280274
}
281275
if (loadA === 1) {
282276
return 1
@@ -285,7 +279,7 @@ function List({ data }: { data?: RSSHubListItem[] }) {
285279
return -1
286280
}
287281

288-
return a.price - b.price || loadA - loadB
282+
return loadA - loadB
289283
}) || []),
290284
]
291285

apps/desktop/vite.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export default ({ mode }) => {
108108
host: true,
109109
port: 2233,
110110
watch: {
111-
ignored: ["**/dist/**", "**/out/**", "**/public/**", ".git/**"],
111+
ignored: ["**/dist/**", "**/out/**", "**/public/**", ".git/**", "**/.env", "**/.env.*"],
112112
},
113113
cors: true,
114114
headers: {

apps/landing/src/components/widgets/landing/SocialProof.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { MagicCard } from '~/components/ui/magic-card'
77
const tweetList = [
88
{
99
id: '1833056589135442345',
10-
text: "Very nice news aggregation, and it gives 2 power token everyday, so far I just try move front end people I followed in, haven't done yet, will try move more rss subscribe.",
10+
text: "Very nice news aggregation. So far I just try move front end people I followed in, haven't done yet, will try move more rss subscribe.",
1111
name: '🦋 AnneInCoding',
1212
screenName: '@anneincoding',
1313
profileImageUrl:

0 commit comments

Comments
 (0)