mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-20 17:31:13 -05:00
Fix: Handle RPC errors gracefully
This commit is contained in:
@@ -18,7 +18,7 @@ import {
|
|||||||
SelectValue,
|
SelectValue,
|
||||||
} from '@/components/ui/select';
|
} from '@/components/ui/select';
|
||||||
import { supabase } from '@/integrations/supabase/client';
|
import { supabase } from '@/integrations/supabase/client';
|
||||||
import { handleError } from '@/lib/errorHandler';
|
import { handleError, getErrorMessage } from '@/lib/errorHandler';
|
||||||
import { logger } from '@/lib/logger';
|
import { logger } from '@/lib/logger';
|
||||||
|
|
||||||
interface Moderator {
|
interface Moderator {
|
||||||
@@ -69,12 +69,22 @@ export function ReassignDialog({
|
|||||||
|
|
||||||
const userIds = roles.map((r) => r.user_id);
|
const userIds = roles.map((r) => r.user_id);
|
||||||
|
|
||||||
const { data: allProfiles, error: profilesError } = await supabase
|
let profiles: Array<{ user_id: string; username: string; display_name?: string | null }> | null = null;
|
||||||
|
const { data: allProfiles, error: rpcError } = await supabase
|
||||||
.rpc('get_users_with_emails');
|
.rpc('get_users_with_emails');
|
||||||
|
|
||||||
const profiles = allProfiles?.filter(p => userIds.includes(p.user_id));
|
if (rpcError) {
|
||||||
|
logger.warn('Failed to fetch users with emails, using basic profiles', { error: getErrorMessage(rpcError) });
|
||||||
|
const { data: basicProfiles } = await supabase
|
||||||
|
.from('profiles')
|
||||||
|
.select('user_id, username, display_name')
|
||||||
|
.in('user_id', userIds);
|
||||||
|
profiles = basicProfiles as typeof profiles;
|
||||||
|
} else {
|
||||||
|
profiles = allProfiles?.filter(p => userIds.includes(p.user_id)) || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (profilesError) throw profilesError;
|
|
||||||
|
|
||||||
const moderatorsList = roles.map((role) => {
|
const moderatorsList = roles.map((role) => {
|
||||||
const profile = profiles?.find((p) => p.user_id === role.user_id);
|
const profile = profiles?.find((p) => p.user_id === role.user_id);
|
||||||
|
|||||||
@@ -191,10 +191,19 @@ export const ReportsQueue = forwardRef<ReportsQueueRef>((props, ref) => {
|
|||||||
const reporterIds = [...new Set((data || []).map(r => r.reporter_id))];
|
const reporterIds = [...new Set((data || []).map(r => r.reporter_id))];
|
||||||
|
|
||||||
// Fetch reporter profiles with emails (for admins)
|
// Fetch reporter profiles with emails (for admins)
|
||||||
const { data: allProfiles } = await supabase
|
let profiles: Array<{ user_id: string; username: string; display_name?: string | null; avatar_url?: string | null }> | null = null;
|
||||||
|
const { data: allProfiles, error: rpcError } = await supabase
|
||||||
.rpc('get_users_with_emails');
|
.rpc('get_users_with_emails');
|
||||||
|
|
||||||
const profiles = allProfiles?.filter(p => reporterIds.includes(p.user_id));
|
if (rpcError) {
|
||||||
|
const { data: basicProfiles } = await supabase
|
||||||
|
.from('profiles')
|
||||||
|
.select('user_id, username, display_name, avatar_url')
|
||||||
|
.in('user_id', reporterIds);
|
||||||
|
profiles = basicProfiles as typeof profiles;
|
||||||
|
} else {
|
||||||
|
profiles = allProfiles?.filter(p => reporterIds.includes(p.user_id)) || null;
|
||||||
|
}
|
||||||
|
|
||||||
const profileMap = new Map(profiles?.map(p => [p.user_id, p]) || []);
|
const profileMap = new Map(profiles?.map(p => [p.user_id, p]) || []);
|
||||||
|
|
||||||
@@ -220,7 +229,16 @@ export const ReportsQueue = forwardRef<ReportsQueueRef>((props, ref) => {
|
|||||||
profileIds.length > 0
|
profileIds.length > 0
|
||||||
? supabase
|
? supabase
|
||||||
.rpc('get_users_with_emails')
|
.rpc('get_users_with_emails')
|
||||||
.then(({ data }) => data?.filter(p => profileIds.includes(p.user_id)) || [])
|
.then(({ data, error }) => {
|
||||||
|
if (error) {
|
||||||
|
return supabase
|
||||||
|
.from('profiles')
|
||||||
|
.select('user_id, username, display_name')
|
||||||
|
.in('user_id', profileIds)
|
||||||
|
.then(({ data: basicProfiles }) => basicProfiles || []);
|
||||||
|
}
|
||||||
|
return data?.filter(p => profileIds.includes(p.user_id)) || [];
|
||||||
|
})
|
||||||
: Promise.resolve([]),
|
: Promise.resolve([]),
|
||||||
|
|
||||||
submissionIds.length > 0
|
submissionIds.length > 0
|
||||||
|
|||||||
@@ -86,11 +86,20 @@ export function UserRoleManager() {
|
|||||||
const userIds = [...new Set((data || []).map(r => r.user_id))];
|
const userIds = [...new Set((data || []).map(r => r.user_id))];
|
||||||
|
|
||||||
// Fetch user profiles with emails (for admins)
|
// Fetch user profiles with emails (for admins)
|
||||||
const {
|
let profiles: Array<{ user_id: string; username: string; display_name?: string }> | null = null;
|
||||||
data: allProfiles
|
const { data: allProfiles, error: rpcError } = await supabase
|
||||||
} = await supabase.rpc('get_users_with_emails');
|
.rpc('get_users_with_emails');
|
||||||
|
|
||||||
const profiles = allProfiles?.filter(p => userIds.includes(p.user_id));
|
if (rpcError) {
|
||||||
|
logger.warn('Failed to fetch users with emails, using basic profiles', { error: getErrorMessage(rpcError) });
|
||||||
|
const { data: basicProfiles } = await supabase
|
||||||
|
.from('profiles')
|
||||||
|
.select('user_id, username, display_name')
|
||||||
|
.in('user_id', userIds);
|
||||||
|
profiles = basicProfiles as typeof profiles;
|
||||||
|
} else {
|
||||||
|
profiles = allProfiles?.filter(p => userIds.includes(p.user_id)) || null;
|
||||||
|
}
|
||||||
const profileMap = new Map(profiles?.map(p => [p.user_id, p]) || []);
|
const profileMap = new Map(profiles?.map(p => [p.user_id, p]) || []);
|
||||||
|
|
||||||
// Combine data with profiles
|
// Combine data with profiles
|
||||||
@@ -114,17 +123,26 @@ export function UserRoleManager() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const {
|
let data;
|
||||||
data: allUsers,
|
const { data: allUsers, error: rpcError } = await supabase
|
||||||
error
|
.rpc('get_users_with_emails');
|
||||||
} = await supabase.rpc('get_users_with_emails');
|
|
||||||
|
|
||||||
// Filter by search term
|
if (rpcError) {
|
||||||
const data = allUsers?.filter(user =>
|
logger.warn('Failed to fetch users with emails, using basic profiles', { error: getErrorMessage(rpcError) });
|
||||||
user.username.toLowerCase().includes(search.toLowerCase()) ||
|
const { data: basicProfiles, error: profilesError } = await supabase
|
||||||
user.display_name?.toLowerCase().includes(search.toLowerCase())
|
.from('profiles')
|
||||||
).slice(0, 10);
|
.select('user_id, username, display_name')
|
||||||
if (error) throw error;
|
.ilike('username', `%${search}%`);
|
||||||
|
|
||||||
|
if (profilesError) throw profilesError;
|
||||||
|
data = basicProfiles?.slice(0, 10);
|
||||||
|
} else {
|
||||||
|
// Filter by search term
|
||||||
|
data = allUsers?.filter(user =>
|
||||||
|
user.username.toLowerCase().includes(search.toLowerCase()) ||
|
||||||
|
user.display_name?.toLowerCase().includes(search.toLowerCase())
|
||||||
|
).slice(0, 10);
|
||||||
|
}
|
||||||
|
|
||||||
// Filter out users who already have roles
|
// Filter out users who already have roles
|
||||||
const existingUserIds = userRoles.map(ur => ur.user_id);
|
const existingUserIds = userRoles.map(ur => ur.user_id);
|
||||||
|
|||||||
@@ -768,10 +768,19 @@ export async function fetchSystemActivities(
|
|||||||
const uniqueUserIds = [...new Set(filteredActivities.map(a => a.actor_id).filter(Boolean))] as string[];
|
const uniqueUserIds = [...new Set(filteredActivities.map(a => a.actor_id).filter(Boolean))] as string[];
|
||||||
|
|
||||||
if (uniqueUserIds.length > 0) {
|
if (uniqueUserIds.length > 0) {
|
||||||
const { data: allProfiles } = await supabase
|
let profiles: Array<{ user_id: string; username: string; display_name?: string | null; avatar_url?: string | null }> | null = null;
|
||||||
|
const { data: allProfiles, error: rpcError } = await supabase
|
||||||
.rpc('get_users_with_emails');
|
.rpc('get_users_with_emails');
|
||||||
|
|
||||||
const profiles = allProfiles?.filter(p => uniqueUserIds.includes(p.user_id));
|
if (rpcError) {
|
||||||
|
const { data: basicProfiles } = await supabase
|
||||||
|
.from('profiles')
|
||||||
|
.select('user_id, username, display_name, avatar_url')
|
||||||
|
.in('user_id', uniqueUserIds);
|
||||||
|
profiles = basicProfiles as typeof profiles;
|
||||||
|
} else {
|
||||||
|
profiles = allProfiles?.filter(p => uniqueUserIds.includes(p.user_id)) || null;
|
||||||
|
}
|
||||||
|
|
||||||
if (profiles) {
|
if (profiles) {
|
||||||
const profileMap = new Map(profiles.map(p => [p.user_id, p]));
|
const profileMap = new Map(profiles.map(p => [p.user_id, p]));
|
||||||
@@ -797,10 +806,19 @@ export async function fetchSystemActivities(
|
|||||||
.filter(Boolean) as string[];
|
.filter(Boolean) as string[];
|
||||||
|
|
||||||
if (targetUserIds.length > 0) {
|
if (targetUserIds.length > 0) {
|
||||||
const { data: allTargetProfiles } = await supabase
|
let targetProfiles: Array<{ user_id: string; username: string; display_name?: string | null }> | null = null;
|
||||||
|
const { data: allTargetProfiles, error: targetRpcError } = await supabase
|
||||||
.rpc('get_users_with_emails');
|
.rpc('get_users_with_emails');
|
||||||
|
|
||||||
const targetProfiles = allTargetProfiles?.filter(p => targetUserIds.includes(p.user_id));
|
if (targetRpcError) {
|
||||||
|
const { data: basicProfiles } = await supabase
|
||||||
|
.from('profiles')
|
||||||
|
.select('user_id, username, display_name')
|
||||||
|
.in('user_id', targetUserIds);
|
||||||
|
targetProfiles = basicProfiles as typeof targetProfiles;
|
||||||
|
} else {
|
||||||
|
targetProfiles = allTargetProfiles?.filter(p => targetUserIds.includes(p.user_id)) || null;
|
||||||
|
}
|
||||||
|
|
||||||
if (targetProfiles) {
|
if (targetProfiles) {
|
||||||
const targetProfileMap = new Map(targetProfiles.map(p => [p.user_id, p]));
|
const targetProfileMap = new Map(targetProfiles.map(p => [p.user_id, p]));
|
||||||
@@ -826,10 +844,19 @@ export async function fetchSystemActivities(
|
|||||||
.filter(Boolean) as string[];
|
.filter(Boolean) as string[];
|
||||||
|
|
||||||
if (accountUserIds.length > 0) {
|
if (accountUserIds.length > 0) {
|
||||||
const { data: allAccountProfiles } = await supabase
|
let accountProfiles: Array<{ user_id: string; username: string; display_name?: string | null }> | null = null;
|
||||||
|
const { data: allAccountProfiles, error: accountRpcError } = await supabase
|
||||||
.rpc('get_users_with_emails');
|
.rpc('get_users_with_emails');
|
||||||
|
|
||||||
const accountProfiles = allAccountProfiles?.filter(p => accountUserIds.includes(p.user_id));
|
if (accountRpcError) {
|
||||||
|
const { data: basicProfiles } = await supabase
|
||||||
|
.from('profiles')
|
||||||
|
.select('user_id, username, display_name')
|
||||||
|
.in('user_id', accountUserIds);
|
||||||
|
accountProfiles = basicProfiles as typeof accountProfiles;
|
||||||
|
} else {
|
||||||
|
accountProfiles = allAccountProfiles?.filter(p => accountUserIds.includes(p.user_id)) || null;
|
||||||
|
}
|
||||||
|
|
||||||
if (accountProfiles) {
|
if (accountProfiles) {
|
||||||
const accountProfileMap = new Map(accountProfiles.map(p => [p.user_id, p]));
|
const accountProfileMap = new Map(accountProfiles.map(p => [p.user_id, p]));
|
||||||
|
|||||||
Reference in New Issue
Block a user