Files
LynkedUpPro_CRM/src/hooks/useGamification.js
T

160 lines
6.8 KiB
JavaScript

import { useMemo } from 'react';
const LEVEL_THRESHOLDS = [
{ level: 1, xp: 0, title: 'Rookie' },
{ level: 2, xp: 1000, title: 'Scout' },
{ level: 3, xp: 2500, title: 'Trekker' },
{ level: 4, xp: 5000, title: 'Pathfinder' },
{ level: 5, xp: 10000, title: 'Roof Warrior' },
{ level: 6, xp: 15000, title: 'Storm Chaser' },
{ level: 7, xp: 25000, title: 'Elite Operator' },
{ level: 8, xp: 40000, title: 'Neighborhood Boss' },
{ level: 9, xp: 60000, title: 'Commanding Officer' },
{ level: 10, xp: 100000, title: 'Legend' }
];
export const useGamification = (user, role = 'FIELD_AGENT') => {
return useMemo(() => {
if (!user) return null;
const xp = user.xp || 0;
// Calculate Level
let currentLevelObj = LEVEL_THRESHOLDS[0];
let nextLevelObj = LEVEL_THRESHOLDS[1];
for (let i = 0; i < LEVEL_THRESHOLDS.length; i++) {
if (xp >= LEVEL_THRESHOLDS[i].xp) {
currentLevelObj = LEVEL_THRESHOLDS[i];
nextLevelObj = LEVEL_THRESHOLDS[i + 1] || LEVEL_THRESHOLDS[i]; // Max level fallback
} else {
break;
}
}
const { level, title } = currentLevelObj;
// XP Progress
let xpProgress = 100;
let xpToNext = 0;
let nextLevelXp = nextLevelObj.xp;
let currentLevelBaseXp = currentLevelObj.xp;
if (level < LEVEL_THRESHOLDS[LEVEL_THRESHOLDS.length - 1].level) {
const range = nextLevelXp - currentLevelBaseXp;
const progress = xp - currentLevelBaseXp;
xpProgress = Math.min(100, Math.max(0, (progress / range) * 100));
xpToNext = nextLevelXp - xp;
}
// --- PHASE 3: CHECKPOINTS & STAGES ---
let STAGES = [];
if (role === 'OWNER') {
STAGES = [
{ id: 1, title: "Q1 Launch", requirement: { type: "onboarding", amount: 3 }, reward: { type: "coupon", name: "Territory Expansion", icon: "map" }, progress: 1, goal: 3 },
{ id: 2, title: "Market Domination", requirement: { type: "revenue", amount: 100 }, reward: { type: "giftcard", name: "Executive Suite Unlock", icon: "star" }, progress: 85, goal: 100 },
{ id: 3, title: "Empire Builder", requirement: { type: "deals", amount: 50 }, reward: { type: "cash", name: "Profit Share Tier 2", icon: "cash" }, progress: 20, goal: 50 }
];
} else if (role === 'ADMIN') {
STAGES = [
{ id: 1, title: "Squad Setup", requirement: { type: "recruits", amount: 5 }, reward: { type: "coupon", name: "Team Bonus Unlock", icon: "users" }, progress: 3, goal: 5 },
{ id: 2, title: "Territory Control", requirement: { type: "regions", amount: 4 }, reward: { type: "giftcard", name: "Admin Power-Up", icon: "zap" }, progress: 4, goal: 4 },
{ id: 3, title: "Regional Manager", requirement: { type: "sales", amount: 20 }, reward: { type: "cash", name: "Override Commission", icon: "cash" }, progress: 12, goal: 20 }
];
} else {
STAGES = [
{
id: 1,
title: "Daily Grind",
requirement: { type: "dailyQuests", amount: 5 },
reward: { type: "xp", name: "+500 XP Boost", icon: "zap" },
progress: 5,
goal: 5
},
{
id: 2,
title: "Door Warrior",
requirement: { type: "doorsKnocked", amount: 40 },
reward: { type: "coupon", name: "$25 Gift Card", icon: "gift" },
progress: 40,
goal: 40
},
{
id: 3,
title: "Lead Machine",
requirement: { type: "leadsGained", amount: 10 },
reward: { type: "cash", name: "$50 Cash Bonus", icon: "cash" },
progress: 4,
goal: 10
},
{
id: 4,
title: "Closer Mode",
requirement: { type: "appointmentsSet", amount: 5 },
reward: { type: "giftcard", name: "$100 Amazon", icon: "amazon" },
progress: 0,
goal: 5
},
{
id: 5,
title: "Legend Run",
requirement: { type: "deals", amount: 3 },
reward: { type: "cash", name: "$250 Bonus", icon: "cash" },
progress: 0,
goal: 3
}
];
}
// Determine lock states
const stages = STAGES.map((s, idx) => {
let status = "locked";
if (s.progress >= s.goal) {
status = "completed";
} else if (idx === 0 || STAGES[idx - 1].progress >= STAGES[idx - 1].goal) {
status = "in-progress";
}
return { ...s, status };
});
const activeStage = stages.find(s => s.status === "in-progress") || stages[stages.length - 1];
// --- PHASE 3: DETAILED BADGE ARCHITECTURE ---
// Mapping known string arrays from mockStore into detailed objects
const BADGE_DEFINITIONS = [
{ id: 'Hot Spot Hunter', title: "Hot Spot Hunter", desc: "Identify 10 high-damage zones.", criteria: "10 Hot Leads identified." },
{ id: 'Storm Chaser', title: "Storm Chaser", desc: "Canvass a territory within 48h of a storm.", criteria: "1 Storm deployed operation." },
{ id: 'Star Closer', title: "Star Closer", desc: "Maintain a 50% conversion rate.", criteria: "Convert 5 deals continuously." },
{ id: 'Map Master', title: "Map Master", desc: "Knock 500 total doors.", criteria: "500 Lifetime Doors." },
{ id: 'First Knock', title: "First Knock", desc: "Complete your first day in the field.", criteria: "Log your first shift." }
];
const badges = BADGE_DEFINITIONS.map(def => {
const isUnlocked = (user.achievements || []).includes(def.id);
return { ...def, status: isUnlocked ? 'unlocked' : 'locked' };
});
// Derived Stats
const stats = {
doorsKnocked: user.doorsKnocked || 0,
leadsGained: user.leadsGained || 0,
appointmentsSet: user.appointmentsSet || 0,
streakDays: user.streakDays || 0,
};
return {
level,
title,
currentXp: xp,
nextLevelXp,
xpProgress,
xpToNext,
stats,
badges,
stages,
activeStage,
achievements: user.achievements || [] // keeping for legacy
};
}, [user]);
};