Skip to main content

👤 My Reels

Fetch and display the current user's own reels with filtering, sorting, and pagination capabilities.

✨ Overview

The My Reels feature allows users to:

  • 📋 View Own Content - Display all reels created by the current user
  • 🔍 Filter by Status - Filter by approval status (approved, pending, rejected)
  • 🎯 Filter by Privacy - Filter by privacy level
  • 🔄 Sort & Order - Sort by field with ascending/descending order
  • 📄 Pagination - Load more reels with cursor-based pagination
  • ⚡ Dynamic Updates - Reload with new filters instantly

🎯 Use Cases

Creator Dashboard

Display user's own reels with management controls:

<MyReelsDashboard 
showFilters
allowEdit
allowDelete
/>

Profile Page

Show user's published reels:

<MyReelsGrid 
filter={{ approving_status: 'approved' }}
sortBy="created_at"
order="desc"
/>

Drafts & Pending Review

Show unpublished or pending reels:

<PendingReels 
filter={{ approving_status: 'pending' }}
/>

📦 Core Package (@xhub-chat/core)

Basic Usage

import { createClient } from '@xhub-chat/core';

const client = createClient({
baseUrl: 'https://your-server.com',
accessToken: 'your-access-token',
userId: '@user:server.com',
});

await client.startClient();

// Fetch my reels with default options
const result = await client.fetchMyReels();

console.log('My reels:', result.reels);
console.log('Has more:', result.hasMore);
console.log('Next cursor:', result.nextCursor);

With Filters

// Filter by approval status
const approvedReels = await client.fetchMyReels({
approving_status: 'approved',
limit: 20,
});

// Filter by multiple criteria
const filteredReels = await client.fetchMyReels({
approving_status: 'approved',
privacy: 1,
sort: 'created_at',
sorted: 'desc',
limit: 10,
});

Pagination

// First page
const firstPage = await client.fetchMyReels({ limit: 10 });

// Load more with cursor
if (firstPage.hasMore && firstPage.nextCursor) {
const secondPage = await client.fetchMyReels({
cursor: firstPage.nextCursor,
limit: 10,
});

const allReels = [...firstPage.reels, ...secondPage.reels];
}

API Reference

fetchMyReels(options?: MyReelsFilter): Promise<MyReelsResponse>

Fetch the current user's reels.

Parameters:

interface MyReelsFilter {
// Filter by approval status
approving_status?: 'approved' | 'rejected' | 'pending';

// Filter by privacy level
privacy?: number;

// Sort by field name
sort?: string;

// Sort order
sorted?: 'asc' | 'desc';

// Pagination cursor
cursor?: string;

// Number of items per page (default: 10)
limit?: number;
}

Returns:

interface MyReelsResponse {
// Array of reel data
reels: ReelData[];

// Cursor for next page (null if no more)
nextCursor: string | null;

// Whether more reels are available
hasMore: boolean;
}

Reel Data Structure:

interface ReelData {
id: string;
title: string;
type: string;
description: string;
owner_id: string;
content: string;

// Media files
media: { type: string; url: string }[];
thumbnail?: { type: string; url: string };

// Metadata
tags: string[];
status: string;
approving_status?: 'approved' | 'rejected' | 'pending';
participants: string[] | null;
is_allow_comment: boolean;

// Timestamps
created_at: string;
updated_at: string;
updated_by: string | null;
scheduled_at: string | null;

// Owner info
owner?: {
id: string;
email: string;
first_name: string;
last_name: string;
avatar: string;
};

// Stats
likes: number;
views: number;
total_comments: number;
liked: boolean;
}

⚛️ React Package (@xhub-chat/react)

Basic Usage

import { useMyReels } from '@xhub-chat/react';

function MyReelsPage() {
const { reels, loading, error, hasMore, loadMore } = useMyReels();

if (loading && reels.length === 0) {
return <div>Loading...</div>;
}

if (error) {
return <div>Error: {error.message}</div>;
}

return (
<div>
<h1>My Reels ({reels.length})</h1>

<div className="reels-grid">
{reels.map(reel => (
<ReelCard key={reel.id} reel={reel} />
))}
</div>

{hasMore && (
<button onClick={loadMore} disabled={loading}>
{loading ? 'Loading...' : 'Load More'}
</button>
)}
</div>
);
}

With Filters

import { useMyReels } from '@xhub-chat/react';

function MyApprovedReels() {
const { reels, loading, setFilters, reload } = useMyReels({
initialFilters: {
approving_status: 'approved',
sort: 'created_at',
sorted: 'desc',
},
});

const handleFilterChange = (status: 'approved' | 'pending' | 'rejected') => {
setFilters({ approving_status: status });
};

return (
<div>
<div className="filters">
<button onClick={() => handleFilterChange('approved')}>
Approved
</button>
<button onClick={() => handleFilterChange('pending')}>
Pending
</button>
<button onClick={() => handleFilterChange('rejected')}>
Rejected
</button>
</div>

<ReelsList reels={reels} loading={loading} />
</div>
);
}

Custom Limit & Manual Load

function MyReelsCustom() {
const { reels, loadMore, reload } = useMyReels({
autoLoad: false, // Don't auto-load on mount
limit: 20, // Load 20 items per page
});

return (
<div>
<button onClick={() => reload()}>Load My Reels</button>

{reels.length > 0 && (
<>
<ReelsList reels={reels} />
<button onClick={loadMore}>Load More</button>
</>
)}
</div>
);
}

Complete Example with All Features

import { useMyReels } from '@xhub-chat/react';
import { useState } from 'react';

function MyReelsDashboard() {
const [filters, setLocalFilters] = useState({
approving_status: 'approved' as const,
sort: 'created_at',
sorted: 'desc' as const,
});

const {
reels,
loading,
error,
hasMore,
loadMore,
reload,
setFilters: updateFilters,
} = useMyReels({
initialFilters: filters,
limit: 12,
});

const handleApplyFilters = () => {
updateFilters(filters);
};

const handleRefresh = () => {
reload(filters);
};

return (
<div className="dashboard">
{/* Filter Controls */}
<div className="filters">
<select
value={filters.approving_status}
onChange={(e) => setLocalFilters({
...filters,
approving_status: e.target.value as any,
})}
>
<option value="">All Status</option>
<option value="approved">Approved</option>
<option value="pending">Pending</option>
<option value="rejected">Rejected</option>
</select>

<select
value={filters.sorted}
onChange={(e) => setLocalFilters({
...filters,
sorted: e.target.value as 'asc' | 'desc',
})}
>
<option value="desc">Newest First</option>
<option value="asc">Oldest First</option>
</select>

<button onClick={handleApplyFilters}>Apply Filters</button>
<button onClick={handleRefresh}>Refresh</button>
</div>

{/* Error State */}
{error && (
<div className="error">
Error: {error.message}
</div>
)}

{/* Reels Grid */}
<div className="reels-grid">
{reels.map(reel => (
<div key={reel.id} className="reel-card">
<img src={reel.thumbnail?.url} alt={reel.title} />
<h3>{reel.title}</h3>
<div className="stats">
<span>❤️ {reel.likes}</span>
<span>👁️ {reel.views}</span>
<span>💬 {reel.total_comments}</span>
</div>
<div className="status">
Status: {reel.approving_status}
</div>
</div>
))}
</div>

{/* Loading State */}
{loading && <div className="loading">Loading...</div>}

{/* Empty State */}
{!loading && reels.length === 0 && (
<div className="empty">No reels found</div>
)}

{/* Load More */}
{hasMore && !loading && (
<button onClick={loadMore} className="load-more">
Load More Reels
</button>
)}

{/* Total Count */}
<div className="summary">
Showing {reels.length} reels
</div>
</div>
);
}

Hook API Reference

useMyReels(options?: UseMyReelsOptions): UseMyReelsReturn

React hook for managing user's own reels with filtering and pagination.

Options:

interface UseMyReelsOptions {
// Auto-load reels on mount (default: true)
autoLoad?: boolean;

// Number of items per page (default: 10)
limit?: number;

// Initial filter values
initialFilters?: MyReelsFilter;
}

Returns:

interface UseMyReelsReturn {
// Array of loaded reels
reels: ReelData[];

// Loading state
loading: boolean;

// Error if any
error: Error | null;

// Whether more reels are available
hasMore: boolean;

// Current filters
filters: MyReelsFilter;

// Load next page of reels
loadMore: () => Promise<void>;

// Reload from start with optional new filters
reload: (newFilters?: MyReelsFilter) => Promise<void>;

// Update filters and trigger reload
setFilters: (newFilters: MyReelsFilter) => void;
}

🎨 Real-World Scenarios

Creator Studio

function CreatorStudio() {
const { reels, setFilters } = useMyReels({
initialFilters: { approving_status: 'approved' },
});

return (
<div>
<h1>My Published Reels</h1>
<Tabs>
<Tab onClick={() => setFilters({ approving_status: 'approved' })}>
Published
</Tab>
<Tab onClick={() => setFilters({ approving_status: 'pending' })}>
Under Review
</Tab>
<Tab onClick={() => setFilters({ approving_status: 'rejected' })}>
Rejected
</Tab>
</Tabs>
<ReelsGrid reels={reels} editable />
</div>
);
}

Analytics Dashboard

function AnalyticsDashboard() {
const { reels } = useMyReels({
initialFilters: {
approving_status: 'approved',
sort: 'views',
sorted: 'desc',
},
});

const totalViews = reels.reduce((sum, reel) => sum + reel.views, 0);
const totalLikes = reels.reduce((sum, reel) => sum + reel.likes, 0);

return (
<div>
<h1>Content Performance</h1>
<Stats>
<Stat label="Total Reels" value={reels.length} />
<Stat label="Total Views" value={totalViews} />
<Stat label="Total Likes" value={totalLikes} />
</Stats>
<TopPerformingReels reels={reels.slice(0, 5)} />
</div>
);
}

⚡ Performance Tips

Optimize Re-renders

import { memo } from 'react';

const ReelCard = memo(({ reel }: { reel: ReelData }) => {
return (
<div className="reel-card">
{/* Card content */}
</div>
);
});

Virtual Scrolling for Large Lists

import { useMyReels } from '@xhub-chat/react';
import { FixedSizeList } from 'react-window';

function VirtualizedReelsList() {
const { reels, loadMore, hasMore } = useMyReels({ limit: 100 });

return (
<FixedSizeList
height={600}
itemCount={reels.length}
itemSize={200}
onItemsRendered={({ visibleStopIndex }) => {
if (visibleStopIndex >= reels.length - 5 && hasMore) {
loadMore();
}
}}
>
{({ index, style }) => (
<div style={style}>
<ReelCard reel={reels[index]} />
</div>
)}
</FixedSizeList>
);
}

🔧 Troubleshooting

Reels Not Loading

Problem: reels array is empty even after loading.

Solution:

  • Ensure user is authenticated with valid accessToken
  • Check that client.startClient() was called
  • Verify API endpoint is accessible
const { reels, error } = useMyReels();

if (error) {
console.error('Failed to load reels:', error);
}

Filters Not Working

Problem: Setting filters doesn't update the list.

Solution: Use setFilters() which automatically triggers reload:

// ✅ Correct
setFilters({ approving_status: 'approved' });

// ❌ Wrong - this won't trigger reload
const { filters } = useMyReels();
filters.approving_status = 'approved';

Duplicate Reels After Pagination

Problem: Same reels appear multiple times.

Solution: The hook automatically prevents duplicate calls. Ensure you're not calling loadMore() multiple times simultaneously:

// ✅ Correct
<button onClick={loadMore} disabled={loading}>
Load More
</button>

// ❌ Wrong - can cause duplicates
<button onClick={() => {
loadMore();
loadMore(); // Don't call twice!
}}>
Load More
</button>


🎯 Next Steps