From c84f8e4c06ac163d43f1e3d19e53f0a040d05138 Mon Sep 17 00:00:00 2001 From: floxxih Date: Fri, 27 Mar 2026 07:22:24 +0100 Subject: [PATCH] feat: add reusable creator metadata and input state UI --- src/components/common/CategoryTag.tsx | 25 ++ .../common/CompactEmptyWalletState.tsx | 33 ++ src/components/common/CreatorCard.tsx | 27 +- .../common/InlineValidationMessage.tsx | 27 ++ src/components/common/SearchBar.tsx | 32 +- src/components/common/VerifiedBadge.tsx | 33 ++ src/pages/LandingPage.tsx | 324 ++++++++++-------- src/services/course.service.ts | 6 +- 8 files changed, 343 insertions(+), 164 deletions(-) create mode 100644 src/components/common/CategoryTag.tsx create mode 100644 src/components/common/CompactEmptyWalletState.tsx create mode 100644 src/components/common/InlineValidationMessage.tsx create mode 100644 src/components/common/VerifiedBadge.tsx diff --git a/src/components/common/CategoryTag.tsx b/src/components/common/CategoryTag.tsx new file mode 100644 index 00000000..a1bb1c11 --- /dev/null +++ b/src/components/common/CategoryTag.tsx @@ -0,0 +1,25 @@ +import { cn } from '@/lib/utils'; + +interface CategoryTagProps { + label?: string; + className?: string; +} + +const CategoryTag: React.FC = ({ + label = 'Uncategorized', + className, +}) => { + return ( + + {label} + + ); +}; + +export default CategoryTag; diff --git a/src/components/common/CompactEmptyWalletState.tsx b/src/components/common/CompactEmptyWalletState.tsx new file mode 100644 index 00000000..b25d5c68 --- /dev/null +++ b/src/components/common/CompactEmptyWalletState.tsx @@ -0,0 +1,33 @@ +import { WalletMinimal } from 'lucide-react'; +import { cn } from '@/lib/utils'; + +interface CompactEmptyWalletStateProps { + title?: string; + description?: string; + className?: string; +} + +const CompactEmptyWalletState: React.FC = ({ + title = 'No wallet balance yet', + description = 'Connect and fund your wallet to unlock creator key purchases.', + className, +}) => { + return ( +
+
+ +
+
+

{title}

+

{description}

+
+
+ ); +}; + +export default CompactEmptyWalletState; diff --git a/src/components/common/CreatorCard.tsx b/src/components/common/CreatorCard.tsx index d36a0c2a..339f2ded 100644 --- a/src/components/common/CreatorCard.tsx +++ b/src/components/common/CreatorCard.tsx @@ -7,6 +7,9 @@ import { ShoppingCart, Wallet, Link as LinkIcon } from 'lucide-react'; import toast from 'react-hot-toast'; import showToast from '@/utils/toast.util'; import TransactionRetryNotice from '@/components/common/TransactionRetryNotice'; +import VerifiedBadge from '@/components/common/VerifiedBadge'; +import CategoryTag from '@/components/common/CategoryTag'; +import CompactEmptyWalletState from '@/components/common/CompactEmptyWalletState'; interface CreatorCardProps { creator: Course; @@ -71,12 +74,21 @@ const CreatorCard: React.FC = ({ creator, className }) => {
-

- {creator.title} -

+
+

+ {creator.title} +

+ +

@{creator.instructorId || 'creator'}

+
+ +
{creator.socialHandle ? (
@@ -116,9 +128,12 @@ const CreatorCard: React.FC = ({ creator, className }) => {
{!isConnected && ( -
- - Wallet Required +
+
+ + Wallet Required +
+
)} diff --git a/src/components/common/InlineValidationMessage.tsx b/src/components/common/InlineValidationMessage.tsx new file mode 100644 index 00000000..1d120a78 --- /dev/null +++ b/src/components/common/InlineValidationMessage.tsx @@ -0,0 +1,27 @@ +import { AlertCircle } from 'lucide-react'; +import { cn } from '@/lib/utils'; + +interface InlineValidationMessageProps { + message: string; + className?: string; +} + +const InlineValidationMessage: React.FC = ({ + message, + className, +}) => { + return ( +

+ + {message} +

+ ); +}; + +export default InlineValidationMessage; diff --git a/src/components/common/SearchBar.tsx b/src/components/common/SearchBar.tsx index 75064a14..cb6bd623 100644 --- a/src/components/common/SearchBar.tsx +++ b/src/components/common/SearchBar.tsx @@ -1,11 +1,13 @@ import { Search } from 'lucide-react'; import { cn } from '@/lib/utils'; +import InlineValidationMessage from '@/components/common/InlineValidationMessage'; interface SearchBarProps { value: string; onChange: (value: string) => void; placeholder?: string; className?: string; + validationMessage?: string; } const SearchBar: React.FC = ({ @@ -13,19 +15,29 @@ const SearchBar: React.FC = ({ onChange, placeholder = 'Search creators by name or handle...', className, + validationMessage, }) => { return ( -
-
-