Skip to content

Commit 0d6c46a

Browse files
committed
update: unified rebalance & analysis history page UI, added google analytics
1 parent 0f7f3a4 commit 0d6c46a

File tree

9 files changed

+142
-70
lines changed

9 files changed

+142
-70
lines changed

index.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,18 @@
4848
<!-- Google AdSense -->
4949
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-9651663494022087"
5050
crossorigin="anonymous"></script>
51+
52+
<!-- Google tag (gtag.js) Google Analytics -->
53+
<script async src="https://www.googletagmanager.com/gtag/js?id=G-HYXMNMH4WX"></script>
54+
<script>
55+
window.dataLayer = window.dataLayer || [];
56+
function gtag(){dataLayer.push(arguments);}
57+
gtag('js', new Date());
58+
59+
gtag('config', 'G-HYXMNMH4WX');
60+
</script>
61+
62+
5163
</head>
5264

5365
<body>

public/Social-Preview.png

550 KB
Loading

src/components/RebalanceHistoryTable.tsx

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -333,23 +333,38 @@ export default function RebalanceHistoryTable() {
333333
}
334334
};
335335

336-
const getStatusVariant = (status: string): "default" | "secondary" | "destructive" | "outline" => {
336+
const getStatusVariant = (status: string): "default" | "secondary" | "destructive" | "outline" | undefined => {
337337
// Convert legacy status to new format for consistent variant display
338338
const normalizedStatus = convertLegacyRebalanceStatus(status);
339339

340340
switch (normalizedStatus) {
341341
case REBALANCE_STATUS.COMPLETED:
342-
return 'default';
342+
return undefined; // No variant, use className only
343343
case REBALANCE_STATUS.CANCELLED:
344344
case REBALANCE_STATUS.ERROR:
345345
return 'destructive';
346346
case REBALANCE_STATUS.RUNNING:
347+
return 'default'; // Use default variant like UnifiedAnalysisHistory
347348
case REBALANCE_STATUS.PENDING:
348349
return 'secondary';
349350
default:
350351
return 'outline';
351352
}
352353
};
354+
355+
const getStatusClassName = (status: string): string => {
356+
// Convert legacy status to new format for consistent variant display
357+
const normalizedStatus = convertLegacyRebalanceStatus(status);
358+
359+
switch (normalizedStatus) {
360+
case REBALANCE_STATUS.COMPLETED:
361+
return 'border border-green-500/30 bg-green-500/10 text-green-600 font-semibold hover:bg-green-500/20';
362+
case REBALANCE_STATUS.RUNNING:
363+
return ''; // Let default variant handle the styling
364+
default:
365+
return '';
366+
}
367+
};
353368

354369
// Calculate completion percentage based on agent step completion
355370
const calculateAgentStepCompletion = (rebalanceRequest: RebalanceRequest): number => {
@@ -542,17 +557,12 @@ export default function RebalanceHistoryTable() {
542557
<div className="flex items-center justify-between">
543558
<div className="flex items-center gap-3">
544559
<span className="font-semibold">Portfolio Rebalance</span>
545-
<Badge variant={getStatusVariant(item.status)}>
560+
<Badge variant={getStatusVariant(item.status)} className={getStatusClassName(item.status)}>
546561
<span className="flex items-center gap-1">
547562
{getStatusIcon(item.status)}
548563
{item.status.replace('_', ' ')}
549564
</span>
550565
</Badge>
551-
{item.total_stocks > 0 && (
552-
<span className="text-sm text-muted-foreground">
553-
{item.stocks_analyzed}/{item.total_stocks} stocks
554-
</span>
555-
)}
556566
</div>
557567
<span className="text-xs text-muted-foreground">
558568
Started {formatDistanceToNow(new Date(item.created_at), { addSuffix: true })}
@@ -608,7 +618,7 @@ export default function RebalanceHistoryTable() {
608618
setSelectedRebalanceId(item.id);
609619
setCancelDialogOpen(true);
610620
}}
611-
className="text-red-500 hover:text-white hover:bg-red-600"
621+
className="text-red-600 dark:text-red-400 hover:bg-red-500/10 hover:text-red-600 dark:hover:text-red-400 focus:bg-red-500/10 focus:text-red-600 dark:focus:text-red-400"
612622
disabled={cancelling}
613623
>
614624
<StopCircle className="h-4 w-4 mr-2" />
@@ -620,7 +630,7 @@ export default function RebalanceHistoryTable() {
620630
setSelectedRebalanceId(item.id);
621631
setDeleteDialogOpen(true);
622632
}}
623-
className="text-red-500 hover:text-white hover:bg-red-600"
633+
className="text-red-600 dark:text-red-400 hover:bg-red-500/10 hover:text-red-600 dark:hover:text-red-400 focus:bg-red-500/10 focus:text-red-600 dark:focus:text-red-400"
624634
>
625635
<Trash2 className="h-4 w-4 mr-2" />
626636
Delete
@@ -650,7 +660,7 @@ export default function RebalanceHistoryTable() {
650660
<div className="flex items-center justify-between">
651661
<div className="flex items-center gap-3">
652662
<span className="font-semibold">Portfolio Rebalance</span>
653-
<Badge variant="default">
663+
<Badge className="border border-green-500/30 bg-green-500/10 text-green-600 font-semibold hover:bg-green-500/20">
654664
<span className="flex items-center gap-1">
655665
<CheckCircle className="h-3 w-3" />
656666
Completed
@@ -700,7 +710,7 @@ export default function RebalanceHistoryTable() {
700710
setSelectedRebalanceId(item.id);
701711
setDeleteDialogOpen(true);
702712
}}
703-
className="text-red-500 hover:text-white hover:bg-red-600"
713+
className="text-red-600 dark:text-red-400 hover:bg-red-500/10 hover:text-red-600 dark:hover:text-red-400 focus:bg-red-500/10 focus:text-red-600 dark:focus:text-red-400"
704714
>
705715
<Trash2 className="h-4 w-4 mr-2" />
706716
Delete
@@ -776,7 +786,7 @@ export default function RebalanceHistoryTable() {
776786
setSelectedRebalanceId(item.id);
777787
setDeleteDialogOpen(true);
778788
}}
779-
className="text-red-500 hover:text-white hover:bg-red-600"
789+
className="text-red-600 dark:text-red-400 hover:bg-red-500/10 hover:text-red-600 dark:hover:text-red-400 focus:bg-red-500/10 focus:text-red-600 dark:focus:text-red-400"
780790
>
781791
<Trash2 className="h-4 w-4 mr-2" />
782792
Delete
@@ -813,17 +823,12 @@ export default function RebalanceHistoryTable() {
813823
<div className="flex items-center justify-between">
814824
<div className="flex items-center gap-3">
815825
<span className="font-semibold">Portfolio Rebalance</span>
816-
<Badge variant={getStatusVariant(item.status)}>
826+
<Badge variant={getStatusVariant(item.status)} className={getStatusClassName(item.status)}>
817827
<span className="flex items-center gap-1">
818828
{getStatusIcon(item.status)}
819829
{getStatusDisplayText(convertLegacyRebalanceStatus(item.status))}
820830
</span>
821831
</Badge>
822-
{item.total_stocks > 0 && (
823-
<span className="text-sm text-muted-foreground">
824-
{item.stocks_analyzed}/{item.total_stocks} stocks
825-
</span>
826-
)}
827832
</div>
828833
<span className="text-xs text-muted-foreground">
829834
Started {formatDistanceToNow(new Date(item.created_at), { addSuffix: true })}
@@ -879,7 +884,7 @@ export default function RebalanceHistoryTable() {
879884
setSelectedRebalanceId(item.id);
880885
setCancelDialogOpen(true);
881886
}}
882-
className="text-red-500 hover:text-white hover:bg-red-600"
887+
className="text-red-600 dark:text-red-400 hover:bg-red-500/10 hover:text-red-600 dark:hover:text-red-400 focus:bg-red-500/10 focus:text-red-600 dark:focus:text-red-400"
883888
disabled={cancelling}
884889
>
885890
<StopCircle className="h-4 w-4 mr-2" />
@@ -891,7 +896,7 @@ export default function RebalanceHistoryTable() {
891896
setSelectedRebalanceId(item.id);
892897
setDeleteDialogOpen(true);
893898
}}
894-
className="text-red-500 hover:text-white hover:bg-red-600"
899+
className="text-red-600 dark:text-red-400 hover:bg-red-500/10 hover:text-red-600 dark:hover:text-red-400 focus:bg-red-500/10 focus:text-red-600 dark:focus:text-red-400"
895900
>
896901
<Trash2 className="h-4 w-4 mr-2" />
897902
Delete
@@ -922,7 +927,7 @@ export default function RebalanceHistoryTable() {
922927
<div className="flex items-center justify-between">
923928
<div className="flex items-center gap-3">
924929
<span className="font-semibold">Portfolio Rebalance</span>
925-
<Badge variant="default">
930+
<Badge className="border border-green-500/30 bg-green-500/10 text-green-600 font-semibold hover:bg-green-500/20">
926931
<span className="flex items-center gap-1">
927932
<CheckCircle className="h-3 w-3" />
928933
Completed
@@ -972,7 +977,7 @@ export default function RebalanceHistoryTable() {
972977
setSelectedRebalanceId(item.id);
973978
setDeleteDialogOpen(true);
974979
}}
975-
className="text-red-500 hover:text-white hover:bg-red-600"
980+
className="text-red-600 dark:text-red-400 hover:bg-red-500/10 hover:text-red-600 dark:hover:text-red-400 focus:bg-red-500/10 focus:text-red-600 dark:focus:text-red-400"
976981
>
977982
<Trash2 className="h-4 w-4 mr-2" />
978983
Delete
@@ -1052,7 +1057,7 @@ export default function RebalanceHistoryTable() {
10521057
setSelectedRebalanceId(item.id);
10531058
setDeleteDialogOpen(true);
10541059
}}
1055-
className="text-red-500 hover:text-white hover:bg-red-600"
1060+
className="text-red-600 dark:text-red-400 hover:bg-red-500/10 hover:text-red-600 dark:hover:text-red-400 focus:bg-red-500/10 focus:text-red-600 dark:focus:text-red-400"
10561061
>
10571062
<Trash2 className="h-4 w-4 mr-2" />
10581063
Delete

src/components/ScheduleListModal.tsx

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ export default function ScheduleListModal({ isOpen, onClose }: ScheduleListModal
102102
});
103103
return;
104104
}
105+
setEditingSchedule(null); // Clear any previous editing schedule
105106
setShowAddModal(true);
106107
};
107108

@@ -461,6 +462,18 @@ export default function ScheduleListModal({ isOpen, onClose }: ScheduleListModal
461462
</div>
462463
</div>
463464
<div className="flex items-center gap-2">
465+
<Button
466+
variant="ghost"
467+
size="sm"
468+
onClick={() => {
469+
setEditingSchedule(schedule);
470+
setShowAddModal(true);
471+
}}
472+
disabled={!isAccessible}
473+
>
474+
<Settings className="w-4 h-4 mr-1" />
475+
Edit
476+
</Button>
464477
<Button
465478
variant="ghost"
466479
size="sm"
@@ -484,8 +497,9 @@ export default function ScheduleListModal({ isOpen, onClose }: ScheduleListModal
484497
size="sm"
485498
onClick={() => setDeletingSchedule(schedule)}
486499
disabled={!isAccessible}
500+
className="hover:bg-red-500/10 hover:text-red-600 dark:hover:text-red-400"
487501
>
488-
<Trash2 className="w-4 h-4 text-destructive" />
502+
<Trash2 className="w-4 h-4 text-red-600 dark:text-red-400" />
489503
</Button>
490504
</div>
491505
</div>
@@ -618,14 +632,14 @@ export default function ScheduleListModal({ isOpen, onClose }: ScheduleListModal
618632
</Dialog >
619633

620634
{/* Add/Edit Schedule Modal */}
621-
< ScheduleRebalanceModal
635+
<ScheduleRebalanceModal
622636
isOpen={showAddModal}
637+
scheduleToEdit={editingSchedule}
623638
onClose={() => {
624639
setShowAddModal(false);
625640
setEditingSchedule(null);
626641
loadSchedules(); // Reload schedules after adding/editing
627-
}
628-
}
642+
}}
629643
/>
630644

631645
{/* Delete Confirmation Dialog */}

src/components/UnifiedAnalysisHistory.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -695,7 +695,7 @@ export default function UnifiedAnalysisHistory() {
695695
setSelectedAnalysisTicker(item.ticker);
696696
setShowCancelDialog(true);
697697
}}
698-
className="text-red-500 hover:text-white hover:bg-red-600"
698+
className="text-red-600 dark:text-red-400 hover:bg-red-500/10 hover:text-red-600 dark:hover:text-red-400 focus:bg-red-500/10 focus:text-red-600 dark:focus:text-red-400"
699699
>
700700
<StopCircle className="h-4 w-4 mr-2" />
701701
Cancel Analysis
@@ -707,7 +707,7 @@ export default function UnifiedAnalysisHistory() {
707707
setSelectedAnalysisTicker(item.ticker);
708708
setShowDeleteDialog(true);
709709
}}
710-
className="text-red-500 hover:text-white hover:bg-red-600"
710+
className="text-red-600 dark:text-red-400 hover:bg-red-500/10 hover:text-red-600 dark:hover:text-red-400 focus:bg-red-500/10 focus:text-red-600 dark:focus:text-red-400"
711711
>
712712
<Trash2 className="h-4 w-4 mr-2" />
713713
Delete

src/components/rebalance-detail/RebalanceWorkflowTab.tsx

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,11 @@ const calculateAgentStepCompletion = (stockAnalyses: any[]): number => {
6767
};
6868

6969
// Workflow Steps Component
70-
function RebalanceWorkflowSteps({
71-
workflowData,
70+
function RebalanceWorkflowSteps({
71+
workflowData,
7272
onNavigateToInsight,
73-
onOpenAnalysisModal
74-
}: {
73+
onOpenAnalysisModal
74+
}: {
7575
workflowData: any;
7676
onNavigateToInsight?: (agentKey: string) => void;
7777
onOpenAnalysisModal?: (ticker: string, analysisId: string) => void;
@@ -88,7 +88,7 @@ function RebalanceWorkflowSteps({
8888
if (step.data?.error || step.status === 'error') {
8989
return 'error';
9090
}
91-
91+
9292
// Special handling for analysis step - check if all analyses are complete
9393
if (step.id === 'analysis' && step.stockAnalyses?.length > 0) {
9494
const completionPercentage = calculateAgentStepCompletion(step.stockAnalyses);
@@ -98,7 +98,7 @@ function RebalanceWorkflowSteps({
9898
return 'running';
9999
}
100100
}
101-
101+
102102
return step.status || 'pending';
103103
};
104104

@@ -129,19 +129,18 @@ function RebalanceWorkflowSteps({
129129
<div key={step.id} className="relative">
130130
<div className="space-y-4">
131131
{/* Step Header */}
132-
<div
133-
className={`rounded-lg border p-4 transition-all ${
134-
(step.id === 'opportunity' || step.id === 'portfolio') && onNavigateToInsight
135-
? 'cursor-pointer hover:shadow-md'
136-
: ''
137-
} ${isCompleted
138-
? 'border-green-500/30 bg-green-500/5 dark:bg-green-500/5'
139-
: isError
140-
? 'border-red-500/30 bg-red-500/5 dark:bg-red-500/5'
141-
: isRunning
142-
? 'border-yellow-500/30 bg-yellow-500/5 dark:bg-yellow-500/5'
143-
: 'border-border'
144-
}`}
132+
<div
133+
className={`rounded-lg border p-4 transition-all ${(step.id === 'opportunity' || step.id === 'portfolio') && onNavigateToInsight
134+
? 'cursor-pointer hover:shadow-md'
135+
: ''
136+
} ${isCompleted
137+
? 'border-green-500/30 bg-green-500/5 dark:bg-green-500/5'
138+
: isError
139+
? 'border-red-500/30 bg-red-500/5 dark:bg-red-500/5'
140+
: isRunning
141+
? 'border-yellow-500/30 bg-yellow-500/5 dark:bg-yellow-500/5'
142+
: 'border-border'
143+
}`}
145144
onClick={() => {
146145
// Handle clicks for opportunity and portfolio agents
147146
if (step.id === 'opportunity' && onNavigateToInsight) {
@@ -164,7 +163,7 @@ function RebalanceWorkflowSteps({
164163
: isError
165164
? 'bg-red-500/10 dark:bg-red-500/5 text-red-600 dark:text-red-400'
166165
: isRunning
167-
? 'bg-yellow-500/10 dark:bg-yellow-500/5 text-yellow-600 dark:text-yellow-400'
166+
? 'bg-yellow-500/10 dark:bg-yellow-100/5 text-yellow-600 dark:text-yellow-400'
168167
: 'bg-muted text-muted-foreground'
169168
}`}>
170169
<Icon className="w-6 h-6" />
@@ -236,7 +235,7 @@ function RebalanceWorkflowSteps({
236235
// Calculate completion percentage
237236
const completionPercentage = calculateAgentStepCompletion(step.stockAnalyses);
238237
const isFullyComplete = completionPercentage >= 100;
239-
238+
240239
// Check if overall rebalance is active (same as RebalanceHistoryTable)
241240
const rebalanceIsActive = workflowData.status && isRebalanceActive(convertLegacyRebalanceStatus(workflowData.status));
242241

@@ -513,17 +512,17 @@ function RebalanceWorkflowSteps({
513512
);
514513
}
515514

516-
export default function RebalanceWorkflowTab({
517-
workflowData,
515+
export default function RebalanceWorkflowTab({
516+
workflowData,
518517
onNavigateToInsight,
519-
onOpenAnalysisModal
518+
onOpenAnalysisModal
520519
}: RebalanceWorkflowTabProps) {
521520
return (
522521
<TabsContent value="workflow" className="data-[state=active]:block hidden">
523522
<ScrollArea className="h-[calc(90vh-220px)] px-6 pt-6">
524523
<div className="pb-6">
525-
<RebalanceWorkflowSteps
526-
workflowData={workflowData}
524+
<RebalanceWorkflowSteps
525+
workflowData={workflowData}
527526
onNavigateToInsight={onNavigateToInsight}
528527
onOpenAnalysisModal={onOpenAnalysisModal}
529528
/>

0 commit comments

Comments
 (0)