82 lines
2.7 KiB
TypeScript
82 lines
2.7 KiB
TypeScript
import type { PageServerLoad } from './$types';
|
|
|
|
export const load: PageServerLoad = async ({ locals, url }) => {
|
|
const searchQuery = url.searchParams.get('search') || '';
|
|
const statusFilter = url.searchParams.get('status') || 'all';
|
|
const roleFilter = url.searchParams.get('role') || 'all';
|
|
|
|
// Get current member's role for privacy filtering
|
|
const { member } = await locals.safeGetSession();
|
|
const isPrivileged = member?.role === 'admin' || member?.role === 'board';
|
|
|
|
// Build the query - select only needed columns to avoid exposing sensitive fields
|
|
let query = locals.supabase
|
|
.from('members_with_dues')
|
|
.select('id, member_id, first_name, last_name, email, phone, role, status_name, type_name, avatar_url, created_at, nationality, address, directory_privacy')
|
|
.order('last_name', { ascending: true });
|
|
|
|
// Apply filters
|
|
if (statusFilter !== 'all') {
|
|
query = query.eq('status_name', statusFilter);
|
|
}
|
|
|
|
if (roleFilter !== 'all') {
|
|
query = query.eq('role', roleFilter);
|
|
}
|
|
|
|
const { data: members } = await query;
|
|
|
|
// Filter by search query in application (for name/email search)
|
|
let filteredMembers = members || [];
|
|
if (searchQuery) {
|
|
const lowerSearch = searchQuery.toLowerCase();
|
|
filteredMembers = filteredMembers.filter(
|
|
(m: any) =>
|
|
m.first_name?.toLowerCase().includes(lowerSearch) ||
|
|
m.last_name?.toLowerCase().includes(lowerSearch) ||
|
|
m.email?.toLowerCase().includes(lowerSearch) ||
|
|
m.member_id?.toLowerCase().includes(lowerSearch)
|
|
);
|
|
}
|
|
|
|
// Get membership statuses for filter dropdown
|
|
const { data: statuses } = await locals.supabase
|
|
.from('membership_statuses')
|
|
.select('*')
|
|
.order('sort_order', { ascending: true });
|
|
|
|
// Calculate stats
|
|
const stats = {
|
|
total: members?.length || 0,
|
|
active: members?.filter((m: any) => m.status_name === 'active').length || 0,
|
|
pending: members?.filter((m: any) => m.status_name === 'pending').length || 0,
|
|
inactive: members?.filter((m: any) => m.status_name === 'inactive').length || 0
|
|
};
|
|
|
|
// Apply directory privacy settings (admins/board see everything)
|
|
const privacyFilteredMembers = isPrivileged
|
|
? filteredMembers
|
|
: filteredMembers.map((m: any) => {
|
|
const privacy = m.directory_privacy || { show_email: true, show_phone: true, show_address: false, show_nationality: true };
|
|
return {
|
|
...m,
|
|
email: privacy.show_email ? m.email : null,
|
|
phone: privacy.show_phone ? m.phone : null,
|
|
address: privacy.show_address ? m.address : null,
|
|
nationality: privacy.show_nationality ? m.nationality : null,
|
|
directory_privacy: undefined
|
|
};
|
|
});
|
|
|
|
return {
|
|
members: privacyFilteredMembers,
|
|
statuses: statuses || [],
|
|
stats,
|
|
filters: {
|
|
search: searchQuery,
|
|
status: statusFilter,
|
|
role: roleFilter
|
|
}
|
|
};
|
|
};
|