@nitrostack/cli 1.0.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 (100) hide show
  1. package/README.md +131 -0
  2. package/dist/commands/build.d.ts +6 -0
  3. package/dist/commands/build.d.ts.map +1 -0
  4. package/dist/commands/build.js +185 -0
  5. package/dist/commands/dev.d.ts +7 -0
  6. package/dist/commands/dev.d.ts.map +1 -0
  7. package/dist/commands/dev.js +365 -0
  8. package/dist/commands/generate-types.d.ts +8 -0
  9. package/dist/commands/generate-types.d.ts.map +1 -0
  10. package/dist/commands/generate-types.js +219 -0
  11. package/dist/commands/generate.d.ts +12 -0
  12. package/dist/commands/generate.d.ts.map +1 -0
  13. package/dist/commands/generate.js +375 -0
  14. package/dist/commands/init.d.ts +7 -0
  15. package/dist/commands/init.d.ts.map +1 -0
  16. package/dist/commands/init.js +324 -0
  17. package/dist/commands/install.d.ts +10 -0
  18. package/dist/commands/install.d.ts.map +1 -0
  19. package/dist/commands/install.js +80 -0
  20. package/dist/commands/start.d.ts +6 -0
  21. package/dist/commands/start.d.ts.map +1 -0
  22. package/dist/commands/start.js +70 -0
  23. package/dist/commands/upgrade.d.ts +10 -0
  24. package/dist/commands/upgrade.d.ts.map +1 -0
  25. package/dist/commands/upgrade.js +214 -0
  26. package/dist/index.d.ts +11 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +94 -0
  29. package/dist/mcp-dev-wrapper.d.ts +15 -0
  30. package/dist/mcp-dev-wrapper.d.ts.map +1 -0
  31. package/dist/mcp-dev-wrapper.js +187 -0
  32. package/dist/ui/branding.d.ts +31 -0
  33. package/dist/ui/branding.d.ts.map +1 -0
  34. package/dist/ui/branding.js +136 -0
  35. package/package.json +69 -0
  36. package/templates/typescript-oauth/.env.example +27 -0
  37. package/templates/typescript-oauth/OAUTH_SETUP.md +592 -0
  38. package/templates/typescript-oauth/README.md +263 -0
  39. package/templates/typescript-oauth/package.json +29 -0
  40. package/templates/typescript-oauth/src/app.module.ts +92 -0
  41. package/templates/typescript-oauth/src/guards/oauth.guard.ts +126 -0
  42. package/templates/typescript-oauth/src/health/system.health.ts +55 -0
  43. package/templates/typescript-oauth/src/index.ts +63 -0
  44. package/templates/typescript-oauth/src/modules/flights/booking.tools.ts +323 -0
  45. package/templates/typescript-oauth/src/modules/flights/flights.module.ts +14 -0
  46. package/templates/typescript-oauth/src/modules/flights/flights.prompts.ts +228 -0
  47. package/templates/typescript-oauth/src/modules/flights/flights.resources.ts +215 -0
  48. package/templates/typescript-oauth/src/modules/flights/flights.tools.ts +457 -0
  49. package/templates/typescript-oauth/src/services/duffel.service.ts +285 -0
  50. package/templates/typescript-oauth/src/widgets/app/airport-search/page.tsx +270 -0
  51. package/templates/typescript-oauth/src/widgets/app/flight-details/page.tsx +261 -0
  52. package/templates/typescript-oauth/src/widgets/app/flight-search-results/page.tsx +378 -0
  53. package/templates/typescript-oauth/src/widgets/app/globals.css +167 -0
  54. package/templates/typescript-oauth/src/widgets/app/layout.tsx +18 -0
  55. package/templates/typescript-oauth/src/widgets/app/order-cancellation/page.tsx +207 -0
  56. package/templates/typescript-oauth/src/widgets/app/order-summary/page.tsx +245 -0
  57. package/templates/typescript-oauth/src/widgets/app/payment-confirmation/page.tsx +152 -0
  58. package/templates/typescript-oauth/src/widgets/app/seat-selection/page.tsx +486 -0
  59. package/templates/typescript-oauth/src/widgets/next-env.d.ts +5 -0
  60. package/templates/typescript-oauth/src/widgets/next.config.js +45 -0
  61. package/templates/typescript-oauth/src/widgets/package-lock.json +4493 -0
  62. package/templates/typescript-oauth/src/widgets/package.json +24 -0
  63. package/templates/typescript-oauth/src/widgets/tsconfig.json +28 -0
  64. package/templates/typescript-oauth/src/widgets/widget-manifest.json +395 -0
  65. package/templates/typescript-oauth/tsconfig.json +23 -0
  66. package/templates/typescript-pizzaz/README.md +252 -0
  67. package/templates/typescript-pizzaz/package.json +34 -0
  68. package/templates/typescript-pizzaz/src/app.module.ts +28 -0
  69. package/templates/typescript-pizzaz/src/index.ts +30 -0
  70. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.data.ts +106 -0
  71. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.module.ts +11 -0
  72. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.service.ts +60 -0
  73. package/templates/typescript-pizzaz/src/modules/pizzaz/pizzaz.tools.ts +197 -0
  74. package/templates/typescript-pizzaz/src/widgets/app/layout.tsx +18 -0
  75. package/templates/typescript-pizzaz/src/widgets/app/pizza-list/page.tsx +272 -0
  76. package/templates/typescript-pizzaz/src/widgets/app/pizza-map/page.tsx +216 -0
  77. package/templates/typescript-pizzaz/src/widgets/app/pizza-shop/page.tsx +374 -0
  78. package/templates/typescript-pizzaz/src/widgets/components/CompactShopCard.tsx +144 -0
  79. package/templates/typescript-pizzaz/src/widgets/components/PizzaCard.tsx +191 -0
  80. package/templates/typescript-pizzaz/src/widgets/next.config.js +45 -0
  81. package/templates/typescript-pizzaz/src/widgets/package.json +30 -0
  82. package/templates/typescript-pizzaz/src/widgets/tsconfig.json +28 -0
  83. package/templates/typescript-pizzaz/src/widgets/widget-manifest.json +253 -0
  84. package/templates/typescript-pizzaz/tsconfig.json +30 -0
  85. package/templates/typescript-starter/README.md +320 -0
  86. package/templates/typescript-starter/package.json +25 -0
  87. package/templates/typescript-starter/src/app.module.ts +34 -0
  88. package/templates/typescript-starter/src/health/system.health.ts +55 -0
  89. package/templates/typescript-starter/src/index.ts +29 -0
  90. package/templates/typescript-starter/src/modules/calculator/calculator.module.ts +12 -0
  91. package/templates/typescript-starter/src/modules/calculator/calculator.prompts.ts +73 -0
  92. package/templates/typescript-starter/src/modules/calculator/calculator.resources.ts +59 -0
  93. package/templates/typescript-starter/src/modules/calculator/calculator.tools.ts +166 -0
  94. package/templates/typescript-starter/src/widgets/app/calculator-result/page.tsx +180 -0
  95. package/templates/typescript-starter/src/widgets/app/layout.tsx +18 -0
  96. package/templates/typescript-starter/src/widgets/next.config.js +45 -0
  97. package/templates/typescript-starter/src/widgets/package.json +24 -0
  98. package/templates/typescript-starter/src/widgets/tsconfig.json +28 -0
  99. package/templates/typescript-starter/src/widgets/widget-manifest.json +48 -0
  100. package/templates/typescript-starter/tsconfig.json +23 -0
@@ -0,0 +1,167 @@
1
+ /* Nitrocloud Widget Styles - Professional Theme */
2
+
3
+ :root {
4
+ /* Professional Color Palette */
5
+ --primary: #3B82F6;
6
+ --primary-hover: #2563EB;
7
+ --secondary: #6B7280;
8
+ --secondary-hover: #4B5563;
9
+
10
+ --success: #10B981;
11
+ --warning: #F59E0B;
12
+ --error: #EF4444;
13
+ --info: #3B82F6;
14
+
15
+ /* Light Theme */
16
+ --bg-primary: #FFFFFF;
17
+ --bg-secondary: #F9FAFB;
18
+ --bg-tertiary: #F3F4F6;
19
+ --bg-elevated: #FFFFFF;
20
+
21
+ --text-primary: #111827;
22
+ --text-secondary: #6B7280;
23
+ --text-muted: #9CA3AF;
24
+
25
+ --border-color: #E5E7EB;
26
+ --border-hover: #D1D5DB;
27
+
28
+ --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
29
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
30
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
31
+ }
32
+
33
+ .dark {
34
+ /* Dark Theme */
35
+ --bg-primary: #111827;
36
+ --bg-secondary: #1F2937;
37
+ --bg-tertiary: #374151;
38
+ --bg-elevated: #1F2937;
39
+
40
+ --text-primary: #F9FAFB;
41
+ --text-secondary: #D1D5DB;
42
+ --text-muted: #9CA3AF;
43
+
44
+ --border-color: #374151;
45
+ --border-hover: #4B5563;
46
+
47
+ --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
48
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4);
49
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.5);
50
+ }
51
+
52
+ /* Reset */
53
+ * {
54
+ box-sizing: border-box;
55
+ margin: 0;
56
+ padding: 0;
57
+ }
58
+
59
+ body {
60
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
61
+ -webkit-font-smoothing: antialiased;
62
+ -moz-osx-font-smoothing: grayscale;
63
+ }
64
+
65
+ /* Card Styles */
66
+ .card {
67
+ background: var(--bg-primary);
68
+ border: 1px solid var(--border-color);
69
+ border-radius: 8px;
70
+ padding: 16px;
71
+ transition: all 0.2s ease;
72
+ box-shadow: var(--shadow-sm);
73
+ }
74
+
75
+ .card:hover {
76
+ border-color: var(--border-hover);
77
+ box-shadow: var(--shadow-md);
78
+ }
79
+
80
+ /* Button Styles */
81
+ .btn-primary {
82
+ background: var(--primary);
83
+ color: white;
84
+ border: none;
85
+ padding: 10px 20px;
86
+ border-radius: 6px;
87
+ font-weight: 600;
88
+ cursor: pointer;
89
+ transition: all 0.2s ease;
90
+ font-size: 14px;
91
+ }
92
+
93
+ .btn-primary:hover {
94
+ background: var(--primary-hover);
95
+ box-shadow: var(--shadow-md);
96
+ }
97
+
98
+ .btn-secondary {
99
+ background: var(--bg-secondary);
100
+ color: var(--text-primary);
101
+ border: 1px solid var(--border-color);
102
+ padding: 10px 20px;
103
+ border-radius: 6px;
104
+ font-weight: 600;
105
+ cursor: pointer;
106
+ transition: all 0.2s ease;
107
+ font-size: 14px;
108
+ }
109
+
110
+ .btn-secondary:hover {
111
+ background: var(--bg-tertiary);
112
+ border-color: var(--border-hover);
113
+ }
114
+
115
+ /* Badge Styles */
116
+ .badge {
117
+ display: inline-flex;
118
+ align-items: center;
119
+ padding: 4px 12px;
120
+ border-radius: 6px;
121
+ font-size: 12px;
122
+ font-weight: 600;
123
+ }
124
+
125
+ .badge-success {
126
+ background: rgba(16, 185, 129, 0.1);
127
+ color: var(--success);
128
+ border: 1px solid rgba(16, 185, 129, 0.2);
129
+ }
130
+
131
+ .badge-warning {
132
+ background: rgba(245, 158, 11, 0.1);
133
+ color: var(--warning);
134
+ border: 1px solid rgba(245, 158, 11, 0.2);
135
+ }
136
+
137
+ .badge-error {
138
+ background: rgba(239, 68, 68, 0.1);
139
+ color: var(--error);
140
+ border: 1px solid rgba(239, 68, 68, 0.2);
141
+ }
142
+
143
+ .badge-info {
144
+ background: rgba(59, 130, 246, 0.1);
145
+ color: var(--info);
146
+ border: 1px solid rgba(59, 130, 246, 0.2);
147
+ }
148
+
149
+ .dark .badge-success {
150
+ background: rgba(16, 185, 129, 0.2);
151
+ color: #6EE7B7;
152
+ }
153
+
154
+ .dark .badge-warning {
155
+ background: rgba(245, 158, 11, 0.2);
156
+ color: #FCD34D;
157
+ }
158
+
159
+ .dark .badge-error {
160
+ background: rgba(239, 68, 68, 0.2);
161
+ color: #FCA5A5;
162
+ }
163
+
164
+ .dark .badge-info {
165
+ background: rgba(59, 130, 246, 0.2);
166
+ color: #93C5FD;
167
+ }
@@ -0,0 +1,18 @@
1
+ 'use client';
2
+
3
+ import { WidgetLayout } from '@nitrostack/widgets';
4
+ import './globals.css';
5
+
6
+ export default function RootLayout({
7
+ children,
8
+ }: {
9
+ children: React.ReactNode;
10
+ }) {
11
+ return (
12
+ <html lang="en">
13
+ <body style={{ margin: 0, padding: 0, fontFamily: 'system-ui, sans-serif' }}>
14
+ <WidgetLayout>{children}</WidgetLayout>
15
+ </body>
16
+ </html>
17
+ );
18
+ }
@@ -0,0 +1,207 @@
1
+ 'use client';
2
+
3
+ import { useWidgetSDK, useTheme } from '@nitrostack/widgets';
4
+
5
+ /**
6
+ * Order Cancellation Widget - Cancellation confirmation with refund info
7
+ */
8
+
9
+ interface CancellationData {
10
+ orderId: string;
11
+ cancellationId: string;
12
+ status: string;
13
+ refundAmount?: string;
14
+ refundCurrency?: string;
15
+ confirmedAt: string;
16
+ message: string;
17
+ }
18
+
19
+ export default function OrderCancellation() {
20
+ const { getToolOutput } = useWidgetSDK();
21
+ const theme = useTheme();
22
+ const data = getToolOutput<CancellationData>();
23
+
24
+ const isDark = theme === 'dark';
25
+
26
+ const formatDateTime = (isoString: string) => {
27
+ return new Date(isoString).toLocaleString('en-US', {
28
+ month: 'long',
29
+ day: 'numeric',
30
+ year: 'numeric',
31
+ hour: '2-digit',
32
+ minute: '2-digit'
33
+ });
34
+ };
35
+
36
+ if (!data) {
37
+ return <div style={{ padding: '24px', textAlign: 'center' }}>Loading...</div>;
38
+ }
39
+
40
+ const hasRefund = data.refundAmount && parseFloat(data.refundAmount) > 0;
41
+
42
+ return (
43
+ <div className={isDark ? 'dark' : ''} style={{
44
+ padding: '24px',
45
+ background: isDark ? '#020617' : '#FFFFFF',
46
+ color: isDark ? '#F8FAFC' : '#020617',
47
+ minHeight: '300px',
48
+ display: 'flex',
49
+ alignItems: 'center',
50
+ justifyContent: 'center'
51
+ }}>
52
+ <div style={{ maxWidth: '550px', width: '100%' }}>
53
+ {/* Icon */}
54
+ <div style={{
55
+ width: '100px',
56
+ height: '100px',
57
+ margin: '0 auto 24px',
58
+ background: hasRefund
59
+ ? 'linear-gradient(135deg, #F59E0B 0%, #D97706 100%)'
60
+ : 'linear-gradient(135deg, #EF4444 0%, #DC2626 100%)',
61
+ borderRadius: '50%',
62
+ display: 'flex',
63
+ alignItems: 'center',
64
+ justifyContent: 'center',
65
+ boxShadow: hasRefund
66
+ ? '0 8px 24px rgba(245, 158, 11, 0.3)'
67
+ : '0 8px 24px rgba(239, 68, 68, 0.3)'
68
+ }}>
69
+ <div style={{ fontSize: '48px', color: 'white' }}>
70
+ {hasRefund ? '💰' : '✗'}
71
+ </div>
72
+ </div>
73
+
74
+ {/* Title */}
75
+ <h2 style={{ margin: '0 0 12px 0', fontSize: '24px', fontWeight: 700, textAlign: 'center' }}>
76
+ Booking Cancelled
77
+ </h2>
78
+
79
+ <p style={{ margin: '0 0 24px 0', fontSize: '14px', color: isDark ? '#94A3B8' : '#64748B', lineHeight: '1.6', textAlign: 'center' }}>
80
+ {data.message}
81
+ </p>
82
+
83
+ {/* Cancellation Details */}
84
+ <div style={{
85
+ background: isDark ? '#0F172A' : '#F8FAFC',
86
+ borderRadius: '12px',
87
+ padding: '20px',
88
+ marginBottom: '20px',
89
+ border: `1px solid ${isDark ? '#334155' : '#E2E8F0'}`
90
+ }}>
91
+ <div style={{ display: 'grid', gap: '16px' }}>
92
+ {/* Order ID */}
93
+ <div>
94
+ <div style={{ fontSize: '11px', color: isDark ? '#94A3B8' : '#64748B', marginBottom: '6px', textTransform: 'uppercase', letterSpacing: '0.5px' }}>
95
+ Order ID
96
+ </div>
97
+ <div style={{ fontSize: '14px', fontWeight: 600, fontFamily: 'monospace', padding: '10px', background: isDark ? '#020617' : 'white', borderRadius: '6px' }}>
98
+ {data.orderId}
99
+ </div>
100
+ </div>
101
+
102
+ {/* Cancellation ID */}
103
+ <div>
104
+ <div style={{ fontSize: '11px', color: isDark ? '#94A3B8' : '#64748B', marginBottom: '6px', textTransform: 'uppercase', letterSpacing: '0.5px' }}>
105
+ Cancellation Reference
106
+ </div>
107
+ <div style={{ fontSize: '14px', fontWeight: 600, fontFamily: 'monospace', padding: '10px', background: isDark ? '#020617' : 'white', borderRadius: '6px' }}>
108
+ {data.cancellationId}
109
+ </div>
110
+ </div>
111
+
112
+ {/* Cancelled On */}
113
+ <div>
114
+ <div style={{ fontSize: '11px', color: isDark ? '#94A3B8' : '#64748B', marginBottom: '6px', textTransform: 'uppercase', letterSpacing: '0.5px' }}>
115
+ Cancelled On
116
+ </div>
117
+ <div style={{ fontSize: '13px', fontWeight: 600, padding: '10px', background: isDark ? '#020617' : 'white', borderRadius: '6px' }}>
118
+ {formatDateTime(data.confirmedAt)}
119
+ </div>
120
+ </div>
121
+
122
+ {/* Refund Information */}
123
+ {hasRefund ? (
124
+ <div style={{
125
+ marginTop: '8px',
126
+ padding: '16px',
127
+ background: '#FEF3C7',
128
+ borderRadius: '8px',
129
+ border: '1px solid #F59E0B'
130
+ }}>
131
+ <div style={{ display: 'flex', alignItems: 'center', gap: '10px', marginBottom: '10px' }}>
132
+ <div style={{ fontSize: '28px' }}>💰</div>
133
+ <div>
134
+ <div style={{ fontSize: '12px', color: '#92400E', fontWeight: 600, marginBottom: '4px' }}>
135
+ Refund Amount
136
+ </div>
137
+ <div style={{ fontSize: '22px', fontWeight: 700, color: '#78350F' }}>
138
+ {data.refundCurrency} {parseFloat(data.refundAmount!).toFixed(2)}
139
+ </div>
140
+ </div>
141
+ </div>
142
+ <div style={{ fontSize: '11px', color: '#92400E', lineHeight: '1.5' }}>
143
+ Refund will be processed to your original payment method within 5-10 business days.
144
+ </div>
145
+ </div>
146
+ ) : (
147
+ <div style={{
148
+ marginTop: '8px',
149
+ padding: '16px',
150
+ background: '#FEE2E2',
151
+ borderRadius: '8px',
152
+ border: '1px solid #EF4444'
153
+ }}>
154
+ <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
155
+ <div style={{ fontSize: '20px' }}>ℹ️</div>
156
+ <div style={{ fontSize: '12px', color: '#991B1B', lineHeight: '1.5' }}>
157
+ <strong>No Refund Available:</strong> This booking was non-refundable or outside the cancellation window.
158
+ </div>
159
+ </div>
160
+ </div>
161
+ )}
162
+ </div>
163
+ </div>
164
+
165
+ {/* Status Badge */}
166
+ <div style={{ textAlign: 'center', marginBottom: '20px' }}>
167
+ <div className="badge badge-error" style={{ padding: '10px 20px', fontSize: '12px', textTransform: 'uppercase', letterSpacing: '0.5px' }}>
168
+ ✗ {data.status}
169
+ </div>
170
+ </div>
171
+
172
+ {/* Action Buttons */}
173
+ <div style={{ display: 'grid', gap: '10px' }}>
174
+ <button className="btn-primary" style={{ width: '100%' }}>
175
+ 🔍 Search New Flights
176
+ </button>
177
+ <button className="btn-secondary" style={{ width: '100%' }}>
178
+ 📧 Email Confirmation
179
+ </button>
180
+ <button className="btn-secondary" style={{ width: '100%' }}>
181
+ 📄 Download Receipt
182
+ </button>
183
+ </div>
184
+
185
+ {/* Help Section */}
186
+ <div style={{
187
+ marginTop: '20px',
188
+ padding: '16px',
189
+ background: isDark ? '#0F172A' : '#F8FAFC',
190
+ borderRadius: '8px',
191
+ border: `1px solid ${isDark ? '#334155' : '#E2E8F0'}`
192
+ }}>
193
+ <div style={{ fontSize: '12px', fontWeight: 600, marginBottom: '8px', display: 'flex', alignItems: 'center', gap: '6px' }}>
194
+ <span>💬</span>
195
+ <span>Need Help?</span>
196
+ </div>
197
+ <div style={{ fontSize: '11px', color: isDark ? '#94A3B8' : '#64748B', lineHeight: '1.5', marginBottom: '10px' }}>
198
+ Questions about this cancellation? Contact our support team 24/7.
199
+ </div>
200
+ <button className="btn-primary" style={{ padding: '8px 16px', fontSize: '12px' }}>
201
+ Contact Support
202
+ </button>
203
+ </div>
204
+ </div>
205
+ </div>
206
+ );
207
+ }
@@ -0,0 +1,245 @@
1
+ 'use client';
2
+
3
+ import { useWidgetSDK, useTheme } from '@nitrostack/widgets';
4
+
5
+ /**
6
+ * Order Summary Widget - Compact booking confirmation
7
+ */
8
+
9
+ interface OrderData {
10
+ orderId: string;
11
+ status: string;
12
+ bookingReference?: string;
13
+ totalAmount: string;
14
+ totalCurrency: string;
15
+ createdAt?: string;
16
+ expiresAt?: string;
17
+ passengers: Array<{ id: string; name: string; type: string; email?: string }>;
18
+ slices: Array<{
19
+ origin: { code: string; city?: string };
20
+ destination: { code: string; city?: string };
21
+ segments?: Array<{ airline: string; flightNumber: string }>;
22
+ }>;
23
+ message?: string;
24
+ }
25
+
26
+ export default function OrderSummary() {
27
+ const { getToolOutput } = useWidgetSDK();
28
+ const theme = useTheme();
29
+ const data = getToolOutput<OrderData>();
30
+
31
+ const isDark = theme === 'dark';
32
+
33
+ const formatDateTime = (isoString: string) => {
34
+ return new Date(isoString).toLocaleString('en-US', {
35
+ month: 'short',
36
+ day: 'numeric',
37
+ year: 'numeric',
38
+ hour: '2-digit',
39
+ minute: '2-digit'
40
+ });
41
+ };
42
+
43
+ const getStatusIcon = (status: string) => {
44
+ return { 'confirmed': '🎉', 'held': '⏱️', 'cancelled': '✗', 'pending': '⋯' }[status.toLowerCase()] || '📋';
45
+ };
46
+
47
+ if (!data) {
48
+ return <div style={{ padding: '24px', textAlign: 'center' }}>Loading...</div>;
49
+ }
50
+
51
+ return (
52
+ <div className={isDark ? 'dark' : ''} style={{
53
+ padding: '16px',
54
+ background: isDark ? '#020617' : '#ffffff',
55
+ color: isDark ? '#F8FAFC' : '#020617'
56
+ }}>
57
+ {/* Header */}
58
+ <div className="card" style={{ marginBottom: '16px', textAlign: 'center' }}>
59
+ <div style={{ fontSize: '40px', marginBottom: '12px' }}>
60
+ {getStatusIcon(data.status)}
61
+ </div>
62
+ <h2 style={{ margin: 0, fontSize: '20px', fontWeight: 700, marginBottom: '8px' }}>
63
+ {data.status === 'confirmed' ? 'Booking Confirmed!' :
64
+ data.status === 'held' ? 'Order On Hold' : 'Order Summary'}
65
+ </h2>
66
+
67
+ {data.bookingReference && (
68
+ <div style={{ fontSize: '14px', color: isDark ? '#94A3B8' : '#64748B', marginBottom: '12px' }}>
69
+ Reference: <strong style={{ color: "var(--primary)", fontWeight: 700 }}>{data.bookingReference}</strong>
70
+ </div>
71
+ )}
72
+
73
+ <div className={`badge badge-${data.status === 'confirmed' ? 'success' : data.status === 'held' ? 'warning' : 'info'}`}>
74
+ {data.status.toUpperCase()}
75
+ </div>
76
+
77
+ {data.message && (
78
+ <div style={{
79
+ marginTop: '12px',
80
+ padding: '10px',
81
+ background: isDark ? '#0F172A' : '#0F172A',
82
+ borderRadius: '6px',
83
+ fontSize: '12px'
84
+ }}>
85
+ {data.message}
86
+ </div>
87
+ )}
88
+
89
+ {data.expiresAt && data.status === 'held' && (
90
+ <div style={{
91
+ marginTop: '12px',
92
+ padding: '12px',
93
+ background: '#FEF3C7',
94
+ borderRadius: '8px',
95
+ border: '1px solid #F59E0B'
96
+ }}>
97
+ <div style={{ fontSize: '11px', fontWeight: 600, color: '#92400E', marginBottom: '4px' }}>
98
+ ⏰ Payment Required
99
+ </div>
100
+ <div style={{ fontSize: '10px', color: '#78350F' }}>
101
+ Complete before: <strong>{formatDateTime(data.expiresAt)}</strong>
102
+ </div>
103
+ </div>
104
+ )}
105
+ </div>
106
+
107
+ {/* Order Info */}
108
+ <div className="card" style={{ marginBottom: '12px' }}>
109
+ <h3 style={{ margin: '0 0 12px 0', fontSize: '14px', fontWeight: 600 }}>Order Information</h3>
110
+ <div style={{ display: 'grid', gap: '8px', fontSize: '12px' }}>
111
+ <div style={{ display: 'flex', justifyContent: 'space-between' }}>
112
+ <span style={{ color: isDark ? '#94A3B8' : '#64748B' }}>Order ID:</span>
113
+ <span style={{ fontWeight: 600, fontFamily: 'monospace' }}>{data.orderId}</span>
114
+ </div>
115
+ <div style={{ display: 'flex', justifyContent: 'space-between', paddingTop: '8px', borderTop: `1px solid ${isDark ? '#334155' : '#E2E8F0'}` }}>
116
+ <span style={{ color: isDark ? '#94A3B8' : '#64748B' }}>Total:</span>
117
+ <span style={{ color: 'var(--primary)', fontWeight: 700, fontSize: '16px' }}>
118
+ {data.totalCurrency} {parseFloat(data.totalAmount).toFixed(2)}
119
+ </span>
120
+ </div>
121
+ {data.createdAt && (
122
+ <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: '11px' }}>
123
+ <span style={{ color: isDark ? '#94A3B8' : '#64748B' }}>Created:</span>
124
+ <span>{formatDateTime(data.createdAt)}</span>
125
+ </div>
126
+ )}
127
+ </div>
128
+ </div>
129
+
130
+ {/* Passengers */}
131
+ <div className="card" style={{ marginBottom: '12px' }}>
132
+ <h3 style={{ margin: '0 0 12px 0', fontSize: '14px', fontWeight: 600, display: 'flex', alignItems: 'center', gap: '6px' }}>
133
+ <span>👥</span>
134
+ <span>Passengers ({data.passengers.length})</span>
135
+ </h3>
136
+ <div style={{ display: 'grid', gap: '8px' }}>
137
+ {data.passengers.map((passenger, index) => (
138
+ <div key={passenger.id} style={{
139
+ padding: '12px',
140
+ background: isDark ? '#0F172A' : '#0F172A',
141
+ borderRadius: '8px',
142
+ display: 'flex',
143
+ justifyContent: 'space-between',
144
+ alignItems: 'center'
145
+ }}>
146
+ <div>
147
+ <div style={{ fontWeight: 600, fontSize: '13px', marginBottom: '2px' }}>
148
+ {passenger.name}
149
+ </div>
150
+ <div style={{ fontSize: '11px', color: isDark ? '#94A3B8' : '#64748B' }}>
151
+ {passenger.type}
152
+ </div>
153
+ {passenger.email && (
154
+ <div style={{ fontSize: '10px', color: isDark ? '#94A3B8' : '#64748B', marginTop: '2px' }}>
155
+ 📧 {passenger.email}
156
+ </div>
157
+ )}
158
+ </div>
159
+ <div style={{
160
+ background: 'var(--primary)',
161
+ color: 'white',
162
+ width: '28px',
163
+ height: '28px',
164
+ borderRadius: '50%',
165
+ display: 'flex',
166
+ alignItems: 'center',
167
+ justifyContent: 'center',
168
+
169
+ fontWeight: 700,
170
+ fontSize: '12px'
171
+ }}>
172
+ {index + 1}
173
+ </div>
174
+ </div>
175
+ ))}
176
+ </div>
177
+ </div>
178
+
179
+ {/* Flight Itinerary */}
180
+ <div className="card">
181
+ <h3 style={{ margin: '0 0 12px 0', fontSize: '14px', fontWeight: 600, display: 'flex', alignItems: 'center', gap: '6px' }}>
182
+ <span>✈️</span>
183
+ <span>Flight Itinerary</span>
184
+ </h3>
185
+ <div style={{ display: 'grid', gap: '12px' }}>
186
+ {data.slices.map((slice, index) => (
187
+ <div key={index} style={{
188
+ padding: '12px',
189
+ background: isDark ? '#0F172A' : '#F8FAFC',
190
+ borderRadius: '8px'
191
+ }}>
192
+ <div style={{ fontSize: '12px', fontWeight: 600, color: '#3B9FFF', marginBottom: '10px' }}>
193
+ {index === 0 ? 'Outbound' : 'Return'} Flight
194
+ </div>
195
+ <div style={{
196
+ display: 'grid',
197
+ gridTemplateColumns: '1fr auto 1fr',
198
+ gap: '12px',
199
+ alignItems: 'center'
200
+ }}>
201
+ <div>
202
+ <div style={{ fontSize: '16px', fontWeight: 700 }}>
203
+ {slice.origin.code}
204
+ </div>
205
+ {slice.origin.city && (
206
+ <div style={{ fontSize: '11px', color: isDark ? '#94A3B8' : '#64748B', marginTop: '2px' }}>
207
+ {slice.origin.city}
208
+ </div>
209
+ )}
210
+ </div>
211
+
212
+ <div style={{
213
+ width: '32px',
214
+ height: '2px',
215
+ background: 'linear-gradient(90deg, #3B9FFF 0%, #2563EB 100%)'
216
+ }} />
217
+
218
+ <div style={{ textAlign: 'right' }}>
219
+ <div style={{ fontSize: '16px', fontWeight: 700 }}>
220
+ {slice.destination.code}
221
+ </div>
222
+ {slice.destination.city && (
223
+ <div style={{ fontSize: '11px', color: isDark ? '#94A3B8' : '#64748B', marginTop: '2px' }}>
224
+ {slice.destination.city}
225
+ </div>
226
+ )}
227
+ </div>
228
+ </div>
229
+
230
+ {slice.segments && slice.segments.length > 0 && (
231
+ <div style={{ marginTop: '10px', paddingTop: '10px', borderTop: `1px solid ${isDark ? '#334155' : '#E2E8F0'}` }}>
232
+ {slice.segments.map((segment, segIndex) => (
233
+ <div key={segIndex} style={{ fontSize: '11px', color: isDark ? '#94A3B8' : '#64748B', marginBottom: '4px' }}>
234
+ {segment.airline} {segment.flightNumber}
235
+ </div>
236
+ ))}
237
+ </div>
238
+ )}
239
+ </div>
240
+ ))}
241
+ </div>
242
+ </div>
243
+ </div>
244
+ );
245
+ }