From 92aa009de9446a00974b3b879615b69d58339605 Mon Sep 17 00:00:00 2001 From: danidfra Date: Wed, 26 Mar 2025 12:42:56 -0300 Subject: [PATCH] Refactor wallet logic to handle Zap Cashu data --- src/components/pure-status-action-bar.tsx | 10 +++---- src/components/status-action-bar.tsx | 10 +++---- .../components/status-interaction-bar.tsx | 6 ++-- .../zap/components/pay-request-form.tsx | 6 ++-- src/features/zap/hooks/useHooks.ts | 28 +++++++++---------- src/normalizers/status.ts | 4 +-- src/reducers/statuses.ts | 19 ++++--------- src/schemas/status.ts | 4 +-- 8 files changed, 40 insertions(+), 47 deletions(-) diff --git a/src/components/pure-status-action-bar.tsx b/src/components/pure-status-action-bar.tsx index ed90e79f5..075fc00cf 100644 --- a/src/components/pure-status-action-bar.tsx +++ b/src/components/pure-status-action-bar.tsx @@ -48,7 +48,7 @@ import DropdownMenu from 'soapbox/components/dropdown-menu/index.ts'; import PureStatusReactionWrapper from 'soapbox/components/pure-status-reaction-wrapper.tsx'; import StatusActionButton from 'soapbox/components/status-action-button.tsx'; import HStack from 'soapbox/components/ui/hstack.tsx'; -import { useNutzapRequest, useWallet } from 'soapbox/features/zap/hooks/useHooks.ts'; +import { useZapCashuRequest, useWallet } from 'soapbox/features/zap/hooks/useHooks.ts'; import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts'; import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts'; import { useDislike } from 'soapbox/hooks/useDislike.ts'; @@ -181,8 +181,8 @@ const PureStatusActionBar: React.FC = ({ const { boostModal, deleteModal } = useSettings(); const { wallet } = useWallet(); - const { nutzapsList } = useNutzapRequest(); - const isNutzapped = Object.keys(nutzapsList).some((nutzap)=> nutzap === status.id); // TODO: Remove "getWallet" after been in backend + const { zapCashuList } = useZapCashuRequest(); + const isZappedCashu = zapCashuList.some((zapCashu)=> zapCashu === status.id); const { account } = useOwnAccount(); const isStaff = account ? account.staff : false; @@ -855,9 +855,9 @@ const PureStatusActionBar: React.FC = ({ color='accent' filled onClick={handleZapClick} - active={status.nutzapped || status.zapped || isNutzapped} + active={status.zapped_cashu || status.zapped || isZappedCashu} theme={statusActionButtonTheme} - count={status?.zaps_amount ? status.zaps_amount / 1000 : 0} + count={(status?.zaps_amount ?? 0) / 1000 + (status?.zaps_amount_cashu ?? 0)} /> )} diff --git a/src/components/status-action-bar.tsx b/src/components/status-action-bar.tsx index ff72a3664..38526dd3f 100644 --- a/src/components/status-action-bar.tsx +++ b/src/components/status-action-bar.tsx @@ -49,7 +49,7 @@ import DropdownMenu from 'soapbox/components/dropdown-menu/index.ts'; import StatusActionButton from 'soapbox/components/status-action-button.tsx'; import StatusReactionWrapper from 'soapbox/components/status-reaction-wrapper.tsx'; import HStack from 'soapbox/components/ui/hstack.tsx'; -import { useNutzapRequest, useWallet } from 'soapbox/features/zap/hooks/useHooks.ts'; +import { useZapCashuRequest, useWallet } from 'soapbox/features/zap/hooks/useHooks.ts'; import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts'; import { useAppSelector } from 'soapbox/hooks/useAppSelector.ts'; import { useFeatures } from 'soapbox/hooks/useFeatures.ts'; @@ -176,8 +176,8 @@ const StatusActionBar: React.FC = ({ const { boostModal, deleteModal } = useSettings(); const { wallet } = useWallet(); - const { nutzapsList } = useNutzapRequest(); - const isNutzapped = Object.keys(nutzapsList).some((nutzap)=> nutzap === status.id); + const { zapCashuList } = useZapCashuRequest(); + const isZappedCashu = zapCashuList.some((zapCashu)=> zapCashu === status.id); const { account } = useOwnAccount(); const isStaff = account ? account.staff : false; @@ -845,9 +845,9 @@ const StatusActionBar: React.FC = ({ color='accent' filled onClick={handleZapClick} - active={status.nutzapped || status.zapped || isNutzapped} + active={status.zapped_cashu || status.zapped || isZappedCashu} theme={statusActionButtonTheme} - count={status?.zaps_amount ? status.zaps_amount / 1000 : 0} + count={(status?.zaps_amount ?? 0) / 1000 + (status?.zaps_amount_cashu ?? 0)} /> )} diff --git a/src/features/status/components/status-interaction-bar.tsx b/src/features/status/components/status-interaction-bar.tsx index 62ee17cf7..9f43a85bb 100644 --- a/src/features/status/components/status-interaction-bar.tsx +++ b/src/features/status/components/status-interaction-bar.tsx @@ -206,13 +206,13 @@ const StatusInteractionBar: React.FC = ({ status }): JSX. }; const getZaps = () => { - if (status.zaps_amount) { + if (status.zaps_amount || status.zaps_amount_cashu) { return ( - + ); diff --git a/src/features/zap/components/pay-request-form.tsx b/src/features/zap/components/pay-request-form.tsx index f822ac1e8..f95d813a0 100644 --- a/src/features/zap/components/pay-request-form.tsx +++ b/src/features/zap/components/pay-request-form.tsx @@ -21,7 +21,7 @@ import Input from 'soapbox/components/ui/input.tsx'; import Stack from 'soapbox/components/ui/stack.tsx'; import SvgIcon from 'soapbox/components/ui/svg-icon.tsx'; import Text from 'soapbox/components/ui/text.tsx'; -import { useNutzapRequest } from 'soapbox/features/zap/hooks/useHooks.ts'; +import { useZapCashuRequest } from 'soapbox/features/zap/hooks/useHooks.ts'; import { usePaymentMethod } from 'soapbox/features/zap/usePaymentMethod.ts'; import { useAppDispatch } from 'soapbox/hooks/useAppDispatch.ts'; import { emojifyText } from 'soapbox/utils/emojify.tsx'; @@ -63,7 +63,7 @@ const PayRequestForm = ({ account, status, onClose }: IPayRequestForm) => { const { method: paymentMethod } = usePaymentMethod(); const isCashu = paymentMethod === 'cashu'; const hasZapSplit = zapArrays.length > 0 && !isCashu; - const { nutzapRequest } = useNutzapRequest(); + const { zapCashuRequest } = useZapCashuRequest(); const handleSubmit = async (e?: React.FormEvent) => { e?.preventDefault(); @@ -71,7 +71,7 @@ const PayRequestForm = ({ account, status, onClose }: IPayRequestForm) => { const splitData = { hasZapSplit, zapSplitAccounts, splitValues }; if (isCashu) { - await nutzapRequest(account, amount, zapComment, status); + await zapCashuRequest(account, amount, zapComment, status); dispatch(closeModal('PAY_REQUEST')); return; } diff --git a/src/features/zap/hooks/useHooks.ts b/src/features/zap/hooks/useHooks.ts index 5d74b75df..496449834 100644 --- a/src/features/zap/hooks/useHooks.ts +++ b/src/features/zap/hooks/useHooks.ts @@ -10,13 +10,13 @@ import type { Account as AccountEntity, Status as StatusEntity } from 'soapbox/t interface WalletState { wallet: WalletData | null; transactions: Transactions | null; - nutzapsList: Record; // TODO: remove + zapCashuList: string[]; prevTransaction?: string | null; nextTransaction?: string | null; setWallet: (wallet: WalletData | null) => void; setTransactions: (transactions: Transactions | null, prevTransaction?: string | null, nextTransaction?: string | null) => void; - addNutzap: (statusId: string, data: { status: StatusEntity; amount: number; comment: string }) => void; + addZapCashu: (statusId: string) => void; } interface IWalletInfo { @@ -29,16 +29,16 @@ const useWalletStore = create((set) => ({ transactions: null, prevTransaction: null, nextTransaction: null, - nutzapsList: {}, + zapCashuList: [], setWallet: (wallet) => set({ wallet }), setTransactions: (transactions, prevTransaction, nextTransaction) => set({ transactions, prevTransaction, nextTransaction }), - addNutzap: (statusId, data) => + addZapCashu: (statusId) => set((state) => ({ - nutzapsList: { - ...state.nutzapsList, - [statusId]: data, - }, + zapCashuList: [ + ...state.zapCashuList, + statusId, + ], })), })); @@ -152,15 +152,15 @@ const useTransactions = () => { return { transactions, isLoading, error, getTransactions, expandTransactions }; }; -const useNutzapRequest = () => { +const useZapCashuRequest = () => { const api = useApi(); - const { nutzapsList, addNutzap } = useWalletStore(); + const { zapCashuList, addZapCashu } = useWalletStore(); const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); const { getWallet } = useWallet(); const { getTransactions } = useTransactions(); - const nutzapRequest = async (account: AccountEntity, amount: number, comment: string, status?: StatusEntity) => { + const zapCashuRequest = async (account: AccountEntity, amount: number, comment: string, status?: StatusEntity) => { setIsLoading(true); setError(null); try { @@ -174,7 +174,7 @@ const useNutzapRequest = () => { const data = await response.json(); if (status) { - addNutzap(status.id, { status, amount, comment }); + addZapCashu(status.id); } toast.success(data.message || 'Zap sent successfully!'); @@ -189,7 +189,7 @@ const useNutzapRequest = () => { } }; - return { nutzapsList, isLoading, error, nutzapRequest }; + return { zapCashuList, isLoading, error, zapCashuRequest }; }; -export { useWallet, useTransactions, useNutzapRequest }; \ No newline at end of file +export { useWallet, useTransactions, useZapCashuRequest }; \ No newline at end of file diff --git a/src/normalizers/status.ts b/src/normalizers/status.ts index 32945ea31..5535050f2 100644 --- a/src/normalizers/status.ts +++ b/src/normalizers/status.ts @@ -77,7 +77,7 @@ export const StatusRecord = ImmutableRecord({ reblogs_count: 0, replies_count: 0, zaps_amount: 0, - nutzaps_amount: 0, + zaps_amount_cashu: 0, sensitive: false, spoiler_text: '', tags: ImmutableList>(), @@ -86,7 +86,7 @@ export const StatusRecord = ImmutableRecord({ url: '', visibility: 'public' as StatusVisibility, zapped: false, - nutzapped: false, + zapped_cashu: false, event: null as ReturnType | null, // Internal fields diff --git a/src/reducers/statuses.ts b/src/reducers/statuses.ts index 69696387b..24c365e79 100644 --- a/src/reducers/statuses.ts +++ b/src/reducers/statuses.ts @@ -222,20 +222,13 @@ const simulateDislike = ( }; /** Simulate zap of status for optimistic interactions */ -const simulatePayment = (state: State, statusId: string, paid: boolean, method: 'cashu' | 'zap'): State => { +const simulatePayment = (state: State, statusId: string, zapped: boolean): State => { const status = state.get(statusId); if (!status) return state; - let updatedStatus; - if (method === 'zap') { - updatedStatus = status.merge({ - zapped: paid, - }); - } else { - updatedStatus = status.merge({ - nutzapped: paid, - }); - } + const updatedStatus = status.merge({ + zapped, + }); return state.set(statusId, updatedStatus); }; @@ -295,9 +288,9 @@ export default function statuses(state = initialState, action: AnyAction): State case DISLIKE_FAIL: return state.get(action.status.id) === undefined ? state : state.setIn([action.status.id, 'disliked'], false); case ZAP_REQUEST: - return simulatePayment(state, action.status.id, true, 'zap'); + return simulatePayment(state, action.status.id, true); case ZAP_FAIL: - return simulatePayment(state, action.status.id, false, 'zap'); + return simulatePayment(state, action.status.id, false); case REBLOG_REQUEST: return state.setIn([action.status.id, 'reblogged'], true); case REBLOG_FAIL: diff --git a/src/schemas/status.ts b/src/schemas/status.ts index 5a5d7280c..e16e74bc1 100644 --- a/src/schemas/status.ts +++ b/src/schemas/status.ts @@ -73,8 +73,8 @@ const baseStatusSchema = z.object({ visibility: z.string().catch('public'), zapped: z.coerce.boolean(), zaps_amount: z.number().catch(0), - nutzapped: z.coerce.boolean(), - nutzaps_amount: z.number().catch(0), + zapped_cashu: z.coerce.boolean(), + zaps_amount_cashu: z.number().catch(0), }); type BaseStatus = z.infer;