FeedPage.tsx to integrate with the backend interfaces - Wiz-DevTech/prettygirllz GitHub Wiki
import {
FeedItem,
CreateFeedItemPayload,
Message,
SendMessagePayload,
Product,
ProductCategory
} from '@social-commerce-service';
import { ProductAPIResponse } from '@gateway-service';
import { getCurrentUser } from '@identity-service';
const FeedContent = () => {
const [postContent, setPostContent] = useState('');
const [feedItems, setFeedItems] = useState<FeedItem[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const loadFeed = async () => {
try {
const user = await getCurrentUser();
// Assuming we have a socialCommerceAPI instance available
const feed = await socialCommerceAPI.getFeed(user.id);
setFeedItems(feed);
} catch (err) {
setError('Failed to load feed');
} finally {
setIsLoading(false);
}
};
loadFeed();
}, []);
const handleCreatePost = async () => {
if (postContent.trim()) {
try {
const payload: CreateFeedItemPayload = {
content: postContent,
visibility: 'PUBLIC',
mediaUrls: [] // Can be updated with actual media URLs
};
const newPost = await socialCommerceAPI.createFeedItem(payload);
setFeedItems([newPost, ...feedItems]);
setPostContent('');
} catch (err) {
setError('Failed to create post');
}
}
};
if (isLoading) return <div>Loading...</div>;
if (error) return <div>{error}</div>;
return (
<div className="max-w-2xl mx-auto pb-16 md:pb-0">
<FlashSaleBanner />
{/* Create Post */}
<div className="bg-white rounded-lg shadow mb-6">
{/* ... existing create post UI ... */}
</div>
{/* Feed Posts */}
{feedItems.map(item => (
<FeedPost
key={item.id}
feedItem={item}
onLike={handleLike}
onComment={handleComment}
/>
))}
<UpsellProducts />
<RecommendationEngine />
</div>
);
};
interface FeedPostProps {
feedItem: FeedItem;
onLike: (feedItemId: string) => Promise<void>;
onComment: (feedItemId: string, comment: string) => Promise<void>;
}
const FeedPost = ({ feedItem, onLike, onComment }: FeedPostProps) => {
const [isLiked, setIsLiked] = useState(false);
const [showComments, setShowComments] = useState(false);
const [commentText, setCommentText] = useState('');
const handleLike = async () => {
try {
await onLike(feedItem.id);
setIsLiked(!isLiked);
} catch (err) {
console.error('Failed to like post', err);
}
};
const handleCommentSubmit = async () => {
if (commentText.trim()) {
try {
await onComment(feedItem.id, commentText);
setCommentText('');
} catch (err) {
console.error('Failed to post comment', err);
}
}
};
return (
<div className="bg-white rounded-lg shadow mb-6">
{/* Post Header */}
<div className="flex items-center p-4">
<img
src={feedItem.user?.avatarUrl || '/api/placeholder/40/40'}
alt={feedItem.user?.username}
className="w-10 h-10 rounded-full mr-3"
/>
<div className="flex-1">
<h3 className="font-semibold text-gray-900">{feedItem.user?.username}</h3>
<p className="text-sm text-gray-500">
{new Date(feedItem.timestamp).toLocaleString()}
</p>
</div>
</div>
{/* Post Content */}
<div className="px-4 pb-3">
<p className="text-gray-800">{feedItem.content}</p>
</div>
{/* Media */}
{feedItem.mediaUrls.length > 0 && (
<div className="relative">
<img
src={feedItem.mediaUrls[0]}
alt="Post content"
className="w-full h-96 object-cover"
/>
</div>
)}
{/* Post Actions */}
<div className="p-4">
<div className="flex items-center space-x-4 mb-3">
<button onClick={handleLike} className="flex items-center space-x-1">
<Heart size={20} fill={isLiked ? 'currentColor' : 'none'} />
<span className="text-sm">{feedItem.likeCount}</span>
</button>
<button
onClick={() => setShowComments(!showComments)}
className="flex items-center space-x-1"
>
<MessageCircle size={20} />
<span className="text-sm">{feedItem.commentCount}</span>
</button>
<button className="flex items-center space-x-1">
<Share size={20} />
<span className="text-sm">{feedItem.shareCount}</span>
</button>
</div>
{showComments && (
<div className="border-t pt-3">
{/* Comments would be fetched separately */}
<div className="space-y-2">
{/* Comment list would go here */}
</div>
<div className="flex space-x-2 mt-3">
<input
type="text"
value={commentText}
onChange={(e) => setCommentText(e.target.value)}
placeholder="Write a comment..."
className="flex-1 px-3 py-2 border rounded-full"
/>
<button onClick={handleCommentSubmit}>
<Send size={16} />
</button>
</div>
</div>
)}
</div>
</div>
);
};
const ProductBubbleScroll = () => {
const [selectedCategory, setSelectedCategory] = useState<ProductCategory | 'all'>('all');
const [products, setProducts] = useState<Product[]>([]);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const loadProducts = async () => {
try {
// Assuming we have a productAPI instance available
const allProducts = await productAPI.listProducts();
setProducts(allProducts);
} catch (err) {
console.error('Failed to load products', err);
} finally {
setIsLoading(false);
}
};
loadProducts();
}, []);
const filteredProducts = selectedCategory === 'all'
? products
: products.filter(product => product.category === selectedCategory);
// ... rest of the component remains similar, but uses real product data
};
const getProductWithCache = async (productId: string): Promise<ProductAPIResponse> => {
try {
// First try to get from gateway service with caching
const response = await gatewayAPI.getProduct(productId);
if (response.cached) {
console.log('Served from cache');
}
return response.data;
} catch (err) {
console.error('Failed to fetch product with cache', err);
// Fallback to direct API call
return await productAPI.getProductById(parseInt(productId));
}
};
const MessagesContent = () => {
const [conversations, setConversations] = useState<Message[]>([]);
const [selectedConversation, setSelectedConversation] = useState<Message | null>(null);
useEffect(() => {
const loadConversations = async () => {
try {
const user = await getCurrentUser();
const messages = await socialCommerceAPI.getConversation(user.id);
setConversations(messages);
} catch (err) {
console.error('Failed to load conversations', err);
}
};
loadConversations();
}, []);
// ... rest of the component implementation
};
Add proper error boundaries and loading states throughout the components to handle API failures gracefully.
Create custom hooks to manage the service interactions:
function useFeed() {
const [feed, setFeed] = useState<FeedItem[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const loadFeed = async () => {
try {
const user = await getCurrentUser();
const data = await socialCommerceAPI.getFeed(user.id);
setFeed(data);
} catch (err) {
setError('Failed to load feed');
} finally {
setLoading(false);
}
};
loadFeed();
}, []);
const createPost = async (content: string) => {
try {
const payload: CreateFeedItemPayload = {
content,
visibility: 'PUBLIC'
};
const newPost = await socialCommerceAPI.createFeedItem(payload);
setFeed(prev => [newPost, ...prev]);
} catch (err) {
setError('Failed to create post');
}
};
return { feed, loading, error, createPost };
}
These changes integrate the FeedPage with the backend services while maintaining the existing UI structure. The key improvements are:
- Type safety using the backend.d.ts interfaces
- Real data fetching from the social commerce and product services
- Caching strategy implementation
- Proper error handling and loading states
- Separation of concerns with service hooks
You'll need to ensure you have the actual service implementations available in your application context to make the API calls. The exact implementation might vary based on how you're managing your API clients and application state.