feat: Add Stripe payment integration and subscription management
- Add Stripe.net SDK for payment processing - Implement StripeService with checkout sessions, customer portal, webhooks - Implement SubscriptionService for quota management - Add quota enforcement to CVCheckService - Create Pricing, Billing, Settings pages - Add checkout success/cancel pages - Update Check and Dashboard with usage indicators - Add ResetMonthlyUsageJob for billing cycle resets - Add database migration for subscription fields Plan tiers: Free (3 checks), Professional £49/mo (30), Enterprise £199/mo (unlimited) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
@implements IDisposable
|
||||
|
||||
@inject ICVCheckService CVCheckService
|
||||
@inject ISubscriptionService SubscriptionService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject AuthenticationStateProvider AuthenticationStateProvider
|
||||
@inject ILogger<Dashboard> Logger
|
||||
@@ -18,6 +19,30 @@
|
||||
<div>
|
||||
<h1 class="fw-bold mb-1">Dashboard</h1>
|
||||
<p class="text-muted mb-0">View and manage your CV verification checks</p>
|
||||
@if (_subscription != null)
|
||||
{
|
||||
<div class="mt-2">
|
||||
@if (_subscription.IsUnlimited)
|
||||
{
|
||||
<span class="badge bg-success-subtle text-success px-3 py-2">
|
||||
Enterprise - Unlimited checks
|
||||
</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
var percentage = _subscription.MonthlyLimit > 0
|
||||
? Math.Min(100, (_subscription.ChecksUsedThisMonth * 100) / _subscription.MonthlyLimit)
|
||||
: 0;
|
||||
<span class="badge @(percentage >= 90 ? "bg-danger-subtle text-danger" : percentage >= 75 ? "bg-warning-subtle text-warning" : "bg-primary-subtle text-primary") px-3 py-2">
|
||||
@_subscription.Plan: @_subscription.ChecksUsedThisMonth / @_subscription.MonthlyLimit checks used
|
||||
</span>
|
||||
@if (_subscription.ChecksRemaining <= 0)
|
||||
{
|
||||
<a href="/pricing" class="btn btn-sm btn-warning ms-2">Upgrade</a>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="d-flex gap-2">
|
||||
<button class="btn btn-outline-secondary" @onclick="ExportToPdf" disabled="@(_isExporting || !HasCompletedChecks())">
|
||||
@@ -486,6 +511,7 @@
|
||||
private bool _isDeleting;
|
||||
private string? _errorMessage;
|
||||
private Guid _userId;
|
||||
private SubscriptionInfoDto? _subscription;
|
||||
private System.Threading.Timer? _pollingTimer;
|
||||
private volatile bool _isPolling;
|
||||
private volatile bool _disposed;
|
||||
@@ -579,6 +605,7 @@
|
||||
}
|
||||
|
||||
_checks = await CVCheckService.GetUserChecksAsync(_userId) ?? [];
|
||||
_subscription = await SubscriptionService.GetSubscriptionInfoAsync(_userId);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user