Skip to main content

Introduction

CricTalk’s component architecture is built with React Native and follows a modular, reusable design pattern. The component library includes UI elements for posts, comments, match rooms, modals, leaderboards, and utility components that maintain consistent styling and behavior throughout the application.

Component Organization

All reusable components are located in the app/components/ directory:
app/components/
├── PostCard.tsx              # Displays individual post with actions
├── CommentCard.tsx           # Displays user comments
├── MatchRoomCard.tsx         # Shows match room status and details
├── CreatePostModal.tsx       # Modal for creating new posts
├── CreateRoomModal.tsx       # Multi-step modal for room creation
├── LeaderboardPodiumUser.tsx # Top 3 leaderboard users
├── LeaderboardUserRow.tsx    # Leaderboard user row (4+)
├── ProfileDrawer.tsx         # Slide-in navigation drawer
├── FilterChip.tsx            # Filter/category selection chip
└── EmptyState.tsx            # Empty state placeholder

Styling Approach

NativeWind (Tailwind CSS)

CricTalk uses NativeWind for styling, which brings Tailwind CSS utility classes to React Native:
<View className="flex-row items-center gap-2">
  <Text className="text-slate-900 font-medium text-lg">
    {post.authorName}
  </Text>
</View>

Color Palette

The application uses a consistent color scheme:
  • Primary: Orange (orange-500, orange-600)
  • Text: Slate shades (slate-900, slate-800, slate-600)
  • Backgrounds: White, gray shades (gray-200, gray-300)
  • Status Colors: Green (live), Yellow (upcoming), Red (finished)

Common Styling Patterns

Interactive Elements

All pressable elements use consistent active states:
<Pressable className="transition-all duration-300 active:scale-[0.98] active:opacity-85">
  {/* Content */}
</Pressable>

Rounded Avatars

User avatars follow this pattern:
<View className="size-10 bg-slate-300 rounded-full items-center justify-center">
  <Text className="text-slate-900 font-medium text-lg capitalize">
    {username.charAt(0)}
  </Text>
</View>

Card Layouts

Cards use consistent spacing and borders:
<View className="mb-4 border-b border-gray-200 pb-4">
  {/* Card content */}
</View>

Common Props and Patterns

User Identification

Many components require userId to determine ownership and enable conditional rendering:
type Props = {
  userId: string;
  // ... other props
};

// Usage in component
{post.authorId === userId && (
  <View>{/* Show edit/delete actions */}</View>
)}

Data Models

Components receive typed data objects defined in schemas:
  • Post: From @/schemas/PostSchema
  • Comment: From @/schemas/CommentSchema
  • Room: From @/schemas/RoomSchema
  • UserStats: From @/interfaces/UserStats

Callback Props

Components use standard callback naming:
  • onPress: Generic press action
  • onClose: Modal/drawer close action
  • onEditPress: Edit action
  • onDeletePress: Delete action

State Management Integration

Zustand Stores

Components integrate with global state using Zustand stores:
import { usePosts } from "@/store/usePosts";
import { useRooms } from "@/store/useRooms";
import { useUser } from "@/store/useUser";

const posts = usePosts((s) => s.posts);
const username = useUser((s) => s.username);

Custom Hooks

Components leverage custom hooks for common operations:
  • useLikePost(): Handle post likes
  • useDeletePost(): Delete post functionality
  • useCreatePost(): Create new posts
  • useViewPost(): Track post views

Icon Usage

Components use @expo/vector-icons (Ionicons) for consistent iconography:
import { Ionicons } from "@expo/vector-icons";

<Ionicons name="heart-outline" size={18} color="gray" />
Common icons:
  • heart-outline/heart-sharp: Likes
  • chatbox-ellipses-outline: Comments
  • eye-outline: Views
  • pencil-outline: Edit
  • trash-outline: Delete
  • add: Create new
Modals in CricTalk follow a consistent pattern:
type Props = {
  isVisible: boolean;
  onClose: () => void;
};

<Modal visible={isVisible} transparent animationType="slide">
  {/* Modal content */}
</Modal>
Components use Expo Router for navigation:
import { router } from "expo-router";

// Navigate to specific route
router.push(`/(posts)/${post.$id}`);

// Go back
router.back();

Accessibility Considerations

  • All interactive elements use <Pressable> for better accessibility
  • Text colors maintain sufficient contrast ratios
  • Touch targets meet minimum size requirements (44x44 points)
  • Visual feedback on all interactive states

Performance Optimizations

List Rendering

Components use @legendapp/list for optimized list rendering:
import { LegendList } from "@legendapp/list";

<LegendList
  data={posts}
  keyExtractor={(item) => item.$id}
  renderItem={({ item }) => <PostCard post={item} userId={userId} />}
  recycleItems
/>

Component Memoization

Components can be wrapped with React.memo() for performance when needed.

Best Practices

  1. Type Safety: Always define TypeScript types for props
  2. Consistent Naming: Use clear, descriptive prop and variable names
  3. Modular Design: Keep components focused on a single responsibility
  4. Reusability: Extract common patterns into shared components
  5. Error Handling: Use toast notifications for user feedback
  6. Loading States: Show activity indicators during async operations
  7. Empty States: Provide meaningful empty state components with CTAs

Next Steps

Build docs developers (and LLMs) love