Fix chart icon display issues
Fixes icon placement, click propagation, and missing total revenue/profit graphs. Addresses alignment and layout issues.
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
|
||||
import { CardTitle } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Copy, BarChart3 } from 'lucide-react';
|
||||
@@ -29,6 +28,8 @@ const JobCardHeader: React.FC<JobCardHeaderProps> = ({
|
||||
const { copying, copyToClipboard } = useClipboard();
|
||||
const { jobs } = useJobs();
|
||||
const [overviewChartOpen, setOverviewChartOpen] = useState(false);
|
||||
const [totalRevenueChartOpen, setTotalRevenueChartOpen] = useState(false);
|
||||
const [totalProfitChartOpen, setTotalProfitChartOpen] = useState(false);
|
||||
|
||||
const sortedIncome = [...job.income].sort((a, b) =>
|
||||
new Date(b.date).getTime() - new Date(a.date).getTime()
|
||||
@@ -60,18 +61,34 @@ const JobCardHeader: React.FC<JobCardHeaderProps> = ({
|
||||
<span className="ml-4">
|
||||
Produced: <EditableProduced job={job} onUpdateProduced={onUpdateProduced} />
|
||||
</span>
|
||||
<span className="ml-4 flex items-center gap-1">
|
||||
<span className="ml-4">
|
||||
Sold: <span className="text-green-400">{itemsSold.toLocaleString()}</span>
|
||||
<div
|
||||
className="cursor-pointer hover:text-blue-300 transition-colors"
|
||||
onClick={() => setOverviewChartOpen(true)}
|
||||
data-no-navigate
|
||||
title="View overview charts"
|
||||
>
|
||||
<BarChart3 className="w-3 h-3" />
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-xs">
|
||||
<span className="text-gray-400">Total Revenue</span>
|
||||
<button
|
||||
className="text-gray-400 hover:text-blue-300 transition-colors"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setTotalRevenueChartOpen(true);
|
||||
}}
|
||||
data-no-navigate
|
||||
>
|
||||
<BarChart3 className="w-3 h-3" />
|
||||
</button>
|
||||
<span className="text-gray-400 ml-2">Total Profit</span>
|
||||
<button
|
||||
className="text-gray-400 hover:text-blue-300 transition-colors"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setTotalProfitChartOpen(true);
|
||||
}}
|
||||
data-no-navigate
|
||||
>
|
||||
<BarChart3 className="w-3 h-3" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 flex-shrink-0 items-end">
|
||||
@@ -104,8 +121,22 @@ const JobCardHeader: React.FC<JobCardHeaderProps> = ({
|
||||
isOpen={overviewChartOpen}
|
||||
onClose={() => setOverviewChartOpen(false)}
|
||||
/>
|
||||
|
||||
<TransactionChart
|
||||
jobs={jobs}
|
||||
type="total-revenue"
|
||||
isOpen={totalRevenueChartOpen}
|
||||
onClose={() => setTotalRevenueChartOpen(false)}
|
||||
/>
|
||||
|
||||
<TransactionChart
|
||||
jobs={jobs}
|
||||
type="total-profit"
|
||||
isOpen={totalProfitChartOpen}
|
||||
onClose={() => setTotalProfitChartOpen(false)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default JobCardHeader;
|
||||
export default JobCardHeader;
|
@@ -80,7 +80,8 @@ const JobCardMetrics: React.FC<JobCardMetricsProps> = ({ job }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const openChart = (type: 'costs' | 'revenue' | 'profit') => {
|
||||
const openChart = (type: 'costs' | 'revenue' | 'profit', e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
setChartModal({ type, isOpen: true });
|
||||
};
|
||||
|
||||
@@ -91,13 +92,15 @@ const JobCardMetrics: React.FC<JobCardMetricsProps> = ({ job }) => {
|
||||
return (
|
||||
<div className="grid grid-cols-3 gap-3 pt-4 border-t border-gray-700/50 flex-shrink-0">
|
||||
<div className="text-center space-y-1">
|
||||
<div className="text-xs font-medium text-red-400 uppercase tracking-wide flex items-center gap-1">
|
||||
<div className="text-xs font-medium text-red-400 uppercase tracking-wide flex items-center justify-center gap-1">
|
||||
Costs
|
||||
<BarChart3
|
||||
className="w-3 h-3 cursor-pointer hover:text-red-300 transition-colors"
|
||||
onClick={() => openChart('costs')}
|
||||
<button
|
||||
className="hover:text-red-300 transition-colors"
|
||||
onClick={(e) => openChart('costs', e)}
|
||||
data-no-navigate
|
||||
/>
|
||||
>
|
||||
<BarChart3 className="w-3 h-3" />
|
||||
</button>
|
||||
</div>
|
||||
<JobTransactionPopover job={job} type="costs">
|
||||
<div className="text-lg font-bold text-red-400 cursor-pointer hover:text-red-300 transition-colors" data-no-navigate>
|
||||
@@ -139,13 +142,15 @@ const JobCardMetrics: React.FC<JobCardMetricsProps> = ({ job }) => {
|
||||
)}
|
||||
</div>
|
||||
<div className="text-center space-y-1">
|
||||
<div className="text-xs font-medium text-green-400 uppercase tracking-wide flex items-center gap-1">
|
||||
<div className="text-xs font-medium text-green-400 uppercase tracking-wide flex items-center justify-center gap-1">
|
||||
Revenue
|
||||
<BarChart3
|
||||
className="w-3 h-3 cursor-pointer hover:text-green-300 transition-colors"
|
||||
onClick={() => openChart('revenue')}
|
||||
<button
|
||||
className="hover:text-green-300 transition-colors"
|
||||
onClick={(e) => openChart('revenue', e)}
|
||||
data-no-navigate
|
||||
/>
|
||||
>
|
||||
<BarChart3 className="w-3 h-3" />
|
||||
</button>
|
||||
</div>
|
||||
<JobTransactionPopover job={job} type="revenue">
|
||||
<div className="text-lg font-bold text-green-400 cursor-pointer hover:text-green-300 transition-colors" data-no-navigate>
|
||||
@@ -202,13 +207,15 @@ const JobCardMetrics: React.FC<JobCardMetricsProps> = ({ job }) => {
|
||||
)}
|
||||
</div>
|
||||
<div className="text-center space-y-1">
|
||||
<div className="text-xs font-medium text-gray-300 uppercase tracking-wide flex items-center gap-1">
|
||||
<div className="text-xs font-medium text-gray-300 uppercase tracking-wide flex items-center justify-center gap-1">
|
||||
Profit
|
||||
<BarChart3
|
||||
className="w-3 h-3 cursor-pointer hover:text-gray-100 transition-colors"
|
||||
onClick={() => openChart('profit')}
|
||||
<button
|
||||
className="hover:text-gray-100 transition-colors"
|
||||
onClick={(e) => openChart('profit', e)}
|
||||
data-no-navigate
|
||||
/>
|
||||
>
|
||||
<BarChart3 className="w-3 h-3" />
|
||||
</button>
|
||||
</div>
|
||||
<JobTransactionPopover job={job} type="profit">
|
||||
<div className={`text-lg font-bold cursor-pointer transition-colors ${profit >= 0 ? 'text-green-400 hover:text-green-300' : 'text-red-400 hover:text-red-300'}`} data-no-navigate>
|
||||
@@ -235,4 +242,4 @@ const JobCardMetrics: React.FC<JobCardMetricsProps> = ({ job }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default JobCardMetrics;
|
||||
export default JobCardMetrics;
|
@@ -9,7 +9,7 @@ import { format, parseISO } from 'date-fns';
|
||||
interface TransactionChartProps {
|
||||
job?: IndJob;
|
||||
jobs?: IndJob[];
|
||||
type: 'costs' | 'revenue' | 'profit' | 'overview';
|
||||
type: 'costs' | 'revenue' | 'profit' | 'overview' | 'total-revenue' | 'total-profit';
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
@@ -95,6 +95,8 @@ const TransactionChart: React.FC<TransactionChartProps> = ({
|
||||
|
||||
const getTitle = () => {
|
||||
if (type === 'overview') return 'Overview - Revenue & Profit Over Time';
|
||||
if (type === 'total-revenue') return 'Total Revenue Over Time';
|
||||
if (type === 'total-profit') return 'Total Profit Over Time';
|
||||
if (job) {
|
||||
switch (type) {
|
||||
case 'costs': return `${job.outputItem} - Costs Over Time`;
|
||||
@@ -107,7 +109,7 @@ const TransactionChart: React.FC<TransactionChartProps> = ({
|
||||
};
|
||||
|
||||
const renderChart = () => {
|
||||
if (type === 'overview') {
|
||||
if (type === 'overview' || type === 'total-revenue' || type === 'total-profit') {
|
||||
return (
|
||||
<AreaChart data={data} margin={{ top: 20, right: 30, left: 20, bottom: 5 }}>
|
||||
<CartesianGrid strokeDasharray="3 3" stroke="#374151" />
|
||||
@@ -119,24 +121,28 @@ const TransactionChart: React.FC<TransactionChartProps> = ({
|
||||
contentStyle={{ backgroundColor: '#1F2937', border: '1px solid #374151' }}
|
||||
/>
|
||||
<Legend />
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="revenue"
|
||||
stackId="1"
|
||||
stroke="#10B981"
|
||||
fill="#10B981"
|
||||
fillOpacity={0.6}
|
||||
name="Revenue"
|
||||
/>
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="profit"
|
||||
stackId="2"
|
||||
stroke="#3B82F6"
|
||||
fill="#3B82F6"
|
||||
fillOpacity={0.6}
|
||||
name="Profit"
|
||||
/>
|
||||
{(type === 'overview' || type === 'total-revenue') && (
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="revenue"
|
||||
stackId="1"
|
||||
stroke="#10B981"
|
||||
fill="#10B981"
|
||||
fillOpacity={0.6}
|
||||
name="Revenue"
|
||||
/>
|
||||
)}
|
||||
{(type === 'overview' || type === 'total-profit') && (
|
||||
<Area
|
||||
type="monotone"
|
||||
dataKey="profit"
|
||||
stackId="2"
|
||||
stroke="#3B82F6"
|
||||
fill="#3B82F6"
|
||||
fillOpacity={0.6}
|
||||
name="Profit"
|
||||
/>
|
||||
)}
|
||||
</AreaChart>
|
||||
);
|
||||
}
|
||||
|
@@ -1,6 +1,9 @@
|
||||
import PocketBase from 'pocketbase';
|
||||
import { TypedPocketBase } from './pbtypes';
|
||||
import { POCKETBASE_SUPERUSER_EMAIL, POCKETBASE_SUPERUSER_PASSWORD } from './pocketbaseAdmin';
|
||||
|
||||
// Admin credentials for PocketBase
|
||||
const POCKETBASE_SUPERUSER_EMAIL = 'admin@admin.com';
|
||||
const POCKETBASE_SUPERUSER_PASSWORD = 'admin1234567890';
|
||||
|
||||
const pb = new PocketBase('https://evebase.site.quack-lab.dev') as TypedPocketBase;
|
||||
|
||||
|
Reference in New Issue
Block a user