-
Notifications
You must be signed in to change notification settings - Fork 6
add merchant cards #657
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add merchant cards #657
Changes from all commits
0fcc1e1
57222f4
f2aa6c6
4e159f4
c6cc93c
19ebf48
3575d52
670f1b2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,6 +8,7 @@ import { | |
| useSuspenseQuery, | ||
| } from '@tanstack/react-query'; | ||
| import { useCallback, useMemo, useRef } from 'react'; | ||
| import { useSearchParams } from 'react-router'; | ||
| import { type Currency, Money } from '~/lib/money'; | ||
| import { useSupabaseRealtime } from '~/lib/supabase'; | ||
| import { useLatest } from '~/lib/use-latest'; | ||
|
|
@@ -19,6 +20,7 @@ import { | |
| type CashuAccount, | ||
| type ExtendedAccount, | ||
| getAccountBalance, | ||
| isStarAccount, | ||
| } from './account'; | ||
| import { | ||
| type AccountRepository, | ||
|
|
@@ -277,6 +279,8 @@ export const accountsQueryOptions = ({ | |
| export function useAccounts<T extends AccountType = AccountType>(select?: { | ||
| currency?: Currency; | ||
| type?: T; | ||
| excludeStarAccounts?: boolean; | ||
| starAccountsOnly?: boolean; | ||
| }): UseSuspenseQueryResult<ExtendedAccount<T>[]> { | ||
| const user = useUser(); | ||
| const accountRepository = useAccountRepository(); | ||
|
|
@@ -301,13 +305,25 @@ export function useAccounts<T extends AccountType = AccountType>(select?: { | |
| if (select.type && account.type !== select.type) { | ||
| return false; | ||
| } | ||
| if (select.excludeStarAccounts && isStarAccount(account)) { | ||
| return false; | ||
| } | ||
| if (select.starAccountsOnly && !isStarAccount(account)) { | ||
| return false; | ||
| } | ||
| return true; | ||
| }, | ||
| ); | ||
|
|
||
| return filteredData; | ||
| }, | ||
| [select?.currency, select?.type, user], | ||
| [ | ||
| select?.currency, | ||
| select?.type, | ||
| select?.excludeStarAccounts, | ||
| select?.starAccountsOnly, | ||
| user, | ||
| ], | ||
| ), | ||
| }); | ||
| } | ||
|
|
@@ -430,14 +446,29 @@ export function useAddCashuAccount() { | |
| return mutateAsync; | ||
| } | ||
|
|
||
| /** | ||
| * @returns the total balance of all accounts for the given currency excluding Star accounts. | ||
| */ | ||
| export function useBalance(currency: Currency) { | ||
| const { data: accounts } = useAccounts({ currency }); | ||
| const balance = accounts.reduce( | ||
| (acc, account) => { | ||
| const accountBalance = getAccountBalance(account); | ||
| return acc.add(accountBalance); | ||
| }, | ||
| new Money({ amount: 0, currency }), | ||
| ); | ||
| const { data: accounts } = useAccounts({ | ||
| currency, | ||
| excludeStarAccounts: true, | ||
| }); | ||
| const balance = accounts.reduce((acc, account) => { | ||
| const accountBalance = getAccountBalance(account); | ||
| return acc.add(accountBalance); | ||
| }, Money.zero(currency)); | ||
| return balance; | ||
| } | ||
|
|
||
| /** | ||
| * Returns the account specified by the account ID in the URL. | ||
| * @param select - The type of the account to get. | ||
| */ | ||
| export function useGetAccountFromLocation(select?: { type?: AccountType }) { | ||
| const [searchParams] = useSearchParams(); | ||
| const accountId = searchParams.get('accountId'); | ||
| const { data: accounts } = useAccounts({ type: select?.type }); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we already have useAccount hook. can we use that? |
||
| const account = accounts.find((account) => account.id === accountId); | ||
| return account; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,17 @@ | ||
| import { LandmarkIcon, Zap } from 'lucide-react'; | ||
| import { LandmarkIcon, StarIcon, Zap } from 'lucide-react'; | ||
| import type { ReactNode } from 'react'; | ||
| import type { AccountType } from './account'; | ||
|
|
||
| const CashuIcon = () => <LandmarkIcon className="h-4 w-4" />; | ||
| const NWCIcon = () => <Zap className="h-4 w-4" />; | ||
| const StarsIcon = () => <StarIcon className="h-4 w-4" />; | ||
|
|
||
| const iconsByAccountType: Record<AccountType, ReactNode> = { | ||
| const iconsByAccountType: Record<AccountType | 'star', ReactNode> = { | ||
| cashu: <CashuIcon />, | ||
| nwc: <NWCIcon />, | ||
| star: <StarsIcon />, | ||
| }; | ||
|
|
||
| export function AccountTypeIcon({ type }: { type: AccountType }) { | ||
| export function AccountTypeIcon({ type }: { type: AccountType | 'star' }) { | ||
| return iconsByAccountType[type]; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| // Duration constants (in ms) | ||
| export const ANIMATION_DURATION = 400; | ||
| export const DETAIL_VIEW_DELAY = 300; // Delay before detail content starts animating | ||
| export const OPACITY_ANIMATION_RATIO = 0.5; // Multiplier for opacity animation duration | ||
|
|
||
| export const EASE_IN_OUT = 'cubic-bezier(0.25, 0.1, 0.25, 1)'; | ||
| export const EASE_OUT = 'cubic-bezier(0, 0, 0.2, 1)'; // Decelerating | ||
|
|
||
| // Layout constants (in px) | ||
| export const CARD_STACK_OFFSET = 64; // Space between cards in collapsed stack | ||
| export const CARD_ASPECT_RATIO = 1.586; // Credit card aspect ratio | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how was this num picked? |
||
|
|
||
| /** | ||
| * Get the off-screen Y offset for sliding cards out | ||
| */ | ||
| export function getOffScreenOffset(): number { | ||
| return typeof window !== 'undefined' ? window.innerHeight + 100 : 900; // Fallback for SSR | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how are these numbers picked? |
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can use https://reactrouter.com/api/hooks/useSearchParams instead