mirror of
https://github.com/jjbrunton/Sauci.git
synced 2026-10-31 18:19:43 +00:00
fix(admin): remove enabled packs filter from outstanding questions query
The couple_packs table has no admin RLS policy, so the enabled packs query returns empty for admin users. Query all partner-answered questions instead — more useful for admin visibility anyway. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
edb2cedda0
commit
8a44fef764
1 file changed
+70
-79
@@ -493,96 +493,87 @@ export function UserDetailPage() {
|
|||||||
// Use partner from state (set earlier in the first couple_id block)
|
// Use partner from state (set earlier in the first couple_id block)
|
||||||
const partnerProfile = partner || (await supabase.from('profiles').select('id, name').eq('couple_id', profileData.couple_id).neq('id', userId).maybeSingle()).data;
|
const partnerProfile = partner || (await supabase.from('profiles').select('id, name').eq('couple_id', profileData.couple_id).neq('id', userId).maybeSingle()).data;
|
||||||
if (partnerProfile) {
|
if (partnerProfile) {
|
||||||
const enabledPackIds = (enabledPacksData || []).map((ep: any) => ep.pack_id);
|
// Get question IDs user has already answered
|
||||||
|
const { data: userResponseIds } = await supabase
|
||||||
|
.from('responses')
|
||||||
|
.select('question_id')
|
||||||
|
.eq('user_id', userId);
|
||||||
|
const answeredIds = new Set((userResponseIds || []).map((r: any) => r.question_id));
|
||||||
|
|
||||||
if (enabledPackIds.length > 0) {
|
// Get all partner responses in this couple
|
||||||
// Get question IDs user has already answered
|
const { data: partnerResponses } = await supabase
|
||||||
const { data: userResponseIds } = await supabase
|
.from('responses')
|
||||||
.from('responses')
|
.select(`
|
||||||
.select('question_id')
|
question_id,
|
||||||
.eq('user_id', userId);
|
answer,
|
||||||
const answeredIds = new Set((userResponseIds || []).map((r: any) => r.question_id));
|
created_at
|
||||||
|
`)
|
||||||
|
.eq('user_id', partnerProfile.id)
|
||||||
|
.eq('couple_id', profileData.couple_id)
|
||||||
|
.order('created_at', { ascending: false });
|
||||||
|
|
||||||
// Get all partner responses in this couple
|
// Filter to only questions user hasn't answered
|
||||||
const { data: partnerResponses } = await supabase
|
const unansweredPartnerResponses = (partnerResponses || []).filter((r: any) => !answeredIds.has(r.question_id));
|
||||||
.from('responses')
|
const unansweredQuestionIds = unansweredPartnerResponses.map((r: any) => r.question_id);
|
||||||
.select(`
|
|
||||||
question_id,
|
|
||||||
answer,
|
|
||||||
created_at
|
|
||||||
`)
|
|
||||||
.eq('user_id', partnerProfile.id)
|
|
||||||
.eq('couple_id', profileData.couple_id)
|
|
||||||
.order('created_at', { ascending: false });
|
|
||||||
|
|
||||||
// Filter to only questions user hasn't answered
|
if (unansweredQuestionIds.length > 0) {
|
||||||
const unansweredPartnerResponses = (partnerResponses || []).filter((r: any) => !answeredIds.has(r.question_id));
|
// Fetch question details (no pack filter — admin sees all)
|
||||||
const unansweredQuestionIds = unansweredPartnerResponses.map((r: any) => r.question_id);
|
const { data: questionDetails } = await supabase
|
||||||
|
.from('questions')
|
||||||
|
.select('id, text, intensity, pack:question_packs(id, name)')
|
||||||
|
.in('id', unansweredQuestionIds);
|
||||||
|
|
||||||
if (unansweredQuestionIds.length > 0) {
|
const questionMap = new Map((questionDetails || []).map((q: any) => [q.id, q]));
|
||||||
// Fetch question details, filtered to enabled packs
|
const partnerResponseMap = new Map(unansweredPartnerResponses.map((r: any) => [r.question_id, r]));
|
||||||
const { data: questionDetails } = await supabase
|
|
||||||
.from('questions')
|
|
||||||
.select('id, text, intensity, pack:question_packs(id, name)')
|
|
||||||
.in('id', unansweredQuestionIds)
|
|
||||||
.in('pack_id', enabledPackIds);
|
|
||||||
|
|
||||||
const questionMap = new Map((questionDetails || []).map((q: any) => [q.id, q]));
|
const outstanding: OutstandingQuestion[] = [];
|
||||||
const partnerResponseMap = new Map(unansweredPartnerResponses.map((r: any) => [r.question_id, r]));
|
for (const qId of unansweredQuestionIds) {
|
||||||
|
const q = questionMap.get(qId);
|
||||||
const outstanding: OutstandingQuestion[] = [];
|
const pr = partnerResponseMap.get(qId);
|
||||||
for (const qId of unansweredQuestionIds) {
|
if (q && pr) {
|
||||||
const q = questionMap.get(qId);
|
outstanding.push({
|
||||||
const pr = partnerResponseMap.get(qId);
|
id: qId,
|
||||||
if (q && pr) {
|
text: q.text || '',
|
||||||
outstanding.push({
|
intensity: q.intensity || null,
|
||||||
id: qId,
|
pack: { id: q.pack?.id || '', name: q.pack?.name || '' },
|
||||||
text: q.text || '',
|
partner_response: { answer: pr.answer, created_at: pr.created_at },
|
||||||
intensity: q.intensity || null,
|
});
|
||||||
pack: { id: q.pack?.id || '', name: q.pack?.name || '' },
|
|
||||||
partner_response: { answer: pr.answer, created_at: pr.created_at },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setOutstandingTotal(outstanding.length);
|
|
||||||
const outFrom = (outstandingPage - 1) * outstandingPageSize;
|
|
||||||
setOutstandingQuestions(outstanding.slice(outFrom, outFrom + outstandingPageSize));
|
|
||||||
} else {
|
|
||||||
setOutstandingQuestions([]);
|
|
||||||
setOutstandingTotal(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate gap status
|
setOutstandingTotal(outstanding.length);
|
||||||
const { data: appConfig } = await supabase
|
const outFrom = (outstandingPage - 1) * outstandingPageSize;
|
||||||
.from('app_config')
|
setOutstandingQuestions(outstanding.slice(outFrom, outFrom + outstandingPageSize));
|
||||||
.select('answer_gap_threshold')
|
|
||||||
.limit(1)
|
|
||||||
.maybeSingle();
|
|
||||||
|
|
||||||
const threshold = appConfig?.answer_gap_threshold ?? 10;
|
|
||||||
setGapThreshold(threshold);
|
|
||||||
|
|
||||||
if (threshold > 0) {
|
|
||||||
// Count questions user answered that partner hasn't
|
|
||||||
const partnerAllAnswered = new Set((partnerResponses || []).map((r: any) => r.question_id));
|
|
||||||
const { data: userResponses } = await supabase
|
|
||||||
.from('responses')
|
|
||||||
.select('question_id')
|
|
||||||
.eq('user_id', userId)
|
|
||||||
.eq('couple_id', profileData.couple_id);
|
|
||||||
const userAhead = (userResponses || []).filter((r: any) => !partnerAllAnswered.has(r.question_id)).length;
|
|
||||||
const partnerAhead = (partnerResponses || []).filter((r: any) => !answeredIds.has(r.question_id)).length;
|
|
||||||
const gap = Math.max(0, userAhead - partnerAhead);
|
|
||||||
setNetGap(gap);
|
|
||||||
setGapDisabled(gap >= threshold);
|
|
||||||
} else {
|
|
||||||
setNetGap(0);
|
|
||||||
setGapDisabled(false);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
setOutstandingQuestions([]);
|
setOutstandingQuestions([]);
|
||||||
setOutstandingTotal(0);
|
setOutstandingTotal(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate gap status
|
||||||
|
const { data: appConfig } = await supabase
|
||||||
|
.from('app_config')
|
||||||
|
.select('answer_gap_threshold')
|
||||||
|
.limit(1)
|
||||||
|
.maybeSingle();
|
||||||
|
|
||||||
|
const threshold = appConfig?.answer_gap_threshold ?? 10;
|
||||||
|
setGapThreshold(threshold);
|
||||||
|
|
||||||
|
if (threshold > 0) {
|
||||||
|
// Count questions user answered that partner hasn't
|
||||||
|
const partnerAllAnswered = new Set((partnerResponses || []).map((r: any) => r.question_id));
|
||||||
|
const { data: userResponses } = await supabase
|
||||||
|
.from('responses')
|
||||||
|
.select('question_id')
|
||||||
|
.eq('user_id', userId)
|
||||||
|
.eq('couple_id', profileData.couple_id);
|
||||||
|
const userAhead = (userResponses || []).filter((r: any) => !partnerAllAnswered.has(r.question_id)).length;
|
||||||
|
const partnerAhead = unansweredPartnerResponses.length;
|
||||||
|
const gap = Math.max(0, userAhead - partnerAhead);
|
||||||
|
setNetGap(gap);
|
||||||
|
setGapDisabled(gap >= threshold);
|
||||||
|
} else {
|
||||||
|
setNetGap(0);
|
||||||
setGapDisabled(false);
|
setGapDisabled(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in new issue
Block a user