Session 2026-05-30: tasks/projects unification, code consolidation, file renames

- Unified Tasks page: 3 role render blocks → 1, normalized row shape, single renderRow/sort/tabs
- Fixed role scoping: external = all tasks in member projects, client = all tasks in company projects
- Fixed client bug: was scoped by submitted_by, now company→project→tasks
- Aligned dashboard client scope to match tasks page
- Hot tasks dashboard: now filters to active statuses only (not completed/invoiced/paid)
- Removed Projects.jsx (dead), fixed /project/ → /projects/ links
- Renamed all page files to match folder path (Team*, External*, Client* prefixes)
- Renamed: RequestsPage→Tasks, Settings→Profile, CompaniesPage→Companies, ProjectDetailPage→ProjectDetail
- Dropped dead fetches from Tasks page (invoices, invoice_items, subcontractor_invoice_items)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Krao Hasanee
2026-05-30 10:19:23 -04:00
parent 6fe7ab1059
commit 13ef1f4ded
30 changed files with 1177 additions and 1258 deletions
+22 -2
View File
@@ -1,6 +1,6 @@
import { createClient } from '@supabase/supabase-js';
const FB_SOURCE = 'files';
const FB_SOURCE = 'srv';
function json(res, status, body) {
res.status(status).setHeader('Content-Type', 'application/json');
@@ -263,7 +263,8 @@ function toListResponse(vPath, entries, { readOnly = false } = {}) {
export default async function handler(req, res) {
try {
const authHeader = req.headers.authorization || '';
const queryToken = String(req.query?.sb_access_token || req.body?.sb_access_token || '').trim();
const authHeader = req.headers.authorization || (queryToken ? `Bearer ${queryToken}` : '');
if (!authHeader) return json(res, 401, { error: 'No authorization header' });
const auth = await requirePortalUser(authHeader);
@@ -333,6 +334,25 @@ export default async function handler(req, res) {
return json(res, 200, { url: downloadUrl, token });
}
if (req.method === 'GET' && action === 'download-blob') {
const resolved = toFbPath();
if (resolved.virtual) return json(res, 400, { error: 'Cannot download virtual directory' });
const token = getToken(config);
const downloadUrl = `${config.url}/api/resources/download?source=${FB_SOURCE}&file=${encodeURIComponent(resolved.fbPath)}&auth=${encodeURIComponent(token)}`;
const upstream = await fetch(downloadUrl);
if (!upstream.ok) {
const text = await upstream.text();
return json(res, upstream.status, { error: text || `Download failed (${upstream.status})` });
}
res.status(upstream.status);
res.setHeader('Cache-Control', 'no-store');
res.setHeader('Content-Type', upstream.headers.get('content-type') || 'application/octet-stream');
res.setHeader('Content-Disposition', upstream.headers.get('content-disposition') || `attachment; filename="${basename(resolved.fbPath) || 'download'}"`);
const arrayBuffer = await upstream.arrayBuffer();
return res.send(Buffer.from(arrayBuffer));
}
if (req.method === 'POST' && action === 'upload-token') {
const resolved = toFbPath();
if (resolved.virtual) return json(res, 400, { error: 'Cannot upload to virtual directory' });