28 - Refactor: User::default(), eliminate double-fetch, type currentAsset
This commit is contained in:
parent
7a17d4d90c
commit
27f0ac8568
4 changed files with 46 additions and 81 deletions
|
|
@ -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!');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue