04e0911e9f
Bug fixes: - TeamInvoices: add useAuth import/currentUser (invoice-create crash) - TeamInvoices: setChartYear -> setExportYear (year-dropdown crash) - TeamDashboard: drop redundant setState-in-effect (cascading renders) - Companies: delete dead _UnusedClientCompanies (illegal hook calls) - annotate intentional empty PDF-fallback catches Load speed: - preconnect/dns-prefetch to Supabase origin - lazy-load heic-to in Converters: page chunk 2737KB -> 9KB - split recharts into its own 'charts' vendor chunk Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
55 lines
2.6 KiB
JavaScript
55 lines
2.6 KiB
JavaScript
import { createClient } from '@supabase/supabase-js';
|
|
|
|
export default async function handler(req, res) {
|
|
if (req.method !== 'DELETE') return res.status(405).json({ error: 'Method not allowed' });
|
|
|
|
const authHeader = req.headers.authorization || '';
|
|
if (!authHeader.startsWith('Bearer ')) return res.status(401).json({ error: 'Unauthorized' });
|
|
|
|
const supabaseUrl = process.env.VITE_SUPABASE_URL || process.env.SUPABASE_URL;
|
|
const anonKey = process.env.VITE_SUPABASE_ANON_KEY || process.env.SUPABASE_ANON_KEY;
|
|
const serviceKey = process.env.SUPABASE_SERVICE_ROLE_KEY;
|
|
|
|
const callerClient = createClient(supabaseUrl, anonKey, {
|
|
auth: { persistSession: false, autoRefreshToken: false },
|
|
global: { headers: { Authorization: authHeader } },
|
|
});
|
|
const { data: userData } = await callerClient.auth.getUser();
|
|
if (!userData?.user) return res.status(401).json({ error: 'Unauthorized' });
|
|
|
|
const { data: profile } = await callerClient.from('profiles').select('id, role').eq('id', userData.user.id).single();
|
|
if (!profile || !['team', 'client'].includes(profile.role)) return res.status(403).json({ error: 'Forbidden' });
|
|
|
|
const taskId = req.query.id;
|
|
if (!taskId) return res.status(400).json({ error: 'Task ID required' });
|
|
|
|
const admin = createClient(supabaseUrl, serviceKey, {
|
|
auth: { persistSession: false, autoRefreshToken: false },
|
|
});
|
|
|
|
const { data: taskRecord } = await admin.from('tasks').select('id').eq('id', taskId).single();
|
|
if (!taskRecord) return res.status(404).json({ error: 'Task not found' });
|
|
|
|
const { data: subs } = await admin.from('submissions').select('id').eq('task_id', taskId);
|
|
const subIds = (subs || []).map(s => s.id);
|
|
|
|
if (subIds.length) {
|
|
const { data: subFiles } = await admin.from('submission_files').select('storage_path').in('submission_id', subIds);
|
|
const subPaths = (subFiles || []).map(f => f.storage_path).filter(Boolean);
|
|
if (subPaths.length) await admin.storage.from('submissions').remove(subPaths);
|
|
|
|
const { data: deliveries } = await admin.from('deliveries').select('id').in('submission_id', subIds);
|
|
const delIds = (deliveries || []).map(d => d.id);
|
|
if (delIds.length) {
|
|
const { data: delFiles } = await admin.from('delivery_files').select('storage_path').in('delivery_id', delIds);
|
|
const delPaths = (delFiles || []).map(f => f.storage_path).filter(Boolean);
|
|
if (delPaths.length) await admin.storage.from('deliveries').remove(delPaths);
|
|
}
|
|
}
|
|
|
|
const { error } = await admin.from('tasks').delete().eq('id', taskId);
|
|
if (error) return res.status(500).json({ error: error.message });
|
|
|
|
return res.status(200).json({ ok: true });
|
|
}
|