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>
|
</tbody>
|
||||||
</table>
|
</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>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -112,4 +100,4 @@ export default function DocsPage({ isEnglish = false, page }: DocsPageProps) {
|
|||||||
</div>
|
</div>
|
||||||
</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 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() {
|
export default function HomePage() {
|
||||||
|
|
||||||
@@ -9,6 +11,30 @@ export default function HomePage() {
|
|||||||
queryFn: () => fetchUsers()
|
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) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen flex items-center justify-center">
|
<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>
|
<a href="/docs" className="btn">help</a>
|
||||||
</div>
|
</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 && (
|
{users?.data && Array.isArray(users.data) && users.data.length > 0 && (
|
||||||
<div className="bg-white rounded-lg p-6">
|
<div className="bg-white rounded-lg p-6">
|
||||||
<div className="grid gap-4">
|
<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 }> => {
|
export const fetchUser = async (userId: number): Promise<{ data: User }> => {
|
||||||
const response = await api.get(`users/${userId}`);
|
const response = await api.get(`users/${userId}`);
|
||||||
return response.data;
|
return response.data;
|
||||||
|
Reference in New Issue
Block a user