565d2ed4bc
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
121 lines
5.0 KiB
JavaScript
121 lines
5.0 KiB
JavaScript
import { supabase } from './supabase';
|
|
|
|
async function fbCall(method, action, body = null) {
|
|
const { data: { session } } = await supabase.auth.getSession();
|
|
if (!session?.access_token) return;
|
|
|
|
await fetch(`/api/filebrowser?action=${action}`, {
|
|
method,
|
|
headers: {
|
|
Authorization: `Bearer ${session.access_token}`,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: body ? JSON.stringify(body) : undefined,
|
|
}).catch(() => {});
|
|
}
|
|
|
|
// Create /Clients/{name}/ folder. Silently fails if already exists.
|
|
export async function createClientFolder(companyName) {
|
|
if (!companyName) return;
|
|
await fbCall('POST', 'mkdir', { path: '/', name: 'Clients' });
|
|
await fbCall('POST', 'mkdir', { path: '/Clients', name: companyName });
|
|
}
|
|
|
|
// Rename /Clients/{oldName} → /Clients/{newName}
|
|
export async function renameClientFolder(oldName, newName) {
|
|
if (!oldName || !newName || oldName === newName) return;
|
|
await fbCall('POST', 'rename', { path: `/Clients/${oldName}`, name: newName });
|
|
}
|
|
|
|
// Same safeName logic as the server (api/filebrowser.js)
|
|
function safeName(v) {
|
|
return String(v || '').trim()
|
|
.replace(/[\\/:*?"<>|#%{}^~[\]`]+/g, '-')
|
|
.replace(/\s+/g, ' ')
|
|
.replace(/^-+|-+$/g, '');
|
|
}
|
|
|
|
// Upload files to the correct Request Info/{rev} folder in FileBrowser.
|
|
// companyName is required. versionNumber defaults to 0 (R00).
|
|
// Best-effort — call with .catch(() => {}) so failures don't block submission.
|
|
export async function uploadFilesToRequestInfo(files, companyName, projectName, taskTitle, versionNumber = 0) {
|
|
if (!files?.length || !companyName || !projectName || !taskTitle) return;
|
|
|
|
const { data: { session } } = await supabase.auth.getSession();
|
|
if (!session?.access_token) return;
|
|
const authHeader = `Bearer ${session.access_token}`;
|
|
|
|
// Determine role
|
|
const { data: profile } = await supabase.from('profiles').select('role').eq('id', session.user.id).single();
|
|
const role = profile?.role;
|
|
|
|
const co = safeName(companyName);
|
|
const proj = safeName(projectName);
|
|
const task = safeName(taskTitle);
|
|
const rev = `R${String(versionNumber).padStart(2, '0')}`;
|
|
|
|
// Build virtual path segments for mkdir.
|
|
// Clients: virtual root is per-company; company folder already exists — start one level in.
|
|
// Team/external: full path under /Clients/{co}/...
|
|
let mkdirs;
|
|
let revPath;
|
|
|
|
if (role === 'client') {
|
|
revPath = `/${co}/Projects/${proj}/${task}/Request Info/${rev}`;
|
|
mkdirs = [
|
|
{ path: `/${co}`, name: 'Projects' },
|
|
{ path: `/${co}/Projects`, name: proj },
|
|
{ path: `/${co}/Projects/${proj}`, name: task },
|
|
{ path: `/${co}/Projects/${proj}/${task}`, name: 'Request Info' },
|
|
{ path: `/${co}/Projects/${proj}/${task}/Request Info`, name: rev },
|
|
];
|
|
} else {
|
|
revPath = `/Clients/${co}/Projects/${proj}/${task}/Request Info/${rev}`;
|
|
mkdirs = [
|
|
{ path: '/Clients', name: co },
|
|
{ path: `/Clients/${co}`, name: 'Projects' },
|
|
{ path: `/Clients/${co}/Projects`, name: proj },
|
|
{ path: `/Clients/${co}/Projects/${proj}`, name: task },
|
|
{ path: `/Clients/${co}/Projects/${proj}/${task}`, name: 'Request Info' },
|
|
{ path: `/Clients/${co}/Projects/${proj}/${task}/Request Info`, name: rev },
|
|
];
|
|
}
|
|
|
|
for (const seg of mkdirs) {
|
|
await fetch('/api/filebrowser?action=mkdir', {
|
|
method: 'POST',
|
|
headers: { Authorization: authHeader, 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(seg),
|
|
}).catch(() => {});
|
|
}
|
|
|
|
// Get upload token for the revision folder
|
|
const tokenRes = await fetch('/api/filebrowser?action=upload-token', {
|
|
method: 'POST',
|
|
headers: { Authorization: authHeader, 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ path: revPath }),
|
|
}).catch(() => null);
|
|
if (!tokenRes?.ok) return;
|
|
|
|
const { token, url, fbPath } = await tokenRes.json();
|
|
if (!token || !url || !fbPath) return;
|
|
|
|
for (const file of files) {
|
|
await fetch(`${url}/api/resources?source=files&path=${encodeURIComponent(`${fbPath}/${file.name}`)}&override=true`, {
|
|
method: 'POST',
|
|
headers: { Authorization: `Bearer ${token}`, 'Content-Type': file.type || 'application/octet-stream' },
|
|
body: file,
|
|
}).catch(() => {});
|
|
}
|
|
}
|
|
|
|
// Create missing /Clients/{name}/ folders for all companies.
|
|
export async function backfillClientFolders() {
|
|
const { data } = await supabase.from('companies').select('name');
|
|
if (!data?.length) return;
|
|
await fbCall('POST', 'mkdir', { path: '/', name: 'Clients' });
|
|
for (const company of data) {
|
|
if (company.name) await fbCall('POST', 'mkdir', { path: '/Clients', name: company.name });
|
|
}
|
|
}
|