File size: 18,694 Bytes
6f32ae8
 
 
 
 
d8a7fc4
6f32ae8
d8a7fc4
6f32ae8
d8a7fc4
 
 
6f32ae8
 
 
 
 
 
 
 
 
 
d8a7fc4
6f32ae8
 
 
 
 
6469525
d8a7fc4
 
6469525
d8a7fc4
 
ec76476
 
 
 
 
d8a7fc4
 
 
 
 
 
 
 
ec76476
d8a7fc4
 
 
 
 
6f32ae8
6469525
a83fc52
6469525
 
 
 
 
 
 
 
 
 
a83fc52
 
6469525
 
 
 
 
 
 
 
 
a83fc52
 
 
6469525
a83fc52
ec76476
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d8a7fc4
 
6f32ae8
 
d8a7fc4
6f32ae8
 
d8a7fc4
 
 
 
 
 
 
6f32ae8
 
d8a7fc4
 
6f32ae8
 
 
 
d8a7fc4
 
 
 
 
 
 
6f32ae8
 
 
d8a7fc4
 
 
 
6f32ae8
d8a7fc4
6f32ae8
d8a7fc4
 
 
6f32ae8
d8a7fc4
6f32ae8
d8a7fc4
 
 
6f32ae8
d8a7fc4
 
 
 
 
 
 
6f32ae8
 
 
a83fc52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6f32ae8
a83fc52
6f32ae8
 
d8a7fc4
 
 
 
 
 
 
 
 
 
6f32ae8
 
 
d8a7fc4
6f32ae8
 
 
 
ec76476
a83fc52
 
 
6f32ae8
 
 
 
 
 
 
 
 
 
 
 
 
ec76476
 
 
 
 
 
a83fc52
 
 
6f32ae8
 
 
 
 
 
 
 
 
a83fc52
d8a7fc4
 
6f32ae8
 
 
a83fc52
6f32ae8
 
a83fc52
 
 
 
 
d8a7fc4
a83fc52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d8a7fc4
6f32ae8
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
@page "/membership"
@using LibraryManagement.Shared.Models
@using BlazorWebAssembly.Services
@inject LibraryApiClient ApiClient
@inject NavigationManager Navigation
@inject IJSRuntime JS

<div class="max-w-7xl mx-auto py-24 px-8 animate-fade">
    <!-- Header -->
    <div class="text-center mb-24">
        <h2 class="text-xs font-black text-primary uppercase tracking-[0.3em] mb-4">Pricing Plans</h2>
        <h1 class="text-7xl font-black tracking-tighter text-main mb-8 uppercase leading-[0.9]">Choose Your <br /> <span class="text-primary italic">Journey.</span></h1>
        <p class="text-xl text-muted max-w-2xl mx-auto leading-relaxed">
            From casual readers to devoted bookworms, we have a plan that perfectly matches your literary appetite.
        </p>
    </div>

    @if (_isLoading)
    {
        <div class="grid grid-cols-1 md:grid-cols-3 gap-8">
            @for (int i = 0; i < 3; i++)
            {
                <div class="animate-pulse bg-card rounded-[3rem] border border-border h-[600px]"></div>
            }
        </div>
    }
    else
    {
        <!-- Auth Section -->
        <AuthorizeView>
            <Authorized>
                <!-- Current Subscription Banner -->
                @if (_currentSub != null)
                {
                    <div class="bg-primary/5 border border-primary/20 rounded-[2.5rem] p-10 mb-12 flex flex-col md:flex-row items-center justify-between gap-8 shadow-sm relative overflow-hidden group">
                        <div class="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-opacity">
                            <svg class="w-32 h-32" fill="currentColor" viewBox="0 0 24 24"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg>
                        </div>
                        <div class="flex items-center gap-8 relative z-10">
                            <div class="w-20 h-20 bg-primary rounded-3xl flex items-center justify-center text-white text-4xl font-black shadow-lg shadow-primary/20">
                                @(_currentSub.MembershipType?[..1].ToUpper())
                            </div>
                            <div>
                                <h3 class="text-3xl font-black text-main uppercase tracking-tight">@_currentSub.MembershipType Plan</h3>
                                <p class="text-muted font-medium">Active until <span class="text-main font-bold">@_currentSub.ExpiryDate.ToString("MMMM dd, yyyy")</span></p>
                            </div>
                        </div>
                        <div class="flex items-center gap-6 relative z-10">
                            <div class="flex flex-col items-end">
                                <span class="px-4 py-1.5 bg-green-500/10 text-green-600 rounded-full text-[10px] font-black uppercase tracking-widest mb-2">Active Status</span>
                                <span class="text-xs text-muted font-bold uppercase tracking-widest">Auto-renews monthly</span>
                            </div>
                        </div>
                    </div>
                }

                <!-- Wallet & Loyalty Summary (Always visible for logged in) -->
                <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-12">
                    <div class="bg-card border border-border rounded-3xl p-6 flex items-center justify-between shadow-sm">
                        <div class="flex items-center gap-4">
                            <div class="w-12 h-12 bg-primary/10 rounded-2xl flex items-center justify-center text-primary">
                                <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"/></svg>
                            </div>
                            <div>
                                <p class="text-[10px] font-black text-muted uppercase tracking-widest">Loyalty Points</p>
                                <p class="text-xl font-black text-main">@(_loyaltyAccount?.CurrentBalance.ToString("N0") ?? "0")</p>
                            </div>
                        </div>
                    </div>
                    <div class="bg-card border border-border rounded-3xl p-6 flex items-center justify-between shadow-sm">
                        <div class="flex items-center gap-4">
                            <div class="w-12 h-12 bg-emerald-500/10 rounded-2xl flex items-center justify-center text-emerald-500">
                                <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
                            </div>
                            <div>
                                <p class="text-[10px] font-black text-muted uppercase tracking-widest">Wallet Balance</p>
                                <p class="text-xl font-black text-main">@_walletBalance.ToString("N0") <span class="text-xs font-bold text-muted">MMK</span></p>
                            </div>
                        </div>
                    </div>
                </div>

                @if (_queuedRewards.Any())
                {
                    <div class="mb-20 animate-fade-in-down">
                        <div class="flex items-center gap-3 mb-8">
                            <div class="h-px flex-grow bg-border"></div>
                            <h3 class="text-xs font-black text-amber-500 uppercase tracking-[0.4em] px-4 whitespace-nowrap">Queued Rewards</h3>
                            <div class="h-px flex-grow bg-border"></div>
                        </div>
                        
                        <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
                            @foreach (var sub in _queuedRewards)
                            {
                                <div class="bg-card border border-amber-500/20 rounded-3xl p-8 flex items-center justify-between shadow-sm hover:shadow-lg transition-all border-l-4 border-l-amber-500 relative overflow-hidden group">
                                    <div class="absolute top-0 right-0 p-4 opacity-[0.03] group-hover:opacity-[0.07] transition-opacity">
                                        <svg class="w-20 h-20" fill="currentColor" viewBox="0 0 24 24"><path d="M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z"/></svg>
                                    </div>
                                    <div class="flex items-center gap-6 relative z-10">
                                        <div class="w-14 h-14 bg-amber-500/10 rounded-2xl flex items-center justify-center text-amber-500">
                                            <svg class="w-7 h-7" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
                                        </div>
                                        <div>
                                            <h4 class="text-xl font-black text-main uppercase">@sub.MembershipType</h4>
                                            <p class="text-sm text-muted font-medium">Starts on @sub.StartDate.ToString("MMM dd, yyyy")</p>
                                        </div>
                                    </div>
                                    <div class="text-right relative z-10">
                                        <span class="inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-[10px] font-black uppercase tracking-widest bg-green-500/10 text-green-500">
                                            <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7"></path></svg>
                                            Approved
                                        </span>
                                        <p class="text-[10px] text-muted font-bold uppercase tracking-widest mt-2">Queued in Pipeline</p>
                                    </div>
                                </div>
                            }
                        </div>
                    </div>
                }
            </Authorized>
        </AuthorizeView>

        <!-- Membership Plans -->
        <div class="grid grid-cols-1 lg:grid-cols-3 gap-10">
            @foreach (var plan in _memberships)
            {
                <div class='relative bg-card rounded-[3.5rem] border p-12 flex flex-col transition-all duration-700 hover:-translate-y-4 @(IsCurrentPlan(plan.Id) ? "border-primary shadow-2xl shadow-primary/10 scale-105 z-10" : "border-border shadow-xl hover:shadow-2xl")'>
                    @if (plan.Price > 20 && !IsCurrentPlan(plan.Id))
                    {
                        <div class="absolute -top-5 left-1/2 -translate-x-1/2 bg-emerald-500 text-white px-6 py-2 rounded-full text-[10px] font-black uppercase tracking-[0.2em] shadow-lg shadow-emerald-500/30">
                            Most Popular
                        </div>
                    }
                    @if (IsCurrentPlan(plan.Id))
                    {
                        <div class="absolute -top-5 left-1/2 -translate-x-1/2 bg-primary text-white px-6 py-2 rounded-full text-[10px] font-black uppercase tracking-[0.2em] shadow-lg shadow-primary/30">
                            Your Current Plan
                        </div>
                    }

                    <div class="mb-10">
                        <h3 class="text-sm font-black text-muted uppercase tracking-[0.3em] mb-6">@plan.Type</h3>
                        <div class="flex flex-col gap-1">
                            <div class="flex items-baseline gap-2 flex-wrap">
                                <span class="text-5xl font-black text-main tracking-tighter">@plan.Price.ToString("N0")</span>
                                <span class="text-2xl font-bold text-muted">mmk</span>
                            </div>
                            <span class="text-muted font-bold uppercase text-sm tracking-widest mt-1">/ @plan.DurationMonths mo</span>
                        </div>
                    </div>

                    <div class="space-y-6 mb-16 flex-grow">
                        <div class="flex items-center gap-5 group/item">
                            <div class="w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center text-primary group-hover/item:scale-110 transition-transform flex-shrink-0">
                                <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7"></path></svg>
                            </div>
                            <span class="text-main font-bold text-lg">Borrow <span class="text-primary">@plan.MaxBooks</span> books</span>
                        </div>
                        <div class="flex items-center gap-5 group/item">
                            <div class="w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center text-primary group-hover/item:scale-110 transition-transform flex-shrink-0">
                                <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7"></path></svg>
                            </div>
                            <span class="text-main font-bold text-lg">@plan.BorrowingDays Day period</span>
                        </div>
                        <div class="flex items-center gap-5 group/item">
                            <div class="w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center text-primary group-hover/item:scale-110 transition-transform flex-shrink-0">
                                <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7"></path></svg>
                            </div>
                            <span class="text-main font-bold text-lg">Digital access included</span>
                        </div>
                        <div class="flex items-center gap-5 group/item">
                            <div class="w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center text-primary group-hover/item:scale-110 transition-transform flex-shrink-0">
                                <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7"></path></svg>
                            </div>
                            <span class="text-main font-bold text-lg">Loyalty point multiplier</span>
                        </div>
                    </div>

                    <div class="space-y-4 mt-auto">
                        <button @onclick="() => SubscribeAsync(plan)" 
                                disabled="@IsCurrentPlan(plan.Id)"
                                class='w-full py-5 rounded-[2rem] font-black uppercase tracking-widest text-[10px] transition-all @(IsCurrentPlan(plan.Id) ? "bg-body text-muted border border-border cursor-not-allowed" : "bg-main text-white hover:bg-black transform hover:scale-[1.02] active:scale-95")'>
                            @(IsCurrentPlan(plan.Id) ? "Active Now" : "Pay Cash at Library")
                        </button>

                        @if (!IsCurrentPlan(plan.Id))
                        {
                            <button @onclick="() => BuyWithWallet(plan)" 
                                    class="w-full py-5 rounded-[2rem] bg-primary text-white font-black uppercase tracking-widest text-[10px] hover:bg-primary-hover shadow-lg shadow-primary/20 transition-all transform hover:scale-[1.02] active:scale-95">
                                Buy with Wallet
                            </button>
                        }
                    </div>
                </div>

            }
        </div>

        <div class="mt-24 text-center">
            <p class="text-muted font-medium mb-8">All plans include 24/7 support and access to our community events.</p>
            <div class="flex items-center justify-center gap-12 opacity-50 grayscale hover:grayscale-0 transition-all">
                <!-- Trust Badges Placeholder -->
                <span class="font-black text-xl uppercase tracking-tighter">Secure Payment</span>
                <span class="font-black text-xl uppercase tracking-tighter">Cancel Anytime</span>
                <span class="font-black text-xl uppercase tracking-tighter">No Hidden Fees</span>
            </div>
        </div>
    }
</div>


@code {
    private bool _isLoading = true;
    private List<MembershipDto> _memberships = new();
    private SubscriptionDto? _currentSub;
    private List<SubscriptionDto> _queuedRewards = new();
    private decimal _walletBalance;
    private LoyaltyAccountDto? _loyaltyAccount;


    protected override async Task OnInitializedAsync()
    {
        await LoadData();
    }

    private async Task LoadData()
    {
        _isLoading = true;
        try
        {
            _memberships = (await ApiClient.GetMembershipsAsync()).ToList();
            _currentSub = await ApiClient.GetMySubscriptionAsync();
            
            var allSubs = await ApiClient.GetMyAllSubscriptionsAsync();
            _queuedRewards = allSubs
                .Where(s => !string.IsNullOrEmpty(s.ExternalRedemptionId) && s.StartDate > DateTime.UtcNow)
                .OrderBy(s => s.StartDate)
                .ToList();

            _walletBalance = await ApiClient.GetWalletBalanceAsync();
            _loyaltyAccount = await ApiClient.GetMyLoyaltyAccountAsync();
        }
        catch { }
        finally { _isLoading = false; }
    }

    private bool IsCurrentPlan(int id) => _currentSub?.MembershipId == id;

    private async Task SubscribeAsync(MembershipDto plan)
    {
        bool confirmed = await JS.InvokeAsync<bool>("confirm", $"Are you sure you want to subscribe to {plan.Type} for {plan.Price:N0} mmk? Please pay the cash at the library counter to activate.");
        if (!confirmed) return;

        var result = await ApiClient.SubscribeAsync(new SubscribeRequest { MembershipId = plan.Id });
        if (result != null)
        {
            await JS.InvokeVoidAsync("alert", "Request submitted! Please visit the librarian to pay and activate.");
            await LoadData();
        }
    }

    private async Task BuyWithWallet(MembershipDto plan)
    {
        try
        {
            var preview = await ApiClient.GetUpgradePreviewAsync(plan.Id);
            if (preview == null || !preview.CanUpgrade)
            {
                await JS.InvokeVoidAsync("alert", preview?.Message ?? "Cannot upgrade to this plan.");
                return;
            }

            string confirmMsg = $"Purchase {plan.Type} membership?\n\n" +
                               $"Price: {preview.OriginalPrice:N0} MMK\n";
            
            if (preview.DiscountAmount > 0)
            {
                confirmMsg += $"Upgrade Discount: -{preview.DiscountAmount:N0} MMK\n";
            }
            
            confirmMsg += $"Total: {preview.FinalPrice:N0} MMK\n\n" +
                         $"Your Balance: {_walletBalance:N0} MMK";

            bool confirmed = await JS.InvokeAsync<bool>("confirm", confirmMsg);
            if (!confirmed) return;

            if (_walletBalance < preview.FinalPrice)
            {
                await JS.InvokeVoidAsync("alert", "Insufficient wallet balance. Please top up at the library counter.");
                return;
            }

            var result = await ApiClient.SubscribeWithWalletAsync(new SubscribeRequest { MembershipId = plan.Id });
            if (result != null)
            {
                await JS.InvokeVoidAsync("alert", "Subscription purchased successfully!");
                await LoadData();
            }
            else
            {
                await JS.InvokeVoidAsync("alert", "Failed to complete purchase.");
            }
        }
        catch (Exception ex)
        {
            await JS.InvokeVoidAsync("alert", "Error: " + ex.Message);
        }
    }
}