Refactor wallet logic to handle Zap Cashu data

merge-requests/3333/head
danidfra 2025-03-26 12:42:56 -03:00
rodzic fc7a8c849c
commit 92aa009de9
8 zmienionych plików z 40 dodań i 47 usunięć

Wyświetl plik

@ -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<IPureStatusActionBar> = ({
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<IPureStatusActionBar> = ({
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)}
/>
)}

Wyświetl plik

@ -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<IStatusActionBar> = ({
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<IStatusActionBar> = ({
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)}
/>
)}

Wyświetl plik

@ -206,13 +206,13 @@ const StatusInteractionBar: React.FC<IStatusInteractionBar> = ({ status }): JSX.
};
const getZaps = () => {
if (status.zaps_amount) {
if (status.zaps_amount || status.zaps_amount_cashu) {
return (
<InteractionCounter count={status.zaps_amount / 1000} onClick={handleOpenZapsModal}>
<InteractionCounter count={(status.zaps_amount ?? 0) / 1000 + (status.zaps_amount_cashu ?? 0)} onClick={handleOpenZapsModal}>
<FormattedMessage
id='status.interactions.zaps'
defaultMessage='{count, plural, one {Zap} other {Zaps}}'
values={{ count: status.zaps_amount }}
values={{ count: (status.zaps_amount ?? 0) + (status.zaps_amount_cashu ?? 0) }}
/>
</InteractionCounter>
);

Wyświetl plik

@ -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<Element>) => {
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;
}

Wyświetl plik

@ -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<string, { status: StatusEntity; amount: number; comment: string }>; // 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<WalletState>((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<string | null>(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 };
export { useWallet, useTransactions, useZapCashuRequest };

Wyświetl plik

@ -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<ImmutableMap<string, any>>(),
@ -86,7 +86,7 @@ export const StatusRecord = ImmutableRecord({
url: '',
visibility: 'public' as StatusVisibility,
zapped: false,
nutzapped: false,
zapped_cashu: false,
event: null as ReturnType<typeof EventRecord> | null,
// Internal fields

Wyświetl plik

@ -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:

Wyświetl plik

@ -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<typeof baseStatusSchema>;