feat(Makefile): install frontend dependencies on dev command

feat(Makefile): patch Layout.jsx queryKey for local development
feat(frontend-web): mock base44 client for local development with role switching
feat(frontend-web): add event assignment modal with conflict detection and bulk assign
feat(frontend-web): add client dashboard with key metrics and quick actions
feat(frontend-web): add layout component with role-based navigation
feat(frontend-web): update various pages to use "@/components" alias
feat(frontend-web): update create event page with ai assistant toggle
feat(frontend-web): update dashboard page with new components
feat(frontend-web): update events page with quick assign popover
feat(frontend-web): update invite vendor page with hover card
feat(frontend-web): update messages page with conversation list and message thread
feat(frontend-web): update operator dashboard page with new components
feat(frontend-web): update partner management page with new components
feat(frontend-web): update permissions page with new components
feat(frontend-web): update procurement dashboard page with new components
feat(frontend-web): update smart vendor onboarding page with new components
feat(frontend-web): update staff directory page with new components
feat(frontend-web): update teams page with new components
feat(frontend-web): update user management page with new components
feat(frontend-web): update vendor compliance page with new components
feat(frontend-web): update main.jsx to include react query provider

feat: add vendor marketplace page
feat: add global import fix to prepare-export script
feat: add patch-layout-query-key script to fix query key
feat: update patch-base44-client script to use a more robust method
This commit is contained in:
bwnyasse
2025-11-13 14:56:31 -05:00
parent f449272ef0
commit 80cd49deb5
49 changed files with 2937 additions and 1508 deletions

View File

@@ -4,22 +4,6 @@ const path = require('path');
const projectRoot = path.resolve(__dirname, '..');
const clientFilePath = path.join(projectRoot, 'frontend-web', 'src', 'api', 'base44Client.js');
const originalMock = `// import { createClient } from '@base44/sdk';
// --- MIGRATION MOCK ---
// This mock completely disables the Base44 SDK to allow for local development.
export const base44 = {
auth: {
me: () => Promise.resolve(null),
logout: () => {},
},
entities: {
ActivityLog: {
filter: () => Promise.resolve([]),
},
},
};`;
const patchedMock = `// import { createClient } from '@base44/sdk';
// --- MIGRATION MOCK ---
@@ -98,26 +82,19 @@ export const base44 = {
};`;
try {
let content = fs.readFileSync(clientFilePath, 'utf8');
const content = fs.readFileSync(clientFilePath, 'utf8');
if (content.includes('me: () => Promise.resolve(null),')) {
content = content.replace(originalMock.trim(), patchedMock.trim());
fs.writeFileSync(clientFilePath, content, 'utf8');
// Check if the file is the original, unpatched version from the export
if (content.includes("createClient({")) {
fs.writeFileSync(clientFilePath, patchedMock, 'utf8');
console.log('✅ Successfully patched frontend-web/src/api/base44Client.js');
} else if (content.includes('const MOCK_USER_KEY')) {
} else if (content.includes("const MOCK_USER_KEY")) {
console.log(' base44Client.js is already patched. Skipping.');
} else {
// Fallback to a simpler, more brittle replacement if the full mock doesn't match
const simpleOriginal = 'me: () => Promise.resolve(null),';
if (content.includes(simpleOriginal)) {
fs.writeFileSync(clientFilePath, patchedMock, 'utf8');
console.log('✅ Successfully patched frontend-web/src/api/base44Client.js using fallback.');
} else {
console.error('❌ Patching failed: Could not find the original mock code in base44Client.js.');
process.exit(1);
}
console.error('❌ Patching failed: Could not find the expected code in base44Client.js. The export format may have changed.');
process.exit(1);
}
} catch (error) {
console.error('❌ An error occurred during patching:', error);
process.exit(1);
}
}

View File

@@ -0,0 +1,26 @@
const fs = require('fs');
const path = require('path');
const projectRoot = path.resolve(__dirname, '..');
const layoutFilePath = path.join(projectRoot, 'frontend-web', 'src', 'pages', 'Layout.jsx');
const oldString = ` queryKey: ['current-user-layout'],`;
const newString = ` queryKey: ['current-user'],`;
try {
const content = fs.readFileSync(layoutFilePath, 'utf8');
if (content.includes(oldString)) {
const newContent = content.replace(oldString, newString);
fs.writeFileSync(layoutFilePath, newContent, 'utf8');
console.log('✅ Successfully patched queryKey in frontend-web/src/pages/Layout.jsx');
} else if (content.includes(newString)) {
console.log(' queryKey in Layout.jsx is already patched. Skipping.');
} else {
console.error('❌ Patching failed: Could not find the expected queryKey in Layout.jsx.');
process.exit(1);
}
} catch (error) {
console.error('❌ An error occurred during patching Layout.jsx queryKey:', error);
process.exit(1);
}

View File

@@ -8,79 +8,74 @@ const __dirname = path.dirname(__filename);
const projectRoot = path.join(__dirname, '..', 'frontend-web');
// --- Fonctions de Patch ---
// --- Patching Functions ---
function applyPatch(filePath, patchInfo) {
const fullPath = path.join(projectRoot, filePath);
if (!fs.existsSync(fullPath)) {
console.warn(`🟡 Fichier non trouvé, patch ignoré : ${filePath}`);
console.warn(`🟡 File not found, patch skipped: ${filePath}`);
return;
}
let content = fs.readFileSync(fullPath, 'utf8');
if (content.includes(patchInfo.new_string)) {
console.log(`✅ Patch déjà appliqué dans ${filePath} (recherche de '${patchInfo.search_string}').`);
if (patchInfo.new_string && content.includes(patchInfo.new_string)) {
console.log(`✅ Patch already applied in ${filePath}.`);
return;
}
if (content.includes(patchInfo.old_string)) {
if (patchInfo.old_string && content.includes(patchInfo.old_string)) {
content = content.replace(patchInfo.old_string, patchInfo.new_string);
fs.writeFileSync(fullPath, content, 'utf8');
console.log(`🟢 Patch appliqué dans ${filePath} (remplacement de '${patchInfo.search_string}').`);
console.log(`🟢 Patch applied in ${filePath}.`);
} else {
console.error(`🔴 Impossible d'appliquer le patch dans ${filePath}. Chaîne non trouvée : '${patchInfo.search_string}'.`);
console.error(`🔴 Could not apply patch in ${filePath}. String not found.`);
}
}
// --- Définition des Patches ---
// --- Global Import Fix ---
const patches = [
{
file: 'src/api/base44Client.js',
search_string: 'createClient',
old_string: `import { createClient } from '@base44/sdk';
// import { getAccessToken } from '@base44/sdk/utils/auth-utils';
function fixAllComponentImports(directory) {
const entries = fs.readdirSync(directory, { withFileTypes: true });
// Create a client with authentication required
export const base44 = createClient({
appId: "68fc6cf01386035c266e7a5d",
requiresAuth: true // Ensure authentication is required for all operations
});`,
new_string: `// import { createClient } from '@base44/sdk';
for (const entry of entries) {
const fullPath = path.join(directory, entry.name);
if (entry.isDirectory()) {
// Recursively search in subdirectories
fixAllComponentImports(fullPath);
} else if (entry.isFile() && (entry.name.endsWith('.jsx') || entry.name.endsWith('.js'))) {
let content = fs.readFileSync(fullPath, 'utf8');
const originalContent = content;
// Regex to find all relative imports to the components directory
// Handles: from "./components/", from "../components/", from "../../components/", etc.
const importRegex = /from\s+(['"])((\.\.\/)+|\.\/)components\//g;
content = content.replace(importRegex, 'from $1@/components/');
// --- MIGRATION MOCK ---
// This mock completely disables the Base44 SDK to allow for local development.
export const base44 = {
auth: {
me: () => Promise.resolve(null),
logout: () => {},
},
entities: {
ActivityLog: {
filter: () => Promise.resolve([]),
},
},
};
`
},
{
file: 'src/main.jsx',
search_string:
`ReactDOM.createRoot(document.getElementById('root')).render(`,
old_string: `import React from 'react'
import ReactDOM from 'react-dom/client'
import App from '@/App.jsx'
import '@/index.css'
if (content !== originalContent) {
console.log(`✅ Fixing component imports in ${fullPath}`);
fs.writeFileSync(fullPath, content, 'utf8');
}
}
}
}
ReactDOM.createRoot(document.getElementById('root')).render(
// --- Exécution ---
function main() {
console.log('--- Applying patches for local environment ---');
// The specific patches are now less critical as the global fix is more robust,
// but we can keep them for specific, non-import related changes.
const patches = [
{
file: 'src/main.jsx',
old_string: `ReactDOM.createRoot(document.getElementById('root')).render(
<App />
)`,
new_string: `import React from 'react'
import ReactDOM from 'react-dom/client'
import App from '@/App.jsx'
import '@/index.css'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
new_string: `import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
@@ -90,17 +85,15 @@ ReactDOM.createRoot(document.getElementById('root')).render(
<App />
</QueryClientProvider>
</React.StrictMode>,
)
`
},
{
file: 'src/pages/Layout.jsx',
search_string: `const { data: user } = useQuery`,
old_string: ` const { data: user } = useQuery({
)`
},
{
file: 'src/pages/Layout.jsx',
old_string: `const { data: user } = useQuery({
queryKey: ['current-user-layout'],
queryFn: () => base44.auth.me(),
});`,
new_string: ` // const { data: user } = useQuery({
new_string: ` // const { data: user } = useQuery({
// queryKey: ['current-user-layout'],
// queryFn: () => base44.auth.me(),
// });
@@ -113,90 +106,17 @@ ReactDOM.createRoot(document.getElementById('root')).render(
profile_picture: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
};
`
},
{
file: 'src/pages/Layout.jsx',
search_string: `const { data: unreadCount = 0 } = useQuery`,
old_string: ` const { data: unreadCount = 0 } = useQuery({
queryKey: ['unread-notifications', user?.id],
queryFn: async () => {
if (!user?.id) return 0;
const notifications = await base44.entities.ActivityLog.filter({
user_id: user?.id,
is_read: false
});
return notifications.length;
},
enabled: !!user?.id,
initialData: 0,
refetchInterval: 10000,
});`,
new_string: ` // Get unread notification count
// const { data: unreadCount = 0 } = useQuery({
const unreadCount = 0; // Mocked value`
},
{
file: 'src/pages/Layout.jsx',
search_string: 'import { Badge } from \"./components/ui/badge\"',
old_string: 'import { Badge } from \"./components/ui/badge\"',
new_string: 'import { Badge } from \"@/components/ui/badge\"',
},
{
file: 'src/pages/Layout.jsx',
search_string: 'import ChatBubble from \"./components/chat/ChatBubble\"',
old_string: 'import ChatBubble from \"./components/chat/ChatBubble\"',
new_string: 'import ChatBubble from \"@/components/chat/ChatBubble\"',
}
];
// --- Global Import Fix ---
function fixComponentImports(directory) {
const entries = fs.readdirSync(directory, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(directory, entry.name);
if (entry.isDirectory()) {
fixComponentImports(fullPath);
} else if (entry.isFile() && entry.name.endsWith('.jsx')) {
let content = fs.readFileSync(fullPath, 'utf8');
const originalContent = content;
// Regex to find all imports from "./components/" (with single or double quotes)
const importRegex = /from\s+(['"])\.\/components\//g;
content = content.replace(importRegex, 'from $1@/components/');
// This specifically handles the badge import which might be different
content = content.replace('from "./components/ui/badge"', 'from "@/components/ui/badge"');
content = content.replace('from "./components/chat/ChatBubble"', 'from "@/components/chat/ChatBubble"');
content = content.replace('from "./components/dev/RoleSwitcher"', 'from "@/components/dev/RoleSwitcher"');
content = content.replace('from "./components/notifications/NotificationPanel"', 'from "@/components/notifications/NotificationPanel"');
content = content.replace('from "./components/ui/toaster"', 'from "@/components/ui/toaster"');
if (content !== originalContent) {
console.log(` Glogal import fix appliqué dans ${fullPath}`);
fs.writeFileSync(fullPath, content, 'utf8');
}
}
}
}
];
// --- Exécution ---
function main() {
console.log('--- Application des patchs pour l\'environnement local ---');
patches.forEach(patchInfo => {
applyPatch(patchInfo.file, patchInfo);
});
console.log('--- Correction globale des imports de composants ---');
fixComponentImports(path.join(projectRoot, 'src'));
console.log('--- Global component import fixes ---');
fixAllComponentImports(path.join(projectRoot, 'src'));
console.log('--- Fin de l\'application des patchs ---');
console.log('--- End of patching process ---');
}
main();
main();