Skip to content

Commit 88de2a0

Browse files
authored
Merge pull request #252 from jahrulezfrancis/feature/transaction-icons-and-dividers
Feature/transaction icons and dividers
2 parents 1311a74 + ad7b6bd commit 88de2a0

8 files changed

Lines changed: 45 additions & 67 deletions

File tree

‎src/components/common/CreatorCard.tsx‎

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,10 @@ import Change24hBadge from '@/components/common/Change24hBadge';
2121
import KeySupplyBadge from '@/components/common/KeySupplyBadge';
2222
import CreatorListRowDivider from '@/components/common/CreatorListRowDivider';
2323
import BuyActionHelperText from '@/components/common/BuyActionHelperText';
24-
import CreatorLabeledStatRow from '@/components/common/CreatorLabeledStatRow';
2524
import CreatorBio from '@/components/common/CreatorBio';
2625
import { useTransactionTelemetry } from '@/hooks/useTransactionTelemetry';
2726
import { useNetworkMismatch } from '@/hooks/useNetworkMismatch';
28-
import { formatCompactNumber, formatNumber, formatFollowerCount } from '@/utils/numberFormat.utils';
27+
import { formatCompactNumber, formatNumber } from '@/utils/numberFormat.utils';
2928

3029
interface CreatorCardProps {
3130
creator: Course;
@@ -180,18 +179,7 @@ const CreatorCard: React.FC<CreatorCardProps> = ({ creator, className }) => {
180179
<MiniStatChip label="Level" value={creator.level || 'Open'} />
181180
</div>
182181
<CreatorListRowDivider className="my-4" />
183-
<div className="mt-3 space-y-1.5">
184-
<CreatorLabeledStatRow
185-
label="Creator Share Supply"
186-
value={
187-
creator.creatorShareSupply
188-
? `${formatFollowerCount(creator.creatorShareSupply)} shares`
189-
: 'Supply pending'
190-
}
191-
className="px-3 py-3"
192-
labelClassName="text-[0.6rem]"
193-
valueClassName="text-sm md:text-sm"
194-
/>
182+
<div className="mt-3 space-y-2">
195183
<CardMetaRow
196184
label={
197185
<span className="inline-flex items-center gap-1.5">
@@ -222,11 +210,13 @@ const CreatorCard: React.FC<CreatorCardProps> = ({ creator, className }) => {
222210
valueClassName="font-grotesque text-base font-black text-amber-400"
223211
/>
224212
</div>
213+
<CreatorListRowDivider className="my-4" />
225214
<CreatorSocialLinksList
226215
handle={creator.socialHandle}
227216
className="mt-4"
228217
/>
229218
</div>
219+
<CreatorListRowDivider className="mt-4 mb-2" />
230220

231221
<div className="flex items-center justify-end gap-4">
232222
<AsyncButton
@@ -242,17 +232,22 @@ const CreatorCard: React.FC<CreatorCardProps> = ({ creator, className }) => {
242232
)}
243233
>
244234
{transactionState === 'success' && (
245-
<TransactionStatusIcon status="success" className="mr-2" />
235+
<TransactionStatusIcon status="success" />
236+
)}
237+
{transactionState === 'submitting' && (
238+
<TransactionStatusIcon status="pending" />
246239
)}
247240
{transactionState === 'failed' && (
248-
<TransactionStatusIcon status="failed" className="mr-2" />
241+
<TransactionStatusIcon status="failed" />
249242
)}
250-
<ShoppingCart className="mr-2 size-4" />
251-
{transactionState === 'success'
252-
? 'Completed'
253-
: transactionState === 'failed'
254-
? 'Retry Purchase'
255-
: 'Buy Key'}
243+
<ShoppingCart className="size-4" />
244+
{transactionState === 'submitting'
245+
? 'Processing...'
246+
: transactionState === 'success'
247+
? 'Completed'
248+
: transactionState === 'failed'
249+
? 'Retry Purchase'
250+
: 'Buy Key'}
256251
</AsyncButton>
257252
</div>
258253

‎src/components/common/TransactionRetryNotice.tsx‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { AlertTriangle, RotateCcw } from 'lucide-react';
1+
import { RotateCcw } from 'lucide-react';
22
import { Button } from '@/components/ui/button';
33
import { cn } from '@/lib/utils';
4+
import TransactionStatusIcon from '@/components/common/TransactionStatusIcon';
45

56
interface TransactionRetryNoticeProps {
67
message: string;
@@ -29,9 +30,7 @@ const TransactionRetryNotice: React.FC<TransactionRetryNoticeProps> = ({
2930
)}
3031
>
3132
<div className="flex items-start gap-3">
32-
<div className="mt-0.5 rounded-full bg-red-500/15 p-2 text-red-300">
33-
<AlertTriangle className="size-4" />
34-
</div>
33+
<TransactionStatusIcon status="failed" className="mt-0.5" />
3534
<div className="min-w-0 flex-1">
3635
<p className="font-jakarta text-sm font-bold text-white">
3736
{title}

‎src/components/common/TransactionStatusIcon.tsx‎

Lines changed: 14 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -18,46 +18,28 @@ const TransactionStatusIcon: React.FC<TransactionStatusIconProps> = ({
1818
status,
1919
className,
2020
}) => {
21-
if (status === 'success') {
22-
return (
23-
<span
24-
aria-label="Transaction success"
25-
className={cn(
26-
'inline-flex rounded-full p-1.5',
27-
statusStyles.success,
28-
className
29-
)}
30-
>
31-
<CheckCircle2 className="size-4" />
32-
</span>
33-
);
34-
}
21+
const Icon =
22+
status === 'success' ? CheckCircle2 : status === 'pending' ? Clock3 : XCircle;
3523

36-
if (status === 'pending') {
37-
return (
38-
<span
39-
aria-label="Transaction pending"
40-
className={cn(
41-
'inline-flex rounded-full p-1.5 motion-safe:animate-pulse motion-reduce:animate-none',
42-
statusStyles.pending,
43-
className
44-
)}
45-
>
46-
<Clock3 className="size-4" />
47-
</span>
48-
);
49-
}
24+
const label =
25+
status === 'success'
26+
? 'Transaction success'
27+
: status === 'pending'
28+
? 'Transaction pending'
29+
: 'Transaction failed';
5030

5131
return (
5232
<span
53-
aria-label="Transaction failed"
33+
aria-label={label}
5434
className={cn(
55-
'inline-flex rounded-full p-1.5',
56-
statusStyles.failed,
35+
'inline-flex items-center justify-center rounded-full p-1.5',
36+
statusStyles[status],
37+
status === 'pending' &&
38+
'motion-safe:animate-pulse motion-reduce:animate-none',
5739
className
5840
)}
5941
>
60-
<XCircle className="size-4" />
42+
<Icon className="size-4" />
6143
</span>
6244
);
6345
};

‎src/components/common/__tests__/KeySupplyBadge.test.tsx‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ describe('Property 3: Relative time formatting', () => {
2727
const iso = new Date(Date.now() - offsetMs).toISOString();
2828
const result = formatRelativeTime(iso);
2929
const validPattern =
30-
result === 'just now' ||
30+
result === 'Updated just now' ||
3131
/^Updated \d+ min ago$/.test(result) ||
3232
/^Updated \d+ hr ago$/.test(result) ||
3333
/^Updated \d+ days? ago$/.test(result);
@@ -106,16 +106,16 @@ describe('formatRelativeTime edge cases', () => {
106106
}
107107

108108
it('future timestamp → "just now"', () => {
109-
const future = new Date(Date.now() + 60_000).toISOString();
110-
expect(formatRelativeTime(future)).toBe('just now');
109+
const future = new Date(Date.now() + 50_000).toISOString();
110+
expect(formatRelativeTime(future)).toBe('Updated just now');
111111
});
112112

113113
it('0 seconds ago → "just now"', () => {
114-
expect(formatRelativeTime(isoSecondsAgo(0))).toBe('just now');
114+
expect(formatRelativeTime(isoSecondsAgo(0))).toBe('Updated just now');
115115
});
116116

117117
it('59 seconds ago → "just now"', () => {
118-
expect(formatRelativeTime(isoSecondsAgo(59))).toBe('just now');
118+
expect(formatRelativeTime(isoSecondsAgo(59))).toBe('Updated just now');
119119
});
120120

121121
it('60 seconds ago → "Updated 1 min ago"', () => {

‎src/main.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { StrictMode } from 'react';
22
import { createRoot } from 'react-dom/client';
33
import './index.css';
44
import App from './App.tsx';
5-
import Web3Provider from '@/providers/Web3Provider';
5+
import Web3Provider from './providers/Web3Provider.tsx';
66

77
createRoot(document.getElementById('root')!).render(
88
<StrictMode>

‎src/test/setup.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
import '@testing-library/jest-dom';
1+
import '@testing-library/jest-dom/vitest';

‎src/utils/keyPrice.utils.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export function formatTimestampTooltip(iso: string | null | undefined): {
2020
} {
2121
if (iso == null) return { display: 'Last updated: N/A', title: null };
2222
const relative = sharedFormatRelativeTime(iso, { prefix: 'Updated' });
23-
return relative === 'N/A'
23+
return relative.includes('N/A')
2424
? { display: 'Last updated: N/A', title: null }
2525
: { display: relative, title: null };
2626
}
@@ -32,5 +32,5 @@ export function formatTimestampTooltip(iso: string | null | undefined): {
3232
export function formatRelativeTime(iso: string | null | undefined): string {
3333
if (iso == null) return 'Last updated: N/A';
3434
const relative = sharedFormatRelativeTime(iso, { prefix: 'Updated' });
35-
return relative === 'N/A' ? 'Last updated: N/A' : relative;
35+
return relative.includes('N/A') ? 'Last updated: N/A' : relative;
3636
}

‎vitest.config.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import path from 'path';
2+
import react from '@vitejs/plugin-react-swc';
23
import { defineConfig } from 'vitest/config';
34

45
export default defineConfig({
6+
plugins: [react()],
57
test: {
68
globals: true,
79
environment: 'jsdom',

0 commit comments

Comments
 (0)