From 27f0ac85680e123068906900f7871d2f4c763c93 Mon Sep 17 00:00:00 2001 From: myrmidex Date: Sat, 2 May 2026 15:07:24 +0200 Subject: [PATCH] 28 - Refactor: User::default(), eliminate double-fetch, type currentAsset --- app/Http/Controllers/AssetController.php | 24 ++------- .../Controllers/Pricing/PricingController.php | 41 +++++--------- app/Models/User.php | 8 +++ resources/js/pages/dashboard.tsx | 54 +++++++------------ 4 files changed, 46 insertions(+), 81 deletions(-) diff --git a/app/Http/Controllers/AssetController.php b/app/Http/Controllers/AssetController.php index b248cc5..aec988c 100644 --- a/app/Http/Controllers/AssetController.php +++ b/app/Http/Controllers/AssetController.php @@ -6,7 +6,6 @@ use App\Models\User; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Auth; class AssetController extends Controller { @@ -19,13 +18,11 @@ public function index(): JsonResponse public function current(): JsonResponse { - // Get the first/default user (since no auth) - $user = User::first(); - $asset = $user ? $user->asset : null; + $user = User::default(); return response()->json([ - 'asset' => $asset, - 'price_tracking_enabled' => $user?->price_tracking_enabled ?? false, + 'asset' => $user->asset, + 'price_tracking_enabled' => $user->price_tracking_enabled, ]); } @@ -41,20 +38,7 @@ public function setCurrent(Request $request) $validated['full_name'] ?? null ); - // Get or create the first/default user (since no auth) - $user = User::first(); - - if (! $user) { - // Create a default user if none exists - $user = User::create([ - 'name' => 'Default User', - 'email' => 'user@example.com', - 'password' => 'password', // This will be hashed automatically - 'asset_id' => $asset->id, - ]); - } else { - $user->update(['asset_id' => $asset->id]); - } + User::default()->update(['asset_id' => $asset->id]); return back()->with('success', 'Asset set successfully!'); } diff --git a/app/Http/Controllers/Pricing/PricingController.php b/app/Http/Controllers/Pricing/PricingController.php index f5fd606..f6ed425 100644 --- a/app/Http/Controllers/Pricing/PricingController.php +++ b/app/Http/Controllers/Pricing/PricingController.php @@ -10,16 +10,17 @@ class PricingController extends Controller { + private User $user; + + public function __construct() + { + $this->user = User::default(); + } + public function current(): JsonResponse { - // Get the first/default user (since no auth) - $user = User::first(); - $assetId = $user ? $user->asset_id : null; - - $price = AssetPrice::current($assetId); - return response()->json([ - 'current_price' => $price, + 'current_price' => AssetPrice::current($this->user->asset_id), ]); } @@ -30,17 +31,14 @@ public function update(Request $request) 'price' => 'required|numeric|min:0.0001', ]); - // Get the first/default user (since no auth) - $user = User::first(); - - if (! $user || ! $user->asset_id) { + if (! $this->user->asset_id) { return back()->withErrors(['asset' => 'Please set an asset first.']); } - AssetPrice::updatePrice($user->asset_id, $validated['date'], $validated['price']); + AssetPrice::updatePrice($this->user->asset_id, $validated['date'], $validated['price']); - if (! $user->price_tracking_enabled) { - $user->update(['price_tracking_enabled' => true]); + if (! $this->user->price_tracking_enabled) { + $this->user->update(['price_tracking_enabled' => true]); } return back()->with('success', 'Asset price updated successfully!'); @@ -48,27 +46,16 @@ public function update(Request $request) public function history(Request $request): JsonResponse { - // Get the first/default user (since no auth) - $user = User::first(); - $assetId = $user ? $user->asset_id : null; - $limit = $request->get('limit', 30); - $history = AssetPrice::history($assetId, $limit); - return response()->json($history); + return response()->json(AssetPrice::history($this->user->asset_id, $limit)); } public function forDate(Request $request, string $date): JsonResponse { - // Get the first/default user (since no auth) - $user = User::first(); - $assetId = $user ? $user->asset_id : null; - - $price = AssetPrice::forDate($date, $assetId); - return response()->json([ 'date' => $date, - 'price' => $price, + 'price' => AssetPrice::forDate($date, $this->user->asset_id), ]); } } diff --git a/app/Models/User.php b/app/Models/User.php index ef412a4..bbc50a0 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -55,6 +55,14 @@ public function asset(): BelongsTo return $this->belongsTo(Asset::class); } + public static function default(): self + { + return self::firstOrCreate( + ['email' => 'user@incr.local'], + ['name' => 'Default User', 'password' => 'password'] + ); + } + public function hasCompletedOnboarding(): bool { return $this->hasPurchases() && $this->hasMilestones(); diff --git a/resources/js/pages/dashboard.tsx b/resources/js/pages/dashboard.tsx index d52f1ec..144d137 100644 --- a/resources/js/pages/dashboard.tsx +++ b/resources/js/pages/dashboard.tsx @@ -23,6 +23,12 @@ interface Milestone { created_at: string; } +interface CurrentAsset { + id: number; + symbol: string; + full_name: string | null; +} + export default function Dashboard() { const [purchaseData, setPurchaseData] = useState({ total_shares: 0, @@ -41,7 +47,7 @@ export default function Dashboard() { const [activeForm, setActiveForm] = useState<'purchase' | 'milestone' | 'price' | null>(null); const [loading, setLoading] = useState(true); const [needsOnboarding, setNeedsOnboarding] = useState(false); - const [currentAsset, setCurrentAsset] = useState(null); + const [currentAsset, setCurrentAsset] = useState(null); const [priceTrackingEnabled, setPriceTrackingEnabled] = useState(false); // Fetch purchase summary, current price, milestones, and check onboarding @@ -55,9 +61,13 @@ export default function Dashboard() { fetch('/assets/current'), ]); + let totalShares = 0; + let milestonesCount = 0; + if (purchaseResponse.ok) { const purchases = await purchaseResponse.json(); setPurchaseData(purchases); + totalShares = purchases.total_shares; } if (priceResponse.ok) { @@ -68,6 +78,7 @@ export default function Dashboard() { if (milestonesResponse.ok) { const milestonesData = await milestonesResponse.json(); setMilestones(milestonesData); + milestonesCount = milestonesData.length; } if (assetResponse.ok) { @@ -76,8 +87,7 @@ export default function Dashboard() { setPriceTrackingEnabled(assetData.price_tracking_enabled ?? false); } - // Check if onboarding is needed after all data is loaded - await checkOnboardingStatus(); + setNeedsOnboarding(totalShares === 0 || milestonesCount === 0); } catch (error) { console.error('Failed to fetch data:', error); } finally { @@ -88,33 +98,6 @@ export default function Dashboard() { fetchData(); }, []); - // Check if user needs onboarding - const checkOnboardingStatus = async () => { - try { - const [assetResponse, purchaseResponse, milestonesResponse] = await Promise.all([ - fetch('/assets/current'), - fetch('/purchases/summary'), - fetch('/milestones'), - ]); - - const assetData = await assetResponse.json(); - const purchaseData = await purchaseResponse.json(); - const milestonesData = await milestonesResponse.json(); - - const hasAsset = !!assetData.asset; - const hasPurchases = purchaseData.total_shares > 0; - const hasMilestones = milestonesData.length > 0; - - // User needs onboarding if any required step is missing - const needsOnboarding = !hasPurchases || !hasMilestones; - setNeedsOnboarding(needsOnboarding); - } catch (error) { - console.error('Failed to check onboarding status:', error); - // If we can't check, assume onboarding is needed - setNeedsOnboarding(true); - } - }; - // Refresh data after successful purchase const handlePurchaseSuccess = async () => { try { @@ -211,10 +194,6 @@ export default function Dashboard() { // Handle onboarding completion const handleOnboardingComplete = async () => { - // Refresh all data and check onboarding status - await checkOnboardingStatus(); - - // Refresh individual data sets const [purchaseResponse, priceResponse, milestonesResponse, assetResponse] = await Promise.all([ fetch('/purchases/summary'), fetch('/pricing/current'), @@ -222,9 +201,13 @@ export default function Dashboard() { fetch('/assets/current'), ]); + let totalShares = 0; + let milestonesCount = 0; + if (purchaseResponse.ok) { const purchases = await purchaseResponse.json(); setPurchaseData(purchases); + totalShares = purchases.total_shares; } if (priceResponse.ok) { @@ -235,6 +218,7 @@ export default function Dashboard() { if (milestonesResponse.ok) { const milestonesData = await milestonesResponse.json(); setMilestones(milestonesData); + milestonesCount = milestonesData.length; } if (assetResponse.ok) { @@ -242,6 +226,8 @@ export default function Dashboard() { setCurrentAsset(assetData.asset); setPriceTrackingEnabled(assetData.price_tracking_enabled ?? false); } + + setNeedsOnboarding(totalShares === 0 || milestonesCount === 0); }; // Show onboarding if needed