kopia lustrzana https://gitlab.com/soapbox-pub/soapbox
Implement transactions
rodzic
e04f7086f8
commit
c3c87c8451
|
@ -28,7 +28,7 @@ import toast from 'soapbox/toast.tsx';
|
|||
|
||||
|
||||
const messages = defineMessages({
|
||||
balance: { id: 'wallet.balance.cashu', defaultMessage: '{amount} sats' },
|
||||
balance: { id: 'wallet.sats', defaultMessage: '{amount} sats' },
|
||||
withdraw: { id: 'wallet.balance.withdraw_button', defaultMessage: 'Withdraw' },
|
||||
exchange: { id: 'wallet.balance.exchange_button', defaultMessage: 'Exchange' },
|
||||
mint: { id: 'wallet.balance.mint_button', defaultMessage: 'Mint' },
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
import withdrawIcon from '@tabler/icons/outline/cash.svg';
|
||||
import arrowBarDownIcon from '@tabler/icons/outline/arrow-bar-down.svg';
|
||||
import arrowBarUpIcon from '@tabler/icons/outline/arrow-bar-up.svg';
|
||||
import moreIcon from '@tabler/icons/outline/dots-circle-horizontal.svg';
|
||||
import infoIcon from '@tabler/icons/outline/info-circle.svg';
|
||||
import questionIcon from '@tabler/icons/outline/question-mark.svg';
|
||||
import exchangeIcon from '@tabler/icons/outline/transfer.svg';
|
||||
import trendingDown from '@tabler/icons/outline/trending-down.svg';
|
||||
import trendingUp from '@tabler/icons/outline/trending-up.svg';
|
||||
import { useEffect } from 'react';
|
||||
import { FormattedDate, defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
// import IconButton from 'soapbox/components/ui/icon-button.tsx';
|
||||
import Button from 'soapbox/components/ui/button.tsx';
|
||||
import Divider from 'soapbox/components/ui/divider.tsx';
|
||||
import HStack from 'soapbox/components/ui/hstack.tsx';
|
||||
import IconButton from 'soapbox/components/ui/icon-button.tsx';
|
||||
import Spinner from 'soapbox/components/ui/spinner.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 { useCashu } from 'soapbox/features/zap/hooks/useCashu.ts';
|
||||
import { useApi } from 'soapbox/hooks/useApi.ts';
|
||||
import { useOwnAccount } from 'soapbox/hooks/useOwnAccount.ts';
|
||||
|
||||
const themes = {
|
||||
|
@ -25,38 +25,36 @@ const themes = {
|
|||
success: '!text-success-600',
|
||||
inherit: '!text-inherit',
|
||||
white: '!text-white',
|
||||
exchange: '!text-blue-600 dark:!text-blue-300',
|
||||
withdraw: '!text-orange-600 dark:!text-orange-300',
|
||||
};
|
||||
|
||||
const capitaliza = (str: string) => {
|
||||
return str.charAt(0).toLocaleUpperCase() + str.slice(1);
|
||||
};
|
||||
|
||||
const transaction = (e: { type: string; amount: number; from?: string | null; to?: string | null; mint?: string | null; date: string }, lastElementIndex: number, index: number) => {
|
||||
const messages = defineMessages({
|
||||
amount: { id: 'wallet.sats', defaultMessage: '{amount} sats' },
|
||||
more: { id: 'wallet.transactions.more', defaultMessage: 'More' },
|
||||
});
|
||||
|
||||
const TransactionItem = (e: { amount: number; created_at: number ; direction: 'in' | 'out' }, lastElementIndex: number, index: number) => {
|
||||
const intl = useIntl();
|
||||
const isLastElement = index === lastElementIndex;
|
||||
let icon, sla, messageColor: typeof themes[keyof typeof themes] | undefined ;
|
||||
const { type, amount, date } = e;
|
||||
switch (type) {
|
||||
case 'received':
|
||||
icon = trendingUp;
|
||||
sla = e.from;
|
||||
let icon, type, messageColor;
|
||||
const { direction, amount, created_at } = e;
|
||||
|
||||
const formattedDate = <FormattedDate value={new Date(created_at * 1000)} hour12 year='numeric' month='short' day='2-digit' hour='numeric' minute='2-digit' />;
|
||||
|
||||
switch (direction) {
|
||||
case 'in':
|
||||
icon = arrowBarDownIcon;
|
||||
type = 'Received';
|
||||
messageColor = themes.success;
|
||||
break;
|
||||
case 'sent':
|
||||
icon = trendingDown;
|
||||
sla = e.to;
|
||||
case 'out':
|
||||
icon = arrowBarUpIcon;
|
||||
type = 'Sent';
|
||||
messageColor = themes.danger;
|
||||
break;
|
||||
case 'exchanged':
|
||||
case 'withdrawn':
|
||||
icon = e.type === 'exchanged' ? exchangeIcon : withdrawIcon;
|
||||
sla = e.mint || 'MoonFileMoney';
|
||||
messageColor = e.type === 'exchanged' ? themes.exchange : themes.withdraw;
|
||||
break;
|
||||
default:
|
||||
messageColor = 'default';
|
||||
type = 'Unknown';
|
||||
icon = questionIcon;
|
||||
}
|
||||
|
||||
|
@ -71,30 +69,22 @@ const transaction = (e: { type: string; amount: number; from?: string | null; t
|
|||
|
||||
<Stack justifyContent='center'>
|
||||
<Text size='lg'>
|
||||
{sla}
|
||||
</Text>
|
||||
<Text theme='muted' size='xs'>
|
||||
{capitaliza(type)}
|
||||
{type}
|
||||
</Text>
|
||||
</Stack>
|
||||
</HStack>
|
||||
|
||||
<HStack space={2} alignItems='center'>
|
||||
<Stack alignItems='end' justifyContent='center'>
|
||||
<HStack space={1}>
|
||||
<Text size='lg'>
|
||||
{amount}
|
||||
</Text>
|
||||
<Text size='lg'>
|
||||
{/* sats */}
|
||||
</Text>
|
||||
</HStack>
|
||||
<Text size='lg'>
|
||||
{intl.formatMessage(messages.amount, { amount: amount })}
|
||||
</Text>
|
||||
<Text theme='muted' size='xs'>
|
||||
{date}
|
||||
{formattedDate}
|
||||
</Text>
|
||||
</Stack>
|
||||
|
||||
<IconButton src={infoIcon} theme='secondary' />
|
||||
{/* <IconButton src={infoIcon} theme='secondary' /> */}
|
||||
</HStack>
|
||||
|
||||
</HStack>
|
||||
|
@ -103,60 +93,31 @@ const transaction = (e: { type: string; amount: number; from?: string | null; t
|
|||
);
|
||||
};
|
||||
|
||||
const eG = [
|
||||
{
|
||||
to: null,
|
||||
from: 'Patrick',
|
||||
type: 'received',
|
||||
mint: null,
|
||||
amount: 100,
|
||||
date: '02/11/24',
|
||||
},
|
||||
{
|
||||
to: 'Alex',
|
||||
from: null,
|
||||
type: 'sent',
|
||||
mint: null,
|
||||
amount: 50,
|
||||
date: '02/09/24',
|
||||
},
|
||||
{
|
||||
to: null,
|
||||
from: null,
|
||||
type: 'exchanged',
|
||||
mint: 'MoonFileMoney',
|
||||
amount: 200,
|
||||
date: '02/07/24',
|
||||
},
|
||||
{
|
||||
to: null,
|
||||
from: null,
|
||||
type: 'withdrawn',
|
||||
mint: 'MoonFileMoney',
|
||||
amount: 300,
|
||||
date: '02/05/24',
|
||||
},
|
||||
];
|
||||
const Transactions = () => {
|
||||
const intl = useIntl();
|
||||
const api = useApi();
|
||||
const { account } = useOwnAccount();
|
||||
const { transactions, getTransactions } = useCashu();
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
getTransactions(api);
|
||||
}
|
||||
, []);
|
||||
|
||||
if (!account) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const lastItem = eG.length - 1;
|
||||
|
||||
return (
|
||||
<Stack className='rounded-lg p-3' alignItems='center' space={4}>
|
||||
|
||||
<Stack space={2} className='w-full'>
|
||||
{eG.map((item, index) => {
|
||||
return transaction(item, lastItem, index);
|
||||
})}
|
||||
{transactions ? transactions.slice(0, 4).map((item, index) => TransactionItem(item, 3, index)) : <Spinner withText={false} />}
|
||||
</Stack>
|
||||
|
||||
<Button icon={moreIcon} theme='primary' >
|
||||
{/* More */}
|
||||
{intl.formatMessage(messages.more)}
|
||||
</Button>
|
||||
|
||||
</Stack>
|
||||
|
|
|
@ -2,7 +2,7 @@ import { produce } from 'immer';
|
|||
import { create } from 'zustand';
|
||||
|
||||
import { MastodonClient } from 'soapbox/api/MastodonClient.ts';
|
||||
import { WalletData, baseWalletSchema } from 'soapbox/schemas/wallet.ts';
|
||||
import { Transactions, WalletData, baseWalletSchema, transactionsSchema } from 'soapbox/schemas/wallet.ts';
|
||||
import toast from 'soapbox/toast.tsx';
|
||||
|
||||
import type { Account as AccountEntity, Status as StatusEntity } from 'soapbox/types/entities.ts';
|
||||
|
@ -17,17 +17,21 @@ interface ICashuState {
|
|||
isLoading: boolean;
|
||||
error: string | null;
|
||||
wallet: WalletData | null;
|
||||
transactions: Transactions | null;
|
||||
|
||||
createWallet: (api: MastodonClient, walletInfo: IWalletInfo) => Promise<void>;
|
||||
getTransactions: (api: MastodonClient) => Promise<void>;
|
||||
getWallet: (api: MastodonClient, hasMessage?: boolean) => Promise<void>;
|
||||
nutzapRequest: (api: MastodonClient, account: AccountEntity, amount: number, comment: string, status?: StatusEntity) => void;
|
||||
}
|
||||
|
||||
// TODO: Convert it into a custom hook after the backend is finished
|
||||
export const useCashu = create<ICashuState>((set) => ({
|
||||
nutzapsList: {},
|
||||
isLoading: false,
|
||||
error: null,
|
||||
wallet: null,
|
||||
transactions: null,
|
||||
|
||||
createWallet: async (api, walletInfo) => {
|
||||
try {
|
||||
|
@ -56,6 +60,19 @@ export const useCashu = create<ICashuState>((set) => ({
|
|||
}
|
||||
},
|
||||
|
||||
getTransactions: async (api) => {
|
||||
try {
|
||||
const response = await api.get('/api/v1/ditto/cashu/transactions');
|
||||
const data: WalletData = await response.json();
|
||||
if (data) {
|
||||
const normalizedData = transactionsSchema.parse(data);
|
||||
set({ transactions: normalizedData });
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error('Transactions not found');
|
||||
}
|
||||
},
|
||||
|
||||
nutzapRequest: async (api, account, amount, comment, status) => {
|
||||
set((state) => ({ ...state, isLoading: true, error: null }));
|
||||
|
||||
|
|
|
@ -1713,7 +1713,7 @@
|
|||
"video.play": "Play",
|
||||
"video.unmute": "Unmute sound",
|
||||
"wallet": "Wallet",
|
||||
"wallet.balance.cashu": "{amount} sats",
|
||||
"wallet.sats": "{amount} sats",
|
||||
"wallet.balance.exchange_button": "Exchange",
|
||||
"wallet.balance.expired": "Expired",
|
||||
"wallet.balance.mint.paid_message": "Your mint was successful, and your sats are now in your balance. Enjoy!",
|
||||
|
@ -1737,6 +1737,7 @@
|
|||
"wallet.relays.error": "Failed to update mints.",
|
||||
"wallet.relays.sucess": "Relays updated with success!",
|
||||
"wallet.transactions": "Transactions",
|
||||
"wallet.transactions.more": "More",
|
||||
"who_to_follow.title": "People To Follow",
|
||||
"zap.button.text.rounded": "{method} {amount}K sats",
|
||||
"zap.finish": "Finish",
|
||||
|
|
Ładowanie…
Reference in New Issue