@digilogiclabs/create-saas-app 1.5.4 → 1.6.0

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.
Files changed (54) hide show
  1. package/CHANGELOG.md +109 -49
  2. package/bin/index.js +1 -1
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/templates/mobile/base/template/App.tsx +113 -23
  5. package/dist/templates/mobile/base/template/package.json +5 -2
  6. package/dist/templates/web/base/template/package.json +1 -1
  7. package/dist/templates/web/base/template/src/app/checkout/page.tsx +99 -8
  8. package/dist/templates/web/base/template/src/app/dashboard/page.tsx +309 -0
  9. package/dist/templates/web/base/template/src/app/globals.css +97 -0
  10. package/dist/templates/web/base/template/src/app/login/page.tsx +36 -8
  11. package/dist/templates/web/base/template/src/app/page.tsx +123 -83
  12. package/dist/templates/web/base/template/src/app/signup/page.tsx +36 -8
  13. package/dist/templates/web/base/template/src/components/shared/header.tsx +49 -30
  14. package/dist/templates/web/ui-auth/template/package.json +2 -2
  15. package/dist/templates/web/ui-auth/template/src/app/page.tsx +203 -61
  16. package/dist/templates/web/ui-auth-payments/template/package.json +2 -2
  17. package/dist/templates/web/ui-auth-payments/template/src/app/checkout/page.tsx +253 -87
  18. package/dist/templates/web/ui-auth-payments/template/src/app/globals.css +129 -0
  19. package/dist/templates/web/ui-auth-payments/template/src/app/page.tsx +246 -74
  20. package/dist/templates/web/ui-auth-payments/template/src/components/shared/header.tsx +106 -40
  21. package/dist/templates/web/ui-auth-payments-audio/template/package.json +2 -2
  22. package/dist/templates/web/ui-auth-payments-audio/template/src/app/page.tsx +221 -82
  23. package/dist/templates/web/ui-auth-payments-audio/template/src/components/shared/header.tsx +132 -40
  24. package/dist/templates/web/ui-auth-payments-video/template/package.json +2 -2
  25. package/dist/templates/web/ui-auth-payments-video/template/src/app/globals.css +146 -0
  26. package/dist/templates/web/ui-auth-payments-video/template/src/app/page.tsx +259 -85
  27. package/dist/templates/web/ui-auth-payments-video/template/src/components/shared/header.tsx +133 -41
  28. package/package.json +106 -106
  29. package/src/templates/mobile/base/template/App.tsx +113 -23
  30. package/src/templates/mobile/base/template/package.json +5 -2
  31. package/src/templates/web/base/template/package.json +1 -1
  32. package/src/templates/web/base/template/src/app/checkout/page.tsx +99 -8
  33. package/src/templates/web/base/template/src/app/dashboard/page.tsx +309 -0
  34. package/src/templates/web/base/template/src/app/globals.css +97 -0
  35. package/src/templates/web/base/template/src/app/login/page.tsx +36 -8
  36. package/src/templates/web/base/template/src/app/page.tsx +123 -83
  37. package/src/templates/web/base/template/src/app/signup/page.tsx +36 -8
  38. package/src/templates/web/base/template/src/components/shared/header.tsx +49 -30
  39. package/src/templates/web/ui-auth/template/package.json +2 -2
  40. package/src/templates/web/ui-auth/template/src/app/page.tsx +203 -61
  41. package/src/templates/web/ui-auth-payments/template/package.json +2 -2
  42. package/src/templates/web/ui-auth-payments/template/src/app/checkout/page.tsx +253 -87
  43. package/src/templates/web/ui-auth-payments/template/src/app/globals.css +129 -0
  44. package/src/templates/web/ui-auth-payments/template/src/app/page.tsx +246 -74
  45. package/src/templates/web/ui-auth-payments/template/src/components/shared/header.tsx +106 -40
  46. package/src/templates/web/ui-auth-payments-audio/template/package.json +2 -2
  47. package/src/templates/web/ui-auth-payments-audio/template/src/app/page.tsx +221 -82
  48. package/src/templates/web/ui-auth-payments-audio/template/src/components/shared/header.tsx +132 -40
  49. package/src/templates/web/ui-auth-payments-video/template/package.json +2 -2
  50. package/src/templates/web/ui-auth-payments-video/template/src/app/globals.css +146 -0
  51. package/src/templates/web/ui-auth-payments-video/template/src/app/page.tsx +259 -85
  52. package/src/templates/web/ui-auth-payments-video/template/src/components/shared/header.tsx +133 -41
  53. package/dist/index.js +0 -1173
  54. package/dist/index.js.map +0 -1
@@ -1,14 +1,32 @@
1
1
  'use client';
2
2
 
3
- import React from 'react';
3
+ import React, { useState } from 'react';
4
4
  import { usePayments, formatCurrency } from '@digilogiclabs/saas-factory-payments';
5
- import { Button, Card } from '@digilogiclabs/saas-factory-ui';
5
+ import {
6
+ Button,
7
+ Card,
8
+ PageTransition,
9
+ MobileContainer,
10
+ ResponsiveGrid,
11
+ SwipeableCard,
12
+ NetworkAwareContent,
13
+ OfflineWrapper,
14
+ TouchInput,
15
+ MobileForm,
16
+ useNetworkInfo,
17
+ useOfflineState
18
+ } from '@digilogiclabs/saas-factory-ui';
19
+ import { CreditCard, Check, Star, Wifi, WifiOff, ArrowLeft, ArrowRight } from 'lucide-react';
6
20
 
7
21
  export default function CheckoutPage() {
8
22
  const { loading } = usePayments();
23
+ const networkInfo = useNetworkInfo();
24
+ const isOnline = useOfflineState();
25
+ const [selectedPlan, setSelectedPlan] = useState<string | null>(null);
9
26
 
10
27
  const handlePlanSelect = (planId: string) => {
11
28
  console.log('Plan selected:', planId);
29
+ setSelectedPlan(planId);
12
30
  // Handle plan selection - redirect to payment processing
13
31
  };
14
32
 
@@ -47,96 +65,244 @@ export default function CheckoutPage() {
47
65
  ];
48
66
 
49
67
  return (
50
- <div className="min-h-screen bg-gray-100 py-8">
51
- <div className="max-w-6xl mx-auto px-4">
52
- <div className="text-center mb-12">
53
- <h1 className="text-4xl font-bold text-gray-900 mb-4">Choose Your Plan</h1>
54
- <p className="text-xl text-gray-600">Select the perfect plan for your needs</p>
55
- </div>
56
-
57
- {/* Subscription Plans */}
58
- <div className="grid md:grid-cols-3 gap-6 mb-8">
68
+ <PageTransition type="slide" direction="up" duration={350}>
69
+ <OfflineWrapper
70
+ cacheStrategy="cache-first"
71
+ showOfflineIndicator={true}
72
+ >
73
+ <div className="min-h-screen bg-gray-100">
74
+ <MobileContainer className="py-8">
75
+ {/* Network Status */}
76
+ <div className="flex justify-center mb-4">
77
+ <div className="flex items-center gap-2 text-sm px-3 py-1 rounded-full bg-white shadow-sm">
78
+ {isOnline ? (
79
+ <>
80
+ <Wifi className="w-4 h-4 text-green-600" />
81
+ <span>Secure Connection</span>
82
+ {networkInfo?.effectiveType && (
83
+ <span className="bg-green-100 text-green-800 px-2 py-1 rounded text-xs">
84
+ {networkInfo.effectiveType.toUpperCase()}
85
+ </span>
86
+ )}
87
+ </>
88
+ ) : (
89
+ <>
90
+ <WifiOff className="w-4 h-4 text-red-600" />
91
+ <span>Offline - Plans cached</span>
92
+ </>
93
+ )}
94
+ </div>
95
+ </div>
96
+
97
+ <div className="text-center mb-12">
98
+ <h1 className="text-3xl md:text-4xl font-bold text-gray-900 mb-4">Choose Your Plan</h1>
99
+ <p className="text-lg md:text-xl text-gray-600">Select the perfect plan for your needs</p>
100
+ </div>
101
+
102
+ {/* Subscription Plans */}
103
+ <NetworkAwareContent
104
+ showOnSlow={
105
+ <ResponsiveGrid columns={{ base: 1, md: 2 }} gap="lg" className="mb-8">
106
+ {plans.slice(0, 2).map((plan) => (
107
+ <Card key={plan.id} className={`p-6 relative ${plan.popular ? 'ring-2 ring-blue-500' : ''}`}>
108
+ {plan.popular && (
109
+ <div className="absolute -top-3 left-1/2 transform -translate-x-1/2">
110
+ <span className="bg-blue-500 text-white px-3 py-1 rounded-full text-sm font-medium flex items-center gap-1">
111
+ <Star className="w-3 h-3" />
112
+ Most Popular
113
+ </span>
114
+ </div>
115
+ )}
116
+ <h3 className="text-xl font-bold mb-2">{plan.name}</h3>
117
+ <div className="text-3xl font-bold mb-4">
118
+ {formatCurrency(plan.price)}
119
+ <span className="text-sm font-normal">/{plan.interval}</span>
120
+ </div>
121
+ <ul className="mb-6 space-y-2">
122
+ {plan.features.slice(0, 3).map((feature, index) => (
123
+ <li key={index} className="flex items-center">
124
+ <Check className="text-green-500 mr-2 w-4 h-4" />
125
+ {feature}
126
+ </li>
127
+ ))}
128
+ </ul>
129
+ <Button
130
+ onClick={() => handlePlanSelect(plan.id)}
131
+ disabled={loading}
132
+ className="w-full"
133
+ variant={plan.popular ? "default" : "outline"}
134
+ size="lg"
135
+ >
136
+ {loading ? 'Processing...' : 'Select Plan'}
137
+ </Button>
138
+ </Card>
139
+ ))}
140
+ </ResponsiveGrid>
141
+ }
142
+ >
143
+ <ResponsiveGrid columns={{ base: 1, md: 3 }} gap="lg" className="mb-8">
59
144
  {plans.map((plan) => (
60
- <Card key={plan.id} className={`p-6 relative ${plan.popular ? 'ring-2 ring-blue-500' : ''}`}>
61
- {plan.popular && (
62
- <div className="absolute -top-3 left-1/2 transform -translate-x-1/2">
63
- <span className="bg-blue-500 text-white px-3 py-1 rounded-full text-sm font-medium">
64
- Most Popular
65
- </span>
145
+ <SwipeableCard
146
+ key={plan.id}
147
+ leftActions={[
148
+ {
149
+ id: 'info',
150
+ label: 'More Info',
151
+ onAction: () => console.log('Show plan details'),
152
+ color: 'blue'
153
+ }
154
+ ]}
155
+ rightActions={[
156
+ {
157
+ id: 'select',
158
+ label: 'Quick Select',
159
+ onAction: () => handlePlanSelect(plan.id),
160
+ color: 'green',
161
+ icon: ArrowRight
162
+ }
163
+ ]}
164
+ threshold={60}
165
+ hapticFeedback={true}
166
+ showActionLabels={true}
167
+ >
168
+ <Card className={`p-6 relative ${plan.popular ? 'ring-2 ring-blue-500' : ''} ${selectedPlan === plan.id ? 'bg-blue-50 border-blue-200' : ''}`}>
169
+ {plan.popular && (
170
+ <div className="absolute -top-3 left-1/2 transform -translate-x-1/2">
171
+ <span className="bg-blue-500 text-white px-3 py-1 rounded-full text-sm font-medium flex items-center gap-1">
172
+ <Star className="w-3 h-3" />
173
+ Most Popular
174
+ </span>
175
+ </div>
176
+ )}
177
+ <h3 className="text-xl font-bold mb-2">{plan.name}</h3>
178
+ <div className="text-3xl font-bold mb-4">
179
+ {formatCurrency(plan.price)}
180
+ <span className="text-sm font-normal">/{plan.interval}</span>
66
181
  </div>
67
- )}
68
- <h3 className="text-xl font-bold mb-2">{plan.name}</h3>
69
- <div className="text-3xl font-bold mb-4">
70
- {formatCurrency(plan.price)}
71
- <span className="text-sm font-normal">/{plan.interval}</span>
72
- </div>
73
- <ul className="mb-6 space-y-2">
74
- {plan.features.map((feature, index) => (
75
- <li key={index} className="flex items-center">
76
- <span className="text-green-500 mr-2">✓</span>
77
- {feature}
78
- </li>
79
- ))}
80
- </ul>
81
- <Button
82
- onClick={() => handlePlanSelect(plan.id)}
83
- disabled={loading}
84
- className="w-full"
85
- variant={plan.popular ? "default" : "outline"}
86
- >
87
- {loading ? 'Processing...' : 'Select Plan'}
88
- </Button>
89
- </Card>
182
+ <ul className="mb-6 space-y-2">
183
+ {plan.features.map((feature, index) => (
184
+ <li key={index} className="flex items-center">
185
+ <Check className="text-green-500 mr-2 w-4 h-4" />
186
+ {feature}
187
+ </li>
188
+ ))}
189
+ </ul>
190
+ <Button
191
+ onClick={() => handlePlanSelect(plan.id)}
192
+ disabled={loading}
193
+ className="w-full"
194
+ variant={selectedPlan === plan.id ? "default" : plan.popular ? "default" : "outline"}
195
+ size="lg"
196
+ >
197
+ {loading ? 'Processing...' : selectedPlan === plan.id ? 'Selected' : 'Select Plan'}
198
+ </Button>
199
+ <p className="text-xs text-center text-gray-500 mt-2">
200
+ Swipe left for details • Swipe right to select
201
+ </p>
202
+ </Card>
203
+ </SwipeableCard>
90
204
  ))}
91
- </div>
205
+ </ResponsiveGrid>
206
+ </NetworkAwareContent>
92
207
 
93
- {/* Payment Form */}
94
- <Card className="p-6 max-w-md mx-auto">
95
- <h2 className="text-2xl font-bold mb-6">Payment Details</h2>
96
- <div className="space-y-4">
97
- <div>
98
- <label className="block text-sm font-medium mb-2">Card Number</label>
99
- <input
100
- type="text"
101
- placeholder="1234 5678 9012 3456"
102
- className="w-full p-3 border rounded-lg"
103
- disabled
104
- />
105
- </div>
106
- <div className="grid grid-cols-2 gap-4">
107
- <div>
108
- <label className="block text-sm font-medium mb-2">Expiry Date</label>
109
- <input
110
- type="text"
111
- placeholder="MM/YY"
112
- className="w-full p-3 border rounded-lg"
113
- disabled
114
- />
115
- </div>
116
- <div>
117
- <label className="block text-sm font-medium mb-2">CVC</label>
118
- <input
119
- type="text"
120
- placeholder="123"
121
- className="w-full p-3 border rounded-lg"
122
- disabled
123
- />
124
- </div>
125
- </div>
126
- <Button
127
- onClick={handlePayment}
128
- disabled={loading}
129
- className="w-full"
208
+ {/* Mobile-Optimized Payment Form */}
209
+ <SwipeableCard
210
+ leftActions={[
211
+ {
212
+ id: 'back',
213
+ label: 'Back',
214
+ onAction: () => window.history.back(),
215
+ color: 'gray',
216
+ icon: ArrowLeft
217
+ }
218
+ ]}
219
+ rightActions={[
220
+ {
221
+ id: 'pay',
222
+ label: 'Pay Now',
223
+ onAction: handlePayment,
224
+ color: 'green',
225
+ icon: CreditCard
226
+ }
227
+ ]}
228
+ threshold={60}
229
+ hapticFeedback={true}
230
+ showActionLabels={true}
231
+ className="max-w-md mx-auto"
130
232
  >
131
- {loading ? 'Processing...' : 'Complete Payment'}
132
- </Button>
133
- <p className="text-sm text-gray-600 text-center">
134
- This is a demo. Payment processing requires Stripe integration.
135
- </p>
136
- </div>
137
- </Card>
138
- </div>
139
- </div>
233
+ <Card className="p-6">
234
+ <div className="flex items-center gap-3 mb-6">
235
+ <div className="p-2 bg-blue-100 rounded-full">
236
+ <CreditCard className="w-5 h-5 text-blue-600" />
237
+ </div>
238
+ <h2 className="text-2xl font-bold">Payment Details</h2>
239
+ </div>
240
+
241
+ <MobileForm className="space-y-4">
242
+ <div>
243
+ <label className="block text-sm font-medium mb-2">Card Number</label>
244
+ <TouchInput
245
+ type="text"
246
+ placeholder="1234 5678 9012 3456"
247
+ disabled
248
+ mobileOptimized={true}
249
+ hapticFeedback={true}
250
+ />
251
+ </div>
252
+ <ResponsiveGrid columns={{ base: 2 }} gap="md">
253
+ <div>
254
+ <label className="block text-sm font-medium mb-2">Expiry Date</label>
255
+ <TouchInput
256
+ type="text"
257
+ placeholder="MM/YY"
258
+ disabled
259
+ mobileOptimized={true}
260
+ hapticFeedback={true}
261
+ />
262
+ </div>
263
+ <div>
264
+ <label className="block text-sm font-medium mb-2">CVC</label>
265
+ <TouchInput
266
+ type="text"
267
+ placeholder="123"
268
+ disabled
269
+ mobileOptimized={true}
270
+ hapticFeedback={true}
271
+ />
272
+ </div>
273
+ </ResponsiveGrid>
274
+
275
+ {selectedPlan && (
276
+ <div className="bg-blue-50 p-4 rounded-lg border border-blue-200">
277
+ <div className="flex items-center justify-between">
278
+ <span className="font-medium">Selected Plan:</span>
279
+ <span className="text-blue-600 font-bold">
280
+ {plans.find(p => p.id === selectedPlan)?.name}
281
+ </span>
282
+ </div>
283
+ </div>
284
+ )}
285
+
286
+ <Button
287
+ onClick={handlePayment}
288
+ disabled={loading || !isOnline}
289
+ className="w-full"
290
+ size="lg"
291
+ >
292
+ {loading ? 'Processing...' : !isOnline ? 'Offline - Cannot Process' : 'Complete Payment'}
293
+ </Button>
294
+
295
+ <div className="space-y-2 text-sm text-gray-600 text-center">
296
+ <p>This is a demo. Payment processing requires Stripe integration.</p>
297
+ <p className="text-xs">Swipe left to go back • Swipe right to pay now</p>
298
+ </div>
299
+ </MobileForm>
300
+ </Card>
301
+ </SwipeableCard>
302
+ </MobileContainer>
303
+ </div>
304
+ </OfflineWrapper>
305
+ </PageTransition>
140
306
  );
141
307
  }
142
308
 
@@ -40,3 +40,132 @@
40
40
  @apply bg-background text-foreground;
41
41
  }
42
42
  }
43
+
44
+ /* Mobile-first optimizations */
45
+ @media (max-width: 768px) {
46
+ .mobile-optimized {
47
+ touch-action: manipulation;
48
+ -webkit-tap-highlight-color: transparent;
49
+ }
50
+
51
+ /* Better touch targets */
52
+ button,
53
+ a,
54
+ input,
55
+ select,
56
+ textarea {
57
+ min-height: 44px;
58
+ min-width: 44px;
59
+ }
60
+
61
+ /* Smooth scrolling for mobile */
62
+ html {
63
+ scroll-behavior: smooth;
64
+ -webkit-overflow-scrolling: touch;
65
+ }
66
+ }
67
+
68
+ /* Animated moving banner */
69
+ @keyframes marquee {
70
+ 0% {
71
+ transform: translate3d(100%, 0, 0);
72
+ }
73
+ 100% {
74
+ transform: translate3d(-100%, 0, 0);
75
+ }
76
+ }
77
+
78
+ .animate-marquee {
79
+ animation: marquee 15s linear infinite;
80
+ }
81
+
82
+ /* Network-aware styles */
83
+ @media (prefers-reduced-data: reduce) {
84
+ .high-bandwidth-content {
85
+ display: none;
86
+ }
87
+ }
88
+
89
+ /* Reduced motion preferences */
90
+ @media (prefers-reduced-motion: reduce) {
91
+ *,
92
+ *::before,
93
+ *::after {
94
+ animation-duration: 0.01ms !important;
95
+ animation-iteration-count: 1 !important;
96
+ transition-duration: 0.01ms !important;
97
+ }
98
+
99
+ .animate-marquee {
100
+ animation: none;
101
+ }
102
+ }
103
+
104
+ /* Hamburger menu animations */
105
+ .hamburger-line {
106
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
107
+ transform-origin: center;
108
+ }
109
+
110
+ .hamburger-open .hamburger-line:nth-child(1) {
111
+ transform: rotate(45deg) translate(6px, 6px);
112
+ }
113
+
114
+ .hamburger-open .hamburger-line:nth-child(2) {
115
+ opacity: 0;
116
+ }
117
+
118
+ .hamburger-open .hamburger-line:nth-child(3) {
119
+ transform: rotate(-45deg) translate(6px, -6px);
120
+ }
121
+
122
+ /* Custom animations for mobile interactions */
123
+ @keyframes haptic-feedback {
124
+ 0% { transform: scale(1); }
125
+ 50% { transform: scale(0.95); }
126
+ 100% { transform: scale(1); }
127
+ }
128
+
129
+ .haptic-feedback {
130
+ animation: haptic-feedback 0.1s ease-in-out;
131
+ }
132
+
133
+ /* Offline indicator styles */
134
+ .offline-indicator {
135
+ position: fixed;
136
+ top: 0;
137
+ left: 0;
138
+ right: 0;
139
+ background: #f59e0b;
140
+ color: white;
141
+ text-align: center;
142
+ padding: 8px;
143
+ font-size: 14px;
144
+ z-index: 9999;
145
+ }
146
+
147
+ /* Loading states */
148
+ .loading-skeleton {
149
+ background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
150
+ background-size: 200% 100%;
151
+ animation: loading 1.5s infinite;
152
+ }
153
+
154
+ @keyframes loading {
155
+ 0% {
156
+ background-position: 200% 0;
157
+ }
158
+ 100% {
159
+ background-position: -200% 0;
160
+ }
161
+ }
162
+
163
+ /* Progressive image loading */
164
+ .progressive-image {
165
+ filter: blur(5px);
166
+ transition: filter 0.3s;
167
+ }
168
+
169
+ .progressive-image.loaded {
170
+ filter: blur(0);
171
+ }