Skip to content

Commit

Permalink
Perioperative Integrations v2.3
Browse files Browse the repository at this point in the history
  • Loading branch information
sudoshi committed Feb 28, 2025
1 parent adac566 commit afdc67e
Show file tree
Hide file tree
Showing 44 changed files with 7,834 additions and 2,101 deletions.
38 changes: 38 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@iconify/icons-solar": "^1.2.3",
"@nivo/bar": "^0.88.0",
"@nivo/calendar": "^0.88.0",
"@nivo/circle-packing": "^0.88.0",
"@nivo/core": "^0.88.0",
"@nivo/heatmap": "^0.88.0",
"@nivo/line": "^0.88.0",
Expand All @@ -51,6 +52,7 @@
"prop-types": "^15.8.1",
"react-chartjs-2": "^5.3.0",
"react-force-graph": "^1.47.3",
"react-heatmap-grid": "^0.9.1",
"reactflow": "^11.11.4",
"tailwind-merge": "^3.0.1"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React, { useState, useEffect } from 'react';
import { usePage } from '@inertiajs/react';
import { motion, AnimatePresence } from 'framer-motion';
import { Icon } from '@iconify/react';
import HierarchicalFilters from '@/Components/Analytics/shared/HierarchicalFilters';
import ErrorBoundary from '@/Components/ErrorBoundary';

// Import view components
import ServiceView from './Views/ServiceView';
Expand All @@ -15,79 +17,28 @@ import NonPrimeView from './Views/NonPrimeView';
// Import mock data
import { mockBlockUtilization } from '@/mock-data/block-utilization';

// Filter sidebar component
const FilterSidebar = ({ filters, onChange, visible }) => {
const handleFilterChange = (e) => {
const { name, value } = e.target;
onChange({ ...filters, [name]: value });
};

return (
<div className={`bg-white dark:bg-gray-800 rounded-lg shadow p-4 ${visible ? 'block' : 'hidden md:block'}`}>
<h3 className="text-lg font-medium mb-4 dark:text-white">Filters</h3>
<div className="space-y-4">
<div>
<label htmlFor="site" className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Site</label>
<select
id="site"
name="site"
value={filters.site}
onChange={handleFilterChange}
className="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md"
>
<option value="all">All Sites</option>
{Object.keys(mockBlockUtilization.sites).map((site, index) => (
<option key={index} value={site}>{site}</option>
))}
</select>
</div>
<div>
<label htmlFor="service" className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Service</label>
<select
id="service"
name="service"
value={filters.service}
onChange={handleFilterChange}
className="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md"
>
<option value="all">All Services</option>
{mockBlockUtilization.serviceData.map((service, index) => (
<option key={index} value={service.name}>{service.name}</option>
))}
</select>
</div>
<div>
<label htmlFor="timeRange" className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Time Range</label>
<select
id="timeRange"
name="timeRange"
value={filters.timeRange}
onChange={handleFilterChange}
className="mt-1 block w-full pl-3 pr-10 py-2 text-base border-gray-300 dark:border-gray-600 dark:bg-gray-700 dark:text-white focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm rounded-md"
>
<option value="30">Last 30 Days</option>
<option value="60">Last 60 Days</option>
<option value="90">Last 90 Days</option>
<option value="180">Last 6 Months</option>
<option value="365">Last 12 Months</option>
</select>
</div>
</div>
</div>
);
};

const BlockUtilizationDashboard = ({ activeView: initialActiveView }) => {
const { url } = usePage();

// Use the provided activeView prop if available, otherwise use the URL parameter
const [activeView, setActiveView] = useState(initialActiveView || 'service');
const [filtersVisible, setFiltersVisible] = useState(false);

// Enhanced filters state to match HierarchicalFilters component
const [filters, setFilters] = useState({
site: 'all',
service: 'all',
timeRange: '90'
selectedHospital: '',
selectedLocation: '',
selectedSpecialty: '',
selectedSurgeon: '',
dateRange: {
startDate: new Date(new Date().setDate(new Date().getDate() - 90)),
endDate: new Date()
},
comparisonDateRange: {
startDate: new Date(new Date().setDate(new Date().getDate() - 180)),
endDate: new Date(new Date().setDate(new Date().getDate() - 91))
},
showComparison: false
});

// Update active view when initialActiveView prop changes
Expand All @@ -97,6 +48,11 @@ const BlockUtilizationDashboard = ({ activeView: initialActiveView }) => {
}
}, [initialActiveView]);

// Handle filter changes from HierarchicalFilters
const handleFilterChange = (newFilters) => {
setFilters(newFilters);
};

// Get the appropriate view component based on activeView
const getViewComponent = () => {
switch (activeView) {
Expand All @@ -119,35 +75,38 @@ const BlockUtilizationDashboard = ({ activeView: initialActiveView }) => {
}
};

// Get visible filters based on active view
const getVisibleFilters = () => {
const baseFilters = ['site', 'timeRange'];

switch (activeView) {
case 'service':
return [...baseFilters];
case 'trend':
return [...baseFilters, 'service'];
case 'dayOfWeek':
return [...baseFilters, 'service'];
case 'location':
return ['timeRange', 'service'];
case 'block':
return [...baseFilters, 'service'];
case 'details':
return [...baseFilters, 'service'];
case 'nonprime':
return [...baseFilters, 'service'];
default:
return baseFilters;
}
};

// Toggle mobile filters visibility
const toggleFilters = () => {
setFiltersVisible(!filtersVisible);
};

// Format locations data for HierarchicalFilters
const formatLocationsData = () => {
return Object.keys(mockBlockUtilization.sites).map(site => ({
id: site,
name: site,
hospitalId: site.split(' ')[0] // Extract hospital ID from site name (e.g., 'MARH' from 'MARH OR')
}));
};

// Format services data for HierarchicalFilters
const formatServicesData = () => {
const services = new Set();
Object.values(mockBlockUtilization.sites).forEach(site => {
site.services.forEach(service => {
services.add(service.service_name);
});
});
return Array.from(services);
};

// Format providers data for HierarchicalFilters (if available)
const formatProvidersData = () => {
// In a real application, this would come from the API
// For now, return an empty array
return [];
};

return (
<div className="w-full">
<div className="mb-4 md:hidden">
Expand All @@ -160,12 +119,17 @@ const BlockUtilizationDashboard = ({ activeView: initialActiveView }) => {
</div>

<div className="flex flex-col md:flex-row gap-6">
<div className="w-full md:w-64 flex-shrink-0">
<FilterSidebar
filters={filters}
onChange={setFilters}
visible={filtersVisible}
/>
<div className="w-full md:w-80 flex-shrink-0">
<ErrorBoundary>
<HierarchicalFilters
locations={formatLocationsData()}
services={formatServicesData()}
providers={formatProvidersData()}
onFilterChange={handleFilterChange}
initialFilters={filters}
className="sticky top-4"
/>
</ErrorBoundary>
</div>

<div className="flex-grow">
Expand Down
Loading

0 comments on commit afdc67e

Please sign in to comment.