appscms-tools-theme 5.2.3 → 5.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 71c8a266a0cb5bd4c81b600a2e2b58e74fd93f35d6e6a232690e6ecb20b169af
4
- data.tar.gz: a39fa1a4a45406117a822d2a92a09f02bdfae55385af7919fd0dc38cfb06693e
3
+ metadata.gz: 2c72045a315e29500c743645c3c663244a4634fdf34e9c1b99d41e9100c18385
4
+ data.tar.gz: 419f2df4838deb2f76dd9c9ab63cb764bd0d36af937cef06b8744fad204ed6ef
5
5
  SHA512:
6
- metadata.gz: '0992af8b2e1cecdf758eab5cdf6d10add51f5239b5b77622eb221a1f580a962719ee186039b75162580ca25a6a6e3e7e776c00a9f06ad831920133356ada137c'
7
- data.tar.gz: 27a948055440214671e4e6753531a6f7b624194999c33fa509f6f0c682fa815e4c1a673247beb02c0d9cbcbcd1b1f6ac14b914465dd2c5f08c7f6550a855b3fb
6
+ metadata.gz: 81e298f6a91ed13c65364e6562e4bafd0f8a022d2ac357075071a65352afb9ff402ad790a0013e40a60f1b64007baa1e84cb28c1a4d55a733af3719bd1f29a7e
7
+ data.tar.gz: 9278501b82f31a5a3f010167624d244e6b14dd4188ea35a3fb56092b11e57ce900e82a31bb9c702d717181884c1beb9fee13bfaeb9c469abad9eee1bbdd902a7
@@ -216,7 +216,7 @@
216
216
 
217
217
 
218
218
 
219
- {%- if page.layout == 'ai-image-home' or page.layout == "ai-image-generator" or page.layout == "ai-image-pricing" -%}
219
+ {%- if page.layout == 'ai-image-home' or page.layout == "ai-image-generator" or page.layout == "ai-image-pricing" or page.layout == "ai-image-profile" -%}
220
220
  <link rel="stylesheet" href="/assets/css/ai-image-home.css" />
221
221
  {%- endif -%}
222
222
 
@@ -233,7 +233,7 @@
233
233
  {%- endif -%}
234
234
 
235
235
  {%- if page.layout != 'contenttool-home' and page.layout != 'content-tool-ai' and page.layout != "ai-image-home" and page.layout != "ai-image-generator"
236
- and page.layout != "ai-image-pricing" -%}
236
+ and page.layout != "ai-image-pricing" and page.layout != "ai-image-profile" -%}
237
237
  <link rel="stylesheet" href="/assets/css/appscms-theme.css" />
238
238
  {%- endif -%}
239
239
 
@@ -60,6 +60,8 @@
60
60
  </div>
61
61
 
62
62
 
63
+
64
+ {%- if page.layout == "ai-image-home" -%}
63
65
  <a href="#" class="modal-item">
64
66
  <div class="item-icon">
65
67
  <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
@@ -75,9 +77,13 @@
75
77
  </g>
76
78
  </svg>
77
79
  </div>
78
- <div class="item-text" id="showCredits">Credits</div>
80
+ <div class="item-text" id="showCredits">Credits 0</div>
79
81
 
80
82
  </a>
83
+ {%- endif -%}
84
+
85
+
86
+
81
87
  <a href="/profile" class="modal-item">
82
88
  <div class="item-icon">
83
89
  <svg height="20" width="20" viewBox="0 0 24 24" id="Layer_1" data-name="Layer 1"
@@ -224,6 +230,8 @@
224
230
  </div>
225
231
  </div>
226
232
  </div>
233
+
234
+
227
235
  <div class="side-modal-overlay" id="modalOverlay"></div>
228
236
  <div class="side-modal" id="sideModal">
229
237
  <div class="modal-header">
@@ -436,11 +444,11 @@
436
444
 
437
445
  <script>
438
446
  document.addEventListener("DOMContentLoaded", function () {
439
- const toggler = document.querySelector(".navbar-toggler");
440
- const menu = document.getElementById("navbarSupportedContent");
447
+ const toggler = document.querySelector(".navbar-toggler");
448
+ const menu = document.getElementById("navbarSupportedContent");
441
449
 
442
- toggler.addEventListener("click", function () {
443
- menu.classList.toggle("show");
450
+ toggler.addEventListener("click", function () {
451
+ menu.classList.toggle("show");
452
+ });
444
453
  });
445
- });
446
454
  </script>
@@ -162,10 +162,6 @@ if page.layout == "appscms-feature" -%}
162
162
  <script src="/assets/js/userUsageCount.js"></script>
163
163
  {%- endif -%}
164
164
 
165
- {%- if page.layout == "ai-image-home" or page.layout == "ai-image-generator" or page.layout == "ai-image-pricing" -%}
166
- <script defer src="/assets/js/get-credits.js"></script>
167
- {%- endif -%}
168
-
169
165
 
170
166
  {%- if page.layout == "ai-image-generator" -%}
171
167
  <script src="/js/ai-image.generator.js"></script>
@@ -55,9 +55,9 @@
55
55
  </select>
56
56
  </div>
57
57
 
58
- <div class="settings d-none">
58
+ <div class="settings">
59
59
  <label class="setting-label">Additional Prompt</label>
60
- <textarea name="" id="additionalPrompt"></textarea>
60
+ <textarea class="select-box" name="" id="additionalPrompt"></textarea>
61
61
  </div>
62
62
 
63
63
  <div class="settings">
@@ -178,7 +178,257 @@
178
178
 
179
179
  <script src="https://checkout.razorpay.com/v1/checkout.js"></script>
180
180
 
181
+
181
182
  <script>
183
+ // Loading Overlay Functions
184
+ function createLoadingOverlays() {
185
+ const overlay = document.createElement("div");
186
+ overlay.id = "pricingLoadingOverlay";
187
+ overlay.innerHTML = `
188
+ <div class="pricing-loading-overlay">
189
+ <div class="pricing-loading-content">
190
+ <div class="pricing-loading-spinner"></div>
191
+ <div class="pricing-loading-text">Loading pricing plans...</div>
192
+ </div>
193
+ </div>
194
+ `;
195
+
196
+ // Add CSS if not already present
197
+ if (!document.querySelector("#pricingLoadingStyles")) {
198
+ const style = document.createElement("style");
199
+ style.id = "pricingLoadingStyles";
200
+ style.textContent = `
201
+ .pricing-loading-overlay {
202
+ position: fixed;
203
+ top: 0;
204
+ left: 0;
205
+ width: 100%;
206
+ height: 100%;
207
+ background: rgba(255, 255, 255, 0.95);
208
+ backdrop-filter: blur(4px);
209
+ display: flex;
210
+ align-items: center;
211
+ justify-content: center;
212
+ z-index: 10000;
213
+ opacity: 1;
214
+ transition: opacity 0.3s ease;
215
+ }
216
+
217
+ .pricing-loading-content {
218
+ text-align: center;
219
+ padding: 40px;
220
+ background: white;
221
+ border-radius: 12px;
222
+ box-shadow: 0 8px 32px rgba(0,0,0,0.1);
223
+ }
224
+
225
+ .pricing-loading-spinner {
226
+ width: 40px;
227
+ height: 40px;
228
+ border: 4px solid #f3f3f3;
229
+ border-top: 4px solid #f59e0b;
230
+ border-radius: 50%;
231
+ animation: pricingLoadingSpin 1s linear infinite;
232
+ margin: 0 auto 16px;
233
+ }
234
+
235
+ .pricing-loading-text {
236
+ color: #333;
237
+ font-size: 16px;
238
+ font-weight: 500;
239
+ }
240
+
241
+ @keyframes pricingLoadingSpin {
242
+ 0% { transform: rotate(0deg); }
243
+ 100% { transform: rotate(360deg); }
244
+ }
245
+
246
+ .pricing-loading-overlay.fade-out {
247
+ opacity: 0;
248
+ pointer-events: none;
249
+ }
250
+ `;
251
+ document.head.appendChild(style);
252
+ }
253
+
254
+ return overlay;
255
+ }
256
+
257
+ // Success Modal Function
258
+ function showSubscriptionSuccess() {
259
+ // Create success modal
260
+ const modal = document.createElement('div');
261
+ modal.id = 'subscriptionSuccessModal';
262
+ modal.innerHTML = `
263
+ <div class="success-modal-overlay">
264
+ <div class="success-modal-content">
265
+ <div class="success-icon-wrapper">
266
+ <svg class="success-checkmark" viewBox="0 0 52 52">
267
+ <circle class="success-checkmark-circle" cx="26" cy="26" r="25" fill="none"/>
268
+ <path class="success-checkmark-check" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8"/>
269
+ </svg>
270
+ </div>
271
+ <h2 class="success-title">Subscription Activated! 🎉</h2>
272
+ <p class="success-message">Your subscription has been successfully activated. You now have full access to all premium features!</p>
273
+ <div class="success-redirect-info">
274
+ <span class="redirect-text">Redirecting to dashboard in <span id="countdown">3</span>s...</span>
275
+ </div>
276
+ </div>
277
+ </div>
278
+ `;
279
+
280
+ // Add CSS for success modal
281
+ const style = document.createElement('style');
282
+ style.textContent = `
283
+ .success-modal-overlay {
284
+ position: fixed;
285
+ top: 0;
286
+ left: 0;
287
+ width: 100%;
288
+ height: 100%;
289
+ background: rgba(0, 0, 0, 0.6);
290
+ backdrop-filter: blur(8px);
291
+ display: flex;
292
+ align-items: center;
293
+ justify-content: center;
294
+ z-index: 10001;
295
+ animation: fadeIn 0.3s ease;
296
+ }
297
+
298
+ .success-modal-content {
299
+ background: white;
300
+ border-radius: 20px;
301
+ padding: 50px 40px;
302
+ max-width: 450px;
303
+ text-align: center;
304
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
305
+ animation: slideUp 0.4s ease;
306
+ }
307
+
308
+ .success-icon-wrapper {
309
+ margin: 0 auto 30px;
310
+ width: 80px;
311
+ height: 80px;
312
+ }
313
+
314
+ .success-checkmark {
315
+ width: 80px;
316
+ height: 80px;
317
+ border-radius: 50%;
318
+ display: block;
319
+ stroke-width: 3;
320
+ stroke: #10b981;
321
+ stroke-miterlimit: 10;
322
+ box-shadow: inset 0px 0px 0px #10b981;
323
+ animation: fill 0.4s ease-in-out 0.4s forwards, scale 0.3s ease-in-out 0.9s both;
324
+ }
325
+
326
+ .success-checkmark-circle {
327
+ stroke-dasharray: 166;
328
+ stroke-dashoffset: 166;
329
+ stroke-width: 3;
330
+ stroke-miterlimit: 10;
331
+ stroke: #10b981;
332
+ fill: none;
333
+ animation: stroke 0.6s cubic-bezier(0.65, 0, 0.45, 1) forwards;
334
+ }
335
+
336
+ .success-checkmark-check {
337
+ transform-origin: 50% 50%;
338
+ stroke-dasharray: 48;
339
+ stroke-dashoffset: 48;
340
+ stroke: #10b981;
341
+ animation: stroke 0.3s cubic-bezier(0.65, 0, 0.45, 1) 0.8s forwards;
342
+ }
343
+
344
+ .success-title {
345
+ font-size: 28px;
346
+ font-weight: 700;
347
+ color: #1f2937;
348
+ margin-bottom: 15px;
349
+ }
350
+
351
+ .success-message {
352
+ font-size: 16px;
353
+ color: #6b7280;
354
+ line-height: 1.6;
355
+ margin-bottom: 25px;
356
+ }
357
+
358
+ .success-redirect-info {
359
+ background: #f0fdf4;
360
+ border: 1px solid #86efac;
361
+ border-radius: 10px;
362
+ padding: 15px;
363
+ }
364
+
365
+ .redirect-text {
366
+ color: #166534;
367
+ font-size: 14px;
368
+ font-weight: 500;
369
+ }
370
+
371
+ #countdown {
372
+ font-weight: 700;
373
+ color: #10b981;
374
+ }
375
+
376
+ @keyframes fadeIn {
377
+ from { opacity: 0; }
378
+ to { opacity: 1; }
379
+ }
380
+
381
+ @keyframes slideUp {
382
+ from {
383
+ transform: translateY(30px);
384
+ opacity: 0;
385
+ }
386
+ to {
387
+ transform: translateY(0);
388
+ opacity: 1;
389
+ }
390
+ }
391
+
392
+ @keyframes stroke {
393
+ 100% {
394
+ stroke-dashoffset: 0;
395
+ }
396
+ }
397
+
398
+ @keyframes scale {
399
+ 0%, 100% {
400
+ transform: none;
401
+ }
402
+ 50% {
403
+ transform: scale3d(1.1, 1.1, 1);
404
+ }
405
+ }
406
+
407
+ @keyframes fill {
408
+ 100% {
409
+ box-shadow: inset 0px 0px 0px 30px #10b981;
410
+ }
411
+ }
412
+ `;
413
+ document.head.appendChild(style);
414
+ document.body.appendChild(modal);
415
+
416
+ // Countdown and redirect
417
+ let countdown = 3;
418
+ const countdownEl = document.getElementById('countdown');
419
+ const interval = setInterval(() => {
420
+ countdown--;
421
+ if (countdownEl) {
422
+ countdownEl.textContent = countdown;
423
+ }
424
+ if (countdown === 0) {
425
+ clearInterval(interval);
426
+ window.location.href = '/';
427
+ }
428
+ }, 1000);
429
+ }
430
+
431
+
182
432
  async function getAuthToken() {
183
433
  const storedToken = localStorage.getItem("authToken");
184
434
  if (storedToken) return storedToken;
@@ -201,11 +451,21 @@
201
451
 
202
452
  async function loadPricingPlans() {
203
453
  try {
454
+
455
+ const overlay = createLoadingOverlays();
456
+ document.body.appendChild(overlay);
457
+
204
458
  const res = await fetch(
205
459
  "https://us-central1-appscms-develop.cloudfunctions.net/payment_api/api/v1/payment-routes/image-toolkit-plans"
206
460
  );
207
461
  const data = await res.json();
208
462
 
463
+ // Remove loading overlay
464
+ const loadingOverlay = document.getElementById("pricingLoadingOverlay");
465
+ if (loadingOverlay) {
466
+ loadingOverlay.remove();
467
+ }
468
+
209
469
  const container = document.getElementById("pricingContainer");
210
470
  container.innerHTML = "";
211
471
 
@@ -222,7 +482,7 @@
222
482
  ${isPopular ? `<span class="popular-badge">Most Popular</span>` : ""}
223
483
 
224
484
  <div class="plan-header">
225
- <h2 class="plan-name">${plan.plan}</h2>
485
+ <h2 class="plan-name">${plan.plan.toLowerCase()}</h2>
226
486
  <p class="plan-description">
227
487
  ${isPopular ? "For creators and professionals" : "Perfect for beginners"}
228
488
  </p>
@@ -235,7 +495,7 @@
235
495
  </div>
236
496
  </div>
237
497
 
238
- <button class="buy-button"
498
+ <button class="buy-button" id=${plan.plan.toLowerCase()}
239
499
  onclick="buyPlan('${plan.razorpay_plan_id}', '${plan.plan}')">
240
500
  Buy Now
241
501
  </button>
@@ -254,6 +514,21 @@
254
514
  container.insertAdjacentHTML("beforeend", card);
255
515
  });
256
516
 
517
+ // After rendering all plans, disable the button for the user's active plan
518
+ if (typeof firebase !== "undefined" && firebase.auth) {
519
+ const user = firebase.auth().currentUser;
520
+ if (user) {
521
+ user.getIdTokenResult().then(tokenResult => {
522
+ const customClaims = tokenResult.claims;
523
+ if (customClaims.plan && window.disableActivePlanButton) {
524
+ window.disableActivePlanButton(customClaims.plan);
525
+ }
526
+ }).catch(err => {
527
+ console.error("Error getting user claims:", err);
528
+ });
529
+ }
530
+ }
531
+
257
532
  } catch (err) {
258
533
  console.error("Pricing load error:", err);
259
534
  }
@@ -262,7 +537,7 @@
262
537
  const PAYMENT_API_URL = "https://us-central1-appscms-develop.cloudfunctions.net/payment_api";
263
538
 
264
539
  async function checkSubscriptionStatus(subscriptionId) {
265
- const POLL_INTERVAL = 3000; // 3 sec (OK to keep)
540
+ const POLL_INTERVAL = 5000; // 3 sec (OK to keep)
266
541
  const TIMEOUT = 2 * 60 * 1000; // 2 minutes max
267
542
 
268
543
  const startTime = Date.now();
@@ -287,8 +562,9 @@
287
562
 
288
563
  // ✅ ACTIVE → STOP
289
564
  if (data.status === "activated") {
290
- alert("✅ Subscription Active!");
291
- hideLoadingOverlay()
565
+ hideLoadingOverlay();
566
+ showSubscriptionSuccess();
567
+ refreshFirebaseToken();
292
568
  return;
293
569
  }
294
570
 
@@ -0,0 +1,434 @@
1
+ {% assign file = page.fileName %} {% assign lang = page.lang %} {% assign folder
2
+ = page.folderName %} {% assign pageData = site.data[folder][lang][file] %} {%-
3
+ assign boxColor = site.data[page.folderName][page.lang][page.fileName].color -%}
4
+
5
+ <!DOCTYPE html>
6
+ <html lang="{{ page.lang }}">
7
+ {%- include appscms/head/head.html -%}
8
+ <link rel="stylesheet" href="/css/profile.css" />
9
+ <link rel="stylesheet" href="/ai-tools/assets/css/content-tool-ai.css" />
10
+
11
+ <body data-developer-key="{{ site.developerKey }}" data-client-id="{{ site.clientId }}" data-app-id="{{ site.appId }}"
12
+ data-dropbox-apikey="{{ site.dropboxapikey }}">
13
+
14
+ <div class="container">
15
+ {%- include /appscms/navbars/ai-image-tools-navbar.html -%}
16
+
17
+ <div class="container user-profile-section mt-5">
18
+ <!-- Sidebar -->
19
+ <div class="profile-sidebar">
20
+ <div class="sidebar-header">
21
+ <div class="avatar-large"></div>
22
+ </div>
23
+ <ul class="sidebar-menu">
24
+ <li class="tab-link active" data-tab="account">Account</li>
25
+ <li class="tab-link" data-tab="subscription">Subscription</li>
26
+ <!-- <li class="tab-link" data-tab="invoices">Invoices</li>
27
+ <li class="tab-link" data-tab="company">Company Information</li>
28
+ <li class="tab-link" data-tab="team">Team</li>
29
+ <li class="tab-link" data-tab="settings">Settings</li> -->
30
+ </ul>
31
+ </div>
32
+
33
+ <!-- Content Area -->
34
+ <div class="content">
35
+ <!-- Account Tab Content -->
36
+ <div id="account" class="tab-content active">
37
+ <h2 class="content-title">Account</h2>
38
+
39
+ <!-- Email Section -->
40
+ <div class="form-section">
41
+ <div class="form-title">
42
+ Email <span class="verified-badge">Verified</span>
43
+ </div>
44
+ <div class="form-group">
45
+ <input id="user-email-input" type="email" class="form-input" value="" readonly />
46
+ </div>
47
+ </div>
48
+
49
+ <!-- Name Section -->
50
+ <div class="form-section">
51
+ <div class="form-title">Name</div>
52
+ <div class="form-group">
53
+ <label class="form-label">Name</label>
54
+ <input type="text" class="form-input username-input" value="" />
55
+ </div>
56
+ </div>
57
+ </div>
58
+
59
+ <!-- Subscription Tab Content -->
60
+ <div id="subscription" class="tab-content">
61
+ <h2 class="content-title">Subscription</h2>
62
+
63
+ <!-- Current Plan Section -->
64
+ <div class="form-section">
65
+ <div class="form-title">Current Plan</div>
66
+ <div class="subscription-card">
67
+ <div class="plan-header">
68
+ <div class="plan-info">
69
+ <h3 class="current-plan-name" style="text-transform: capitalize">
70
+ Free Plan
71
+ </h3>
72
+ <!-- <span class="plan-badge current-plan-badge">Free</span> -->
73
+ </div>
74
+ <div class="plan-status">
75
+ <span class="subscription-status active">Loading...</span>
76
+ </div>
77
+ </div>
78
+ <div class="plan-details">
79
+ <!-- <div class="detail-item">
80
+ <span class="detail-label">Token Limit:</span>
81
+ <span class="token-limit">Loading...</span>
82
+ </div>
83
+ <div class="detail-item">
84
+ <span class="detail-label">Plan Duration:</span>
85
+ <span class="plan-duration">Loading...</span>
86
+ </div> -->
87
+ <div class="detail-item">
88
+ <span class="detail-label">Expires On:</span>
89
+ <span class="plan-expiry">Loading...</span>
90
+ </div>
91
+ <div class="detail-item">
92
+ <span class="detail-label">Subscription ID:</span>
93
+ <span class="subscription-id">Loading...</span>
94
+ </div>
95
+ </div>
96
+ </div>
97
+ </div>
98
+
99
+ <!-- Usage Section -->
100
+ <div class="form-section d-none">
101
+ <div class="form-title">Usage Statistics</div>
102
+ <div class="usage-card">
103
+ <div class="usage-item">
104
+ <div class="usage-header">
105
+ <span class="usage-label">Tokens Used This Month</span>
106
+ <span class="usage-value">
107
+ <span class="tokens-used">0</span> /
108
+ <span class="token-limit-display">0</span>
109
+ tokens
110
+ </span>
111
+ </div>
112
+ <div class="usage-progress">
113
+ <div class="progress-bar">
114
+ <div class="progress-fill" style="width: 0%"></div>
115
+ </div>
116
+ <span class="usage-percentage">0%</span>
117
+ </div>
118
+ </div>
119
+ <div class="usage-item">
120
+ <div class="usage-header">
121
+ <span class="usage-label">Days Remaining</span>
122
+ <span class="usage-value days-remaining">Loading...</span>
123
+ </div>
124
+ </div>
125
+ </div>
126
+ </div>
127
+
128
+ <!-- Plan Features Section -->
129
+ <div class="form-section d-none">
130
+ <div class="form-title">Plan Features</div>
131
+ <div class="features-card">
132
+ <div class="features-list" id="current-plan-features">
133
+ <!-- Features will be populated by JavaScript -->
134
+ </div>
135
+ </div>
136
+ </div>
137
+
138
+ <!-- Actions Section -->
139
+ <div class="form-section">
140
+ <div class="form-title">Actions</div>
141
+ <div class="actions-card">
142
+ <button class="btn-manage" onclick="window.location.href='/pricing'">
143
+ Manage Subscription
144
+ </button>
145
+ <button class="btn-cancel-subscription" id="cancelSubscriptionBtn"
146
+ onclick="showCancelConfirmation()" style="display: none;">
147
+ Cancel Subscription
148
+ </button>
149
+ </div>
150
+ </div>
151
+
152
+ <!-- Expiry Warning -->
153
+ <div class="expiry-warning" style="display: none">
154
+ <div class="warning-content">
155
+ <i class="warning-icon">⚠️</i>
156
+ <span class="warning-text">Your plan expires soon!</span>
157
+ </div>
158
+ </div>
159
+ </div>
160
+
161
+ </div>
162
+ </div>
163
+ </div>
164
+
165
+ <!-- Cancel Subscription Confirmation Modal -->
166
+ <div id="cancelConfirmationModal" class="cancel-modal" style="display: none;">
167
+ <div class="cancel-modal-overlay" onclick="hideCancelConfirmation()"></div>
168
+ <div class="cancel-modal-content">
169
+ <div class="cancel-modal-header">
170
+ <div class="cancel-icon-wrapper">
171
+ <svg class="cancel-warning-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
172
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
173
+ d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
174
+ </svg>
175
+ </div>
176
+ <h3 class="cancel-modal-title">Cancel Subscription?</h3>
177
+ <p class="cancel-modal-description">
178
+ Are you sure you want to cancel your subscription? You will lose access to all premium features at
179
+ the end of your current billing period.
180
+ </p>
181
+ </div>
182
+ <div class="cancel-modal-body">
183
+ <div class="cancel-warning-box">
184
+ <strong>⚠️ What you'll lose:</strong>
185
+ <ul class="cancel-loss-list">
186
+ <li>Access to premium AI image generation</li>
187
+ <li>Higher token limits</li>
188
+ <li>Priority support</li>
189
+ <li>Advanced features</li>
190
+ </ul>
191
+ </div>
192
+ </div>
193
+ <div class="cancel-modal-footer">
194
+ <button class="btn-cancel-action" onclick="hideCancelConfirmation()">
195
+ Keep Subscription
196
+ </button>
197
+ <button class="btn-confirm-cancel" onclick="confirmCancelSubscription()">
198
+ Yes, Cancel Subscription
199
+ </button>
200
+ </div>
201
+ </div>
202
+ </div>
203
+
204
+ <style>
205
+ /* Cancel Subscription Button */
206
+ .btn-cancel-subscription {
207
+ background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
208
+ color: white;
209
+ border: none;
210
+ border-radius: 8px;
211
+ font-size: 14px;
212
+ font-weight: 600;
213
+ cursor: pointer;
214
+ transition: all 0.3s ease;
215
+ padding: 10px 20px;
216
+ }
217
+
218
+ .btn-cancel-subscription:hover {
219
+ background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%);
220
+ transform: translateY(-2px);
221
+ box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3);
222
+ }
223
+
224
+ /* Cancel Modal */
225
+ .cancel-modal {
226
+ position: fixed;
227
+ top: 0;
228
+ left: 0;
229
+ width: 100%;
230
+ height: 100%;
231
+ z-index: 10000;
232
+ display: flex;
233
+ align-items: center;
234
+ justify-content: center;
235
+ }
236
+
237
+ .cancel-modal-overlay {
238
+ position: absolute;
239
+ top: 0;
240
+ left: 0;
241
+ width: 100%;
242
+ height: 100%;
243
+ background: rgba(0, 0, 0, 0.6);
244
+ backdrop-filter: blur(4px);
245
+ animation: fadeIn 0.3s ease;
246
+ }
247
+
248
+ .cancel-modal-content {
249
+ position: relative;
250
+ background: white;
251
+ border-radius: 16px;
252
+ max-width: 500px;
253
+ width: 90%;
254
+ padding: 30px;
255
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
256
+ animation: slideUp 0.3s ease;
257
+ z-index: 10001;
258
+ }
259
+
260
+ .cancel-modal-header {
261
+ text-align: center;
262
+ margin-bottom: 25px;
263
+ }
264
+
265
+ .cancel-icon-wrapper {
266
+ width: 80px;
267
+ height: 80px;
268
+ margin: 0 auto 20px;
269
+ background: #fef2f2;
270
+ border-radius: 50%;
271
+ display: flex;
272
+ align-items: center;
273
+ justify-content: center;
274
+ }
275
+
276
+ .cancel-warning-icon {
277
+ width: 40px;
278
+ height: 40px;
279
+ color: #ef4444;
280
+ }
281
+
282
+ .cancel-modal-title {
283
+ font-size: 24px;
284
+ font-weight: 700;
285
+ color: #1f2937;
286
+ margin-bottom: 10px;
287
+ }
288
+
289
+ .cancel-modal-description {
290
+ font-size: 15px;
291
+ color: #6b7280;
292
+ line-height: 1.6;
293
+ }
294
+
295
+ .cancel-modal-body {
296
+ margin-bottom: 25px;
297
+ }
298
+
299
+ .cancel-warning-box {
300
+ background: #fef2f2;
301
+ border: 1px solid #fecaca;
302
+ border-radius: 10px;
303
+ padding: 15px;
304
+ color: #991b1b;
305
+ }
306
+
307
+ .cancel-warning-box strong {
308
+ display: block;
309
+ margin-bottom: 10px;
310
+ font-size: 14px;
311
+ }
312
+
313
+ .cancel-loss-list {
314
+ margin: 0;
315
+ padding-left: 20px;
316
+ font-size: 13px;
317
+ line-height: 1.8;
318
+ }
319
+
320
+ .cancel-loss-list li {
321
+ margin-bottom: 5px;
322
+ }
323
+
324
+ .cancel-modal-footer {
325
+ display: flex;
326
+ gap: 12px;
327
+ flex-direction: column-reverse;
328
+ }
329
+
330
+ .btn-cancel-action,
331
+ .btn-confirm-cancel {
332
+ padding: 12px 24px;
333
+ border-radius: 8px;
334
+ font-size: 14px;
335
+ font-weight: 600;
336
+ cursor: pointer;
337
+ transition: all 0.3s ease;
338
+ border: none;
339
+ width: 100%;
340
+ }
341
+
342
+ .btn-cancel-action {
343
+ background: #f3f4f6;
344
+ color: #374151;
345
+ }
346
+
347
+ .btn-cancel-action:hover {
348
+ background: #e5e7eb;
349
+ }
350
+
351
+ .btn-confirm-cancel {
352
+ background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%);
353
+ color: white;
354
+ }
355
+
356
+ .btn-confirm-cancel:hover {
357
+ background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%);
358
+ }
359
+
360
+ @keyframes fadeIn {
361
+ from {
362
+ opacity: 0;
363
+ }
364
+
365
+ to {
366
+ opacity: 1;
367
+ }
368
+ }
369
+
370
+ @keyframes slideUp {
371
+ from {
372
+ transform: translateY(30px);
373
+ opacity: 0;
374
+ }
375
+
376
+ to {
377
+ transform: translateY(0);
378
+ opacity: 1;
379
+ }
380
+ }
381
+
382
+ @media (min-width: 640px) {
383
+ .cancel-modal-footer {
384
+ flex-direction: row;
385
+ }
386
+ }
387
+ </style>
388
+
389
+ <script>
390
+ // Tab functionality
391
+ document.addEventListener("DOMContentLoaded", function () {
392
+ const tabLinks = document.querySelectorAll(".tab-link");
393
+ const tabContents = document.querySelectorAll(".tab-content");
394
+
395
+ tabLinks.forEach((link) => {
396
+ link.addEventListener("click", () => {
397
+ // Remove active class from all tabs
398
+ tabLinks.forEach((l) => l.classList.remove("active"));
399
+ tabContents.forEach((c) => c.classList.remove("active"));
400
+
401
+ // Add active class to clicked tab
402
+ link.classList.add("active");
403
+
404
+ // Show corresponding content
405
+ const tabId = link.getAttribute("data-tab");
406
+ document.getElementById(tabId).classList.add("active");
407
+ });
408
+ });
409
+
410
+ // Password visibility toggle
411
+ const toggleButtons = document.querySelectorAll(".password-toggle");
412
+ toggleButtons.forEach((button) => {
413
+ button.addEventListener("click", () => {
414
+ const input = button.previousElementSibling;
415
+ const icon = button.querySelector(".material-icons");
416
+
417
+ if (input.type === "password") {
418
+ input.type = "text";
419
+ icon.textContent = "visibility_off";
420
+ } else {
421
+ input.type = "password";
422
+ icon.textContent = "visibility";
423
+ }
424
+ });
425
+ });
426
+ });
427
+
428
+ </script>
429
+
430
+ {%- include appscms/scripts/script.html -%}
431
+ </body>
432
+
433
+ </html>
434
+ ```
@@ -27,6 +27,9 @@ body {
27
27
  .nav-item .nav-link {
28
28
  color: var(--black-color);
29
29
  }
30
+ .logged-in-user-email{
31
+ font-size: 12px;
32
+ }
30
33
 
31
34
  .btn-generate,
32
35
  .login-btn {
@@ -404,8 +407,8 @@ body {
404
407
  }
405
408
 
406
409
  .profile-user-avatar {
407
- width: 60px;
408
- height: 60px;
410
+ width: 50px;
411
+ height: 50px;
409
412
  border-radius: 50%;
410
413
  background-color: var(--primary-color);
411
414
  color: white;
@@ -1,91 +0,0 @@
1
-
2
- async function getAuthToken() {
3
- return new Promise((resolve) => {
4
- // First try to get from localStorage (set by Firebase auth)
5
- const storedToken = localStorage.getItem("authToken");
6
- if (storedToken) {
7
- resolve(storedToken);
8
- return;
9
- }
10
-
11
- // If Firebase is available and user is logged in, get fresh token
12
- if (typeof firebase !== "undefined" && firebase.auth) {
13
- try {
14
- const user = firebase.auth().currentUser;
15
- if (user) {
16
- user
17
- .getIdToken(true) // Force refresh
18
- .then((token) => {
19
- // Save to localStorage for faster access
20
- localStorage.setItem("authToken", token);
21
- resolve(token);
22
- })
23
- .catch((error) => {
24
- console.warn("Failed to get auth token:", error);
25
- resolve(null);
26
- });
27
- } else {
28
- console.warn("User not logged in");
29
- resolve(null);
30
- }
31
- } catch (error) {
32
- console.warn("Firebase check error:", error);
33
- resolve(null);
34
- }
35
- } else {
36
- // Fallback to session storage
37
- const sessionToken = sessionStorage.getItem("authToken");
38
- resolve(sessionToken || null);
39
- }
40
- });
41
- }
42
- const BACKEND_API_URL = 'https://us-central1-appscms-develop.cloudfunctions.net/ai_image_tools/api/v1/image-tools-routes';
43
-
44
- async function getUserCredits() {
45
- try {
46
- const authToken = await getAuthToken();
47
- if (!authToken) {
48
- throw new Error("User not authenticated");
49
- }
50
- const res = await fetch(`${BACKEND_API_URL}/remaining-credits`, {
51
- method: "GET",
52
- headers: {
53
- "Authorization": `Bearer ${authToken}`,
54
- "Content-Type": "application/json"
55
- }
56
- });
57
-
58
- if (!res.ok) {
59
- const errorText = await res.text();
60
- let errorMsg = "Failed to fetch credits";
61
-
62
- try {
63
- const errorJson = JSON.parse(errorText);
64
- errorMsg = errorJson.detail || errorMsg;
65
- } catch { }
66
-
67
- throw new Error(errorMsg);
68
- }
69
-
70
- const data = await res.json();
71
-
72
- return data;
73
-
74
- } catch (error) {
75
- console.error("Get credits error:", error);
76
- showError(error.message || "Unable to fetch credits");
77
- return null;
78
- }
79
- }
80
-
81
- (async () => {
82
- const creditData = await getUserCredits();
83
-
84
- if (creditData) {
85
- const creditEl = document.querySelector("#showCredits");
86
- if (creditEl) {
87
- creditEl.innerHTML = `Credits: ${creditData.credits}`;
88
- console.log("Credits:", creditData.credits);
89
- }
90
- }
91
- })();
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appscms-tools-theme
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.3
4
+ version: 5.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - vivek-appscms
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-12-30 00:00:00.000000000 Z
11
+ date: 2026-01-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jekyll
@@ -266,6 +266,7 @@ files:
266
266
  - _layouts/ai-image-generator.html
267
267
  - _layouts/ai-image-home.html
268
268
  - _layouts/ai-image-pricing.html
269
+ - _layouts/ai-image-profile.html
269
270
  - _layouts/allAuthors.html
270
271
  - _layouts/appscms-about.html
271
272
  - _layouts/appscms-audio.html