diff --git a/src/components/common/CreatorBreadcrumb.tsx b/src/components/common/CreatorBreadcrumb.tsx index 55c1f69..7be56b8 100644 --- a/src/components/common/CreatorBreadcrumb.tsx +++ b/src/components/common/CreatorBreadcrumb.tsx @@ -2,6 +2,7 @@ import React from 'react'; import { Link } from 'react-router'; import { ChevronRight } from 'lucide-react'; import { cn } from '@/lib/utils'; +import { normalizeCreatorDisplayName } from '@/utils/creatorDisplayName.utils'; interface CreatorBreadcrumbProps { parentLabel: string; @@ -16,6 +17,9 @@ const CreatorBreadcrumb: React.FC = ({ currentLabel, className, }) => { + const displayCurrentLabel = + normalizeCreatorDisplayName(currentLabel) || 'Unnamed creator'; + return ( ); diff --git a/src/components/common/CreatorCard.tsx b/src/components/common/CreatorCard.tsx index 705a3f7..cc9edae 100644 --- a/src/components/common/CreatorCard.tsx +++ b/src/components/common/CreatorCard.tsx @@ -2,7 +2,15 @@ import { useRef, useState } from 'react'; import { useAccount } from 'wagmi'; import type { Course } from '@/services/course.service'; import { cn } from '@/lib/utils'; -import { ShoppingCart, Link as LinkIcon, TrendingUp, MoreVertical, Copy, Share2, ExternalLink } from 'lucide-react'; +import { + ShoppingCart, + Link as LinkIcon, + TrendingUp, + MoreVertical, + Copy, + Share2, + ExternalLink, +} from 'lucide-react'; import { DropdownMenu, DropdownMenuContent, @@ -17,6 +25,8 @@ import showToast from '@/utils/toast.util'; import { formatCompactNumber } from '@/utils/numberFormat.utils'; import { formatCreatorKeyPriceDisplay } from '@/utils/keyPriceDisplay.utils'; import { formatCreatorHandle } from '@/utils/handleDisplay.utils'; +import { normalizeCreatorDisplayName } from '@/utils/creatorDisplayName.utils'; +import { getCreatorPriceChartAccessibilityCopy } from '@/utils/creatorPriceChartAccessibility.utils'; import { formatJoinDate } from '@/utils/formatJoinDate'; import { useSystemTheme } from '@/utils/useSystemTheme'; import { Tooltip } from '@/components/ui/tooltip'; @@ -68,22 +78,36 @@ const CreatorCard: React.FC = ({ const displayInstructorHandle = formatCreatorHandle(creator.instructorId) || '@creator'; const displaySocialHandle = formatCreatorHandle(creator.socialHandle); + const displayCreatorName = + normalizeCreatorDisplayName(creator.title) || 'Unnamed creator'; + const priceChartAccessibility = getCreatorPriceChartAccessibilityCopy({ + name: displayCreatorName, + price: creator.price, + priceStroops: creator.priceStroops, + change24h: creator.change24h, + }); + const priceChartDescriptionId = `creator-price-chart-description-${creator.id}`; const { isConnected } = useAccount(); - const { isMismatch: isNetworkMismatch, expectedChainName } = useNetworkMismatch(); + const { isMismatch: isNetworkMismatch, expectedChainName } = + useNetworkMismatch(); const [transactionState, setTransactionState] = useState< 'idle' | 'submitting' | 'failed' | 'success' >('idle'); const [failureDrawerOpen, setFailureDrawerOpen] = useState(false); - const [failureDetails, setFailureDetails] = useState({ - errorMessage: '', - }); + const [failureDetails, setFailureDetails] = + useState({ + errorMessage: '', + }); const hasFailedOnceRef = useRef(false); const trackTransactionEvent = useTransactionTelemetry(); const runPurchaseAttempt = () => { setTransactionState('submitting'); - trackTransactionEvent('tx_submitted', { creatorId: creator.id, creatorTitle: creator.title }); - showToast.loading(`Purchasing keys for ${creator.title}...`); + trackTransactionEvent('tx_submitted', { + creatorId: creator.id, + creatorTitle: displayCreatorName, + }); + showToast.loading(`Purchasing keys for ${displayCreatorName}...`); window.setTimeout(() => { toast.remove(); @@ -92,7 +116,8 @@ const CreatorCard: React.FC = ({ hasFailedOnceRef.current = true; setTransactionState('failed'); setFailureDetails({ - errorMessage: 'Transaction failed: Insufficient balance to complete the purchase.', + errorMessage: + 'Transaction failed: Insufficient balance to complete the purchase.', errorCode: 'ERR_INSUFFICIENT_BALANCE', txHash: '0xabcd1234...failed', developerDetails: { @@ -108,10 +133,13 @@ const CreatorCard: React.FC = ({ hasFailedOnceRef.current = false; setTransactionState('success'); - trackTransactionEvent('tx_confirmed', { creatorId: creator.id, creatorTitle: creator.title }); + trackTransactionEvent('tx_confirmed', { + creatorId: creator.id, + creatorTitle: displayCreatorName, + }); showToast.transactionSuccess( 'Purchase Successful!', - `You successfully bought a key for ${creator.title}`, + `You successfully bought a key for ${displayCreatorName}`, '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef', 'https://stellar.expert/explorer/testnet/tx/0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef' ); @@ -136,7 +164,7 @@ const CreatorCard: React.FC = ({ const handleShare = () => { const url = `${window.location.origin}/creator/${creator.id}`; if (navigator.share) { - navigator.share({ title: creator.title, url }).catch(() => {}); + navigator.share({ title: displayCreatorName, url }).catch(() => {}); } else { navigator.clipboard .writeText(url) @@ -160,7 +188,7 @@ const CreatorCard: React.FC = ({ return; } - toast.success(`Purchasing keys for ${creator.title}...`, { + toast.success(`Purchasing keys for ${displayCreatorName}...`, { duration: 3000, }); // Implementation for contract interaction would go here @@ -177,7 +205,7 @@ const CreatorCard: React.FC = ({