Fix form border
This commit is contained in:
parent
2359e93d58
commit
19afa660da
4 changed files with 85 additions and 68 deletions
|
|
@ -3,6 +3,7 @@ import AddPurchaseForm from '@/components/Transactions/AddPurchaseForm';
|
||||||
import UpdatePriceForm from '@/components/Pricing/UpdatePriceForm';
|
import UpdatePriceForm from '@/components/Pricing/UpdatePriceForm';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { X } from 'lucide-react';
|
import { X } from 'lucide-react';
|
||||||
|
import ComponentTitle from '@/components/ui/ComponentTitle';
|
||||||
|
|
||||||
interface InlineFormProps {
|
interface InlineFormProps {
|
||||||
type: 'purchase' | 'milestone' | 'price' | null;
|
type: 'purchase' | 'milestone' | 'price' | null;
|
||||||
|
|
@ -13,66 +14,66 @@ interface InlineFormProps {
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function InlineForm({
|
export default function InlineForm({
|
||||||
type,
|
type,
|
||||||
onClose,
|
onClose,
|
||||||
onPurchaseSuccess,
|
onPurchaseSuccess,
|
||||||
onMilestoneSuccess,
|
onMilestoneSuccess,
|
||||||
onPriceSuccess,
|
onPriceSuccess,
|
||||||
className
|
className
|
||||||
}: InlineFormProps) {
|
}: InlineFormProps) {
|
||||||
if (!type) return null;
|
if (!type) return null;
|
||||||
|
|
||||||
const title = type === 'purchase' ? 'ADD PURCHASE' : type === 'milestone' ? 'ADD MILESTONE' : 'UPDATE PRICE';
|
const title = type === 'purchase' ? 'ADD PURCHASE' : type === 'milestone' ? 'ADD MILESTONE' : 'UPDATE PRICE';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"bg-black border-4 border-gray-800 rounded-lg",
|
"bg-black p-8",
|
||||||
"shadow-2xl shadow-red-500/20",
|
"transition-all duration-300",
|
||||||
"p-6",
|
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="flex items-center justify-between mb-6">
|
<div className="w-full border-4 border-red-500 p-2 bg-black space-y-4">
|
||||||
<h2 className="text-red-500 font-mono tracking-wide text-lg">
|
<div className="flex items-center justify-between mb-6">
|
||||||
{title}
|
<ComponentTitle>{title}</ComponentTitle>
|
||||||
</h2>
|
|
||||||
<button
|
|
||||||
onClick={onClose}
|
|
||||||
className="text-red-400 hover:text-red-300 transition-colors p-1"
|
|
||||||
aria-label="Close form"
|
|
||||||
>
|
|
||||||
<X className="w-5 h-5" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Form Content */}
|
<button
|
||||||
<div className="flex justify-center">
|
onClick={onClose}
|
||||||
{type === 'purchase' ? (
|
className="text-red-400 hover:text-red-300 transition-colors p-1"
|
||||||
<AddPurchaseForm
|
aria-label="Close form"
|
||||||
onSuccess={() => {
|
>
|
||||||
if (onPurchaseSuccess) onPurchaseSuccess();
|
<X className="w-5 h-5" />
|
||||||
onClose();
|
</button>
|
||||||
}}
|
</div>
|
||||||
/>
|
|
||||||
) : type === 'milestone' ? (
|
{/* Form Content */}
|
||||||
<AddMilestoneForm
|
<div className="flex justify-center">
|
||||||
onSuccess={() => {
|
{type === 'purchase' ? (
|
||||||
if (onMilestoneSuccess) onMilestoneSuccess();
|
<AddPurchaseForm
|
||||||
onClose();
|
onSuccess={() => {
|
||||||
}}
|
if (onPurchaseSuccess) onPurchaseSuccess();
|
||||||
/>
|
onClose();
|
||||||
) : (
|
}}
|
||||||
<UpdatePriceForm
|
/>
|
||||||
onSuccess={() => {
|
) : type === 'milestone' ? (
|
||||||
if (onPriceSuccess) onPriceSuccess();
|
<AddMilestoneForm
|
||||||
onClose();
|
onSuccess={() => {
|
||||||
}}
|
if (onMilestoneSuccess) onMilestoneSuccess();
|
||||||
/>
|
onClose();
|
||||||
)}
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<UpdatePriceForm
|
||||||
|
onSuccess={() => {
|
||||||
|
if (onPriceSuccess) onPriceSuccess();
|
||||||
|
onClose();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { Plus, ChevronRight } from 'lucide-react';
|
import { Plus, ChevronRight } from 'lucide-react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
import ComponentTitle from '@/components/ui/ComponentTitle';
|
||||||
|
|
||||||
interface Milestone {
|
interface Milestone {
|
||||||
target: number;
|
target: number;
|
||||||
|
|
@ -72,9 +73,8 @@ export default function StatsBox({
|
||||||
<div className="w-full border-4 border-red-500 p-2 bg-black space-y-4">
|
<div className="w-full border-4 border-red-500 p-2 bg-black space-y-4">
|
||||||
{/* STATS Title and Current Price */}
|
{/* STATS Title and Current Price */}
|
||||||
<div className="flex justify-between items-center mb-6 relative">
|
<div className="flex justify-between items-center mb-6 relative">
|
||||||
<h2 className="text-red-500 text-lg font-mono font-bold tracking-wider">
|
<ComponentTitle>Stats</ComponentTitle>
|
||||||
STATS
|
|
||||||
</h2>
|
|
||||||
<div className="flex items-center space-x-2 relative">
|
<div className="flex items-center space-x-2 relative">
|
||||||
{stats.currentPrice && (
|
{stats.currentPrice && (
|
||||||
<div className="text-red-500 text-sm font-mono tracking-wider">
|
<div className="text-red-500 text-sm font-mono tracking-wider">
|
||||||
|
|
@ -185,8 +185,8 @@ export default function StatsBox({
|
||||||
key={index}
|
key={index}
|
||||||
className={cn(
|
className={cn(
|
||||||
isSelectedMilestone
|
isSelectedMilestone
|
||||||
? "text-red-500 font-bold"
|
? "bg-red-500 text-black"
|
||||||
: "bg-red-500 text-black"
|
: "text-red-500 font-bold"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<td className="py-1 pr-4">
|
<td className="py-1 pr-4">
|
||||||
|
|
|
||||||
15
resources/js/components/ui/ComponentTitle.tsx
Normal file
15
resources/js/components/ui/ComponentTitle.tsx
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { FC, ReactNode } from 'react';
|
||||||
|
|
||||||
|
interface ComponentTitleProps {
|
||||||
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ComponentTitle: FC<ComponentTitleProps> = ({ children }) => {
|
||||||
|
return (
|
||||||
|
<h2 className="text-red-500 text-lg font-mono font-bold tracking-wider uppercase">
|
||||||
|
{ children }
|
||||||
|
</h2>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ComponentTitle
|
||||||
|
|
@ -27,11 +27,11 @@ export default function Dashboard() {
|
||||||
total_investment: 0,
|
total_investment: 0,
|
||||||
average_cost_per_share: 0,
|
average_cost_per_share: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [priceData, setPriceData] = useState<CurrentPrice>({
|
const [priceData, setPriceData] = useState<CurrentPrice>({
|
||||||
current_price: null,
|
current_price: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const [milestones, setMilestones] = useState<Milestone[]>([]);
|
const [milestones, setMilestones] = useState<Milestone[]>([]);
|
||||||
const [selectedMilestoneIndex, setSelectedMilestoneIndex] = useState(0);
|
const [selectedMilestoneIndex, setSelectedMilestoneIndex] = useState(0);
|
||||||
const [showProgressBar, setShowProgressBar] = useState(false);
|
const [showProgressBar, setShowProgressBar] = useState(false);
|
||||||
|
|
@ -121,14 +121,14 @@ export default function Dashboard() {
|
||||||
|
|
||||||
|
|
||||||
// Calculate portfolio stats
|
// Calculate portfolio stats
|
||||||
const currentValue = priceData.current_price
|
const currentValue = priceData.current_price
|
||||||
? purchaseData.total_shares * priceData.current_price
|
? purchaseData.total_shares * priceData.current_price
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const profitLoss = currentValue
|
const profitLoss = currentValue
|
||||||
? currentValue - purchaseData.total_investment
|
? currentValue - purchaseData.total_investment
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const profitLossPercentage = profitLoss && purchaseData.total_investment > 0
|
const profitLossPercentage = profitLoss && purchaseData.total_investment > 0
|
||||||
? (profitLoss / purchaseData.total_investment) * 100
|
? (profitLoss / purchaseData.total_investment) * 100
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
@ -168,36 +168,37 @@ export default function Dashboard() {
|
||||||
|
|
||||||
const handleProgressClick = () => {
|
const handleProgressClick = () => {
|
||||||
setShowStatsBox(!showStatsBox);
|
setShowStatsBox(!showStatsBox);
|
||||||
|
setActiveForm(null)
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head title="VWCE Tracker" />
|
<Head title="VWCE Tracker" />
|
||||||
|
|
||||||
{/* Stacked Layout */}
|
{/* Stacked Layout */}
|
||||||
<div className="min-h-screen bg-black">
|
<div className="min-h-screen bg-black">
|
||||||
<div className="w-full max-w-4xl mx-auto px-4">
|
<div className="w-full max-w-4xl mx-auto px-4">
|
||||||
{/* Box 1: LED Number Display - Fixed position from top */}
|
{/* Box 1: LED Number Display - Fixed position from top */}
|
||||||
<div className="pt-32">
|
<div className="pt-32">
|
||||||
<LedDisplay
|
<LedDisplay
|
||||||
value={purchaseData.total_shares}
|
value={purchaseData.total_shares}
|
||||||
onClick={handleLedClick}
|
onClick={handleLedClick}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Box 2: Progress Bar (toggleable) */}
|
{/* Box 2: Progress Bar (toggleable) */}
|
||||||
<div className="mt-4" style={{ display: showProgressBar ? 'block' : 'none' }}>
|
<div style={{ display: showProgressBar ? 'block' : 'none' }}>
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
currentShares={purchaseData.total_shares}
|
currentShares={purchaseData.total_shares}
|
||||||
milestones={milestones}
|
milestones={milestones}
|
||||||
selectedMilestoneIndex={selectedMilestoneIndex}
|
selectedMilestoneIndex={selectedMilestoneIndex}
|
||||||
onClick={handleProgressClick}
|
onClick={handleProgressClick}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Box 3: Stats Box (toggleable) */}
|
{/* Box 3: Stats Box (toggleable) */}
|
||||||
<div className="mt-4" style={{ display: showStatsBox ? 'block' : 'none' }}>
|
<div style={{ display: showStatsBox ? 'block' : 'none' }}>
|
||||||
<StatsBox
|
<StatsBox
|
||||||
stats={statsData}
|
stats={statsData}
|
||||||
milestones={milestones}
|
milestones={milestones}
|
||||||
selectedMilestoneIndex={selectedMilestoneIndex}
|
selectedMilestoneIndex={selectedMilestoneIndex}
|
||||||
|
|
@ -207,9 +208,9 @@ export default function Dashboard() {
|
||||||
onUpdatePrice={() => setActiveForm('price')}
|
onUpdatePrice={() => setActiveForm('price')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Box 4: Forms (only when active form is set) */}
|
{/* Box 4: Forms (only when active form is set) */}
|
||||||
<div className="mt-4" style={{ display: activeForm ? 'block' : 'none' }}>
|
<div style={{ display: activeForm && showProgressBar && showStatsBox ? 'block' : 'none' }}>
|
||||||
<InlineForm
|
<InlineForm
|
||||||
type={activeForm}
|
type={activeForm}
|
||||||
onClose={() => setActiveForm(null)}
|
onClose={() => setActiveForm(null)}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue