Add favorite cards display on homepage
- Fetch and display users' favorite cards at the top of homepage - Filter users with fav \!== '0' to avoid empty display - Use useQueries to fetch multiple users' cards in parallel - Display cards in grid layout with owner username below - Cards are shown above the user list section 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
		| @@ -85,18 +85,6 @@ export default function DocsPage({ isEnglish = false, page }: DocsPageProps) { | ||||
|           </tbody> | ||||
|         </table> | ||||
|  | ||||
|         <h3>{isEnglish ? 'Battle' : '対戦について'}</h3> | ||||
|         <p><code>@yui.syui.ai /card -b</code></p> | ||||
|         <p>{isEnglish ? 'Random match, one of the top 3 cards on hand will be chosen at random' : 'ランダムマッチ、手持ちの上位3枚のうち1枚がランダムで選ばれます'}</p> | ||||
|  | ||||
|         <h3>Mastodon</h3> | ||||
|         <p> | ||||
|           <code> | ||||
|             <a href="https://mstdn.syui.ai/@yui" target="_blank" rel="noopener noreferrer"> | ||||
|               @yui@syui.ai | ||||
|             </a> /card | ||||
|           </code> | ||||
|         </p> | ||||
|       </div> | ||||
|     ); | ||||
|   }; | ||||
| @@ -112,4 +100,4 @@ export default function DocsPage({ isEnglish = false, page }: DocsPageProps) { | ||||
|       </div> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,8 @@ | ||||
| import { useQuery } from '@tanstack/react-query'; | ||||
| import { useQuery, useQueries } from '@tanstack/react-query'; | ||||
| import Navigation from '../common/Navigation'; | ||||
| import { fetchUsers } from '../../utils/api'; | ||||
| import { fetchUsers, fetchUserCards } from '../../utils/api'; | ||||
| import SpecialCard from '../card/SpecialCard'; | ||||
| import type { Card } from '../../types'; | ||||
|  | ||||
| export default function HomePage() { | ||||
|    | ||||
| @@ -9,6 +11,30 @@ export default function HomePage() { | ||||
|     queryFn: () => fetchUsers() | ||||
|   }); | ||||
|  | ||||
|   // Get all users with fav cards | ||||
|   const usersWithFav = users?.data?.filter(user => user.fav && user.fav !== '0') || []; | ||||
|    | ||||
|   // Fetch cards for each user with fav | ||||
|   const favCardQueries = useQueries({ | ||||
|     queries: usersWithFav.map(user => ({ | ||||
|       queryKey: ['userCards', user.id], | ||||
|       queryFn: () => fetchUserCards(user.id), | ||||
|       enabled: !!user.id | ||||
|     })) | ||||
|   }); | ||||
|  | ||||
|   // Extract fav cards | ||||
|   const favCards: { user: typeof usersWithFav[0], card: Card }[] = []; | ||||
|   usersWithFav.forEach((user, index) => { | ||||
|     const userCards = favCardQueries[index]?.data?.data; | ||||
|     if (userCards && user.fav) { | ||||
|       const favCard = userCards.find(card => card.id === parseInt(user.fav)); | ||||
|       if (favCard) { | ||||
|         favCards.push({ user, card: favCard }); | ||||
|       } | ||||
|     } | ||||
|   }); | ||||
|  | ||||
|   if (isLoading) { | ||||
|     return ( | ||||
|       <div className="min-h-screen flex items-center justify-center"> | ||||
| @@ -28,6 +54,25 @@ export default function HomePage() { | ||||
|           <a href="/docs" className="btn">help</a> | ||||
|         </div> | ||||
|  | ||||
|         {/* Favorite Cards Section */} | ||||
|         {favCards.length > 0 && ( | ||||
|           <div className="mb-8"> | ||||
|             <h2 className="text-xl font-bold mb-4">Favorite Cards</h2> | ||||
|             <div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-4"> | ||||
|               {favCards.map(({ user, card }) => ( | ||||
|                 <div key={`${user.id}-${card.id}`}> | ||||
|                   <SpecialCard card={card} /> | ||||
|                   <div className="text-center text-sm mt-2"> | ||||
|                     <a href={`/${user.username}`} className="text-gray-600 hover:text-primary"> | ||||
|                       @{user.username} | ||||
|                     </a> | ||||
|                   </div> | ||||
|                 </div> | ||||
|               ))} | ||||
|             </div> | ||||
|           </div> | ||||
|         )} | ||||
|  | ||||
|         {users?.data && Array.isArray(users.data) && users.data.length > 0 && ( | ||||
|           <div className="bg-white rounded-lg p-6"> | ||||
|             <div className="grid gap-4"> | ||||
|   | ||||
| @@ -52,6 +52,16 @@ export const fetchUserCards = async (userId: number, itemsPerPage = 8000): Promi | ||||
|   } | ||||
| }; | ||||
|  | ||||
| export const fetchCardById = async (cardId: number): Promise<Card | null> => { | ||||
|   try { | ||||
|     const response = await api.get(`cards/${cardId}`); | ||||
|     return response.data; | ||||
|   } catch (error) { | ||||
|     console.error('Failed to fetch card by ID:', error); | ||||
|     return null; | ||||
|   } | ||||
| }; | ||||
|  | ||||
| export const fetchUser = async (userId: number): Promise<{ data: User }> => { | ||||
|   const response = await api.get(`users/${userId}`); | ||||
|   return response.data; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user