fix planet
This commit is contained in:
1
.github/workflows/gh-pages.yml
vendored
1
.github/workflows/gh-pages.yml
vendored
@@ -30,5 +30,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
publish_dir: ./dist
|
publish_dir: ./dist
|
||||||
|
force_orphan: true
|
||||||
user_name: 'ai[bot]'
|
user_name: 'ai[bot]'
|
||||||
user_email: '138105980+yui-syui-ai[bot]@users.noreply.github.com'
|
user_email: '138105980+yui-syui-ai[bot]@users.noreply.github.com'
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,3 +7,4 @@ package-lock.json
|
|||||||
yarn.lock
|
yarn.lock
|
||||||
**DS_Store
|
**DS_Store
|
||||||
.claude
|
.claude
|
||||||
|
repos
|
||||||
|
@@ -1,14 +1,35 @@
|
|||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { useEffect } from 'react';
|
||||||
import Navigation from '../common/Navigation';
|
import Navigation from '../common/Navigation';
|
||||||
import { fetchUsers } from '../../utils/api';
|
import { fetchUsersWithCache } from '../../utils/api';
|
||||||
|
import { api } from '../../utils/api';
|
||||||
|
|
||||||
export default function HomePage() {
|
export default function HomePage() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
const { data: users, isLoading } = useQuery({
|
const { data: users, isLoading } = useQuery({
|
||||||
queryKey: ['users'],
|
queryKey: ['users'],
|
||||||
queryFn: () => fetchUsers()
|
queryFn: () => fetchUsersWithCache(),
|
||||||
|
staleTime: 0, // Always consider data stale
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Refresh with API data after cache load
|
||||||
|
useEffect(() => {
|
||||||
|
if (users?.isFromCache) {
|
||||||
|
// Fetch fresh data from API in background
|
||||||
|
api.get('users?itemsPerPage=8000').then(response => {
|
||||||
|
console.log('Background API fetch successful, got', response.data.length, 'users with planet data');
|
||||||
|
// Update the query cache with fresh data
|
||||||
|
queryClient.setQueryData(['users'], {
|
||||||
|
data: response.data,
|
||||||
|
isFromCache: false
|
||||||
|
});
|
||||||
|
}).catch(error => {
|
||||||
|
console.error('Background API fetch failed:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [users?.isFromCache, queryClient]);
|
||||||
|
|
||||||
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">
|
||||||
|
@@ -4,17 +4,27 @@ import Navigation from '../common/Navigation';
|
|||||||
import CardGrid from '../card/CardGrid';
|
import CardGrid from '../card/CardGrid';
|
||||||
import UserProfile from '../user/UserProfile';
|
import UserProfile from '../user/UserProfile';
|
||||||
import SpecialCard from '../card/SpecialCard';
|
import SpecialCard from '../card/SpecialCard';
|
||||||
import { fetchUsers, fetchUserCards } from '../../utils/api';
|
import { fetchUsers, fetchUserCards, fetchUser } from '../../utils/api';
|
||||||
|
|
||||||
export default function UserPage() {
|
export default function UserPage() {
|
||||||
const { username } = useParams<{ username: string }>();
|
const { username } = useParams<{ username: string }>();
|
||||||
|
|
||||||
|
// First get users list to find the user ID
|
||||||
const { data: users, isLoading } = useQuery({
|
const { data: users, isLoading } = useQuery({
|
||||||
queryKey: ['users'],
|
queryKey: ['users'],
|
||||||
queryFn: () => fetchUsers(),
|
queryFn: () => fetchUsers(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const user = users?.data.find(u => u.username === username);
|
const userId = users?.data.find(u => u.username === username)?.id;
|
||||||
|
|
||||||
|
// Then fetch full user data from API to get planet value
|
||||||
|
const { data: userResponse } = useQuery({
|
||||||
|
queryKey: ['user', userId],
|
||||||
|
queryFn: () => fetchUser(userId!),
|
||||||
|
enabled: !!userId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const user = userResponse?.data || users?.data.find(u => u.username === username);
|
||||||
|
|
||||||
const { data: cards, isLoading: cardsLoading } = useQuery({
|
const { data: cards, isLoading: cardsLoading } = useQuery({
|
||||||
queryKey: ['userCards', user?.id],
|
queryKey: ['userCards', user?.id],
|
||||||
|
@@ -6,14 +6,6 @@ interface UserProfileProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function UserProfile({ user, cards }: UserProfileProps) {
|
export default function UserProfile({ user, cards }: UserProfileProps) {
|
||||||
const formatPlanet = (planet: number) => {
|
|
||||||
if (planet >= 1000000) {
|
|
||||||
return `${(planet / 1000000).toFixed(2)}M`;
|
|
||||||
} else if (planet >= 1000) {
|
|
||||||
return `${(planet / 1000).toFixed(2)}K`;
|
|
||||||
}
|
|
||||||
return planet.toLocaleString();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-white rounded-lg p-6 mb-8">
|
<div className="bg-white rounded-lg p-6 mb-8">
|
||||||
@@ -38,7 +30,7 @@ export default function UserProfile({ user, cards }: UserProfileProps) {
|
|||||||
)}
|
)}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 text-sm">
|
<div className="grid grid-cols-2 md:grid-cols-5 gap-4 text-sm">
|
||||||
<div>
|
<div>
|
||||||
<strong>ID:</strong> {user.id}
|
<strong>ID:</strong> {user.id}
|
||||||
</div>
|
</div>
|
||||||
@@ -54,12 +46,10 @@ export default function UserProfile({ user, cards }: UserProfileProps) {
|
|||||||
<span className="icon-ai"></span>
|
<span className="icon-ai"></span>
|
||||||
{cards.filter(c => c.card >= 96 && c.card <= 121).length}
|
{cards.filter(c => c.card >= 96 && c.card <= 121).length}
|
||||||
</div>
|
</div>
|
||||||
{user.planet && (
|
<div className="flex items-center gap-1">
|
||||||
<div className="flex items-center gap-1">
|
<i className="fa-solid fa-earth-americas"></i>
|
||||||
<i className="fa-solid fa-earth-americas"></i>
|
{user.planet?.toLocaleString() || '0'}
|
||||||
{formatPlanet(user.planet)}
|
</div>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Badge Images */}
|
{/* Badge Images */}
|
||||||
|
@@ -15,32 +15,44 @@ export const api = axios.create({
|
|||||||
// API関数
|
// API関数
|
||||||
export const fetchUsers = async (itemsPerPage = 8000): Promise<{ data: User[] }> => {
|
export const fetchUsers = async (itemsPerPage = 8000): Promise<{ data: User[] }> => {
|
||||||
try {
|
try {
|
||||||
// First try to load cached users.json for fast initial loading
|
// Directly fetch from API to get complete user data including planet
|
||||||
const cachedResponse = await axios.get('/json/users.json');
|
const response = await api.get(`users?itemsPerPage=${itemsPerPage}`);
|
||||||
|
return { data: response.data };
|
||||||
// Background fetch for fresh data
|
|
||||||
setTimeout(async () => {
|
|
||||||
try {
|
|
||||||
await api.get(`users?itemsPerPage=${itemsPerPage}`);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Background fetch failed:', error);
|
|
||||||
}
|
|
||||||
}, 100);
|
|
||||||
|
|
||||||
return { data: cachedResponse.data };
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to fetch cached users:', error);
|
console.error('Failed to fetch users from API:', error);
|
||||||
// Fallback to API if cached JSON fails
|
// Fallback to cached data (but it doesn't have planet field)
|
||||||
try {
|
try {
|
||||||
const response = await api.get(`users?itemsPerPage=${itemsPerPage}`);
|
const cachedResponse = await axios.get('/json/users.json');
|
||||||
return { data: response.data };
|
return { data: cachedResponse.data };
|
||||||
} catch (apiError) {
|
} catch (cacheError) {
|
||||||
console.error('API fallback failed:', apiError);
|
console.error('Cache fallback failed:', cacheError);
|
||||||
return { data: [] };
|
return { data: [] };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Fetch users with cache-first strategy for home page
|
||||||
|
export const fetchUsersWithCache = async (): Promise<{ data: User[], isFromCache?: boolean }> => {
|
||||||
|
try {
|
||||||
|
// First, try to get cached data
|
||||||
|
console.log('Attempting to load cached users.json');
|
||||||
|
const cachedResponse = await axios.get('/json/users.json');
|
||||||
|
console.log('Successfully loaded cached data:', cachedResponse.data.length, 'users');
|
||||||
|
return { data: cachedResponse.data, isFromCache: true };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Cache read failed, fetching from API:', error);
|
||||||
|
// If cache fails, fetch from API
|
||||||
|
try {
|
||||||
|
const response = await api.get('users?itemsPerPage=8000');
|
||||||
|
console.log('Successfully loaded from API:', response.data.length, 'users');
|
||||||
|
return { data: response.data, isFromCache: false };
|
||||||
|
} catch (apiError) {
|
||||||
|
console.error('API fetch also failed:', apiError);
|
||||||
|
return { data: [], isFromCache: false };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const fetchUserCards = async (userId: number, itemsPerPage = 8000): Promise<{ data: Card[] }> => {
|
export const fetchUserCards = async (userId: number, itemsPerPage = 8000): Promise<{ data: Card[] }> => {
|
||||||
try {
|
try {
|
||||||
const response = await api.get(`users/${userId}/card?itemsPerPage=${itemsPerPage}`);
|
const response = await api.get(`users/${userId}/card?itemsPerPage=${itemsPerPage}`);
|
||||||
|
Reference in New Issue
Block a user