28 - Refactor: User::default(), eliminate double-fetch, type currentAsset

This commit is contained in:
myrmidex 2026-05-02 15:07:24 +02:00
parent 7a17d4d90c
commit 27f0ac8568
4 changed files with 46 additions and 81 deletions

View file

@ -6,7 +6,6 @@
use App\Models\User; use App\Models\User;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class AssetController extends Controller class AssetController extends Controller
{ {
@ -19,13 +18,11 @@ public function index(): JsonResponse
public function current(): JsonResponse public function current(): JsonResponse
{ {
// Get the first/default user (since no auth) $user = User::default();
$user = User::first();
$asset = $user ? $user->asset : null;
return response()->json([ return response()->json([
'asset' => $asset, 'asset' => $user->asset,
'price_tracking_enabled' => $user?->price_tracking_enabled ?? false, 'price_tracking_enabled' => $user->price_tracking_enabled,
]); ]);
} }
@ -41,20 +38,7 @@ public function setCurrent(Request $request)
$validated['full_name'] ?? null $validated['full_name'] ?? null
); );
// Get or create the first/default user (since no auth) User::default()->update(['asset_id' => $asset->id]);
$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]);
}
return back()->with('success', 'Asset set successfully!'); return back()->with('success', 'Asset set successfully!');
} }

View file

@ -10,16 +10,17 @@
class PricingController extends Controller class PricingController extends Controller
{ {
private User $user;
public function __construct()
{
$this->user = User::default();
}
public function current(): JsonResponse 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([ 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', 'price' => 'required|numeric|min:0.0001',
]); ]);
// Get the first/default user (since no auth) if (! $this->user->asset_id) {
$user = User::first();
if (! $user || ! $user->asset_id) {
return back()->withErrors(['asset' => 'Please set an asset first.']); 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) { if (! $this->user->price_tracking_enabled) {
$user->update(['price_tracking_enabled' => true]); $this->user->update(['price_tracking_enabled' => true]);
} }
return back()->with('success', 'Asset price updated successfully!'); return back()->with('success', 'Asset price updated successfully!');
@ -48,27 +46,16 @@ public function update(Request $request)
public function history(Request $request): JsonResponse 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); $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 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([ return response()->json([
'date' => $date, 'date' => $date,
'price' => $price, 'price' => AssetPrice::forDate($date, $this->user->asset_id),
]); ]);
} }
} }

View file

@ -55,6 +55,14 @@ public function asset(): BelongsTo
return $this->belongsTo(Asset::class); 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 public function hasCompletedOnboarding(): bool
{ {
return $this->hasPurchases() && $this->hasMilestones(); return $this->hasPurchases() && $this->hasMilestones();

View file

@ -23,6 +23,12 @@ interface Milestone {
created_at: string; created_at: string;
} }
interface CurrentAsset {
id: number;
symbol: string;
full_name: string | null;
}
export default function Dashboard() { export default function Dashboard() {
const [purchaseData, setPurchaseData] = useState<PurchaseSummary>({ const [purchaseData, setPurchaseData] = useState<PurchaseSummary>({
total_shares: 0, total_shares: 0,
@ -41,7 +47,7 @@ export default function Dashboard() {
const [activeForm, setActiveForm] = useState<'purchase' | 'milestone' | 'price' | null>(null); const [activeForm, setActiveForm] = useState<'purchase' | 'milestone' | 'price' | null>(null);
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [needsOnboarding, setNeedsOnboarding] = useState(false); const [needsOnboarding, setNeedsOnboarding] = useState(false);
const [currentAsset, setCurrentAsset] = useState<any>(null); const [currentAsset, setCurrentAsset] = useState<CurrentAsset | null>(null);
const [priceTrackingEnabled, setPriceTrackingEnabled] = useState(false); const [priceTrackingEnabled, setPriceTrackingEnabled] = useState(false);
// Fetch purchase summary, current price, milestones, and check onboarding // Fetch purchase summary, current price, milestones, and check onboarding
@ -55,9 +61,13 @@ export default function Dashboard() {
fetch('/assets/current'), fetch('/assets/current'),
]); ]);
let totalShares = 0;
let milestonesCount = 0;
if (purchaseResponse.ok) { if (purchaseResponse.ok) {
const purchases = await purchaseResponse.json(); const purchases = await purchaseResponse.json();
setPurchaseData(purchases); setPurchaseData(purchases);
totalShares = purchases.total_shares;
} }
if (priceResponse.ok) { if (priceResponse.ok) {
@ -68,6 +78,7 @@ export default function Dashboard() {
if (milestonesResponse.ok) { if (milestonesResponse.ok) {
const milestonesData = await milestonesResponse.json(); const milestonesData = await milestonesResponse.json();
setMilestones(milestonesData); setMilestones(milestonesData);
milestonesCount = milestonesData.length;
} }
if (assetResponse.ok) { if (assetResponse.ok) {
@ -76,8 +87,7 @@ export default function Dashboard() {
setPriceTrackingEnabled(assetData.price_tracking_enabled ?? false); setPriceTrackingEnabled(assetData.price_tracking_enabled ?? false);
} }
// Check if onboarding is needed after all data is loaded setNeedsOnboarding(totalShares === 0 || milestonesCount === 0);
await checkOnboardingStatus();
} catch (error) { } catch (error) {
console.error('Failed to fetch data:', error); console.error('Failed to fetch data:', error);
} finally { } finally {
@ -88,33 +98,6 @@ export default function Dashboard() {
fetchData(); 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 // Refresh data after successful purchase
const handlePurchaseSuccess = async () => { const handlePurchaseSuccess = async () => {
try { try {
@ -211,10 +194,6 @@ export default function Dashboard() {
// Handle onboarding completion // Handle onboarding completion
const handleOnboardingComplete = async () => { const handleOnboardingComplete = async () => {
// Refresh all data and check onboarding status
await checkOnboardingStatus();
// Refresh individual data sets
const [purchaseResponse, priceResponse, milestonesResponse, assetResponse] = await Promise.all([ const [purchaseResponse, priceResponse, milestonesResponse, assetResponse] = await Promise.all([
fetch('/purchases/summary'), fetch('/purchases/summary'),
fetch('/pricing/current'), fetch('/pricing/current'),
@ -222,9 +201,13 @@ export default function Dashboard() {
fetch('/assets/current'), fetch('/assets/current'),
]); ]);
let totalShares = 0;
let milestonesCount = 0;
if (purchaseResponse.ok) { if (purchaseResponse.ok) {
const purchases = await purchaseResponse.json(); const purchases = await purchaseResponse.json();
setPurchaseData(purchases); setPurchaseData(purchases);
totalShares = purchases.total_shares;
} }
if (priceResponse.ok) { if (priceResponse.ok) {
@ -235,6 +218,7 @@ export default function Dashboard() {
if (milestonesResponse.ok) { if (milestonesResponse.ok) {
const milestonesData = await milestonesResponse.json(); const milestonesData = await milestonesResponse.json();
setMilestones(milestonesData); setMilestones(milestonesData);
milestonesCount = milestonesData.length;
} }
if (assetResponse.ok) { if (assetResponse.ok) {
@ -242,6 +226,8 @@ export default function Dashboard() {
setCurrentAsset(assetData.asset); setCurrentAsset(assetData.asset);
setPriceTrackingEnabled(assetData.price_tracking_enabled ?? false); setPriceTrackingEnabled(assetData.price_tracking_enabled ?? false);
} }
setNeedsOnboarding(totalShares === 0 || milestonesCount === 0);
}; };
// Show onboarding if needed // Show onboarding if needed