Implement comprehensive report system with detailed viewing and AI enhancements

- Add detailed report viewing with full-screen ReportDetail component for both company and employee reports
- Fix company wiki to display onboarding Q&A in card format matching Figma designs
- Exclude company owners from employee submission counts (owners contribute to wiki, not employee data)
- Fix employee report generation to include company context (wiki + company report + employee answers)
- Fix company report generation to use filtered employee submissions only
- Add proper error handling for submission data format variations
- Update Firebase functions to use gpt-4o model instead of deprecated gpt-4.1
- Fix UI syntax errors and improve report display functionality
- Add comprehensive logging for debugging report generation flow

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ra
2025-08-18 19:08:29 -07:00
parent 557b113196
commit 1a9e92d7bd
20 changed files with 1793 additions and 635 deletions

88
services/api.ts Normal file
View File

@@ -0,0 +1,88 @@
import { API_URL } from '../constants';
// Get auth token from localStorage (persistent across sessions)
const getAuthToken = (): string | null => {
return localStorage.getItem('auditly_auth_token');
};
// Make authenticated API call
export const makeAuthenticatedRequest = async (
endpoint: string,
options: RequestInit = {},
orgId?: string
): Promise<Response> => {
const token = getAuthToken();
if (!token) {
throw new Error('No authentication token found. Please log in again.');
}
const headers = new Headers(options.headers);
headers.set('Authorization', `Bearer ${token}`);
headers.set('Content-Type', 'application/json');
// Add orgId to request body if provided and it's a POST/PUT request
let body = options.body;
if (orgId && (options.method === 'POST' || options.method === 'PUT')) {
if (typeof body === 'string') {
try {
const parsedBody = JSON.parse(body);
parsedBody.orgId = orgId;
body = JSON.stringify(parsedBody);
} catch (e) {
// If body isn't JSON, create a new object
body = JSON.stringify({ orgId, data: body });
}
} else if (body instanceof FormData) {
body.append('orgId', orgId);
} else if (body && typeof body === 'object') {
body = JSON.stringify({ orgId, ...body });
} else {
body = JSON.stringify({ orgId });
}
}
const url = endpoint.startsWith('http') ? endpoint : `${API_URL}${endpoint}`;
// Add timeout to prevent hanging forever
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 30000); // 30 second timeout
try {
const response = await fetch(url, {
...options,
headers,
body,
signal: controller.signal,
});
clearTimeout(timeoutId);
return response;
} catch (error) {
clearTimeout(timeoutId);
if (error.name === 'AbortError') {
throw new Error('Request timeout: The server took too long to respond');
}
throw error;
}
};
// Convenience methods for different HTTP verbs
export const apiGet = (endpoint: string, orgId?: string) =>
makeAuthenticatedRequest(endpoint, { method: 'GET' }, orgId);
export const apiPost = (endpoint: string, data: any = {}, orgId?: string) => {
console.log('apiPost called with:', { endpoint, data, orgId, hasToken: !!getAuthToken() });
return makeAuthenticatedRequest(endpoint, {
method: 'POST',
body: JSON.stringify(data)
}, orgId);
};
export const apiPut = (endpoint: string, data: any = {}, orgId?: string) =>
makeAuthenticatedRequest(endpoint, {
method: 'PUT',
body: JSON.stringify(data)
}, orgId);
export const apiDelete = (endpoint: string, orgId?: string) =>
makeAuthenticatedRequest(endpoint, { method: 'DELETE' }, orgId);

View File

@@ -1,6 +1,6 @@
import { initializeApp, getApps } from 'firebase/app';
import { getAuth, GoogleAuthProvider } from 'firebase/auth';
import { getFirestore } from 'firebase/firestore';
import { getAuth, GoogleAuthProvider, setPersistence, browserLocalPersistence } from 'firebase/auth';
import { getFirestore, connectFirestoreEmulator } from 'firebase/firestore';
const firebaseConfig = {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
@@ -17,9 +17,7 @@ export const isFirebaseConfigured = Boolean(
firebaseConfig.projectId &&
firebaseConfig.apiKey !== 'undefined' &&
firebaseConfig.authDomain !== 'undefined' &&
firebaseConfig.projectId !== 'undefined' &&
// Force demo mode on localhost for testing
!window.location.hostname.includes('localhost')
firebaseConfig.projectId !== 'undefined'
);
let app;
@@ -30,12 +28,29 @@ let googleProvider;
if (isFirebaseConfigured) {
app = getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];
auth = getAuth(app);
setPersistence(auth, browserLocalPersistence);
db = getFirestore(app);
googleProvider = new GoogleAuthProvider();
// Connect to emulator in development
const isLocalhost = typeof window !== 'undefined' &&
(window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1');
if (isLocalhost && !db._settings?.host?.includes('localhost')) {
try {
connectFirestoreEmulator(db, 'localhost', 5003);
console.log('🔥 Connected to Firestore emulator on localhost:5003');
} catch (error) {
console.log('⚠️ Firestore emulator already connected or connection failed');
}
}
console.log('🔥 Firebase initialized successfully');
} else {
auth = null;
db = null;
googleProvider = null;
console.log('⚠️ Firebase not configured - missing environment variables');
}
export { auth, db, googleProvider };