diff --git a/app/Http/Controllers/CustomerLicenseController.php b/app/Http/Controllers/CustomerLicenseController.php
index 62cc960a..4f85638a 100644
--- a/app/Http/Controllers/CustomerLicenseController.php
+++ b/app/Http/Controllers/CustomerLicenseController.php
@@ -63,8 +63,9 @@ public function index(): View
default => 'No accounts connected',
};
- // Total purchases (licenses + plugins)
- $totalPurchases = $licenseCount + $pluginLicenseCount;
+ // Total purchases (licenses + plugins + products)
+ $productLicenseCount = $user->productLicenses()->count();
+ $totalPurchases = $licenseCount + $pluginLicenseCount + $productLicenseCount;
return view('customer.dashboard', compact(
'licenseCount',
diff --git a/app/Http/Controllers/PurchaseHistoryController.php b/app/Http/Controllers/PurchaseHistoryController.php
index fb2f0b45..e2fd10eb 100644
--- a/app/Http/Controllers/PurchaseHistoryController.php
+++ b/app/Http/Controllers/PurchaseHistoryController.php
@@ -61,8 +61,28 @@ public function index(): View
];
});
+ // Fetch product licenses (e.g. Plugin Dev Kit, Masterclass)
+ $productLicenses = $user->productLicenses()
+ ->with('product')
+ ->orderBy('purchased_at', 'desc')
+ ->get()
+ ->map(function ($productLicense) {
+ return [
+ 'type' => 'product',
+ 'name' => $productLicense->product->name ?? 'Product',
+ 'description' => $productLicense->product->description ?? null,
+ 'price' => $productLicense->price_paid,
+ 'currency' => $productLicense->currency,
+ 'purchased_at' => $productLicense->purchased_at,
+ 'expires_at' => null,
+ 'is_active' => true,
+ 'href' => $productLicense->product ? route('products.show', $productLicense->product) : null,
+ ];
+ });
+
// Combine and sort by purchased_at descending
$purchases = $licenses->concat($pluginLicenses)
+ ->concat($productLicenses)
->sortByDesc('purchased_at')
->values();
diff --git a/resources/views/customer/purchase-history/index.blade.php b/resources/views/customer/purchase-history/index.blade.php
index fe821f34..46e1b80f 100644
--- a/resources/views/customer/purchase-history/index.blade.php
+++ b/resources/views/customer/purchase-history/index.blade.php
@@ -41,6 +41,10 @@
+ @elseif($purchase['type'] === 'product')
+
+
+
@else
@@ -63,6 +67,10 @@
License
+ @elseif($purchase['type'] === 'product')
+
+ Product
+
@else
Plugin
diff --git a/tests/Feature/PurchaseHistoryTest.php b/tests/Feature/PurchaseHistoryTest.php
new file mode 100644
index 00000000..b79c7191
--- /dev/null
+++ b/tests/Feature/PurchaseHistoryTest.php
@@ -0,0 +1,122 @@
+get('/customer/purchase-history');
+
+ $response->assertRedirect('/login');
+ }
+
+ public function test_purchase_history_shows_product_licenses(): void
+ {
+ $user = User::factory()->create();
+ $product = Product::factory()->create(['name' => 'Plugin Dev Kit']);
+
+ ProductLicense::factory()->create([
+ 'user_id' => $user->id,
+ 'product_id' => $product->id,
+ 'price_paid' => 4900,
+ 'currency' => 'USD',
+ 'purchased_at' => now()->subDay(),
+ ]);
+
+ $response = $this->actingAs($user)->get('/customer/purchase-history');
+
+ $response->assertStatus(200);
+ $response->assertSee('Plugin Dev Kit');
+ $response->assertSee('Product');
+ $response->assertSee('$49.00');
+ }
+
+ public function test_purchase_history_shows_multiple_product_types(): void
+ {
+ $user = User::factory()->create();
+
+ $devKit = Product::factory()->create(['name' => 'Plugin Dev Kit']);
+ $masterclass = Product::factory()->create(['name' => 'The NativePHP Masterclass']);
+
+ ProductLicense::factory()->create([
+ 'user_id' => $user->id,
+ 'product_id' => $devKit->id,
+ 'price_paid' => 4900,
+ 'purchased_at' => now()->subDays(2),
+ ]);
+
+ ProductLicense::factory()->create([
+ 'user_id' => $user->id,
+ 'product_id' => $masterclass->id,
+ 'price_paid' => 10100,
+ 'purchased_at' => now()->subDay(),
+ ]);
+
+ $response = $this->actingAs($user)->get('/customer/purchase-history');
+
+ $response->assertStatus(200);
+ $response->assertSee('Plugin Dev Kit');
+ $response->assertSee('The NativePHP Masterclass');
+ }
+
+ public function test_dashboard_total_purchases_includes_product_licenses(): void
+ {
+ $user = User::factory()->create();
+ $product = Product::factory()->create();
+
+ ProductLicense::factory()->create([
+ 'user_id' => $user->id,
+ 'product_id' => $product->id,
+ ]);
+
+ $response = $this->actingAs($user)->get('/dashboard');
+
+ $response->assertStatus(200);
+ $response->assertViewHas('totalPurchases', 1);
+ }
+
+ public function test_purchase_history_shows_empty_state_when_no_purchases(): void
+ {
+ $user = User::factory()->create();
+
+ $response = $this->actingAs($user)->get('/customer/purchase-history');
+
+ $response->assertStatus(200);
+ $response->assertSee('No purchases yet');
+ }
+
+ public function test_product_purchases_show_as_active(): void
+ {
+ $user = User::factory()->create();
+ $product = Product::factory()->create(['name' => 'Plugin Dev Kit']);
+
+ ProductLicense::factory()->create([
+ 'user_id' => $user->id,
+ 'product_id' => $product->id,
+ 'purchased_at' => now(),
+ ]);
+
+ $response = $this->actingAs($user)->get('/customer/purchase-history');
+
+ $response->assertStatus(200);
+ $response->assertSee('Active');
+ }
+}