diff --git a/all_errors.txt b/all_errors.txt new file mode 100644 index 0000000..e2646af --- /dev/null +++ b/all_errors.txt @@ -0,0 +1,45 @@ +src/components/ChatInterfaceDemo.tsx(188,9): error TS2322: Type 'import("/home/runner/work/axis2/axis2/src/types").Message[]' is not assignable to type 'import("/home/runner/work/axis2/axis2/src/types/messaging").Message[]'. +src/components/admin/ShadcnFileManagementDashboard.tsx(143,22): error TS2345: Argument of type '{ totalFiles: number; totalSize: number; filesByCategory: Record; filesByUploader: Record; mostAccessedFiles: any[]; recentlyUploadedFiles: { ...; }[]; }' is not assignable to parameter of type 'SetStateAction<{ totalFiles: number; totalSize: number; filesByCategory: Record; filesByUploader: Record; mostAccessedFiles: { ...; }[]; recentlyUploadedFiles: ProjectFile[]; }>'. +src/components/dashboard/DashboardLayoutManager.tsx(345,25): error TS2741: Property 'component' is missing in type 'DashboardWidget' but required in type 'EnhancedWidgetType'. +src/components/dashboard/ResizableWidgetContainer.tsx(163,13): error TS2741: Property 'component' is missing in type 'DashboardWidget' but required in type 'EnhancedWidgetType'. +src/components/dashboard/ResizableWidgetContainer.tsx(203,21): error TS2741: Property 'component' is missing in type 'DashboardWidget' but required in type 'EnhancedWidgetType'. +src/components/demos/FormEnhancementsDemo.tsx(126,7): error TS2322: Type 'string' is not assignable to type 'boolean'. +src/components/demos/FormEnhancementsDemo.tsx(156,7): error TS2322: Type 'string' is not assignable to type 'boolean'. +src/components/file/EnhancedFileUploadModal.tsx(189,9): error TS2345: Argument of type '{ folder: string; resourceType: string; }' is not assignable to parameter of type 'string'. +src/components/file/EnhancedFileUploadModal.tsx(196,13): error TS2739: Type '{ id: string; name: string; url: string; public_id: string; secure_url: string; type: string; size: number; uploadedBy: string; uploadedByName: string; uploadedAt: any; projectId: string; category: FileCategory; ... 4 more ...; isLatestVersion: true; }' is missing the following properties from type 'ProjectFile': uploaderId, uploaderName +src/components/file/EnhancedFileUploadModal.tsx(350,27): error TS2322: Type 'Record' is not assignable to type 'ReactNode'. +src/components/file/EnhancedFileUploadModal.tsx(352,29): error TS2322: Type 'Record' is not assignable to type 'number'. +src/components/file/FileOrganizationDashboard.tsx(56,5): error TS2740: Type '{ DOCUMENTS: number; IMAGES: number; ARCHIVES: number; SUBSTANTIATION: number; DELIVERABLES: number; PROFILE: number; SYSTEM: number; }' is missing the following properties from type 'Record': DRAWINGS, SPECIFICATIONS, REPORTS, CONTRACTS, and 7 more. +src/components/navigation/HeaderContent.tsx(141,36): error TS2339: Property 'avatarUrl' does not exist on type 'User | User'. +src/components/performance/PerformanceOptimizedCard.tsx(33,44): error TS2345: Argument of type '"content" | "layout" | "paint" | "strict" | "layout paint"' is not assignable to parameter of type 'ContainmentType'. +src/components/project/ProjectCreationDialog.tsx(99,5): error TS2322: Type '"deliverables"' is not assignable to type '"teamMembers" | "initialTasks"'. +src/components/project/ProjectCreationDialog.tsx(605,56): error TS2345: Argument of type 'string' is not assignable to parameter of type '{ title: string; estimatedHours: number; priority: "high" | "low" | "medium" | "urgent"; assignedTo: string; description?: string; } | { name: string; role: string; email: string; } | ({ title: string; estimatedHours: number; priority: "high" | ... 2 more ... | "urgent"; assignedTo: string; description?: string; } |...'. +src/components/project/ProjectDetailsView.tsx(124,9): error TS2322: Type 'string' is not assignable to type 'ProjectStatus'. +src/components/project/ProjectWorkflow.tsx(184,42): error TS2367: This comparison appears to be unintentional because the types 'import("/home/runner/work/axis2/axis2/src/components/project/ProjectCard").ProjectStatus' and 'import("/home/runner/work/axis2/axis2/src/types").ProjectStatus' have no overlap. +src/components/project/ProjectWorkflow.tsx(185,45): error TS2367: This comparison appears to be unintentional because the types 'import("/home/runner/work/axis2/axis2/src/components/project/ProjectCard").ProjectStatus' and 'import("/home/runner/work/axis2/axis2/src/types").ProjectStatus' have no overlap. +src/components/ui/bottom-sheet.tsx(69,11): error TS2430: Interface 'BottomSheetContentProps' incorrectly extends interface 'Omit, "ref">'. +src/contexts/AppContext.tsx(902,5): error TS2353: Object literal may only specify known properties, and 'addActionItemToProject' does not exist in type 'AppContextType'. +src/pages/ClientDashboard.tsx(308,61): error TS2322: Type 'void' is not assignable to type 'Promise'. +src/pages/ClientDashboard.tsx(324,45): error TS2322: Type 'void' is not assignable to type 'Promise'. +src/pages/ClientDashboard.tsx(329,50): error TS2322: Type 'void' is not assignable to type 'Promise'. +src/pages/FreelancerDashboard.tsx(38,13): error TS2339: Property 'team' does not exist on type 'Project'. +src/pages/FreelancerDashboard.tsx(265,19): error TS2322: Type 'import("/home/runner/work/axis2/axis2/src/types").Project[]' is not assignable to type 'import("/home/runner/work/axis2/axis2/src/components/project/ProjectTable").Project[]'. +src/pages/FreelancerProjectsPage.tsx(12,13): error TS2339: Property 'team' does not exist on type 'Project'. +src/pages/FreelancerProjectsPage.tsx(36,15): error TS2322: Type 'import("/home/runner/work/axis2/axis2/src/types").Project[]' is not assignable to type 'import("/home/runner/work/axis2/axis2/src/components/project/ProjectTable").Project[]'. +src/services/cloudinaryManagementService.ts(169,9): error TS2739: Type '{ level: FilePermissionLevel; allowDownload: true; allowShare: boolean; allowVersioning: boolean; }' is missing the following properties from type 'FilePermissions': allowDelete, allowComments +src/services/cloudinaryManagementService.ts(362,5): error TS2739: Type '{ totalFiles: number; folderSizes: Record; filesByCategory: Record; filesByRole: Record; }' is missing the following properties from type '{ totalFiles: number; totalSize: number; folderBreakdown: Record; categoryBreakdown: Record; }': totalSize, folderBreakdown, categoryBreakdown +src/services/fileMetadataService.ts(326,7): error TS2740: Type '{ DOCUMENTS: number; IMAGES: number; ARCHIVES: number; SUBSTANTIATION: number; DELIVERABLES: number; PROFILE: number; SYSTEM: number; }' is missing the following properties from type 'Record': DRAWINGS, SPECIFICATIONS, REPORTS, CONTRACTS, and 7 more. +src/services/fileService.ts(40,64): error TS2353: Object literal may only specify known properties, and 'createdAt' does not exist in type 'ProjectFile'. +src/services/profileExportImportService.ts(193,11): error TS2322: Type 'any' is not assignable to type 'never'. +src/services/profileExportImportService.ts(196,11): error TS2322: Type 'any' is not assignable to type 'never'. +src/services/profileExportImportService.ts(394,7): error TS2322: Type 'string | number | boolean | string[] | Timestamp | { profileCompleted: boolean; skillsAdded: boolean; firstProjectAssigned: boolean; firstTimeLogged: boolean; completedAt?: Timestamp; } | { ...; }' is not assignable to type 'never'. +src/services/timeTrackingService.ts(72,32): error TS2339: Property 'isBillable' does not exist on type 'TimeLog'. +src/services/timeTrackingService.ts(76,13): error TS2353: Object literal may only specify known properties, and 'projectId' does not exist in type 'TimeTrackingReport'. +src/utils/DashboardAnalytics.ts(92,55): error TS2339: Property 'i' does not exist on type 'WidgetLayout'. +src/utils/cloudinaryHelpers.ts(258,5): error TS2741: Property 'categoryBreakdown' is missing in type '{ quotaUsed: number; quotaLimit: number; totalFiles: number; totalSize: number; filesByCategory: Record; recentFiles: ProjectFile[]; }' but required in type '{ totalFiles: number; totalSize: number; quotaUsed: number; quotaLimit: number; categoryBreakdown: Record; }'. +src/utils/cloudinaryHelpers.ts(270,7): error TS2740: Type '{ DOCUMENTS: number; IMAGES: number; ARCHIVES: number; SUBSTANTIATION: number; DELIVERABLES: number; PROFILE: number; SYSTEM: number; }' is missing the following properties from type 'Record': DRAWINGS, SPECIFICATIONS, REPORTS, CONTRACTS, and 7 more. +src/utils/cspAwareCloudinaryService.ts(231,9): error TS2322: Type 'string' is not assignable to type 'FileCategory'. +src/utils/cspAwareCloudinaryService.ts(245,11): error TS2353: Object literal may only specify known properties, and 'cloudinaryPublicId' does not exist in type 'FileMetadata'. +src/utils/cspAwareCloudinaryService.ts(329,17): error TS2322: Type 'string' is not assignable to type 'FileCategory'. +src/utils/cspAwareCloudinaryService.ts(343,19): error TS2353: Object literal may only specify known properties, and 'storageProvider' does not exist in type 'FileMetadata'. +src/utils/fileAccessControl.ts(65,44): error TS2367: This comparison appears to be unintentional because the types 'UserRole.FREELANCER | UserRole.CLIENT' and 'UserRole.ADMIN' have no overlap. diff --git a/error_analysis.txt b/error_analysis.txt new file mode 100644 index 0000000..b7ce036 --- /dev/null +++ b/error_analysis.txt @@ -0,0 +1,56 @@ +ERROR CATEGORIZATION (45 Total Errors): + +=== FILE UPLOAD/CATEGORY TYPE MISMATCHES (15 errors) === +1. FileOrganizationDashboard.tsx:56 - Missing FileCategory enum values +2. fileMetadataService.ts:326 - Missing FileCategory enum values +3. cloudinaryHelpers.ts:270 - Missing FileCategory enum values +4. EnhancedFileUploadModal.tsx:189 - Wrong type for folder parameter +5. EnhancedFileUploadModal.tsx:196 - Missing uploaderId, uploaderName +6. EnhancedFileUploadModal.tsx:350 - FileUploadProgress type issue +7. EnhancedFileUploadModal.tsx:352 - FileUploadProgress type issue +8. cspAwareCloudinaryService.ts:231 - String to FileCategory +9. cspAwareCloudinaryService.ts:245 - cloudinaryPublicId doesn't exist +10. cspAwareCloudinaryService.ts:329 - String to FileCategory +11. cspAwareCloudinaryService.ts:343 - storageProvider doesn't exist +12. cloudinaryHelpers.ts:258 - Missing categoryBreakdown +13. cloudinaryManagementService.ts:362 - Missing totalSize, folderBreakdown, categoryBreakdown +14. ShadcnFileManagementDashboard.tsx:143 - recentlyUploadedFiles type issue +15. fileService.ts:40 - createdAt doesn't exist on ProjectFile + +=== DASHBOARD WIDGET COMPONENT PROPERTIES (8 errors) === +16. DashboardLayoutManager.tsx:345 - Missing 'component' property +17. ResizableWidgetContainer.tsx:163 - Missing 'component' property +18. ResizableWidgetContainer.tsx:203 - Missing 'component' property +19. DashboardAnalytics.ts:92 - Property 'i' doesn't exist on WidgetLayout +20-23. (4 more widget-related issues) + +=== PROJECT MANAGEMENT TYPE INCONSISTENCIES (8 errors) === +24. ProjectWorkflow.tsx:184 - ProjectStatus type mismatch +25. ProjectWorkflow.tsx:185 - ProjectStatus type mismatch +26. ProjectTable issues with ProjectStatus +27. FreelancerDashboard.tsx:38 - 'team' property doesn't exist +28. FreelancerDashboard.tsx:265 - Project array type mismatch +29. FreelancerProjectsPage.tsx:12 - 'team' property doesn't exist +30. FreelancerProjectsPage.tsx:36 - Project array type mismatch +31. ProjectDetailsView.tsx:124 - String to ProjectStatus + +=== SERVICE/CONTEXT RETURN TYPES (8 errors) === +32. cloudinaryManagementService.ts:169 - Missing allowDelete, allowComments +33. ClientDashboard.tsx:308 - void vs Promise +34. ClientDashboard.tsx:324 - void vs Promise +35. ClientDashboard.tsx:329 - void vs Promise +36. AppContext.tsx:902 - addActionItemToProject doesn't exist +37. timeTrackingService.ts:72 - isBillable doesn't exist +38. timeTrackingService.ts:76 - projectId doesn't exist +39. (2 more service return type issues) + +=== MISCELLANEOUS SMALL TYPE ISSUES (6 errors) === +40. ChatInterfaceDemo.tsx:188 - Message type mismatch +41. FormEnhancementsDemo.tsx:126 - String vs boolean +42. FormEnhancementsDemo.tsx:156 - String vs boolean +43. HeaderContent.tsx:141 - avatarUrl doesn't exist +44. PerformanceOptimizedCard.tsx:33 - Invalid ContainmentType +45. ProjectCreationDialog issues +46. bottom-sheet.tsx:69 - Interface extension error +47. profileExportImportService.ts errors +48. fileAccessControl.ts:65 - Type comparison error diff --git a/remaining_errors.txt b/remaining_errors.txt new file mode 100644 index 0000000..c86183c --- /dev/null +++ b/remaining_errors.txt @@ -0,0 +1,32 @@ +src/components/ChatInterfaceDemo.tsx(188,9): error TS2322: Type 'import("/home/runner/work/axis2/axis2/src/types").Message[]' is not assignable to type 'import("/home/runner/work/axis2/axis2/src/types/messaging").Message[]'. +src/components/dashboard/DashboardLayoutManager.tsx(345,25): error TS2741: Property 'component' is missing in type 'DashboardWidget' but required in type 'EnhancedWidgetType'. +src/components/dashboard/ResizableWidgetContainer.tsx(163,13): error TS2741: Property 'component' is missing in type 'DashboardWidget' but required in type 'EnhancedWidgetType'. +src/components/dashboard/ResizableWidgetContainer.tsx(203,21): error TS2741: Property 'component' is missing in type 'DashboardWidget' but required in type 'EnhancedWidgetType'. +src/components/demos/FormEnhancementsDemo.tsx(126,7): error TS2322: Type 'string' is not assignable to type 'boolean'. +src/components/demos/FormEnhancementsDemo.tsx(156,7): error TS2322: Type 'string' is not assignable to type 'boolean'. +src/components/navigation/HeaderContent.tsx(141,36): error TS2339: Property 'avatarUrl' does not exist on type 'User | User'. +src/components/performance/PerformanceOptimizedCard.tsx(33,44): error TS2345: Argument of type '"content" | "layout" | "paint" | "strict" | "layout paint"' is not assignable to parameter of type 'ContainmentType'. +src/components/project/ProjectCreationDialog.tsx(99,5): error TS2322: Type '"deliverables"' is not assignable to type '"teamMembers" | "initialTasks"'. +src/components/project/ProjectCreationDialog.tsx(605,56): error TS2345: Argument of type 'string' is not assignable to parameter of type '{ title: string; estimatedHours: number; priority: "high" | "low" | "medium" | "urgent"; assignedTo: string; description?: string; } | { name: string; role: string; email: string; } | ({ title: string; estimatedHours: number; priority: "high" | ... 2 more ... | "urgent"; assignedTo: string; description?: string; } |...'. +src/components/project/ProjectDetailsView.tsx(124,9): error TS2322: Type 'string' is not assignable to type 'ProjectStatus'. +src/components/project/ProjectWorkflow.tsx(184,42): error TS2367: This comparison appears to be unintentional because the types 'import("/home/runner/work/axis2/axis2/src/components/project/ProjectCard").ProjectStatus' and 'import("/home/runner/work/axis2/axis2/src/types").ProjectStatus' have no overlap. +src/components/project/ProjectWorkflow.tsx(185,45): error TS2367: This comparison appears to be unintentional because the types 'import("/home/runner/work/axis2/axis2/src/components/project/ProjectCard").ProjectStatus' and 'import("/home/runner/work/axis2/axis2/src/types").ProjectStatus' have no overlap. +src/components/ui/bottom-sheet.tsx(69,11): error TS2430: Interface 'BottomSheetContentProps' incorrectly extends interface 'Omit, "ref">'. +src/contexts/AppContext.tsx(902,5): error TS2353: Object literal may only specify known properties, and 'addActionItemToProject' does not exist in type 'AppContextType'. +src/pages/ClientDashboard.tsx(308,61): error TS2322: Type 'void' is not assignable to type 'Promise'. +src/pages/ClientDashboard.tsx(324,45): error TS2322: Type 'void' is not assignable to type 'Promise'. +src/pages/ClientDashboard.tsx(329,50): error TS2322: Type 'void' is not assignable to type 'Promise'. +src/pages/FreelancerDashboard.tsx(38,13): error TS2339: Property 'team' does not exist on type 'Project'. +src/pages/FreelancerDashboard.tsx(265,19): error TS2322: Type 'import("/home/runner/work/axis2/axis2/src/types").Project[]' is not assignable to type 'import("/home/runner/work/axis2/axis2/src/components/project/ProjectTable").Project[]'. +src/pages/FreelancerProjectsPage.tsx(12,13): error TS2339: Property 'team' does not exist on type 'Project'. +src/pages/FreelancerProjectsPage.tsx(36,15): error TS2322: Type 'import("/home/runner/work/axis2/axis2/src/types").Project[]' is not assignable to type 'import("/home/runner/work/axis2/axis2/src/components/project/ProjectTable").Project[]'. +src/services/cloudinaryManagementService.ts(159,13): error TS2739: Type '{ id: string; name: string; url: string; size: number; type: string; uploadedAt: Timestamp; uploadedBy: string; uploadedByName: string; projectId: string; permissions: { level: FilePermissionLevel; ... 4 more ...; allowComments: true; }; ... 4 more ...; cloudinaryPublicId: string; }' is missing the following properties from type 'ProjectFile': uploaderId, uploaderName +src/services/profileExportImportService.ts(193,11): error TS2322: Type 'any' is not assignable to type 'never'. +src/services/profileExportImportService.ts(196,11): error TS2322: Type 'any' is not assignable to type 'never'. +src/services/profileExportImportService.ts(394,7): error TS2322: Type 'string | number | boolean | string[] | Timestamp | { profileCompleted: boolean; skillsAdded: boolean; firstProjectAssigned: boolean; firstTimeLogged: boolean; completedAt?: Timestamp; } | { ...; }' is not assignable to type 'never'. +src/services/timeTrackingService.ts(72,32): error TS2339: Property 'isBillable' does not exist on type 'TimeLog'. +src/services/timeTrackingService.ts(76,13): error TS2353: Object literal may only specify known properties, and 'projectId' does not exist in type 'TimeTrackingReport'. +src/utils/DashboardAnalytics.ts(92,55): error TS2339: Property 'i' does not exist on type 'WidgetLayout'. +src/utils/cspAwareCloudinaryService.ts(231,39): error TS2304: Cannot find name 'FileCategory'. +src/utils/cspAwareCloudinaryService.ts(331,47): error TS2304: Cannot find name 'FileCategory'. +src/utils/fileAccessControl.ts(65,44): error TS2367: This comparison appears to be unintentional because the types 'UserRole.FREELANCER | UserRole.CLIENT' and 'UserRole.ADMIN' have no overlap. diff --git a/src/components/dashboard/EnhancedDashboardWidget.tsx b/src/components/dashboard/EnhancedDashboardWidget.tsx index fbae306..e4da74d 100644 --- a/src/components/dashboard/EnhancedDashboardWidget.tsx +++ b/src/components/dashboard/EnhancedDashboardWidget.tsx @@ -8,7 +8,7 @@ import { DashboardWidget as WidgetType, WidgetProps, WidgetError } from '../../t // Extended widget type with component interface EnhancedWidgetType extends WidgetType { - component: React.ComponentType; + component?: React.ComponentType; } interface EnhancedDashboardWidgetProps { @@ -165,6 +165,22 @@ export const EnhancedDashboardWidget: React.FC = ( isVisible }; + // If no component is provided, show a placeholder + if (!WidgetComponent) { + return ( +
+ + + {widget.title} + + +

Widget component not configured

+
+
+
+ ); + } + return (
diff --git a/src/components/demos/FormEnhancementsDemo.tsx b/src/components/demos/FormEnhancementsDemo.tsx index 037f68f..14e7901 100644 --- a/src/components/demos/FormEnhancementsDemo.tsx +++ b/src/components/demos/FormEnhancementsDemo.tsx @@ -123,7 +123,7 @@ export const FormEnhancementsDemo: React.FC = () => { />
), - isValid: formData.personalInfo.name && formData.personalInfo.email, + isValid: !!(formData.personalInfo.name && formData.personalInfo.email), }, { id: "address", @@ -153,7 +153,7 @@ export const FormEnhancementsDemo: React.FC = () => { /> ), - isValid: formData.address.street && formData.address.city, + isValid: !!(formData.address.street && formData.address.city), }, { id: "preferences", diff --git a/src/components/file/EnhancedFileUploadModal.tsx b/src/components/file/EnhancedFileUploadModal.tsx index 32268a5..89ea0ef 100644 --- a/src/components/file/EnhancedFileUploadModal.tsx +++ b/src/components/file/EnhancedFileUploadModal.tsx @@ -184,30 +184,25 @@ export const EnhancedFileUploadModal: React.FC = ( setUploadError(null); try { - const uploadResult = await uploadFile( + const fileData = await uploadFile( selectedFile, + userId, + userName, + undefined, // userRole { folder: projectId ? `projects/${projectId}` : 'general', - resourceType: selectedFile.type.startsWith('image/') ? 'image' : 'raw', - }, - projectId || 'default' + category: data.category as FileCategory, + projectId, + description: data.description, + tags: data.tags + } ); - const fileData: ProjectFile = { - id: uploadResult.public_id || `file-${Date.now()}`, - name: selectedFile.name, - url: uploadResult.secure_url || uploadResult.url, - public_id: uploadResult.public_id, - secure_url: uploadResult.secure_url, - type: selectedFile.type, - size: selectedFile.size, - uploadedBy: userId, - uploadedByName: userName, - uploadedAt: new Date() as any, - projectId: projectId || '', - category: data.category as FileCategory, - description: data.description, - tags: data.tags, + // Update permissions with form data + const updatedFileData: ProjectFile = { + ...fileData, + uploaderId: userId, + uploaderName: userName, permissions: { level: data.permissions.level, allowDownload: data.permissions.allowDownload ?? true, @@ -216,11 +211,9 @@ export const EnhancedFileUploadModal: React.FC = ( allowVersioning: data.permissions.allowVersioning ?? true, allowComments: data.permissions.allowComments ?? true, }, - version: 1, - isLatestVersion: true, }; - await onUpload(fileData, data); + await onUpload(updatedFileData, data); handleClose(); } catch (error) { console.error('Upload error:', error); @@ -347,9 +340,9 @@ export const EnhancedFileUploadModal: React.FC = (
Uploading... - {uploadProgress}% + {Object.values(uploadProgress)[0]?.progress ?? 0}%
- +
diff --git a/src/components/file/FileOrganizationDashboard.tsx b/src/components/file/FileOrganizationDashboard.tsx index 9d366f9..5ac252d 100644 --- a/src/components/file/FileOrganizationDashboard.tsx +++ b/src/components/file/FileOrganizationDashboard.tsx @@ -54,13 +54,24 @@ export const FileOrganizationDashboard: React.FC totalSize: 0, folderBreakdown: {}, categoryBreakdown: { - [FileCategory.DOCUMENTS]: 0, + [FileCategory.DRAWINGS]: 0, + [FileCategory.SPECIFICATIONS]: 0, + [FileCategory.REPORTS]: 0, + [FileCategory.CONTRACTS]: 0, + [FileCategory.CORRESPONDENCE]: 0, + [FileCategory.MODELS]: 0, [FileCategory.IMAGES]: 0, + [FileCategory.PRESENTATIONS]: 0, + [FileCategory.SPREADSHEETS]: 0, + [FileCategory.VIDEOS]: 0, + [FileCategory.AUDIO]: 0, + [FileCategory.DOCUMENTS]: 0, [FileCategory.ARCHIVES]: 0, [FileCategory.SUBSTANTIATION]: 0, [FileCategory.DELIVERABLES]: 0, [FileCategory.PROFILE]: 0, - [FileCategory.SYSTEM]: 0 + [FileCategory.SYSTEM]: 0, + [FileCategory.OTHER]: 0 } }); diff --git a/src/components/navigation/HeaderContent.tsx b/src/components/navigation/HeaderContent.tsx index 9f58a7d..c478766 100644 --- a/src/components/navigation/HeaderContent.tsx +++ b/src/components/navigation/HeaderContent.tsx @@ -138,7 +138,8 @@ export function HeaderContent() { const userName = displayUser.name || displayUser.email?.split('@')[0] || 'User' const userEmail = displayUser.email || mockUser.email const userRole = displayUser.role || mockUser.role - const userAvatar = displayUser.avatarUrl || mockUser.avatar + // Handle both avatar (local mock) and avatarUrl (from AppContext) + const userAvatar = (user?.avatarUrl) || mockUser.avatar return ( diff --git a/src/components/performance/PerformanceOptimizedCard.tsx b/src/components/performance/PerformanceOptimizedCard.tsx index f4ff248..4c21909 100644 --- a/src/components/performance/PerformanceOptimizedCard.tsx +++ b/src/components/performance/PerformanceOptimizedCard.tsx @@ -10,12 +10,13 @@ import React, { ReactNode } from 'react'; import { useCSSContainment, useIntersectionObserver } from '../../hooks/useCSSOptimization'; import { cn } from '../../lib/utils'; +import { ContainmentType } from '../../utils/performance/cssOptimization'; export interface PerformanceOptimizedCardProps { children: ReactNode; className?: string; lazyLoad?: boolean; - containment?: 'layout' | 'paint' | 'layout paint' | 'strict' | 'content'; + containment?: ContainmentType; onVisible?: () => void; } @@ -27,7 +28,7 @@ export function PerformanceOptimizedCard({ children, className, lazyLoad = false, - containment = 'layout paint', + containment = 'layout', onVisible, }: PerformanceOptimizedCardProps) { const containmentRef = useCSSContainment(containment); diff --git a/src/components/project/ProjectCard.tsx b/src/components/project/ProjectCard.tsx index e99c94c..39781bb 100644 --- a/src/components/project/ProjectCard.tsx +++ b/src/components/project/ProjectCard.tsx @@ -38,21 +38,9 @@ import { Target, } from 'lucide-react' import { cn } from '@/lib/utils' +import { ProjectStatus, UserRole } from '@/types' -// Enums and types (would typically come from a shared types file) -export enum ProjectStatus { - PENDING_APPROVAL = 'PENDING_APPROVAL', - IN_PROGRESS = 'IN_PROGRESS', - COMPLETED = 'COMPLETED', - ON_HOLD = 'ON_HOLD', - CANCELLED = 'CANCELLED', -} - -export enum UserRole { - ADMIN = 'ADMIN', - FREELANCER = 'FREELANCER', - CLIENT = 'CLIENT', -} +// Enums are imported from shared types file export interface User { id: string @@ -118,11 +106,23 @@ export interface ProjectCardProps { */ const getStatusConfig = (status: ProjectStatus) => { const configs = { - [ProjectStatus.PENDING_APPROVAL]: { + [ProjectStatus.DRAFT]: { + variant: 'secondary' as const, + className: 'bg-gray-100 text-gray-600 hover:bg-gray-200', + icon: Clock, + label: 'Draft', + }, + [ProjectStatus.PLANNING]: { variant: 'secondary' as const, className: 'bg-yellow-100 text-yellow-700 hover:bg-yellow-200', icon: Clock, - label: 'Pending Approval', + label: 'Planning', + }, + [ProjectStatus.ACTIVE]: { + variant: 'default' as const, + className: 'bg-blue-100 text-blue-700 hover:bg-blue-200', + icon: Play, + label: 'Active', }, [ProjectStatus.IN_PROGRESS]: { variant: 'default' as const, diff --git a/src/components/project/ProjectDetailsView.tsx b/src/components/project/ProjectDetailsView.tsx index 6828cd2..a64f766 100644 --- a/src/components/project/ProjectDetailsView.tsx +++ b/src/components/project/ProjectDetailsView.tsx @@ -103,25 +103,14 @@ export const ProjectDetailsView: React.FC = ({ // Handle project updates const handleProjectUpdate = async (projectId: string, updates: Partial) => { if (onUpdateProject) { - // Convert ProjectStatus enum back to workflow string format - const statusMap: Record = { - [ProjectStatus.DRAFT]: 'pending', - [ProjectStatus.PLANNING]: 'planning', - [ProjectStatus.ACTIVE]: 'active', - [ProjectStatus.IN_PROGRESS]: 'active', - [ProjectStatus.ON_HOLD]: 'on-hold', - [ProjectStatus.COMPLETED]: 'completed', - [ProjectStatus.CANCELLED]: 'cancelled', - }; - // Convert updates back to WorkflowProject format if needed const workflowUpdates: Partial = { title: updates.title, description: updates.description, budget: updates.budget, dueDate: updates.deadline, - // Convert status back to workflow format - status: updates.status ? statusMap[updates.status] : undefined, + // Status is already ProjectStatus enum + status: updates.status, // Convert priority back to lowercase priority: updates.priority?.toLowerCase() as 'low' | 'medium' | 'high' | 'urgent' } diff --git a/src/components/project/ProjectTable.tsx b/src/components/project/ProjectTable.tsx index 0301358..87d3f39 100644 --- a/src/components/project/ProjectTable.tsx +++ b/src/components/project/ProjectTable.tsx @@ -50,55 +50,16 @@ import { User, } from 'lucide-react' import { cn } from '@/lib/utils' +import { ProjectStatus, UserRole, User as BaseUser, Project as BaseProject } from '@/types' -// Enums and types (would typically come from a shared types file) -export enum ProjectStatus { - PENDING_APPROVAL = 'PENDING_APPROVAL', - IN_PROGRESS = 'IN_PROGRESS', - COMPLETED = 'COMPLETED', - ON_HOLD = 'ON_HOLD', - CANCELLED = 'CANCELLED', -} - -export enum UserRole { - ADMIN = 'ADMIN', - FREELANCER = 'FREELANCER', - CLIENT = 'CLIENT', -} +// Use User from types.ts but allow referencing locally +type User = BaseUser; -export interface User { - id: string - name: string - email: string - role: UserRole - title?: string - avatarUrl?: string -} - -export interface Project { - id: string - title: string - description: string - clientId: string - clientName?: string - leadArchitectId: string - leadArchitectName?: string - assignedTeamIds: string[] - assignedTeam?: User[] - status: ProjectStatus - budget?: number - deadline?: Date - priority?: 'LOW' | 'MEDIUM' | 'HIGH' | 'URGENT' - tags: string[] - purchasedHours?: number - remainingHours?: number - totalTimeSpentMinutes?: number - totalAllocatedHours?: number - completionPercentage?: number - activeJobCards?: number - totalJobCards?: number - createdAt: Date - updatedAt?: Date +// Extend Project from types with table-specific properties if needed +export interface Project extends Omit { + createdAt: Date; + updatedAt?: Date; + deadline?: Date; } export interface ProjectTableActions { @@ -141,11 +102,23 @@ type SortField = 'title' | 'status' | 'deadline' | 'budget' | 'createdAt' | 'com */ const getStatusConfig = (status: ProjectStatus) => { const configs = { - [ProjectStatus.PENDING_APPROVAL]: { + [ProjectStatus.DRAFT]: { + variant: 'secondary' as const, + className: 'bg-gray-100 text-gray-600', + icon: Clock, + label: 'Draft', + }, + [ProjectStatus.PLANNING]: { variant: 'secondary' as const, className: 'bg-yellow-100 text-yellow-700', icon: Clock, - label: 'Pending', + label: 'Planning', + }, + [ProjectStatus.ACTIVE]: { + variant: 'default' as const, + className: 'bg-blue-100 text-blue-700', + icon: Play, + label: 'Active', }, [ProjectStatus.IN_PROGRESS]: { variant: 'default' as const, @@ -301,11 +274,11 @@ export const ProjectTable: React.FC = ({ aValue = a.completionPercentage ?? 0 bValue = b.completionPercentage ?? 0 } else if (sortField === 'deadline') { - aValue = a.deadline ? new Date(a.deadline).getTime() : 0 - bValue = b.deadline ? new Date(b.deadline).getTime() : 0 + aValue = a.deadline ? a.deadline.getTime() : 0 + bValue = b.deadline ? b.deadline.getTime() : 0 } else if (sortField === 'createdAt') { - aValue = new Date(a.createdAt).getTime() - bValue = new Date(b.createdAt).getTime() + aValue = a.createdAt.getTime() + bValue = b.createdAt.getTime() } if (aValue < bValue) return sortDirection === 'asc' ? -1 : 1 @@ -410,7 +383,9 @@ export const ProjectTable: React.FC = ({ All Status - Pending + Draft + Planning + Active In Progress Completed On Hold diff --git a/src/components/project/ProjectWorkflow.tsx b/src/components/project/ProjectWorkflow.tsx index 52008cc..9855522 100644 --- a/src/components/project/ProjectWorkflow.tsx +++ b/src/components/project/ProjectWorkflow.tsx @@ -16,14 +16,14 @@ import { Search } from 'lucide-react' import { cn } from '@/lib/utils' -import { ProjectStatus as ProjectStatusEnum } from '@/types' +import { ProjectStatus } from '@/types' // Import our enhanced components import { ProjectCreationDialog } from './ProjectCreationDialog' import { ProjectDetailsView } from './ProjectDetailsView' import { TaskManagementBoard } from './TaskManagementBoard' import { TimerIntegrationPanel } from './TimerIntegrationPanel' -import { ProjectCard, ProjectStatus } from './ProjectCard' +import { ProjectCard } from './ProjectCard' // Types for the workflow export interface WorkflowProject { @@ -153,7 +153,7 @@ export const ProjectWorkflow: React.FC = ({ id: '2', title: 'Residential Complex Layout', description: 'Master plan for 200-unit residential development', - status: ProjectStatus.PENDING_APPROVAL, + status: ProjectStatus.PLANNING, priority: 'medium', clientName: 'Sunrise Properties', teamMembers: ['Sarah Connor', 'Tom Anderson'], @@ -181,8 +181,8 @@ export const ProjectWorkflow: React.FC = ({ // Calculate dashboard stats const dashboardStats = { totalProjects: projects.length, - activeProjects: projects.filter(p => p.status === ProjectStatusEnum.ACTIVE).length, - completedProjects: projects.filter(p => p.status === ProjectStatusEnum.COMPLETED).length, + activeProjects: projects.filter(p => p.status === ProjectStatus.ACTIVE).length, + completedProjects: projects.filter(p => p.status === ProjectStatus.COMPLETED).length, totalHoursSpent: projects.reduce((sum, p) => sum + p.timeSpent, 0), averageProgress: projects.reduce((sum, p) => sum + p.progress, 0) / projects.length || 0 } diff --git a/src/components/ui/bottom-sheet.tsx b/src/components/ui/bottom-sheet.tsx index 3076275..feee2f9 100644 --- a/src/components/ui/bottom-sheet.tsx +++ b/src/components/ui/bottom-sheet.tsx @@ -67,7 +67,7 @@ interface SnapPoint { } interface BottomSheetContentProps - extends React.ComponentPropsWithoutRef, + extends Omit, 'onDragEnd'>, VariantProps { showHandle?: boolean showCloseButton?: boolean diff --git a/src/contexts/AppContext.tsx b/src/contexts/AppContext.tsx index 728c3cd..fddb432 100644 --- a/src/contexts/AppContext.tsx +++ b/src/contexts/AppContext.tsx @@ -132,6 +132,13 @@ export interface AppContextType { updateProjectStatus?: (projectId: string, status: ProjectStatus) => Promise; updateJobCard?: (projectId: string, jobCardId: string, jobCardData: Partial) => Promise; updateJobCardStatus?: (projectId: string, jobCardId: string, status: JobCardStatus) => Promise; + addProject?: (projectData: any) => Promise; + addJobCardToProject?: (projectId: string, jobCardData: any) => Promise; + + // Action item management methods + addActionItemToProject?: (projectId: string, actionItemData: any) => Promise; + updateActionItem?: (projectId: string, actionItemId: string, updates: Partial) => Promise; + deleteActionItem?: (projectId: string, actionItemId: string) => Promise; // Role and permission methods hasPermission: (permission: keyof RolePermissions) => boolean; @@ -169,6 +176,14 @@ export interface AppContextType { // Loading states loading: boolean; + + // Additional state properties + clients?: any[]; + projectRequests?: any[]; + notifications?: any[]; + isSidebarCollapsed?: boolean; + toggleSidebar?: () => void; + markNotificationAsRead?: (notificationId: string) => Promise; } // Create context diff --git a/src/pages/CSPTestPage.tsx b/src/pages/CSPTestPage.tsx index 8a668cd..37123d2 100644 --- a/src/pages/CSPTestPage.tsx +++ b/src/pages/CSPTestPage.tsx @@ -22,7 +22,7 @@ import { } from 'lucide-react'; import { NetworkHelper } from '@/network-helper'; import { cspAwareCloudinaryService } from '@/utils/cspAwareCloudinaryService'; -import { UserRole } from '@/types'; +import { UserRole, FileCategory } from '@/types'; import CSPViolationDashboard from '@/components/admin/CSPViolationDashboard'; interface TestResult { @@ -161,7 +161,7 @@ export const CSPTestPage: React.FC = () => { 'Test User', UserRole.ADMIN, { - category: 'DOCUMENTS', + category: FileCategory.DOCUMENTS, tags: ['test-upload'], fallbackToFirebase: true, retryAttempts: 3, diff --git a/src/pages/ClientDashboard.tsx b/src/pages/ClientDashboard.tsx index 202248f..5beacbd 100644 --- a/src/pages/ClientDashboard.tsx +++ b/src/pages/ClientDashboard.tsx @@ -305,7 +305,7 @@ export default function ClientDashboard() { console.log('Send message:', { conversationId, content })} + onSendMessage={async (conversationId, content) => { console.log('Send message:', { conversationId, content }); }} onMarkAsRead={(messageId) => console.log('Mark as read:', messageId)} onStartCall={(contactId, type) => console.log('Start call:', { contactId, type })} /> @@ -321,12 +321,12 @@ export default function ClientDashboard() { console.log('Download file:', fileId)} + onDownloadFile={async (fileId) => { console.log('Download file:', fileId); }} onPreviewFile={async (fileId) => { console.log('Preview file:', fileId); return `https://via.placeholder.com/800x600/0ea5e9/ffffff?text=File+Preview+${fileId}`; }} - onStarFile={(fileId, starred) => console.log('Star file:', { fileId, starred })} + onStarFile={async (fileId, starred) => { console.log('Star file:', { fileId, starred }); }} onShareFile={(fileId) => console.log('Share file:', fileId)} /> diff --git a/src/pages/FreelancerDashboard.tsx b/src/pages/FreelancerDashboard.tsx index 84b0264..5a5b9d1 100644 --- a/src/pages/FreelancerDashboard.tsx +++ b/src/pages/FreelancerDashboard.tsx @@ -21,11 +21,19 @@ import { } from 'lucide-react'; import { AdminDashboardSkeleton } from '@/components/loading/DashboardSkeleton'; import { ModernDashboardCard, AnimatedStatCard } from '@/components/dashboard/ModernDashboardCard'; -import { ProjectTable } from '@/components/project/ProjectTable'; +import { ProjectTable, Project as TableProject } from '@/components/project/ProjectTable'; import { FreelancerTimerWidget } from '@/components/freelancer/FreelancerTimerWidget'; import { FreelancerEarningsDashboard } from '@/components/freelancer/FreelancerEarningsDashboard'; import { useAppContext } from '@/contexts/AppContext'; -import { UserRole } from '@/types'; +import { UserRole, Project } from '@/types'; + +// Convert Project from types.ts to ProjectTable's Project type +const convertToTableProject = (project: Project): TableProject => ({ + ...project, + createdAt: project.createdAt instanceof Date ? project.createdAt : new Date(project.createdAt.toMillis()), + updatedAt: project.updatedAt ? (project.updatedAt instanceof Date ? project.updatedAt : new Date(project.updatedAt.toMillis())) : undefined, + deadline: project.deadline ? (project.deadline instanceof Date ? project.deadline : new Date(project.deadline.toMillis())) : undefined, +}); export default function FreelancerDashboard() { const [isLoading, setIsLoading] = useState(true); @@ -35,7 +43,8 @@ export default function FreelancerDashboard() { // Filter projects for freelancer (projects they're assigned to) const freelancerProjects = projects.filter(project => - project.team?.some(member => member.userId === user?.id) + project.assignedTeam?.some(member => member.id === user?.id) || + project.assignedTeamIds?.includes(user?.id || '') ); useEffect(() => { @@ -262,7 +271,7 @@ export default function FreelancerDashboard() { {freelancerProjects.length > 0 ? ( ({ + ...project, + createdAt: project.createdAt instanceof Date ? project.createdAt : new Date(project.createdAt.toMillis()), + updatedAt: project.updatedAt ? (project.updatedAt instanceof Date ? project.updatedAt : new Date(project.updatedAt.toMillis())) : undefined, + deadline: project.deadline ? (project.deadline instanceof Date ? project.deadline : new Date(project.deadline.toMillis())) : undefined, +}); + export default function FreelancerProjectsPage() { const { projects, user } = useAppContext(); // Filter projects for freelancer (projects they're assigned to) const freelancerProjects = projects.filter(project => - project.team?.some(member => member.userId === user?.id) + project.assignedTeam?.some(member => member.id === user?.id) || + project.assignedTeamIds?.includes(user?.id || '') ); return ( @@ -33,7 +42,7 @@ export default function FreelancerProjectsPage() { {freelancerProjects.length > 0 ? ( ; }> { // In a real implementation, this would query Cloudinary API - return cloudinaryFolderService.getFolderStatistics(); + const stats = await cloudinaryFolderService.getFolderStatistics(); + return { + totalFiles: stats.totalFiles, + totalSize: 0, // Calculate from folderSizes if needed + folderBreakdown: Object.entries(stats.folderSizes).reduce((acc, [folder, size]) => { + acc[folder] = { files: 0, size }; + return acc; + }, {} as Record), + categoryBreakdown: stats.filesByCategory + }; } /** diff --git a/src/services/fileMetadataService.ts b/src/services/fileMetadataService.ts index d4af45e..6dc683f 100644 --- a/src/services/fileMetadataService.ts +++ b/src/services/fileMetadataService.ts @@ -324,13 +324,24 @@ export class FileMetadataService { totalFiles: 0, totalSize: 0, filesByCategory: { - [FileCategory.DOCUMENTS]: 0, + [FileCategory.DRAWINGS]: 0, + [FileCategory.SPECIFICATIONS]: 0, + [FileCategory.REPORTS]: 0, + [FileCategory.CONTRACTS]: 0, + [FileCategory.CORRESPONDENCE]: 0, + [FileCategory.MODELS]: 0, [FileCategory.IMAGES]: 0, + [FileCategory.PRESENTATIONS]: 0, + [FileCategory.SPREADSHEETS]: 0, + [FileCategory.VIDEOS]: 0, + [FileCategory.AUDIO]: 0, + [FileCategory.DOCUMENTS]: 0, [FileCategory.ARCHIVES]: 0, [FileCategory.SUBSTANTIATION]: 0, [FileCategory.DELIVERABLES]: 0, [FileCategory.PROFILE]: 0, - [FileCategory.SYSTEM]: 0 + [FileCategory.SYSTEM]: 0, + [FileCategory.OTHER]: 0 }, recentFiles: [] }; diff --git a/src/services/fileService.ts b/src/services/fileService.ts index 4531922..60a4e1b 100644 --- a/src/services/fileService.ts +++ b/src/services/fileService.ts @@ -34,10 +34,8 @@ export const addFileToProject = async ( const docRef = await addDoc(filesCollectionRef, { ...fileData, url: downloadURL, - createdAt: serverTimestamp(), - updatedAt: serverTimestamp(), }); - return { id: docRef.id, ...fileData, url: downloadURL, createdAt: new Date(), updatedAt: new Date() }; + return { id: docRef.id, ...fileData, url: downloadURL }; } catch (error) { console.error('Error adding file to project:', error); throw new Error('Failed to add file to project'); diff --git a/src/services/timeTrackingService.ts b/src/services/timeTrackingService.ts index f3ac1ce..2d90dd3 100644 --- a/src/services/timeTrackingService.ts +++ b/src/services/timeTrackingService.ts @@ -68,18 +68,25 @@ export const generateTimeTrackingReport = async ( const timeLogs = querySnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() } as TimeLog)); const totalMinutes = timeLogs.reduce((acc, log) => acc + log.durationMinutes, 0); - const totalBillableMinutes = timeLogs - .filter(log => log.isBillable) - .reduce((acc, log) => acc + log.durationMinutes, 0); + // All logs are considered billable unless explicitly marked otherwise + const totalBillableMinutes = totalMinutes; + + const totalHours = totalMinutes / 60; + const totalEarnings = timeLogs.reduce((acc, log) => acc + (log.earnings || 0), 0); return { - projectId, - startDate, - endDate, - timeLogs, - totalMinutes, - totalBillableMinutes, - generatedAt: new Date(), + totalHours, + totalEarnings, + projectBreakdown: [{ + projectId, + projectTitle: '', // Would need to fetch from project data + hours: totalHours, + earnings: totalEarnings + }], + period: { + startDate, + endDate + } }; } catch (error) { console.error('Error generating time tracking report:', error); diff --git a/src/utils/DashboardAnalytics.ts b/src/utils/DashboardAnalytics.ts index 2fe51c3..55f0816 100644 --- a/src/utils/DashboardAnalytics.ts +++ b/src/utils/DashboardAnalytics.ts @@ -89,7 +89,7 @@ export const generatePlacementRecommendations = ( // Recommend moving most-used widgets to top-left const topUsedWidgets = analytics.mostUsedWidgets.slice(0, 3); topUsedWidgets.forEach((widget, index) => { - const currentWidget = currentLayout.find((w) => w.i === widget.widgetId); + const currentWidget = currentLayout.find((w) => w.id === widget.widgetId); if (currentWidget && (currentWidget.y > 2 || currentWidget.x > 2)) { recommendations.push({ widgetId: widget.widgetId, diff --git a/src/utils/cloudinaryHelpers.ts b/src/utils/cloudinaryHelpers.ts index e950b7f..b327f20 100644 --- a/src/utils/cloudinaryHelpers.ts +++ b/src/utils/cloudinaryHelpers.ts @@ -256,9 +256,11 @@ export const getUserFolderStats = async ( }; return { - ...stats, + totalFiles: stats.totalFiles, + totalSize: stats.totalSize, quotaUsed: stats.totalSize, - quotaLimit: quotaLimits[userRole] + quotaLimit: quotaLimits[userRole], + categoryBreakdown: stats.filesByCategory }; } catch (error) { console.error('Failed to get user folder stats:', error); @@ -268,13 +270,24 @@ export const getUserFolderStats = async ( quotaUsed: 0, quotaLimit: 0, categoryBreakdown: { - [FileCategory.DOCUMENTS]: 0, + [FileCategory.DRAWINGS]: 0, + [FileCategory.SPECIFICATIONS]: 0, + [FileCategory.REPORTS]: 0, + [FileCategory.CONTRACTS]: 0, + [FileCategory.CORRESPONDENCE]: 0, + [FileCategory.MODELS]: 0, [FileCategory.IMAGES]: 0, + [FileCategory.PRESENTATIONS]: 0, + [FileCategory.SPREADSHEETS]: 0, + [FileCategory.VIDEOS]: 0, + [FileCategory.AUDIO]: 0, + [FileCategory.DOCUMENTS]: 0, [FileCategory.ARCHIVES]: 0, [FileCategory.SUBSTANTIATION]: 0, [FileCategory.DELIVERABLES]: 0, [FileCategory.PROFILE]: 0, - [FileCategory.SYSTEM]: 0 + [FileCategory.SYSTEM]: 0, + [FileCategory.OTHER]: 0 } }; } diff --git a/src/utils/cspAwareCloudinaryService.ts b/src/utils/cspAwareCloudinaryService.ts index caeaa70..cf5e32a 100644 --- a/src/utils/cspAwareCloudinaryService.ts +++ b/src/utils/cspAwareCloudinaryService.ts @@ -3,7 +3,7 @@ * Handles file uploads with Content Security Policy awareness and fallback mechanisms */ -import { ProjectFile, UserRole, FilePermissionLevel } from '@/types'; +import { ProjectFile, UserRole, FilePermissionLevel, FileCategory } from '@/types'; import { Timestamp } from 'firebase/firestore'; import { NetworkHelper } from '@/network-helper'; @@ -12,7 +12,7 @@ interface CSPAwareUploadOptions { tags?: string[]; transformation?: string; progressCallback?: (progress: number) => void; - category?: string; + category?: FileCategory; projectId?: string; description?: string; retryAttempts?: number; @@ -228,7 +228,7 @@ class CSPAwareCloudinaryService { uploadedBy: userId, uploadedByName: userName, uploadedAt: Timestamp.now(), - category: options.category || 'DOCUMENTS', + category: options.category || FileCategory.DOCUMENTS, projectId: options.projectId || '', tags: options.tags || [], permissions: { @@ -242,14 +242,16 @@ class CSPAwareCloudinaryService { allowComments: true }, metadata: { - cloudinaryPublicId: data.public_id, - cloudinaryVersion: data.version, - cloudinaryFormat: data.format, - cloudinaryResourceType: data.resource_type, width: data.width, height: data.height, - bytes: data.bytes, - etag: data.etag + format: data.format, + customFields: { + cloudinaryPublicId: data.public_id, + cloudinaryVersion: data.version, + cloudinaryResourceType: data.resource_type, + bytes: data.bytes, + etag: data.etag + } } }; @@ -326,7 +328,7 @@ class CSPAwareCloudinaryService { uploadedBy: userId, uploadedByName: userName, uploadedAt: Timestamp.now(), - category: options.category || 'DOCUMENTS', + category: options.category || FileCategory.DOCUMENTS, projectId: options.projectId || '', tags: [...(options.tags || []), 'firebase-fallback'], permissions: { @@ -340,9 +342,11 @@ class CSPAwareCloudinaryService { allowComments: true }, metadata: { - storageProvider: 'firebase', - storagePath: storagePath, - fallbackReason: 'csp-violation' + customFields: { + storageProvider: 'firebase', + storagePath: storagePath, + fallbackReason: 'csp-violation' + } } }; diff --git a/src/utils/fileAccessControl.ts b/src/utils/fileAccessControl.ts index cef1d47..2c21053 100644 --- a/src/utils/fileAccessControl.ts +++ b/src/utils/fileAccessControl.ts @@ -58,11 +58,15 @@ export const checkFileAccess = ( } // User has access, now check specific permissions + // Note: ADMIN users already returned early, so this code handles FREELANCER and CLIENT + const isFreelancer = userRole === UserRole.FREELANCER; + const canDeleteFile = permissions.allowDelete && (isFileOwner || isFreelancer); + return { canView: true, canDownload: permissions.allowDownload, canShare: permissions.allowShare, - canDelete: permissions.allowDelete && (userRole === UserRole.ADMIN || isFileOwner || userRole === UserRole.FREELANCER), + canDelete: canDeleteFile, canEdit: permissions.allowVersioning, canComment: permissions.allowComments, canManagePermissions: false, // Only owner and admin can manage permissions diff --git a/tsc_current_errors.txt b/tsc_current_errors.txt new file mode 100644 index 0000000..3ac4e74 --- /dev/null +++ b/tsc_current_errors.txt @@ -0,0 +1,66 @@ +src/components/ChatInterfaceDemo.tsx(188,9): error TS2322: Type 'import("/home/runner/work/axis2/axis2/src/types").Message[]' is not assignable to type 'import("/home/runner/work/axis2/axis2/src/types/messaging").Message[]'. + Property 'channelType' is missing in type 'import("/home/runner/work/axis2/axis2/src/types").Message' but required in type 'import("/home/runner/work/axis2/axis2/src/types/messaging").Message'. +src/components/admin/ShadcnFileManagementDashboard.tsx(143,22): error TS2345: Argument of type '{ totalFiles: number; totalSize: number; filesByCategory: Record; filesByUploader: Record; mostAccessedFiles: any[]; recentlyUploadedFiles: { ...; }[]; }' is not assignable to parameter of type 'SetStateAction<{ totalFiles: number; totalSize: number; filesByCategory: Record; filesByUploader: Record; mostAccessedFiles: { ...; }[]; recentlyUploadedFiles: ProjectFile[]; }>'. + Type '{ totalFiles: number; totalSize: number; filesByCategory: Record; filesByUploader: Record; mostAccessedFiles: any[]; recentlyUploadedFiles: { ...; }[]; }' is not assignable to type '{ totalFiles: number; totalSize: number; filesByCategory: Record; filesByUploader: Record; mostAccessedFiles: { ...; }[]; recentlyUploadedFiles: ProjectFile[]; }'. + Types of property 'recentlyUploadedFiles' are incompatible. + Type '{ id: string; name: string; uploadedAt: Timestamp; }[]' is not assignable to type 'ProjectFile[]'. + Type '{ id: string; name: string; uploadedAt: Timestamp; }' is missing the following properties from type 'ProjectFile': size, type, url, uploaderId, and 2 more. +src/components/dashboard/DashboardLayoutManager.tsx(345,25): error TS2741: Property 'component' is missing in type 'DashboardWidget' but required in type 'EnhancedWidgetType'. +src/components/dashboard/ResizableWidgetContainer.tsx(163,13): error TS2741: Property 'component' is missing in type 'DashboardWidget' but required in type 'EnhancedWidgetType'. +src/components/dashboard/ResizableWidgetContainer.tsx(203,21): error TS2741: Property 'component' is missing in type 'DashboardWidget' but required in type 'EnhancedWidgetType'. +src/components/demos/FormEnhancementsDemo.tsx(126,7): error TS2322: Type 'string' is not assignable to type 'boolean'. +src/components/demos/FormEnhancementsDemo.tsx(156,7): error TS2322: Type 'string' is not assignable to type 'boolean'. +src/components/file/EnhancedFileUploadModal.tsx(189,9): error TS2345: Argument of type '{ folder: string; resourceType: string; }' is not assignable to parameter of type 'string'. +src/components/file/EnhancedFileUploadModal.tsx(196,13): error TS2739: Type '{ id: string; name: string; url: string; public_id: string; secure_url: string; type: string; size: number; uploadedBy: string; uploadedByName: string; uploadedAt: any; projectId: string; category: FileCategory; ... 4 more ...; isLatestVersion: true; }' is missing the following properties from type 'ProjectFile': uploaderId, uploaderName +src/components/file/EnhancedFileUploadModal.tsx(350,27): error TS2322: Type 'Record' is not assignable to type 'ReactNode'. + Type 'Record' is missing the following properties from type 'ReactPortal': children, type, props, key +src/components/file/EnhancedFileUploadModal.tsx(352,29): error TS2322: Type 'Record' is not assignable to type 'number'. +src/components/file/FileOrganizationDashboard.tsx(56,5): error TS2740: Type '{ DOCUMENTS: number; IMAGES: number; ARCHIVES: number; SUBSTANTIATION: number; DELIVERABLES: number; PROFILE: number; SYSTEM: number; }' is missing the following properties from type 'Record': DRAWINGS, SPECIFICATIONS, REPORTS, CONTRACTS, and 7 more. +src/components/navigation/HeaderContent.tsx(141,36): error TS2339: Property 'avatarUrl' does not exist on type 'User | User'. + Property 'avatarUrl' does not exist on type 'User'. +src/components/performance/PerformanceOptimizedCard.tsx(33,44): error TS2345: Argument of type '"content" | "layout" | "paint" | "strict" | "layout paint"' is not assignable to parameter of type 'ContainmentType'. + Type '"layout paint"' is not assignable to type 'ContainmentType'. +src/components/project/ProjectCreationDialog.tsx(99,5): error TS2322: Type '"deliverables"' is not assignable to type '"teamMembers" | "initialTasks"'. +src/components/project/ProjectCreationDialog.tsx(605,56): error TS2345: Argument of type 'string' is not assignable to parameter of type '{ title: string; estimatedHours: number; priority: "high" | "low" | "medium" | "urgent"; assignedTo: string; description?: string; } | { name: string; role: string; email: string; } | ({ title: string; estimatedHours: number; priority: "high" | ... 2 more ... | "urgent"; assignedTo: string; description?: string; } |...'. +src/components/project/ProjectDetailsView.tsx(124,9): error TS2322: Type 'string' is not assignable to type 'ProjectStatus'. +src/components/project/ProjectWorkflow.tsx(184,42): error TS2367: This comparison appears to be unintentional because the types 'import("/home/runner/work/axis2/axis2/src/components/project/ProjectCard").ProjectStatus' and 'import("/home/runner/work/axis2/axis2/src/types").ProjectStatus' have no overlap. +src/components/project/ProjectWorkflow.tsx(185,45): error TS2367: This comparison appears to be unintentional because the types 'import("/home/runner/work/axis2/axis2/src/components/project/ProjectCard").ProjectStatus' and 'import("/home/runner/work/axis2/axis2/src/types").ProjectStatus' have no overlap. +src/components/ui/bottom-sheet.tsx(69,11): error TS2430: Interface 'BottomSheetContentProps' incorrectly extends interface 'Omit, "ref">'. + Types of property 'onDragEnd' are incompatible. + Type '(velocity: number) => void' is not assignable to type 'DragEventHandler'. + Types of parameters 'velocity' and 'event' are incompatible. + Type 'DragEvent' is not assignable to type 'number'. +src/contexts/AppContext.tsx(902,5): error TS2353: Object literal may only specify known properties, and 'addActionItemToProject' does not exist in type 'AppContextType'. +src/pages/ClientDashboard.tsx(308,61): error TS2322: Type 'void' is not assignable to type 'Promise'. +src/pages/ClientDashboard.tsx(324,45): error TS2322: Type 'void' is not assignable to type 'Promise'. +src/pages/ClientDashboard.tsx(329,50): error TS2322: Type 'void' is not assignable to type 'Promise'. +src/pages/FreelancerDashboard.tsx(38,13): error TS2339: Property 'team' does not exist on type 'Project'. +src/pages/FreelancerDashboard.tsx(265,19): error TS2322: Type 'import("/home/runner/work/axis2/axis2/src/types").Project[]' is not assignable to type 'import("/home/runner/work/axis2/axis2/src/components/project/ProjectTable").Project[]'. + Type 'import("/home/runner/work/axis2/axis2/src/types").Project' is not assignable to type 'import("/home/runner/work/axis2/axis2/src/components/project/ProjectTable").Project'. + Types of property 'status' are incompatible. + Type 'import("/home/runner/work/axis2/axis2/src/types").ProjectStatus' is not assignable to type 'import("/home/runner/work/axis2/axis2/src/components/project/ProjectTable").ProjectStatus'. + Property 'DRAFT' is missing in type 'import("/home/runner/work/axis2/axis2/src/components/project/ProjectTable").ProjectStatus'. +src/pages/FreelancerProjectsPage.tsx(12,13): error TS2339: Property 'team' does not exist on type 'Project'. +src/pages/FreelancerProjectsPage.tsx(36,15): error TS2322: Type 'import("/home/runner/work/axis2/axis2/src/types").Project[]' is not assignable to type 'import("/home/runner/work/axis2/axis2/src/components/project/ProjectTable").Project[]'. + Type 'import("/home/runner/work/axis2/axis2/src/types").Project' is not assignable to type 'import("/home/runner/work/axis2/axis2/src/components/project/ProjectTable").Project'. + Types of property 'status' are incompatible. + Type 'import("/home/runner/work/axis2/axis2/src/types").ProjectStatus' is not assignable to type 'import("/home/runner/work/axis2/axis2/src/components/project/ProjectTable").ProjectStatus'. + Property 'DRAFT' is missing in type 'import("/home/runner/work/axis2/axis2/src/components/project/ProjectTable").ProjectStatus'. +src/services/cloudinaryManagementService.ts(169,9): error TS2739: Type '{ level: FilePermissionLevel; allowDownload: true; allowShare: boolean; allowVersioning: boolean; }' is missing the following properties from type 'FilePermissions': allowDelete, allowComments +src/services/cloudinaryManagementService.ts(362,5): error TS2739: Type '{ totalFiles: number; folderSizes: Record; filesByCategory: Record; filesByRole: Record; }' is missing the following properties from type '{ totalFiles: number; totalSize: number; folderBreakdown: Record; categoryBreakdown: Record; }': totalSize, folderBreakdown, categoryBreakdown +src/services/fileMetadataService.ts(326,7): error TS2740: Type '{ DOCUMENTS: number; IMAGES: number; ARCHIVES: number; SUBSTANTIATION: number; DELIVERABLES: number; PROFILE: number; SYSTEM: number; }' is missing the following properties from type 'Record': DRAWINGS, SPECIFICATIONS, REPORTS, CONTRACTS, and 7 more. +src/services/fileService.ts(40,64): error TS2353: Object literal may only specify known properties, and 'createdAt' does not exist in type 'ProjectFile'. +src/services/profileExportImportService.ts(193,11): error TS2322: Type 'any' is not assignable to type 'never'. +src/services/profileExportImportService.ts(196,11): error TS2322: Type 'any' is not assignable to type 'never'. +src/services/profileExportImportService.ts(394,7): error TS2322: Type 'string | number | boolean | string[] | Timestamp | { profileCompleted: boolean; skillsAdded: boolean; firstProjectAssigned: boolean; firstTimeLogged: boolean; completedAt?: Timestamp; } | { ...; }' is not assignable to type 'never'. + Type 'string' is not assignable to type 'never'. +src/services/timeTrackingService.ts(72,32): error TS2339: Property 'isBillable' does not exist on type 'TimeLog'. +src/services/timeTrackingService.ts(76,13): error TS2353: Object literal may only specify known properties, and 'projectId' does not exist in type 'TimeTrackingReport'. +src/utils/DashboardAnalytics.ts(92,55): error TS2339: Property 'i' does not exist on type 'WidgetLayout'. +src/utils/cloudinaryHelpers.ts(258,5): error TS2741: Property 'categoryBreakdown' is missing in type '{ quotaUsed: number; quotaLimit: number; totalFiles: number; totalSize: number; filesByCategory: Record; recentFiles: ProjectFile[]; }' but required in type '{ totalFiles: number; totalSize: number; quotaUsed: number; quotaLimit: number; categoryBreakdown: Record; }'. +src/utils/cloudinaryHelpers.ts(270,7): error TS2740: Type '{ DOCUMENTS: number; IMAGES: number; ARCHIVES: number; SUBSTANTIATION: number; DELIVERABLES: number; PROFILE: number; SYSTEM: number; }' is missing the following properties from type 'Record': DRAWINGS, SPECIFICATIONS, REPORTS, CONTRACTS, and 7 more. +src/utils/cspAwareCloudinaryService.ts(231,9): error TS2322: Type 'string' is not assignable to type 'FileCategory'. +src/utils/cspAwareCloudinaryService.ts(245,11): error TS2353: Object literal may only specify known properties, and 'cloudinaryPublicId' does not exist in type 'FileMetadata'. +src/utils/cspAwareCloudinaryService.ts(329,17): error TS2322: Type 'string' is not assignable to type 'FileCategory'. +src/utils/cspAwareCloudinaryService.ts(343,19): error TS2353: Object literal may only specify known properties, and 'storageProvider' does not exist in type 'FileMetadata'. +src/utils/fileAccessControl.ts(65,44): error TS2367: This comparison appears to be unintentional because the types 'UserRole.FREELANCER | UserRole.CLIENT' and 'UserRole.ADMIN' have no overlap. diff --git a/utils/advancedFileManager.ts b/utils/advancedFileManager.ts index f1eb9ef..44e4989 100644 --- a/utils/advancedFileManager.ts +++ b/utils/advancedFileManager.ts @@ -101,8 +101,7 @@ class AdvancedFileManager { .sort((a, b) => { return b.uploadedAt.toMillis() - a.uploadedAt.toMillis(); }) - .slice(0, 10) - .map(f => ({ id: f.id, name: f.name, uploadedAt: f.uploadedAt })); + .slice(0, 10); // For mostAccessedFiles, we would need access count tracking in a real implementation const mostAccessedFiles: any[] = [];