### Local Development Setup and Build Source: https://github.com/leaksopan/sipandai/blob/master/README.md Instructions for setting up the project locally, including installing dependencies, configuring environment variables for Firebase, and running the development server. Also includes the command for building the production-ready application. ```bash # Install dependencies npm install # Create a .env file in the root directory with your Firebase credentials # REACT_APP_FIREBASE_API_KEY=xxx # REACT_APP_FIREBASE_AUTH_DOMAIN=xxx # REACT_APP_FIREBASE_PROJECT_ID=xxx # REACT_APP_FIREBASE_STORAGE_BUCKET=xxx # REACT_APP_FIREBASE_MESSAGING_SENDER_ID=xxx # REACT_APP_FIREBASE_APP_ID=xxx # REACT_APP_FIREBASE_MEASUREMENT_ID=xxx # Start the development server npm start # Build for production npm run build ``` -------------------------------- ### React File Search Component Example Source: https://context7.com/leaksopan/sipandai/llms.txt A React component demonstrating how to use the file search and filtering functions. It manages state for search terms, dates, and results, and provides buttons to trigger different search modes. This component relies on the `useState` hook and the previously defined search/filter functions. ```javascript // Example: Search component function FileSearchComponent() { const [searchTerm, setSearchTerm] = useState(''); const [startDate, setStartDate] = useState(''); const [endDate, setEndDate] = useState(''); const [results, setResults] = useState([]); const [searchMode, setSearchMode] = useState('simple'); const handleSimpleSearch = async () => { const files = await searchFiles(searchTerm); setResults(files); }; const handleDateFilter = async () => { const files = await filterFilesByDateRange(startDate, endDate); setResults(files); }; const handleAdvancedSearch = async () => { const filters = { name: searchTerm, startDate, endDate, type: 'pdf', minSize: 0, maxSize: 10 * 1024 * 1024 // 10 MB }; const files = await advancedSearch(filters); setResults(files); }; return (
setSearchTerm(e.target.value)} />
setStartDate(e.target.value)} /> setEndDate(e.target.value)} />
); } ``` -------------------------------- ### Testing Firestore Security Rules with JavaScript Source: https://context7.com/leaksopan/sipandai/llms.txt Demonstrates how to test Firestore security rules programmatically using JavaScript. It includes examples of operations that should succeed (reading own data, creating files) and fail (reading another user's data), verifying the implemented security logic. ```javascript // Example: Testing security rules in application async function testSecurityRules() { try { // This should succeed - reading own user document const userDoc = await getDoc(doc(db, 'users', user.uid)); console.log('✓ Can read own user document'); // This should succeed - reading files as authenticated user const filesSnapshot = await getDocs(collection(db, 'files')); console.log('✓ Can read files collection'); // This should succeed - creating file as authenticated user await addDoc(collection(db, 'files'), { name: 'test.txt', userId: user.uid }); console.log('✓ Can create file'); // This should fail - trying to read another user's document try { await getDoc(doc(db, 'users', 'another-user-id')); console.log('✗ Should not be able to read other user documents'); } catch (error) { console.log('✓ Correctly blocked from reading other user documents'); } } catch (error) { console.error('Security test failed:', error); } } ``` -------------------------------- ### Manage User Roles and Status with Firebase in JavaScript Source: https://context7.com/leaksopan/sipandai/llms.txt Provides functions to load all users, update user roles, and toggle user active status using Firebase Firestore. It assumes a 'users' collection with fields like 'role', 'isActive', and 'updatedAt'. The code is designed for an administrative interface, likely within a React application, as indicated by the example usage with hooks. ```javascript // Example: User management operations import { collection, getDocs, doc, updateDoc } from 'firebase/firestore'; import { db } from './firebase/config'; // Load all users (admin only) async function loadAllUsers() { try { const usersCollection = collection(db, 'users'); const usersSnapshot = await getDocs(usersCollection); const users = usersSnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); console.log(`Loaded ${users.length} users`); return users; } catch (error) { console.error('Failed to load users:', error); throw error; } } // Update user role async function updateUserRole(userId, newRole) { try { const userDocRef = doc(db, 'users', userId); await updateDoc(userDocRef, { role: newRole, updatedAt: new Date().toISOString() }); console.log(`User ${userId} role updated to ${newRole}`); return true; } catch (error) { console.error('Failed to update user role:', error); throw error; } } // Toggle user active status async function toggleUserStatus(userId, currentStatus) { try { const userDocRef = doc(db, 'users', userId); const newStatus = !currentStatus; await updateDoc(userDocRef, { isActive: newStatus, updatedAt: new Date().toISOString() }); console.log(`User ${userId} ${newStatus ? 'activated' : 'deactivated'}`); return newStatus; } catch (error) { console.error('Failed to toggle user status:', error); throw error; } } // Example usage in component function UserManagementPanel() { const [users, setUsers] = useState([]); const { hasPermission } = useUserRole(); useEffect(() => { if (hasPermission('canManageRoles')) { loadAllUsers().then(setUsers); } }, [hasPermission]); const handleRoleChange = async (userId, newRole) => { await updateUserRole(userId, newRole); // Refresh users list setUsers(users.map(u => u.id === userId ? { ...u, role: newRole } : u )); }; const handleStatusToggle = async (userId, currentStatus) => { const newStatus = await toggleUserStatus(userId, currentStatus); setUsers(users.map(u => u.id === userId ? { ...u, isActive: newStatus } : u )); }; if (!hasPermission('canManageRoles')) { return
Access Denied
; } return (

User Management

{users.map(user => ( ))}
Name Email Role Status Actions
{user.displayName} {user.email} {user.isActive ? 'Active' : 'Inactive'}
); } ``` -------------------------------- ### Initialize Firebase Configuration Source: https://github.com/leaksopan/sipandai/blob/master/README.md Sets up the Firebase SDK with credentials for authentication, Firestore database, and Storage. Ensure all REACT_APP_FIREBASE_* environment variables are correctly set in a .env file. ```javascript import { initializeApp } from "firebase/app"; import { getAuth } from "firebase/auth"; import { getFirestore } from "firebase/firestore"; import { getStorage } from "firebase/storage"; const firebaseConfig = { apiKey: process.env.REACT_APP_FIREBASE_API_KEY, authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN, projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID, storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET, messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID, appId: process.env.REACT_APP_FIREBASE_APP_ID, measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID }; const app = initializeApp(firebaseConfig); const auth = getAuth(app); const db = getFirestore(app); const storage = getStorage(app); export { auth, db, storage }; ``` -------------------------------- ### Initialize Firebase Services for React App Source: https://context7.com/leaksopan/sipandai/llms.txt Configures and initializes Firebase services including authentication, Firestore database, and Cloud Storage for a React application. It relies on environment variables for secure credential management. Essential for connecting the frontend to Firebase backend. ```javascript // src/firebase/config.js import { initializeApp } from 'firebase/app'; import { getAuth, GoogleAuthProvider } from 'firebase/auth'; import { getFirestore } from 'firebase/firestore'; import { getStorage } from 'firebase/storage'; const firebaseConfig = { apiKey: process.env.REACT_APP_FIREBASE_API_KEY, authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN, projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID, storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET, messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID, appId: process.env.REACT_APP_FIREBASE_APP_ID, measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID }; const app = initializeApp(firebaseConfig); export const auth = getAuth(app); export const googleProvider = new GoogleAuthProvider(); export const db = getFirestore(app); export const storage = getStorage(app); export default app; ``` -------------------------------- ### Firebase Staff Application Management (JavaScript) Source: https://context7.com/leaksopan/sipandai/llms.txt Handles staff application submissions, loading pending applications, and approving or rejecting them within the Sipandai project. It relies on Firebase Firestore for database operations and assumes Firebase configuration and authentication context are available. ```javascript // Example: Staff application submission and approval import { collection, addDoc, query, where, getDocs, doc, updateDoc } from 'firebase/firestore'; import { db } from './firebase/config'; // Submit staff application (guest user) async function submitStaffApplication(user, applicationData) { try { const application = { userId: user.uid, userEmail: user.email, userDisplayName: user.displayName, userPhotoURL: user.photoURL, nama: applicationData.nama, section: applicationData.section, status: 'pending', createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() }; const docRef = await addDoc(collection(db, 'staff_applications'), application); console.log('Application submitted:', { id: docRef.id, nama: applicationData.nama, section: applicationData.section }); return { id: docRef.id, ...application }; } catch (error) { console.error('Failed to submit application:', error); throw error; } } // Load all pending applications (admin) async function loadPendingApplications() { try { const q = query( collection(db, 'staff_applications'), where('status', '==', 'pending') ); const snapshot = await getDocs(q); const applications = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); console.log(`Found ${applications.length} pending applications`); return applications; } catch (error) { console.error('Failed to load applications:', error); throw error; } } // Approve application (admin) async function approveApplication(applicationId, userId) { try { // Update user role to Auditor await updateUserRole(userId, 'Auditor'); // Update application status const appDocRef = doc(db, 'staff_applications', applicationId); await updateDoc(appDocRef, { status: 'approved', updatedAt: new Date().toISOString(), processedAt: new Date().toISOString() }); console.log(`Application ${applicationId} approved, user promoted to Auditor`); return true; } catch (error) { console.error('Failed to approve application:', error); throw error; } } // Reject application (admin) async function rejectApplication(applicationId) { try { const appDocRef = doc(db, 'staff_applications', applicationId); await updateDoc(appDocRef, { status: 'rejected', updatedAt: new Date().toISOString(), processedAt: new Date().toISOString() }); console.log(`Application ${applicationId} rejected`); return true; } catch (error) { console.error('Failed to reject application:', error); throw error; } } ``` -------------------------------- ### React Application Management Component (JavaScript) Source: https://context7.com/leaksopan/sipandai/llms.txt A React component for administrators to view and manage pending staff applications. It fetches applications using `loadPendingApplications` and provides buttons to approve or reject them, updating the UI accordingly. ```javascript // Example: Application management component (admin) function ApplicationManagement() { const [applications, setApplications] = useState([]); const { hasPermission } = useUserRole(); useEffect(() => { if (hasPermission('canManageRoles')) { loadPendingApplications().then(setApplications); } }, [hasPermission]); const handleApprove = async (appId, userId) => { await approveApplication(appId, userId); setApplications(applications.filter(app => app.id !== appId)); }; const handleReject = async (appId) => { await rejectApplication(appId); setApplications(applications.filter(app => app.id !== appId)); }; return (

Staff Applications ({applications.length} pending)

{applications.map(app => (

{app.nama}

Email: {app.userEmail}

Section: {app.section}

``` -------------------------------- ### Firebase Authentication Hook Source: https://github.com/leaksopan/sipandai/blob/master/README.md Manages user authentication state, including login (Google, email/password), registration, logout, and synchronization of user data with Firestore. It provides authentication status and user information. ```javascript import { useState, useEffect } from 'react'; import { auth, db } from '../firebase/config'; import { onAuthStateChanged, GoogleAuthProvider, signInWithPopup, signInWithEmailAndPassword, createUserWithEmailAndPassword, signOut } from 'firebase/auth'; import { doc, setDoc, getDoc, updateDoc } from 'firebase/firestore'; const useAuth = () => { const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { const unsubscribe = onAuthStateChanged(auth, async (firebaseUser) => { if (firebaseUser) { const userDocRef = doc(db, 'users', firebaseUser.uid); const userDocSnap = await getDoc(userDocRef); if (userDocSnap.exists()) { setUser({ ...firebaseUser, ...userDocSnap.data() }); } else { // New user, create profile with default role await setDoc(userDocRef, { email: firebaseUser.email, role: 'guest', isActive: true }); setUser({ ...firebaseUser, role: 'guest', isActive: true }); } } else { setUser(null); } setLoading(false); }); return unsubscribe; }, []); const loginWithGoogle = async () => { const provider = new GoogleAuthProvider(); try { const result = await signInWithPopup(auth, provider); // User logged in, effect handles profile sync return result.user; } catch (error) { console.error('Google Sign-In Error:', error); throw error; } }; const loginWithEmailPassword = async (email, password) => { try { const userCredential = await signInWithEmailAndPassword(auth, email, password); // User logged in, effect handles profile sync return userCredential.user; } catch (error) { console.error('Email/Password Login Error:', error); throw error; } }; const registerWithEmailPassword = async (email, password) => { try { const userCredential = await createUserWithEmailAndPassword(auth, email, password); // User registered, create profile with default role const userDocRef = doc(db, 'users', userCredential.user.uid); await setDoc(userDocRef, { email: email, role: 'guest', isActive: true }); setUser({ ...userCredential.user, role: 'guest', isActive: true }); return userCredential.user; } catch (error) { console.error('Email/Password Registration Error:', error); throw error; } }; const logout = async () => { await signOut(auth); setUser(null); }; const updateUserRole = async (uid, newRole) => { try { const userDocRef = doc(db, 'users', uid); await updateDoc(userDocRef, { role: newRole }); setUser(prevUser => prevUser ? { ...prevUser, role: newRole } : null); return true; } catch (error) { console.error('Error updating user role:', error); return false; } }; const toggleUserActiveStatus = async (uid, isActive) => { try { const userDocRef = doc(db, 'users', uid); await updateDoc(userDocRef, { isActive: isActive }); setUser(prevUser => prevUser ? { ...prevUser, isActive: isActive } : null); return true; } catch (error) { console.error('Error toggling user active status:', error); return false; } }; return { user, loading, loginWithGoogle, loginWithEmailPassword, registerWithEmailPassword, logout, updateUserRole, toggleUserActiveStatus }; }; export default useAuth; ``` -------------------------------- ### User Role and Permissions Hook Source: https://github.com/leaksopan/sipandai/blob/master/README.md Fetches user roles from Firestore and provides methods to check permissions for specific actions or UI elements. It maps roles to granular permissions and offers helper functions for displaying role labels. ```javascript import { useState, useEffect, useContext } from 'react'; import { db } from '../firebase/config'; import { doc, onSnapshot } from 'firebase/firestore'; import { AuthContext } from './AuthContext'; // Assuming you have an AuthContext const rolePermissions = { super_admin: { canViewDashboard: true, canManageUsers: true, canAccessFileManager: true, canUploadFiles: true, canDownloadFiles: true, canApproveStaff: true, canDeleteFiles: true, canCreateFolders: true, }, Irban: { canViewDashboard: true, canManageUsers: false, canAccessFileManager: true, canUploadFiles: true, canDownloadFiles: true, canApproveStaff: true, canDeleteFiles: true, canCreateFolders: true, }, Auditor: { canViewDashboard: true, canManageUsers: false, canAccessFileManager: true, canUploadFiles: true, canDownloadFiles: false, // Auditors have limited download permissions canApproveStaff: false, canDeleteFiles: false, canCreateFolders: false, }, guest: { canViewDashboard: true, canManageUsers: false, canAccessFileManager: false, canUploadFiles: false, canDownloadFiles: false, canApproveStaff: false, canDeleteFiles: false, canCreateFolders: false, }, }; const roleLabels = { super_admin: 'Super Admin', Irban: 'Irban', Auditor: 'Auditor', guest: 'Guest', }; const useUserRole = () => { const { user } = useContext(AuthContext); // Get user from AuthContext const [role, setRole] = useState('guest'); const [loadingRole, setLoadingRole] = useState(true); useEffect(() => { if (user) { const userDocRef = doc(db, 'users', user.uid); const unsubscribe = onSnapshot(userDocRef, (docSnap) => { if (docSnap.exists()) { const userData = docSnap.data(); setRole(userData.role || 'guest'); } else { setRole('guest'); // Default if user doc somehow missing } setLoadingRole(false); }); return () => unsubscribe(); // Cleanup subscription on unmount } else { setRole('guest'); // Reset role if user logs out setLoadingRole(false); } }, [user]); // Re-run effect if user changes const hasPermission = (permission) => { const currentRolePermissions = rolePermissions[role] || {}; return currentRolePermissions[permission] || false; }; const getRoleLabel = () => { return roleLabels[role] || 'Unknown Role'; }; return { role, loadingRole, hasPermission, getRoleLabel, permissions: rolePermissions[role] || {} }; }; export default useUserRole; ``` -------------------------------- ### Batch Upload Files with Progress Tracking (JavaScript) Source: https://context7.com/leaksopan/sipandai/llms.txt This function handles uploading multiple files sequentially, providing progress updates for the entire batch. It iterates through an array of files, calling the single upload function for each and aggregating results. A progress callback function is essential for real-time UI updates. It depends on the `uploadFileWithMetadata` function and requires user authentication. ```javascript async function uploadMultipleFiles(files, currentFolder, user, onProgress) { const totalFiles = files.length; let completed = 0; const results = []; for (const file of files) { try { const result = await uploadFileWithMetadata(file, currentFolder, user); results.push(result); completed++; // Update progress const progress = (completed / totalFiles) * 100; onProgress(progress, completed, totalFiles); } catch (error) { console.error(`Failed to upload ${file.name}:`, error); results.push({ success: false, fileName: file.name, error }); } } return results; } ``` -------------------------------- ### File Upload Component with Progress Display (JavaScript) Source: https://context7.com/leaksopan/sipandai/llms.txt A React component demonstrating the usage of the batch file upload functionality. It includes an input element for file selection and displays the upload progress percentage. This component requires React, `useState` hook for state management, and a `useAuth` hook for user authentication. It integrates with `uploadMultipleFiles` to provide user feedback during uploads. ```javascript import { useState } from 'react'; import { useAuth } from './auth'; // Assuming useAuth is defined elsewhere // Assume uploadMultipleFiles is imported or defined in the same scope function FileUploadComponent() { const [uploadProgress, setUploadProgress] = useState(0); const { user } = useAuth(); const handleFileSelect = async (event) => { const files = Array.from(event.target.files); await uploadMultipleFiles( files, '/documents/2024', user, (progress, completed, total) => { setUploadProgress(progress); console.log(`Uploaded ${completed} of ${total} files (${progress.toFixed(1)}%)`); } ); console.log('All uploads completed'); }; return (
{uploadProgress > 0 && (
Upload Progress: {uploadProgress.toFixed(1)}%
)}
); } ``` -------------------------------- ### JavaScript: Use useUserRole Hook for RBAC Source: https://context7.com/leaksopan/sipandai/llms.txt Demonstrates the usage of the `useUserRole` hook in a React component for implementing role-based access control. It shows how to check permissions, manage user roles, and conditionally render UI elements based on user roles and permissions. Assumes the existence of the `useUserRole` hook and its associated logic. ```javascript // Example usage in a component import useUserRole from './hooks/useUserRole'; function ProtectedFeature() { const { userRole, loading, hasPermission, updateUserRole, getRoleLabel, isSuperAdmin, isIrban, isAuditor, isGuest, ROLES, ROLE_LABELS } = useUserRole(); // Check specific permission const canUploadFiles = hasPermission('canUploadFiles'); const canDeleteFiles = hasPermission('canDeleteFiles'); const canManageUsers = hasPermission('canManageRoles'); const canAccessAllFiles = hasPermission('canAccessAllFiles'); // Update user role (admin only) const promoteUser = async (userId) => { try { const success = await updateUserRole(userId, ROLES.IRBAN); if (success) { console.log('User promoted to Irban role'); } } catch (err) { console.error('Failed to update role:', err); } }; // Role-based UI rendering if (loading) return
Loading permissions...
; return (

User Role: {getRoleLabel(userRole?.role)}

{/* Conditional rendering based on permissions */} {canUploadFiles && ( )} {canDeleteFiles && ( )} {/* Role-specific features */} {isSuperAdmin && (

Admin Panel

)} {isGuest && (

You have limited access. Apply for staff role to unlock features.

)} {/* Display all available roles */}
); } // Permission matrix by role: // super_admin: All permissions enabled // Irban: File operations + folder management, no user management // Auditor: View and upload files, limited folder operations // guest: No file or system access ``` -------------------------------- ### React Staff Application Form Component (JavaScript) Source: https://context7.com/leaksopan/sipandai/llms.txt A React component for guest users to submit staff applications. It manages form state using `useState` and interacts with the `submitStaffApplication` function. It displays a confirmation message upon successful submission. ```javascript // Example: Application form component (guest user) function StaffApplicationForm() { const [formData, setFormData] = useState({ nama: '', section: '' }); const [submitted, setSubmitted] = useState(false); const { user } = useAuth(); const handleSubmit = async (e) => { e.preventDefault(); await submitStaffApplication(user, formData); setSubmitted(true); }; if (submitted) { return (

Application Submitted

Your application has been submitted and is pending approval.

); } return (

Apply for Staff Role

setFormData({ ...formData, nama: e.target.value })} required />
); } ``` -------------------------------- ### UseAuth Hook for Authentication State Management Source: https://context7.com/leaksopan/sipandai/llms.txt A custom React hook that encapsulates authentication logic, providing user state, loading status, error handling, and functions for Google OAuth login, email/password login, registration, and logout. It simplifies authentication flow in React components. ```javascript // Example usage in a component import useAuth from './hooks/useAuth'; function LoginComponent() { const { user, loading, error, handleGoogleLogin, handleEmailPasswordLogin, handleEmailPasswordRegister, handleLogout } = useAuth(); // Google OAuth login const loginWithGoogle = async () => { try { await handleGoogleLogin(); console.log('Logged in successfully with Google'); } catch (err) { console.error('Login failed:', err); } }; // Email/password login const loginWithEmail = async () => { try { await handleEmailPasswordLogin('user@example.com', 'password123'); console.log('Logged in successfully with email'); } catch (err) { console.error('Login failed:', err); } }; // Register new user with email/password const registerUser = async () => { try { await handleEmailPasswordRegister( 'newuser@example.com', 'securePassword123', 'John Doe' ); console.log('User registered and logged in'); // User automatically created in Firestore with role: "guest" } catch (err) { console.error('Registration failed:', err); } }; // Logout const logout = async () => { try { await handleLogout(); console.log('Logged out successfully'); } catch (err) { console.error('Logout failed:', err); } }; if (loading) return
Loading...
; if (error) return
Error: {error}
; return user ? (

Welcome, {user.displayName}

) : (
); } ``` -------------------------------- ### Display Recent Activity Logs in React Source: https://context7.com/leaksopan/sipandai/llms.txt This React component, ActivityLogsViewer, displays a list of recent activity logs fetched from Firebase. It uses the `useEffect` hook to load logs when the component mounts or when user permissions change. Access to the logs is controlled by a `hasPermission` function, and logs are rendered in an HTML table. Dependencies include React hooks (`useState`, `useEffect`) and a custom hook `useUserRole`. ```javascript // Example: Activity logs viewer function ActivityLogsViewer() { const [logs, setLogs] = useState([]); const { hasPermission } = useUserRole(); useEffect(() => { if (hasPermission('canViewLogs')) { loadRecentLogs(100).then(setLogs); } }, [hasPermission]); if (!hasPermission('canViewLogs')) { return
Access Denied
; } return (

Activity Logs

{logs.map(log => ( ))}
Timestamp User Action Target Details
{new Date(log.createdAt).toLocaleString()} {log.userName} ({log.userEmail}) {log.action} {log.targetType}: {log.targetName} {log.details}
); } ``` -------------------------------- ### Log User Actions with Firebase Source: https://context7.com/leaksopan/sipandai/llms.txt This JavaScript utility logs user activities to a Firebase Firestore collection named 'activityLogs'. It captures details like user information, action performed, target of the action, and a timestamp. It uses Firebase SDK for database operations and includes constants for predefined action and target types. Failures in logging do not disrupt the main application flow. ```javascript // Example: Activity logging utility import { collection, addDoc, serverTimestamp, query, orderBy, limit, getDocs } from 'firebase/firestore'; import { db } from './firebase/config'; // Log activity async function logActivity({ userEmail, userName, action, targetType, targetName, details = '' }) { try { await addDoc(collection(db, 'activityLogs'), { userEmail, userName, action, targetType, targetName, details, timestamp: serverTimestamp(), createdAt: new Date().toISOString() }); } catch (error) { console.error('Failed to log activity:', error); // Don't throw - logging failures shouldn't break main operations } } // Action and target type constants const ACTION_TYPES = { FILE_UPLOAD: 'UPLOAD FILE', FILE_DELETE: 'DELETE FILE', FILE_RENAME: 'RENAME FILE', FILE_DOWNLOAD: 'DOWNLOAD FILE', FOLDER_CREATE: 'CREATE FOLDER', FOLDER_DELETE: 'DELETE FOLDER', USER_ROLE_CHANGE: 'CHANGE USER ROLE', LOGIN: 'LOGIN', LOGOUT: 'LOGOUT' }; const TARGET_TYPES = { FILE: 'FILE', FOLDER: 'FOLDER', USER: 'USER', SYSTEM: 'SYSTEM' }; // Example: Log file upload async function uploadFileWithLogging(file, user) { try { // Upload file (simplified) const result = await uploadFileWithMetadata(file, '', user); // Log the activity await logActivity({ userEmail: user.email, userName: user.displayName, action: ACTION_TYPES.FILE_UPLOAD, targetType: TARGET_TYPES.FILE, targetName: file.name, details: `Size: ${(file.size / 1024).toFixed(2)} KB` }); return result; } catch (error) { console.error('Upload failed:', error); throw error; } } // Example: Log role change async function updateRoleWithLogging(userId, newRole, adminUser, targetUser) { try { await updateUserRole(userId, newRole); await logActivity({ userEmail: adminUser.email, userName: adminUser.displayName, action: ACTION_TYPES.USER_ROLE_CHANGE, targetType: TARGET_TYPES.USER, targetName: targetUser.email, details: `Changed role to ${newRole}` }); } catch (error) { console.error('Failed to update role:', error); throw error; } } // Load recent activity logs async function loadRecentLogs(maxLogs = 50) { try { const q = query( collection(db, 'activityLogs'), orderBy('timestamp', 'desc'), limit(maxLogs) ); const snapshot = await getDocs(q); const logs = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); return logs; } catch (error) { console.error('Failed to load logs:', error); throw error; } } ``` -------------------------------- ### Firestore Folder Operations with JavaScript Source: https://context7.com/leaksopan/sipandai/llms.txt Handles core folder management tasks in Firestore, including creation, retrieval, and deletion. It queries collections for 'folders' and 'files', allowing for user-specific access control. Dependencies include Firebase SDK for Firestore and potentially a custom authentication hook (`useAuth`) and user role hook (`useUserRole`). ```javascript import { collection, addDoc, query, where, getDocs, deleteDoc, doc } from 'firebase/firestore'; import { db } from './firebase/config'; // Create new folder async function createFolder(folderName, parentFolder, user) { try { const folderData = { name: folderName, parentFolder: parentFolder || '', userId: user.uid, userEmail: user.email, userName: user.displayName, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString() }; const docRef = await addDoc(collection(db, 'folders'), folderData); console.log('Folder created:', { id: docRef.id, name: folderName, path: parentFolder ? `${parentFolder}/${folderName}` : folderName }); return { id: docRef.id, ...folderData }; } catch (error) { console.error('Failed to create folder:', error); throw error; } } // Load folders and files for current path async function loadFolderContents(currentPath, user, hasFullAccess) { try { // Query folders let foldersQuery = query( collection(db, 'folders'), where('parentFolder', '==', currentPath) ); if (!hasFullAccess) { foldersQuery = query( collection(db, 'folders'), where('parentFolder', '==', currentPath), where('userId', '==', user.uid) ); } const foldersSnapshot = await getDocs(foldersQuery); const folders = foldersSnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); // Query files let filesQuery = query( collection(db, 'files'), where('folder', '==', currentPath) ); if (!hasFullAccess) { filesQuery = query( collection(db, 'files'), where('folder', '==', currentPath), where('userId', '==', user.uid) ); } const filesSnapshot = await getDocs(filesQuery); const files = filesSnapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); return { folders, files }; } catch (error) { console.error('Failed to load folder contents:', error); throw error; } } // Delete folder async function deleteFolder(folderId) { try { await deleteDoc(doc(db, 'folders', folderId)); console.log('Folder deleted:', folderId); } catch (error) { console.error('Failed to delete folder:', error); throw error; } } // Example usage in component function FolderManager() { const [currentPath, setCurrentPath] = useState(''); const [folders, setFolders] = useState([]); const [files, setFiles] = useState([]); const { user } = useAuth(); const { hasPermission } = useUserRole(); useEffect(() => { async function loadContents() { const hasFullAccess = hasPermission('canAccessAllFiles'); const contents = await loadFolderContents(currentPath, user, hasFullAccess); setFolders(contents.folders); setFiles(contents.files); } loadContents(); }, [currentPath, user]); const handleCreateFolder = async () => { const newFolder = await createFolder('New Folder', currentPath, user); setFolders([...folders, newFolder]); }; const handleFolderClick = (folderName) => { const newPath = currentPath ? `${currentPath}/${folderName}` : folderName; setCurrentPath(newPath); }; const handleGoBack = () => { const pathParts = currentPath.split('/'); pathParts.pop(); setCurrentPath(pathParts.join('/')); }; return (
Current Path: {currentPath || '/'}
{currentPath && }

Folders

{folders.map(folder => (
handleFolderClick(folder.name)}> 📁 {folder.name}
))}

Files

{files.map(file => (
📄 {file.name} ({(file.size / 1024).toFixed(2)} KB)
))}
); } ``` -------------------------------- ### JavaScript Firebase File Search and Filtering Functions Source: https://context7.com/leaksopan/sipandai/llms.txt Provides functions to search for files by name, filter by date range, and perform advanced searches with multiple criteria using Firebase Firestore. It relies on the 'firebase/firestore' library and a local 'firebase/config' file. Input includes search terms, date ranges, and filter objects. Output is an array of file objects. ```javascript import { collection, query, where, getDocs, orderBy } from 'firebase/firestore'; import { db } from './firebase/config'; // Search files by name async function searchFiles(searchTerm, currentFolder = '') { try { const filesRef = collection(db, 'files'); let q = query(filesRef); if (currentFolder) { q = query(filesRef, where('folder', '==', currentFolder)); } const snapshot = await getDocs(q); const allFiles = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); // Client-side filtering for name search const filtered = allFiles.filter(file => file.name.toLowerCase().includes(searchTerm.toLowerCase()) ); console.log(`Found ${filtered.length} files matching "${searchTerm}"`); return filtered; } catch (error) { console.error('Search failed:', error); throw error; } } // Filter files by date range async function filterFilesByDateRange(startDate, endDate, currentFolder = '') { try { let q = query(collection(db, 'files')); if (currentFolder) { q = query(q, where('folder', '==', currentFolder)); } const snapshot = await getDocs(q); const allFiles = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); // Filter by date range const filtered = allFiles.filter(file => { const fileDate = new Date(file.uploadedAt); const start = startDate ? new Date(startDate) : new Date(0); const end = endDate ? new Date(endDate) : new Date(); return fileDate >= start && fileDate <= end; }); console.log(`Found ${filtered.length} files between ${startDate} and ${endDate}`); return filtered; } catch (error) { console.error('Filter failed:', error); throw error; } } // Advanced search with multiple criteria async function advancedSearch(filters) { try { let q = query(collection(db, 'files')); const snapshot = await getDocs(q); let results = snapshot.docs.map(doc => ({ id: doc.id, ...doc.data() })); // Apply filters if (filters.name) { results = results.filter(file => file.name.toLowerCase().includes(filters.name.toLowerCase()) ); } if (filters.type) { results = results.filter(file => file.type && file.type.includes(filters.type) ); } if (filters.minSize) { results = results.filter(file => file.size >= filters.minSize); } if (filters.maxSize) { results = results.filter(file => file.size <= filters.maxSize); } if (filters.uploader) { results = results.filter(file => file.userEmail.toLowerCase().includes(filters.uploader.toLowerCase()) ); } if (filters.startDate && filters.endDate) { const start = new Date(filters.startDate); const end = new Date(filters.endDate); results = results.filter(file => { const fileDate = new Date(file.uploadedAt); return fileDate >= start && fileDate <= end; }); } // Sort by date, newest first results.sort((a, b) => new Date(b.uploadedAt) - new Date(a.uploadedAt) ); console.log(`Advanced search found ${results.length} results`); return results; } catch (error) { console.error('Advanced search failed:', error); throw error; } } ```