HEX
Server: nginx/1.18.0
System: Linux vcwordpress 5.15.0-174-generic #184-Ubuntu SMP Fri Mar 13 18:41:50 UTC 2026 x86_64
User: root (0)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /var/www/igsms.viitorcloud.co/igsmsportal/App.tsx
import React, { useState, useMemo } from 'react';
import { UserRole, User, Grievance, GrievanceStatus } from './types';
import Sidebar from './components/Sidebar';
import CitizenDashboard from './views/CitizenDashboard';
import OfficerDashboard from './views/OfficerDashboard';
import AnalyticsOverview from './views/AnalyticsOverview';
import ProfileView from './views/ProfileView';
import Navbar from './components/Navbar';
import FloatingChatbot from './components/FloatingChatbot';

const INITIAL_GRIEVANCES: Grievance[] = [
  {
    id: '1', ticketNumber: 'GUJ-2023-8821', title: 'Water pipe leakage in Sector 24', description: 'The main supply pipe is leaking for the last 3 days causing significant water waste.', department: 'Water Resources', category: 'Pipeline Leakage', status: GrievanceStatus.IN_PROGRESS, createdAt: '2023-11-20T10:00:00Z', updatedAt: '2023-11-21T14:30:00Z', citizenName: 'Jayesh Patel', contactNumber: '9876543210', district: 'Gandhinagar', taluka: 'Gandhinagar', slaDeadline: '2023-11-23T10:00:00Z', priority: 'MEDIUM'
  },
  {
    id: '2', ticketNumber: 'GUJ-2023-1044', title: 'Garbage Collection Irregularity', description: 'Door to door garbage collection vehicle has not visited our society for the past 4 days.', department: 'Urban Development and Urban Housing', category: 'Sanitation', status: GrievanceStatus.PENDING, createdAt: new Date(Date.now() - 1000 * 3600 * 72).toISOString(), updatedAt: new Date(Date.now() - 1000 * 3600 * 2).toISOString(), citizenName: 'Jayesh Patel', contactNumber: '9876543210', district: 'Ahmedabad', taluka: 'Ahmedabad City', slaDeadline: new Date(Date.now() - 1000 * 3600 * 4).toISOString(), priority: 'URGENT'
  },
  {
    id: '3', ticketNumber: 'GUJ-2023-4412', title: 'Potholes on Highway 41', description: 'Large potholes formed after recent rains near the bypass.', department: 'Roads and Buildings', category: 'Road Maintenance', status: GrievanceStatus.ASSIGNED, createdAt: '2023-11-18T09:00:00Z', updatedAt: '2023-11-19T11:00:00Z', citizenName: 'Jayesh Patel', contactNumber: '9876543210', district: 'Rajkot', taluka: 'Rajkot', slaDeadline: '2023-11-25T09:00:00Z', priority: 'HIGH'
  },
  {
    id: '4', ticketNumber: 'GUJ-2023-5591', title: 'Land Encroachment on Public Path', description: 'Illegal construction starting on the common utility path in my village area.', department: 'Revenue', category: 'Encroachment', status: GrievanceStatus.ESCALATED, createdAt: '2023-11-15T14:20:00Z', updatedAt: '2023-11-20T09:15:00Z', citizenName: 'Jayesh Patel', contactNumber: '9876543210', district: 'Bhavnagar', taluka: 'Talaja', slaDeadline: '2023-11-22T14:20:00Z', priority: 'HIGH'
  },
  {
    id: '5', ticketNumber: 'GUJ-2023-1282', title: 'Primary Health Center Closed', description: 'The local PHC was closed during official hours when I went for my child vaccination.', department: 'Health and Family Welfare', category: 'Service Availability', status: GrievanceStatus.RESOLVED, createdAt: '2023-11-10T08:00:00Z', updatedAt: '2023-11-12T16:00:00Z', citizenName: 'Jayesh Patel', contactNumber: '9876543210', district: 'Surat', taluka: 'Choryasi', slaDeadline: '2023-11-17T08:00:00Z', priority: 'URGENT', resolutionRemarks: 'Staff has been issued a warning and regular attendance monitoring is now active.'
  },
  {
    id: '6', ticketNumber: 'GUJ-2023-3390', title: 'Streetlights Not Working', description: 'Entire street from Crossroad to Temple has no functioning lights for a week.', department: 'Urban Development and Urban Housing', category: 'Public Lighting', status: GrievanceStatus.IN_PROGRESS, createdAt: '2023-11-22T19:00:00Z', updatedAt: '2023-11-23T10:00:00Z', citizenName: 'Jayesh Patel', contactNumber: '9876543210', district: 'Vadodara', taluka: 'Vadodara', slaDeadline: '2023-11-26T19:00:00Z', priority: 'MEDIUM'
  },
  {
    id: '7', ticketNumber: 'GUJ-2023-7712', title: 'Delayed Seed Subsidy', description: 'Applied for groundnut seed subsidy 2 months ago, still no transfer in DBT account.', department: 'Agriculture, Farmers Welfare and Co-operation', category: 'Subsidy', status: GrievanceStatus.PENDING, createdAt: '2023-11-12T11:00:00Z', updatedAt: '2023-11-12T11:00:00Z', citizenName: 'Jayesh Patel', contactNumber: '9876543210', district: 'Jamnagar', taluka: 'Dhrol', slaDeadline: '2023-11-28T11:00:00Z', priority: 'MEDIUM'
  },
  {
    id: '8', ticketNumber: 'GUJ-2023-6623', title: 'Noise Pollution from Factory', description: 'Nearby small scale unit is operating heavy machinery late at night.', department: 'Home', category: 'Public Nuisance', status: GrievanceStatus.ASSIGNED, createdAt: '2023-11-21T23:30:00Z', updatedAt: '2023-11-22T08:00:00Z', citizenName: 'Jayesh Patel', contactNumber: '9876543210', district: 'Junagadh', taluka: 'Junagadh City', slaDeadline: '2023-11-24T23:30:00Z', priority: 'LOW'
  },
  {
    id: '9', ticketNumber: 'GUJ-2023-9901', title: 'Mid-day Meal Quality', description: 'The quality of food served at the Primary School in Sector 2 is substandard.', department: 'Education', category: 'Student Welfare', status: GrievanceStatus.RESOLVED, createdAt: '2023-11-05T12:00:00Z', updatedAt: '2023-11-07T14:00:00Z', citizenName: 'Jayesh Patel', contactNumber: '9876543210', district: 'Gandhinagar', taluka: 'Gandhinagar', slaDeadline: '2023-11-12T12:00:00Z', priority: 'HIGH', resolutionRemarks: 'Contractor has been replaced and a new kitchen supervisor appointed.'
  },
  {
    id: '10', ticketNumber: 'GUJ-2023-2110', title: 'Drainage Blockage in Society', description: 'Main manhole is overflowing onto the street, causing health hazard.', department: 'Urban Development and Urban Housing', category: 'Sewage', status: GrievanceStatus.PENDING, createdAt: '2023-11-23T06:00:00Z', updatedAt: '2023-11-23T06:00:00Z', citizenName: 'Jayesh Patel', contactNumber: '9876543210', district: 'Ahmedabad', taluka: 'Sabarmati', slaDeadline: '2023-11-25T06:00:00Z', priority: 'URGENT'
  }
];

const App: React.FC = () => {
  const [currentUser, setCurrentUser] = useState<User>({ id: '1', name: 'Jayesh Patel', role: UserRole.CITIZEN });
  const [grievances, setGrievances] = useState<Grievance[]>(INITIAL_GRIEVANCES);
  const [activeTab, setActiveTab] = useState<string>('dashboard');
  const [searchQuery, setSearchQuery] = useState<string>('');

  const addGrievance = (newGrievance: Grievance) => setGrievances(prev => [newGrievance, ...prev]);
  const updateGrievanceStatus = (id: string, status: GrievanceStatus) => setGrievances(prev => prev.map(g => g.id === id ? { ...g, status, updatedAt: new Date().toISOString() } : g));

  const handleUpdateUser = (updatedFields: Partial<User>) => {
    setCurrentUser(prev => ({ ...prev, ...updatedFields }));
  };

  const roleGrievances = useMemo(() => {
    switch (currentUser.role) {
      case UserRole.CITIZEN:
        return grievances.filter(g => g.citizenName === currentUser.name);
      case UserRole.OFFICER:
        // Prototype change: Show ALL grievances to the officer so the portal isn't empty
        // In production, this would be: grievances.filter(g => !currentUser.department || g.department === currentUser.department)
        return grievances;
      case UserRole.CMO:
        return grievances;
      default:
        return [];
    }
  }, [grievances, currentUser]);

  const filteredGrievances = useMemo(() => {
    if (!searchQuery.trim()) return roleGrievances;
    const query = searchQuery.toLowerCase().trim();
    return roleGrievances.filter(g => 
      g.ticketNumber.toLowerCase().includes(query) || 
      g.title.toLowerCase().includes(query) || 
      g.description.toLowerCase().includes(query)
    );
  }, [roleGrievances, searchQuery]);

  const handleRoleChange = (role: UserRole) => {
    const newUser: User = {
      id: role === UserRole.CITIZEN ? '1' : (role === UserRole.OFFICER ? '101' : '500'),
      name: role === UserRole.CITIZEN ? 'Jayesh Patel' : (role === UserRole.OFFICER ? 'Urban Officer' : 'Chief Secretary'),
      role,
      department: role === UserRole.OFFICER ? 'Urban Development and Urban Housing' : undefined
    };
    
    setCurrentUser(newUser);
    setActiveTab('dashboard');
    setSearchQuery('');
  };

  const renderContent = () => {
    if (activeTab === 'profile') {
      return <ProfileView user={currentUser} grievances={roleGrievances} onUpdateUser={handleUpdateUser} />;
    }

    switch (currentUser.role) {
      case UserRole.CITIZEN:
        return <CitizenDashboard activeTab={activeTab} grievances={filteredGrievances} onAddGrievance={addGrievance} />;
      case UserRole.OFFICER:
        return <OfficerDashboard activeTab={activeTab} user={currentUser} grievances={filteredGrievances} onUpdateStatus={updateGrievanceStatus} />;
      case UserRole.CMO:
        return <AnalyticsOverview activeTab={activeTab} grievances={filteredGrievances} />;
      default:
        return (
          <div className="h-96 flex flex-col items-center justify-center text-center p-12 bg-white rounded-[2.5rem] border border-slate-100 shadow-sm">
            <div className="w-16 h-16 bg-red-50 text-red-500 rounded-full flex items-center justify-center text-2xl mb-4">
              <i className="fa-solid fa-lock"></i>
            </div>
            <h3 className="text-xl font-black text-slate-800">Unauthorized Access</h3>
            <p className="text-slate-500 mt-2">You do not have the required permissions to view this dashboard.</p>
          </div>
        );
    }
  };

  return (
    <div className="flex h-screen bg-slate-50 font-sans overflow-hidden">
      <Sidebar role={currentUser.role} activeTab={activeTab} onTabChange={setActiveTab} />
      
      <div className="flex-1 flex flex-col min-w-0">
        <Navbar user={currentUser} onRoleChange={handleRoleChange} onSearch={setSearchQuery} />
        
        <main className="flex-1 overflow-y-auto px-10 pb-10">
          <div className="max-w-7xl mx-auto py-6">
            <div className="mb-4 flex items-center justify-between px-2">
               <div className="flex items-center gap-2">
                  <div className={`w-2 h-2 rounded-full ${currentUser.role === UserRole.CMO ? 'bg-orange-500 animate-pulse' : 'bg-blue-500'}`}></div>
                  <span className="text-[10px] font-black text-slate-400 uppercase tracking-widest">
                    {currentUser.role === UserRole.CITIZEN ? 'Restricted: Personal Records' : 
                     currentUser.role === UserRole.OFFICER ? 'Prototype Mode: All Departments' : 
                     'Full Access: State Insights'}
                  </span>
               </div>
            </div>

            {searchQuery && (
              <div className="mb-6 flex items-center justify-between px-6 py-3 bg-blue-50/50 rounded-2xl border border-blue-100 animate-fade-in">
                <div className="flex items-center gap-3 text-sm font-bold text-blue-600">
                  <i className="fa-solid fa-magnifying-glass"></i>
                  <span>Searching within <span className="text-slate-900 font-black">"{currentUser.role.toLowerCase()}"</span> workspace for <span className="text-slate-900 font-black">"{searchQuery}"</span></span>
                </div>
                <button onClick={() => setSearchQuery('')} className="text-[10px] font-black uppercase text-blue-400 hover:text-blue-600 tracking-widest">Reset</button>
              </div>
            )}
            
            <div className="transition-all duration-500 transform">
              {renderContent()}
            </div>
          </div>
        </main>
      </div>

      <FloatingChatbot grievances={grievances} />
    </div>
  );
};

export default App;