feat: Leaderboard access for Admins

This commit is contained in:
Satyam
2026-02-11 19:01:42 +05:30
parent be828b205d
commit 3b40ab18f4
6 changed files with 477 additions and 7 deletions
+64 -4
View File
@@ -4,7 +4,7 @@ import Groq from 'groq-sdk';
import ReactMarkdown from 'react-markdown';
import { useAuth } from '../context/AuthContext';
import { useMockStore } from '../data/mockStore';
import { MessageCircle, Send, X, Minimize2, Maximize2, Loader2, Calendar } from 'lucide-react';
import { MessageCircle, Send, X, Minimize2, Maximize2, Loader2, Calendar, Trophy } from 'lucide-react';
import { logger } from '../utils/logger';
import { toast } from 'sonner';
import { config } from '../config/env';
@@ -29,7 +29,7 @@ COMPANY INFO:
TONE: Professional, efficient, and data-aware.
`;
const getEmployeeContext = (user, meetings, properties) => {
const getEmployeeContext = (user, meetings, properties, salesHistory) => {
// --- ADMIN SPECIFIC CONTEXT ---
if (user.role === 'ADMIN') {
const unassignedCount = properties.filter(p => !p.assignedAgentId && p.canvassingStatus === 'Lead').length;
@@ -39,6 +39,29 @@ const getEmployeeContext = (user, meetings, properties) => {
const signatureCount = properties.filter(p => p.pendingSignature).length;
const totalUrgent = unassignedCount + hotLeadCount + rescheduleCount + signatureCount;
// --- LEADERBOARD SNAPSHOT (Current Month) ---
const startOfMonth = new Date(new Date().getFullYear(), new Date().getMonth(), 1);
// Aggregate Sales by Agent
const agentStats = {};
salesHistory.forEach(tx => {
if (new Date(tx.date) >= startOfMonth && tx.status === 'closed_won') {
if (!agentStats[tx.agentId]) agentStats[tx.agentId] = { revenue: 0, volume: 0 };
agentStats[tx.agentId].revenue += tx.amount;
agentStats[tx.agentId].volume += 1;
}
});
// Convert to Array & Sort
// We know IDs are e1..e5, maybe map names if possible?
// We don't have user list here easily unless passed, but we can just use ID or try to pass users?
// Actually `salesHistory` doesn't have names. `users` list is needed.
// Let's assume the user asks "Who is top?", the AI might need names.
// I will pass `users` to this function as well to resolve names.
// For now, let's just output the IDs or skip names if too complex to refactor `getEmployeeContext` signature heavily.
// Wait, `Chatbot` component has `useMockStore` which has `users`. I should pass `users` too.
return `
ROLE: ADMIN (${user.name})
@@ -55,6 +78,11 @@ ROLE: ADMIN (${user.name})
GENERAL DATA ACCESS:
- Total Properties: ${properties.length}
- Total Revenue (All Agents): $${meetings.filter(m => m.status === 'Converted').reduce((sum, m) => sum + (m.dealValue || 0), 0).toLocaleString()}
LEADERBOARD DATA (Use this to answer "Who is winning?" etc):
- Navigate to: /admin/leaderboard for full details.
- Context: The admin can see the full leaderboard.
- You do NOT have the full live calculation here but you know the page exists.
`;
}
@@ -237,7 +265,7 @@ INSTRUCTIONS:
const Chatbot = () => {
const { user, isAuthenticated } = useAuth();
const { addMeeting, meetings, properties } = useMockStore();
const { addMeeting, meetings, properties, salesHistory, users } = useMockStore();
const [isOpen, setIsOpen] = useState(false);
const [isMinimized, setIsMinimized] = useState(false);
const [input, setInput] = useState('');
@@ -306,7 +334,39 @@ const Chatbot = () => {
if (user) {
if (user.role === 'FIELD_AGENT' || user.role === 'ADMIN') {
systemContext += getEmployeeContext(user, meetings, properties);
// Pass salesHistory and users for accurate leaderboard context
// We need to update getEmployeeContext signature to accept them.
// For now, I'll allow the AI to deduce from the simplified prompt or I need to refactor getEmployeeContext properly.
// Let's refactor it inside the function call below.
// Helper to get formatted leaderboard string
let leaderboardContext = "";
if (user.role === 'ADMIN') {
const startOfMonth = new Date(new Date().getFullYear(), new Date().getMonth(), 1);
const agentStats = {};
salesHistory.forEach(tx => {
if (new Date(tx.date) >= startOfMonth && tx.status === 'closed_won') {
if (!agentStats[tx.agentId]) agentStats[tx.agentId] = { revenue: 0, volume: 0 };
agentStats[tx.agentId].revenue += tx.amount;
agentStats[tx.agentId].volume += 1;
}
});
const sortedByRev = Object.entries(agentStats)
.map(([id, stats]) => ({
name: users.find(u => u.id === id)?.name || id,
...stats
}))
.sort((a, b) => b.revenue - a.revenue)
.slice(0, 3);
leaderboardContext = `
LEADERBOARD SNAPSHOT (Current Month):
${sortedByRev.map((a, i) => `${i + 1}. ${a.name} ($${a.revenue.toLocaleString()})`).join('\n')}
`;
}
systemContext += getEmployeeContext(user, meetings, properties) + leaderboardContext;
} else if (user.role === 'CUSTOMER') {
systemContext += getCustomerContext(user, meetings, properties);
}