mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-23 02:31:12 -05:00
Refactor profile stats calculation
This commit is contained in:
@@ -48,6 +48,11 @@ export default function Profile() {
|
||||
const [formErrors, setFormErrors] = useState<Record<string, string>>({});
|
||||
const [avatarUrl, setAvatarUrl] = useState<string>('');
|
||||
const [avatarImageId, setAvatarImageId] = useState<string>('');
|
||||
const [calculatedStats, setCalculatedStats] = useState({
|
||||
rideCount: 0,
|
||||
coasterCount: 0,
|
||||
parkCount: 0
|
||||
});
|
||||
|
||||
// Username validation
|
||||
const usernameValidation = useUsernameValidation(editForm.username, profile?.username);
|
||||
@@ -59,6 +64,50 @@ export default function Profile() {
|
||||
fetchCurrentUserProfile();
|
||||
}
|
||||
}, [username]);
|
||||
|
||||
const fetchCalculatedStats = async (userId: string) => {
|
||||
try {
|
||||
// Fetch ride credits stats
|
||||
const { data: ridesData, error: ridesError } = await supabase
|
||||
.from('user_ride_credits')
|
||||
.select(`
|
||||
ride_count,
|
||||
rides!inner(category, park_id)
|
||||
`)
|
||||
.eq('user_id', userId);
|
||||
|
||||
if (ridesError) throw ridesError;
|
||||
|
||||
// Calculate total rides count (sum of all ride_count values)
|
||||
const totalRides = ridesData?.reduce((sum, credit) => sum + (credit.ride_count || 0), 0) || 0;
|
||||
|
||||
// Calculate coasters count (distinct rides where category is roller_coaster)
|
||||
const coasterRides = ridesData?.filter(credit =>
|
||||
credit.rides?.category === 'roller_coaster'
|
||||
) || [];
|
||||
const uniqueCoasters = new Set(coasterRides.map(credit => credit.rides));
|
||||
const coasterCount = uniqueCoasters.size;
|
||||
|
||||
// Calculate parks count (distinct parks where user has ridden at least one ride)
|
||||
const parkRides = ridesData?.map(credit => credit.rides?.park_id).filter(Boolean) || [];
|
||||
const uniqueParks = new Set(parkRides);
|
||||
const parkCount = uniqueParks.size;
|
||||
|
||||
setCalculatedStats({
|
||||
rideCount: totalRides,
|
||||
coasterCount: coasterCount,
|
||||
parkCount: parkCount
|
||||
});
|
||||
} catch (error: any) {
|
||||
console.error('Error fetching calculated stats:', error);
|
||||
// Set defaults on error
|
||||
setCalculatedStats({
|
||||
rideCount: 0,
|
||||
coasterCount: 0,
|
||||
parkCount: 0
|
||||
});
|
||||
}
|
||||
};
|
||||
const getCurrentUser = async () => {
|
||||
const {
|
||||
data: {
|
||||
@@ -69,11 +118,14 @@ export default function Profile() {
|
||||
};
|
||||
const fetchProfile = async (profileUsername: string) => {
|
||||
try {
|
||||
const {
|
||||
data,
|
||||
error
|
||||
} = await supabase.from('profiles').select(`*, location:locations(*)`).eq('username', profileUsername).maybeSingle();
|
||||
const { data, error } = await supabase
|
||||
.from('profiles')
|
||||
.select(`*, location:locations(*)`)
|
||||
.eq('username', profileUsername)
|
||||
.maybeSingle();
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
if (data) {
|
||||
setProfile(data as ProfileType);
|
||||
setEditForm({
|
||||
@@ -83,6 +135,9 @@ export default function Profile() {
|
||||
});
|
||||
setAvatarUrl(data.avatar_url || '');
|
||||
setAvatarImageId(data.avatar_image_id || '');
|
||||
|
||||
// Fetch calculated stats for this user
|
||||
await fetchCalculatedStats(data.user_id);
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('Error fetching profile:', error);
|
||||
@@ -97,20 +152,20 @@ export default function Profile() {
|
||||
};
|
||||
const fetchCurrentUserProfile = async () => {
|
||||
try {
|
||||
const {
|
||||
data: {
|
||||
user
|
||||
}
|
||||
} = await supabase.auth.getUser();
|
||||
const { data: { user } } = await supabase.auth.getUser();
|
||||
if (!user) {
|
||||
navigate('/auth');
|
||||
return;
|
||||
}
|
||||
const {
|
||||
data,
|
||||
error
|
||||
} = await supabase.from('profiles').select(`*, location:locations(*)`).eq('user_id', user.id).maybeSingle();
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('profiles')
|
||||
.select(`*, location:locations(*)`)
|
||||
.eq('user_id', user.id)
|
||||
.maybeSingle();
|
||||
|
||||
if (error) throw error;
|
||||
|
||||
if (data) {
|
||||
setProfile(data as ProfileType);
|
||||
setEditForm({
|
||||
@@ -120,6 +175,9 @@ export default function Profile() {
|
||||
});
|
||||
setAvatarUrl(data.avatar_url || '');
|
||||
setAvatarImageId(data.avatar_image_id || '');
|
||||
|
||||
// Fetch calculated stats for the current user
|
||||
await fetchCalculatedStats(user.id);
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('Error fetching profile:', error);
|
||||
@@ -410,19 +468,19 @@ export default function Profile() {
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8">
|
||||
<Card>
|
||||
<CardContent className="p-4 text-center">
|
||||
<div className="text-2xl font-bold text-primary">{profile.ride_count}</div>
|
||||
<div className="text-2xl font-bold text-primary">{calculatedStats.rideCount}</div>
|
||||
<div className="text-sm text-muted-foreground">Rides</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardContent className="p-4 text-center">
|
||||
<div className="text-2xl font-bold text-accent">{profile.coaster_count}</div>
|
||||
<div className="text-2xl font-bold text-accent">{calculatedStats.coasterCount}</div>
|
||||
<div className="text-sm text-muted-foreground">Coasters</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardContent className="p-4 text-center">
|
||||
<div className="text-2xl font-bold text-secondary">{profile.park_count}</div>
|
||||
<div className="text-2xl font-bold text-secondary">{calculatedStats.parkCount}</div>
|
||||
<div className="text-sm text-muted-foreground">Parks</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user