forked from sagnik/Project_Velocity
338 lines
9.9 KiB
TypeScript
338 lines
9.9 KiB
TypeScript
import { create } from 'zustand';
|
|
import { persist } from 'zustand/middleware';
|
|
import type {
|
|
ModuleId,
|
|
User,
|
|
ChatMessage,
|
|
Lead,
|
|
Visitor,
|
|
DashboardMetrics,
|
|
LeadVelocityData,
|
|
Unit,
|
|
SystemStatus
|
|
} from '@/types';
|
|
|
|
// Auth State
|
|
interface AuthState {
|
|
isAuthenticated: boolean;
|
|
user: User | null;
|
|
login: (user: User) => void;
|
|
logout: () => void;
|
|
}
|
|
|
|
// Navigation State
|
|
interface NavigationState {
|
|
activeModule: ModuleId;
|
|
sidebarExpanded: boolean;
|
|
setActiveModule: (module: ModuleId) => void;
|
|
toggleSidebar: () => void;
|
|
setSidebarExpanded: (expanded: boolean) => void;
|
|
}
|
|
|
|
// Oracle State
|
|
interface OracleState {
|
|
leads: Lead[];
|
|
activeLeadId: string | null;
|
|
messages: Record<string, ChatMessage[]>;
|
|
isOracleThinking: boolean;
|
|
setActiveLead: (leadId: string | null) => void;
|
|
addMessage: (leadId: string, message: ChatMessage) => void;
|
|
setOracleThinking: (thinking: boolean) => void;
|
|
markLeadAsRead: (leadId: string) => void;
|
|
}
|
|
|
|
// Sentinel State
|
|
interface SentinelState {
|
|
visitors: Visitor[];
|
|
isAlertActive: boolean;
|
|
alertMessage: string;
|
|
addVisitor: (visitor: Visitor) => void;
|
|
removeVisitor: (visitorId: string) => void;
|
|
triggerAlert: (message: string) => void;
|
|
clearAlert: () => void;
|
|
}
|
|
|
|
// Dashboard State
|
|
interface DashboardState {
|
|
metrics: DashboardMetrics;
|
|
velocityData: LeadVelocityData[];
|
|
updateMetrics: (metrics: Partial<DashboardMetrics>) => void;
|
|
addVelocityDataPoint: (data: LeadVelocityData) => void;
|
|
}
|
|
|
|
// Inventory State
|
|
interface InventoryState {
|
|
units: Unit[];
|
|
selectedUnitId: string | null;
|
|
filterStatus: Unit['status'] | 'all';
|
|
setSelectedUnit: (unitId: string | null) => void;
|
|
setFilterStatus: (status: Unit['status'] | 'all') => void;
|
|
}
|
|
|
|
// System State
|
|
interface SystemState {
|
|
status: SystemStatus;
|
|
updateStatus: (status: Partial<SystemStatus>) => void;
|
|
}
|
|
|
|
// Combined Store
|
|
interface StoreState extends
|
|
AuthState,
|
|
NavigationState,
|
|
OracleState,
|
|
SentinelState,
|
|
DashboardState,
|
|
InventoryState,
|
|
SystemState { }
|
|
|
|
// Mock Data
|
|
const mockLeads: Lead[] = [
|
|
{
|
|
id: '1',
|
|
name: 'Mohammed Al-Rashid',
|
|
phone: '+971 55 123 4567',
|
|
source: 'whatsapp',
|
|
status: 'hot',
|
|
lastMessage: 'Can we schedule a viewing for the penthouse tomorrow?',
|
|
lastActive: new Date(Date.now() - 1000 * 60 * 5),
|
|
unreadCount: 2,
|
|
qualification: 'whale',
|
|
budget: 'AED 15M+',
|
|
interest: 'Penthouse Suite',
|
|
},
|
|
{
|
|
id: '2',
|
|
name: 'Sarah Chen',
|
|
phone: '+971 50 987 6543',
|
|
source: 'walkin',
|
|
status: 'engaged',
|
|
lastMessage: 'Thank you for the brochure. I will review with my partner.',
|
|
lastActive: new Date(Date.now() - 1000 * 60 * 30),
|
|
unreadCount: 0,
|
|
qualification: 'potential',
|
|
budget: 'AED 5-8M',
|
|
interest: '2 Bedroom Sea View',
|
|
},
|
|
{
|
|
id: '3',
|
|
name: 'James Wilson',
|
|
phone: '+971 52 456 7890',
|
|
source: 'website',
|
|
status: 'new',
|
|
lastMessage: 'Interested in investment opportunities.',
|
|
lastActive: new Date(Date.now() - 1000 * 60 * 60 * 2),
|
|
unreadCount: 1,
|
|
qualification: 'potential',
|
|
budget: 'AED 3-5M',
|
|
interest: '1 Bedroom Investment',
|
|
},
|
|
{
|
|
id: '4',
|
|
name: 'Fatima Hassan',
|
|
phone: '+971 54 321 0987',
|
|
source: 'whatsapp',
|
|
status: 'qualified',
|
|
lastMessage: 'What are the payment plan options?',
|
|
lastActive: new Date(Date.now() - 1000 * 60 * 60 * 4),
|
|
unreadCount: 0,
|
|
qualification: 'whale',
|
|
budget: 'AED 12M+',
|
|
interest: '3 Bedroom + Maid',
|
|
},
|
|
{
|
|
id: '5',
|
|
name: 'David Kumar',
|
|
phone: '+971 56 789 0123',
|
|
source: 'walkin',
|
|
status: 'closed',
|
|
lastMessage: 'Contract signed. Thank you!',
|
|
lastActive: new Date(Date.now() - 1000 * 60 * 60 * 24),
|
|
unreadCount: 0,
|
|
qualification: 'whale',
|
|
budget: 'AED 20M',
|
|
interest: 'Full Floor',
|
|
},
|
|
];
|
|
|
|
const mockMessages: Record<string, ChatMessage[]> = {
|
|
'1': [
|
|
{
|
|
id: 'm1',
|
|
sender: 'user',
|
|
content: 'Hi, I am interested in the penthouse units.',
|
|
timestamp: new Date(Date.now() - 1000 * 60 * 60 * 2),
|
|
},
|
|
{
|
|
id: 'm2',
|
|
sender: 'oracle',
|
|
content: 'Welcome! Our penthouse collection features 4 exclusive units with panoramic sea views. Prices start at AED 15M. Would you like to know more about specific floor plans?',
|
|
timestamp: new Date(Date.now() - 1000 * 60 * 60 * 2 + 1000 * 30),
|
|
},
|
|
{
|
|
id: 'm3',
|
|
sender: 'user',
|
|
content: 'Can we schedule a viewing for the penthouse tomorrow?',
|
|
timestamp: new Date(Date.now() - 1000 * 60 * 5),
|
|
},
|
|
],
|
|
'2': [
|
|
{
|
|
id: 'm4',
|
|
sender: 'oracle',
|
|
content: 'Hello Sarah! Thank you for visiting our Experience Center today. Here is the digital brochure for the 2-bedroom units we discussed.',
|
|
timestamp: new Date(Date.now() - 1000 * 60 * 60 * 4),
|
|
},
|
|
{
|
|
id: 'm5',
|
|
sender: 'user',
|
|
content: 'Thank you for the brochure. I will review with my partner.',
|
|
timestamp: new Date(Date.now() - 1000 * 60 * 30),
|
|
},
|
|
],
|
|
};
|
|
|
|
const mockVisitors: Visitor[] = [
|
|
{
|
|
id: 'v1',
|
|
faceId: 'face_001',
|
|
sentiment: 'excited',
|
|
confidence: 0.92,
|
|
dwellTime: 450,
|
|
zone: 'Penthouse Showroom',
|
|
timestamp: new Date(),
|
|
},
|
|
{
|
|
id: 'v2',
|
|
faceId: 'face_002',
|
|
sentiment: 'interested',
|
|
confidence: 0.87,
|
|
dwellTime: 320,
|
|
zone: 'Amenity Deck VR',
|
|
timestamp: new Date(),
|
|
},
|
|
{
|
|
id: 'v3',
|
|
faceId: 'face_003',
|
|
sentiment: 'neutral',
|
|
confidence: 0.78,
|
|
dwellTime: 180,
|
|
zone: 'Reception',
|
|
timestamp: new Date(),
|
|
},
|
|
];
|
|
|
|
const mockVelocityData: LeadVelocityData[] = Array.from({ length: 12 }, (_, i) => ({
|
|
time: `${9 + Math.floor(i / 2)}:${i % 2 === 0 ? '00' : '30'}`,
|
|
generated: Math.floor(Math.random() * 8) + 2,
|
|
closed: Math.floor(Math.random() * 3),
|
|
}));
|
|
|
|
const mockUnits: Unit[] = [
|
|
{ id: 'u1', unitNumber: 'PH-01', type: 'penthouse', floor: 45, area: 520, price: 25000000, status: 'available', view: 'Panoramic Sea', lastUpdated: new Date() },
|
|
{ id: 'u2', unitNumber: 'PH-02', type: 'penthouse', floor: 45, area: 480, price: 22000000, status: 'reserved', view: 'Sea & Marina', lastUpdated: new Date() },
|
|
{ id: 'u3', unitNumber: '4501', type: '3br', floor: 45, area: 280, price: 12000000, status: 'available', view: 'Sea View', lastUpdated: new Date() },
|
|
{ id: 'u4', unitNumber: '4502', type: '3br', floor: 45, area: 265, price: 11500000, status: 'sold', view: 'Marina View', lastUpdated: new Date() },
|
|
{ id: 'u5', unitNumber: '4401', type: '2br', floor: 44, area: 180, price: 7500000, status: 'available', view: 'Sea View', lastUpdated: new Date() },
|
|
{ id: 'u6', unitNumber: '4402', type: '2br', floor: 44, area: 175, price: 7200000, status: 'hold', view: 'City View', lastUpdated: new Date() },
|
|
{ id: 'u7', unitNumber: '4301', type: '1br', floor: 43, area: 95, price: 4200000, status: 'available', view: 'Sea View', lastUpdated: new Date() },
|
|
{ id: 'u8', unitNumber: '4302', type: '1br', floor: 43, area: 92, price: 4000000, status: 'available', view: 'City View', lastUpdated: new Date() },
|
|
];
|
|
|
|
export const useStore = create<StoreState>()(
|
|
persist(
|
|
(set) => ({
|
|
// Auth State
|
|
isAuthenticated: false,
|
|
user: null,
|
|
login: (user) => set({ isAuthenticated: true, user }),
|
|
logout: () => set({ isAuthenticated: false, user: null }),
|
|
|
|
// Navigation State
|
|
activeModule: 'dashboard',
|
|
sidebarExpanded: false,
|
|
setActiveModule: (module) => set({ activeModule: module }),
|
|
toggleSidebar: () => set((state) => ({ sidebarExpanded: !state.sidebarExpanded })),
|
|
setSidebarExpanded: (expanded) => set({ sidebarExpanded: expanded }),
|
|
|
|
// Oracle State
|
|
leads: mockLeads,
|
|
activeLeadId: null,
|
|
messages: mockMessages,
|
|
isOracleThinking: false,
|
|
setActiveLead: (leadId) => set({ activeLeadId: leadId }),
|
|
addMessage: (leadId, message) => set((state) => ({
|
|
messages: {
|
|
...state.messages,
|
|
[leadId]: [...(state.messages[leadId] || []), message],
|
|
},
|
|
})),
|
|
setOracleThinking: (thinking) => set({ isOracleThinking: thinking }),
|
|
markLeadAsRead: (leadId) => set((state) => ({
|
|
leads: state.leads.map((lead) =>
|
|
lead.id === leadId ? { ...lead, unreadCount: 0 } : lead
|
|
),
|
|
})),
|
|
|
|
// Sentinel State
|
|
visitors: mockVisitors,
|
|
isAlertActive: false,
|
|
alertMessage: '',
|
|
addVisitor: (visitor) => set((state) => ({
|
|
visitors: [...state.visitors, visitor]
|
|
})),
|
|
removeVisitor: (visitorId) => set((state) => ({
|
|
visitors: state.visitors.filter((v) => v.id !== visitorId),
|
|
})),
|
|
triggerAlert: (message) => set({ isAlertActive: true, alertMessage: message }),
|
|
clearAlert: () => set({ isAlertActive: false, alertMessage: '' }),
|
|
|
|
// Dashboard State
|
|
metrics: {
|
|
activeVisitors: 12,
|
|
todayLeads: 24,
|
|
closedDeals: 3,
|
|
conversionRate: 12.5,
|
|
sentiment: 78,
|
|
systemHealth: {
|
|
cpu: 34,
|
|
gpu: 28,
|
|
memory: 42,
|
|
temperature: 58,
|
|
},
|
|
},
|
|
velocityData: mockVelocityData,
|
|
updateMetrics: (metrics) => set((state) => ({
|
|
metrics: { ...state.metrics, ...metrics },
|
|
})),
|
|
addVelocityDataPoint: (data) => set((state) => ({
|
|
velocityData: [...state.velocityData.slice(1), data],
|
|
})),
|
|
|
|
// Inventory State
|
|
units: mockUnits,
|
|
selectedUnitId: null,
|
|
filterStatus: 'all',
|
|
setSelectedUnit: (unitId) => set({ selectedUnitId: unitId }),
|
|
setFilterStatus: (status) => set({ filterStatus: status }),
|
|
|
|
// System State
|
|
status: {
|
|
isConnected: true,
|
|
serverStatus: 'online',
|
|
lastSync: new Date(),
|
|
version: '2.1.0',
|
|
},
|
|
updateStatus: (status) => set((state) => ({
|
|
status: { ...state.status, ...status },
|
|
}))
|
|
}),
|
|
{
|
|
name: 'velocity-webos-storage',
|
|
partialize: (state) => ({
|
|
user: state.user,
|
|
activeModule: state.activeModule,
|
|
}),
|
|
}
|
|
)
|
|
);
|